diff options
174 files changed, 3640 insertions, 832 deletions
@@ -25,4 +25,4 @@ tasks: ninja - clang: | cd wlroots/build-clang - ninja + ninja scan-build diff --git a/.editorconfig b/.editorconfig index b6b6a367..c74fecda 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,10 +5,8 @@ end_of_line = lf insert_final_newline = true charset = utf-8 indent_style = tab -indent_size = 4 trim_trailing_whitespace = true [*.xml] indent_style = space indent_size = 2 -tab_width = 8 diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index 61d2f6e1..335c9de1 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -199,14 +199,20 @@ static bool atomic_crtc_move_cursor(struct wlr_drm_backend *drm, static bool atomic_crtc_set_gamma(struct wlr_drm_backend *drm, struct wlr_drm_crtc *crtc, uint16_t *r, uint16_t *g, uint16_t *b, uint32_t size) { - struct drm_color_lut gamma[size]; - // Fallback to legacy gamma interface when gamma properties are not available // (can happen on older intel gpu's that support gamma but not degamma) - if (crtc->props.gamma_lut == 0) { + // TEMP: This is broken on AMDGPU. Always fallback to legacy until they get + // it fixed. Ref https://bugs.freedesktop.org/show_bug.cgi?id=107459 + if (crtc->props.gamma_lut == 0 || true) { return legacy_iface.crtc_set_gamma(drm, crtc, r, g, b, size); } + struct drm_color_lut *gamma = malloc(size * sizeof(struct drm_color_lut)); + if (gamma == NULL) { + wlr_log(WLR_ERROR, "Failed to allocate gamma table"); + return false; + } + for (uint32_t i = 0; i < size; i++) { gamma[i].red = r[i]; gamma[i].green = g[i]; @@ -218,10 +224,12 @@ static bool atomic_crtc_set_gamma(struct wlr_drm_backend *drm, } if (drmModeCreatePropertyBlob(drm->fd, gamma, - sizeof(struct drm_color_lut) * size, &crtc->gamma_lut)) { + size * sizeof(struct drm_color_lut), &crtc->gamma_lut)) { + free(gamma); wlr_log_errno(WLR_ERROR, "Unable to create property blob"); return false; } + free(gamma); struct atomic atom; atomic_begin(crtc, &atom); diff --git a/backend/drm/backend.c b/backend/drm/backend.c index 5833d46e..1df5cdd1 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -51,7 +51,12 @@ static void backend_destroy(struct wlr_backend *backend) { static struct wlr_renderer *backend_get_renderer( struct wlr_backend *backend) { struct wlr_drm_backend *drm = (struct wlr_drm_backend *)backend; - return drm->renderer.wlr_rend; + + if (drm->parent) { + return drm->parent->renderer.wlr_rend; + } else { + return drm->renderer.wlr_rend; + } } static struct wlr_backend_impl backend_impl = { diff --git a/backend/drm/drm.c b/backend/drm/drm.c index c4674235..e37eba74 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -27,6 +27,23 @@ #include "util/signal.h" bool check_drm_features(struct wlr_drm_backend *drm) { + if (drm->parent) { + uint64_t cap; + if (drmGetCap(drm->fd, DRM_CAP_PRIME, &cap) || + !(cap & DRM_PRIME_CAP_IMPORT)) { + wlr_log(WLR_ERROR, + "PRIME import not supported on secondary GPU"); + return false; + } + + if (drmGetCap(drm->parent->fd, DRM_CAP_PRIME, &cap) || + !(cap & DRM_PRIME_CAP_EXPORT)) { + wlr_log(WLR_ERROR, + "PRIME export not supported on primary GPU"); + return false; + } + } + if (drmSetClientCap(drm->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) { wlr_log(WLR_ERROR, "DRM universal planes unsupported"); return false; @@ -228,30 +245,54 @@ static bool drm_connector_swap_buffers(struct wlr_output *output, return true; } -static void drm_connector_set_gamma(struct wlr_output *output, - uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b) { +static void fill_empty_gamma_table(uint32_t size, + uint16_t *r, uint16_t *g, uint16_t *b) { + for (uint32_t i = 0; i < size; ++i) { + uint16_t val = (uint32_t)0xffff * i / (size - 1); + r[i] = g[i] = b[i] = val; + } +} + +static uint32_t drm_connector_get_gamma_size(struct wlr_output *output) { struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend; - bool ok; if (conn->crtc) { - ok = drm->iface->crtc_set_gamma(drm, conn->crtc, r, g, b, size); - if (ok) { - wlr_output_update_needs_swap(output); - } + return drm->iface->crtc_get_gamma_size(drm, conn->crtc); } + return 0; } -static uint32_t drm_connector_get_gamma_size(struct wlr_output *output) { +static bool drm_connector_set_gamma(struct wlr_output *output, + uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b) { struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend; - if (conn->crtc) { - return drm->iface->crtc_get_gamma_size(drm, conn->crtc); + if (!conn->crtc) { + return false; } - return 0; + uint16_t *reset_table = NULL; + if (size == 0) { + size = drm_connector_get_gamma_size(output); + reset_table = malloc(3 * size * sizeof(uint16_t)); + if (reset_table == NULL) { + wlr_log(WLR_ERROR, "Failed to allocate gamma table"); + return false; + } + r = reset_table; + g = reset_table + size; + b = reset_table + 2 * size; + fill_empty_gamma_table(size, r, g, b); + } + + bool ok = drm->iface->crtc_set_gamma(drm, conn->crtc, r, g, b, size); + if (ok) { + wlr_output_update_needs_swap(output); + } + free(reset_table); + return ok; } static bool drm_connector_export_dmabuf(struct wlr_output *output, @@ -303,7 +344,8 @@ static void drm_connector_start_renderer(struct wlr_drm_connector *conn) { void enable_drm_connector(struct wlr_output *output, bool enable) { struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; - if (conn->state != WLR_DRM_CONN_CONNECTED) { + if (conn->state != WLR_DRM_CONN_CONNECTED + && conn->state != WLR_DRM_CONN_NEEDS_MODESET) { return; } @@ -362,9 +404,11 @@ static void realloc_planes(struct wlr_drm_backend *drm, const uint32_t *crtc_in, struct wlr_drm_plane *new = &drm->type_planes[type][crtc_res[i]]; if (*old != new) { - wlr_log(WLR_DEBUG, "Assigning plane %d -> %d to CRTC %d", + wlr_log(WLR_DEBUG, + "Assigning plane %d -> %d (type %zu) to CRTC %d", *old ? (int)(*old)->id : -1, new ? (int)new->id : -1, + type, c->id); changed_outputs[crtc_res[i]] = true; @@ -378,192 +422,41 @@ static void realloc_planes(struct wlr_drm_backend *drm, const uint32_t *crtc_in, } } -static void realloc_crtcs(struct wlr_drm_backend *drm, - struct wlr_drm_connector *conn, bool *changed_outputs) { - uint32_t crtc[drm->num_crtcs]; - uint32_t crtc_res[drm->num_crtcs]; - ssize_t num_outputs = wl_list_length(&drm->outputs); - uint32_t possible_crtc[num_outputs]; - - for (size_t i = 0; i < drm->num_crtcs; ++i) { - crtc[i] = UNMATCHED; - } - - memset(possible_crtc, 0, sizeof(possible_crtc)); - - wlr_log(WLR_DEBUG, "Reallocating CRTCs for output '%s'", conn->output.name); - - ssize_t index = -1, i = -1; - struct wlr_drm_connector *c; - wl_list_for_each(c, &drm->outputs, link) { - i++; - if (c == conn) { - index = i; - } - - wlr_log(WLR_DEBUG, "output '%s' crtc=%p state=%d", - c->output.name, c->crtc, c->state); - - if (c->crtc) { - crtc[c->crtc - drm->crtcs] = i; - } - - if (c->state == WLR_DRM_CONN_CONNECTED) { - possible_crtc[i] = c->possible_crtc; - } - } - assert(index != -1); - - possible_crtc[index] = conn->possible_crtc; - match_obj(wl_list_length(&drm->outputs), possible_crtc, - drm->num_crtcs, crtc, crtc_res); - - bool matched[num_outputs]; - memset(matched, false, sizeof(matched)); - for (size_t i = 0; i < drm->num_crtcs; ++i) { - if (crtc_res[i] != UNMATCHED) { - matched[crtc_res[i]] = true; - } - } - - // There is no point doing anything if this monitor doesn't get activated - if (!matched[index]) { - wlr_log(WLR_DEBUG, "Could not match a CRTC for this output"); - return; - } - - for (size_t i = 0; i < drm->num_crtcs; ++i) { - // We don't want any of the current monitors to be deactivated. - if (crtc[i] != UNMATCHED && !matched[crtc[i]]) { - wlr_log(WLR_DEBUG, "Could not match a CRTC for other output %d", - crtc[i]); - return; - } - } - - changed_outputs[index] = true; - - for (size_t i = 0; i < drm->num_crtcs; ++i) { - if (crtc_res[i] == UNMATCHED) { - continue; - } - - if (crtc_res[i] != crtc[i]) { - changed_outputs[crtc_res[i]] = true; - struct wlr_drm_connector *c; - size_t pos = 0; - wl_list_for_each(c, &drm->outputs, link) { - if (pos == crtc_res[i]) { - break; - } - pos++; - } - c->crtc = &drm->crtcs[i]; - - wlr_log(WLR_DEBUG, "Assigning CRTC %d to output '%s'", - drm->crtcs[i].id, c->output.name); - } - } - - realloc_planes(drm, crtc_res, changed_outputs); -} - -static uint32_t get_possible_crtcs(int fd, uint32_t conn_id) { - drmModeConnector *conn = drmModeGetConnector(fd, conn_id); - if (!conn) { - wlr_log_errno(WLR_ERROR, "Failed to get DRM connector"); - return 0; - } - - if (conn->connection != DRM_MODE_CONNECTED || conn->count_modes == 0) { - wlr_log(WLR_ERROR, "Output is not connected"); - goto error_conn; - } - - drmModeEncoder *enc = NULL; - for (int i = 0; !enc && i < conn->count_encoders; ++i) { - enc = drmModeGetEncoder(fd, conn->encoders[i]); - } - - if (!enc) { - wlr_log(WLR_ERROR, "Failed to get DRM encoder"); - goto error_conn; - } - - uint32_t ret = enc->possible_crtcs; - drmModeFreeEncoder(enc); - drmModeFreeConnector(conn); - return ret; - -error_conn: - drmModeFreeConnector(conn); - return 0; -} - static void drm_connector_cleanup(struct wlr_drm_connector *conn); static bool drm_connector_set_mode(struct wlr_output *output, struct wlr_output_mode *mode) { struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend; - bool changed_outputs[wl_list_length(&drm->outputs)]; - - wlr_log(WLR_INFO, "Modesetting '%s' with '%ux%u@%u mHz'", conn->output.name, - mode->width, mode->height, mode->refresh); - - conn->possible_crtc = get_possible_crtcs(drm->fd, conn->id); - if (conn->possible_crtc == 0) { - goto error_conn; + if (conn->crtc == NULL) { + wlr_log(WLR_ERROR, "Cannot modeset '%s': no CRTC for this connector", + conn->output.name); + // Save the desired mode for later, when we'll get a proper CRTC + conn->desired_mode = mode; + return false; } - memset(changed_outputs, false, sizeof(changed_outputs)); - realloc_crtcs(drm, conn, changed_outputs); + wlr_log(WLR_INFO, "Modesetting '%s' with '%ux%u@%u mHz'", + conn->output.name, mode->width, mode->height, mode->refresh); - struct wlr_drm_crtc *crtc = conn->crtc; - if (!crtc) { - wlr_log(WLR_ERROR, "Unable to match %s with a CRTC", conn->output.name); - goto error_conn; + if (!init_drm_plane_surfaces(conn->crtc->primary, drm, + mode->width, mode->height, GBM_FORMAT_XRGB8888)) { + wlr_log(WLR_ERROR, "Failed to initialize renderer for plane"); + return false; } - wlr_log(WLR_DEBUG, "%s: crtc=%td ovr=%td pri=%td cur=%td", conn->output.name, - crtc - drm->crtcs, - crtc->overlay ? crtc->overlay - drm->overlay_planes : -1, - crtc->primary ? crtc->primary - drm->primary_planes : -1, - crtc->cursor ? crtc->cursor - drm->cursor_planes : -1); conn->state = WLR_DRM_CONN_CONNECTED; + conn->desired_mode = NULL; wlr_output_update_mode(&conn->output, mode); + wlr_output_update_enabled(&conn->output, true); + + drm_connector_start_renderer(conn); // When switching VTs, the mode is not updated but the buffers become // invalid, so we need to manually damage the output here wlr_output_damage_whole(&conn->output); - // Since realloc_crtcs can deallocate planes on OTHER outputs, - // we actually need to reinitialize any that has changed - ssize_t output_index = -1; - wl_list_for_each(conn, &drm->outputs, link) { - output_index++; - struct wlr_output_mode *mode = conn->output.current_mode; - struct wlr_drm_crtc *crtc = conn->crtc; - - if (conn->state != WLR_DRM_CONN_CONNECTED || - !changed_outputs[output_index]) { - continue; - } - - if (!init_drm_plane_surfaces(crtc->primary, drm, - mode->width, mode->height, GBM_FORMAT_XRGB8888)) { - wlr_log(WLR_ERROR, "Failed to initialize renderer for plane"); - goto error_conn; - } - - drm_connector_start_renderer(conn); - } - return true; - -error_conn: - drm_connector_cleanup(conn); - return false; } bool wlr_drm_connector_add_mode(struct wlr_output *output, @@ -604,7 +497,6 @@ static bool drm_connector_set_cursor(struct wlr_output *output, bool update_texture) { struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend; - struct wlr_drm_renderer *renderer = &drm->renderer; struct wlr_drm_crtc *crtc = conn->crtc; if (!crtc) { @@ -630,13 +522,16 @@ 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, GBM_FORMAT_ARGB8888, 0)) { wlr_log(WLR_ERROR, "Cannot allocate cursor resources"); return false; } - plane->cursor_bo = gbm_bo_create(renderer->gbm, w, h, + plane->cursor_bo = gbm_bo_create(drm->renderer.gbm, w, h, GBM_FORMAT_ARGB8888, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE); if (!plane->cursor_bo) { wlr_log_errno(WLR_ERROR, "Failed to create cursor bo"); @@ -811,6 +706,176 @@ static const int32_t subpixel_map[] = { [DRM_MODE_SUBPIXEL_NONE] = WL_OUTPUT_SUBPIXEL_NONE, }; +static void dealloc_crtc(struct wlr_drm_connector *conn) { + struct wlr_drm_backend *drm = (struct wlr_drm_backend *)conn->output.backend; + if (conn->crtc == NULL) { + return; + } + + wlr_log(WLR_DEBUG, "De-allocating CRTC %zu for output '%s'", + conn->crtc - drm->crtcs, conn->output.name); + + for (size_t type = 0; type < 3; ++type) { + struct wlr_drm_plane *plane = conn->crtc->planes[type]; + if (plane == NULL) { + continue; + } + + finish_drm_surface(&plane->surf); + conn->crtc->planes[type] = NULL; + } + + drm->iface->conn_enable(drm, conn, false); + + conn->crtc = NULL; +} + +void realloc_crtcs(struct wlr_drm_backend *drm, bool *changed_outputs) { + size_t num_outputs = wl_list_length(&drm->outputs); + + wlr_log(WLR_DEBUG, "Reallocating CRTCs"); + + uint32_t crtc[drm->num_crtcs]; + for (size_t i = 0; i < drm->num_crtcs; ++i) { + crtc[i] = UNMATCHED; + } + + uint32_t possible_crtc[num_outputs]; + memset(possible_crtc, 0, sizeof(possible_crtc)); + + wlr_log(WLR_DEBUG, "State before reallocation:"); + ssize_t i = -1; + struct wlr_drm_connector *conn; + wl_list_for_each(conn, &drm->outputs, link) { + i++; + + wlr_log(WLR_DEBUG, " '%s' crtc=%d state=%d", conn->output.name, + conn->crtc ? (int)(conn->crtc - drm->crtcs) : -1, conn->state); + + if (conn->crtc) { + crtc[conn->crtc - drm->crtcs] = i; + } + + if (conn->state == WLR_DRM_CONN_CONNECTED || + conn->state == WLR_DRM_CONN_NEEDS_MODESET) { + possible_crtc[i] = conn->possible_crtc; + } + } + + uint32_t crtc_res[drm->num_crtcs]; + match_obj(wl_list_length(&drm->outputs), possible_crtc, + drm->num_crtcs, crtc, crtc_res); + + bool matched[num_outputs]; + memset(matched, false, sizeof(matched)); + for (size_t i = 0; i < drm->num_crtcs; ++i) { + if (crtc_res[i] != UNMATCHED) { + matched[crtc_res[i]] = true; + } + } + + for (size_t i = 0; i < drm->num_crtcs; ++i) { + // We don't want any of the current monitors to be deactivated + if (crtc[i] != UNMATCHED && !matched[crtc[i]]) { + wlr_log(WLR_DEBUG, "Could not match a CRTC for connected output %d", + crtc[i]); + return; + } + } + + struct wlr_drm_connector *connectors[num_outputs]; + i = 0; + wl_list_for_each(conn, &drm->outputs, link) { + connectors[i] = conn; + i++; + } + + for (size_t i = 0; i < drm->num_crtcs; ++i) { + if (crtc_res[i] == UNMATCHED) { + // De-allocate CRTCs we don't use anymore + if (crtc[i] != UNMATCHED) { + dealloc_crtc(connectors[crtc[i]]); + } + continue; + } + + if (crtc_res[i] != crtc[i]) { + changed_outputs[crtc_res[i]] = true; + + struct wlr_drm_connector *conn = connectors[crtc_res[i]]; + + dealloc_crtc(conn); + conn->crtc = &drm->crtcs[i]; + + wlr_log(WLR_DEBUG, "Assigning CRTC %zu to output %d -> %d '%s'", + i, crtc[i], crtc_res[i], conn->output.name); + } + } + + wlr_log(WLR_DEBUG, "State after reallocation:"); + wl_list_for_each(conn, &drm->outputs, link) { + wlr_log(WLR_DEBUG, " '%s' crtc=%d state=%d", conn->output.name, + conn->crtc ? (int)(conn->crtc - drm->crtcs) : -1, conn->state); + } + + realloc_planes(drm, crtc_res, changed_outputs); + + // We need to reinitialize any plane that has changed + i = -1; + wl_list_for_each(conn, &drm->outputs, link) { + i++; + struct wlr_output_mode *mode = conn->output.current_mode; + + if (conn->state != WLR_DRM_CONN_CONNECTED || !changed_outputs[i]) { + continue; + } + assert(conn->crtc); + + if (!init_drm_plane_surfaces(conn->crtc->primary, drm, + mode->width, mode->height, GBM_FORMAT_XRGB8888)) { + wlr_log(WLR_ERROR, "Failed to initialize renderer for plane"); + drm_connector_cleanup(conn); + break; + } + + drm_connector_start_renderer(conn); + + wlr_output_damage_whole(&conn->output); + } +} + +static uint32_t get_possible_crtcs(int fd, uint32_t conn_id) { + drmModeConnector *conn = drmModeGetConnector(fd, conn_id); + if (!conn) { + wlr_log_errno(WLR_ERROR, "Failed to get DRM connector"); + return 0; + } + + if (conn->connection != DRM_MODE_CONNECTED || conn->count_modes == 0) { + wlr_log(WLR_ERROR, "Output is not connected"); + goto error_conn; + } + + drmModeEncoder *enc = NULL; + for (int i = 0; !enc && i < conn->count_encoders; ++i) { + enc = drmModeGetEncoder(fd, conn->encoders[i]); + } + + if (!enc) { + wlr_log(WLR_ERROR, "Failed to get DRM encoder"); + goto error_conn; + } + + uint32_t ret = enc->possible_crtcs; + drmModeFreeEncoder(enc); + drmModeFreeConnector(conn); + return ret; + +error_conn: + drmModeFreeConnector(conn); + return 0; +} + void scan_drm_connectors(struct wlr_drm_backend *drm) { wlr_log(WLR_INFO, "Scanning DRM connectors"); @@ -824,7 +889,9 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { // +1 so length can never be 0, which is undefined behaviour. // Last element isn't used. bool seen[seen_len + 1]; - memset(seen, 0, sizeof(seen)); + memset(seen, false, sizeof(seen)); + size_t new_outputs_len = 0; + struct wlr_drm_connector *new_outputs[res->count_connectors + 1]; for (int i = 0; i < res->count_connectors; ++i) { drmModeConnector *drm_conn = drmModeGetConnector(drm->fd, @@ -864,17 +931,16 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { wlr_conn->state = WLR_DRM_CONN_DISCONNECTED; wlr_conn->id = drm_conn->connector_id; + snprintf(wlr_conn->output.name, sizeof(wlr_conn->output.name), + "%s-%"PRIu32, conn_get_name(drm_conn->connector_type), + drm_conn->connector_type_id); + if (curr_enc) { wlr_conn->old_crtc = drmModeGetCrtc(drm->fd, curr_enc->crtc_id); } - snprintf(wlr_conn->output.name, sizeof(wlr_conn->output.name), - "%s-%"PRIu32, - conn_get_name(drm_conn->connector_type), - drm_conn->connector_type_id); - wl_list_insert(&drm->outputs, &wlr_conn->link); - wlr_log(WLR_INFO, "Found display '%s'", wlr_conn->output.name); + wlr_log(WLR_INFO, "Found connector '%s'", wlr_conn->output.name); } else { seen[index] = true; } @@ -930,18 +996,20 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { wl_list_insert(&wlr_conn->output.modes, &mode->wlr_mode.link); } - wlr_output_update_enabled(&wlr_conn->output, true); + wlr_conn->possible_crtc = get_possible_crtcs(drm->fd, wlr_conn->id); + if (wlr_conn->possible_crtc == 0) { + wlr_log(WLR_ERROR, "No CRTC possible for connector '%s'", + wlr_conn->output.name); + } + + wlr_output_update_enabled(&wlr_conn->output, wlr_conn->crtc != NULL); wlr_conn->state = WLR_DRM_CONN_NEEDS_MODESET; - wlr_log(WLR_INFO, "Sending modesetting signal for '%s'", - wlr_conn->output.name); - wlr_signal_emit_safe(&drm->backend.events.new_output, - &wlr_conn->output); + new_outputs[new_outputs_len++] = wlr_conn; } else if (wlr_conn->state == WLR_DRM_CONN_CONNECTED && drm_conn->connection != DRM_MODE_CONNECTED) { wlr_log(WLR_INFO, "'%s' disconnected", wlr_conn->output.name); - wlr_output_update_enabled(&wlr_conn->output, false); drm_connector_cleanup(wlr_conn); } @@ -967,6 +1035,44 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { wl_list_remove(&conn->link); free(conn); } + + bool changed_outputs[wl_list_length(&drm->outputs)]; + memset(changed_outputs, false, sizeof(changed_outputs)); + for (size_t i = 0; i < new_outputs_len; ++i) { + struct wlr_drm_connector *conn = new_outputs[i]; + + ssize_t pos = -1; + struct wlr_drm_connector *c; + wl_list_for_each(c, &drm->outputs, link) { + ++pos; + if (c == conn) { + break; + } + } + assert(pos >= 0); + + changed_outputs[pos] = true; + } + + realloc_crtcs(drm, changed_outputs); + + for (size_t i = 0; i < new_outputs_len; ++i) { + struct wlr_drm_connector *conn = new_outputs[i]; + + wlr_log(WLR_INFO, "Requesting modeset for '%s'", + conn->output.name); + wlr_signal_emit_safe(&drm->backend.events.new_output, + &conn->output); + } + + // Try to modeset any output that has a desired mode and a CRTC (ie. was + // lacking a CRTC on last modeset) + wl_list_for_each(conn, &drm->outputs, link) { + if (conn->state == WLR_DRM_CONN_NEEDS_MODESET && conn->crtc != NULL && + conn->desired_mode != NULL) { + drm_connector_set_mode(&conn->output, conn->desired_mode); + } + } } static void page_flip_handler(int fd, unsigned seq, @@ -1062,23 +1168,28 @@ static void drm_connector_cleanup(struct wlr_drm_connector *conn) { } conn->output.current_mode = NULL; + conn->desired_mode = NULL; struct wlr_drm_mode *mode, *tmp; wl_list_for_each_safe(mode, tmp, &conn->output.modes, wlr_mode.link) { wl_list_remove(&mode->wlr_mode.link); free(mode); } + conn->output.enabled = false; + conn->output.width = conn->output.height = conn->output.refresh = 0; + memset(&conn->output.make, 0, sizeof(conn->output.make)); memset(&conn->output.model, 0, sizeof(conn->output.model)); memset(&conn->output.serial, 0, sizeof(conn->output.serial)); - conn->crtc = NULL; - conn->possible_crtc = 0; conn->pageflip_pending = false; /* Fallthrough */ case WLR_DRM_CONN_NEEDS_MODESET: wlr_log(WLR_INFO, "Emitting destruction signal for '%s'", conn->output.name); + dealloc_crtc(conn); + conn->possible_crtc = 0; + conn->desired_mode = NULL; wlr_signal_emit_safe(&conn->output.events.destroy, &conn->output); break; case WLR_DRM_CONN_DISCONNECTED: diff --git a/backend/drm/legacy.c b/backend/drm/legacy.c index d27cf137..c205e167 100644 --- a/backend/drm/legacy.c +++ b/backend/drm/legacy.c @@ -39,7 +39,10 @@ bool legacy_crtc_set_cursor(struct wlr_drm_backend *drm, } if (!bo) { - drmModeSetCursor(drm->fd, crtc->id, 0, 0, 0); + if (drmModeSetCursor(drm->fd, crtc->id, 0, 0, 0)) { + wlr_log_errno(WLR_DEBUG, "Failed to clear hardware cursor"); + return false; + } return true; } diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 38e6315d..fa7d090e 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -188,46 +188,29 @@ bool export_drm_bo(struct gbm_bo *bo, struct wlr_dmabuf_attributes *attribs) { return true; } -struct tex { - struct wlr_egl *egl; - EGLImageKHR img; - struct wlr_texture *tex; -}; - -static void free_eglimage(struct gbm_bo *bo, void *data) { - struct tex *tex = data; - - wlr_egl_destroy_image(tex->egl, tex->img); - wlr_texture_destroy(tex->tex); - free(tex); +static void free_tex(struct gbm_bo *bo, void *data) { + struct wlr_texture *tex = data; + wlr_texture_destroy(tex); } static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer, struct gbm_bo *bo) { - struct tex *tex = gbm_bo_get_user_data(bo); - if (tex != NULL) { - return tex->tex; - } - - tex = calloc(1, sizeof(struct tex)); - if (tex == NULL) { - return NULL; + struct wlr_texture *tex = gbm_bo_get_user_data(bo); + if (tex) { + return tex; } struct wlr_dmabuf_attributes attribs; if (!export_drm_bo(bo, &attribs)) { - free(tex); return NULL; } - tex->tex = wlr_texture_from_dmabuf(renderer->wlr_rend, &attribs); - if (tex->tex == NULL) { - free(tex); - return NULL; + tex = wlr_texture_from_dmabuf(renderer->wlr_rend, &attribs); + if (tex) { + gbm_bo_set_user_data(bo, tex, free_tex); } - gbm_bo_set_user_data(bo, tex, free_eglimage); - return tex->tex; + return tex; } struct gbm_bo *copy_drm_surface_mgpu(struct wlr_drm_surface *dest, @@ -238,7 +221,7 @@ struct gbm_bo *copy_drm_surface_mgpu(struct wlr_drm_surface *dest, assert(tex); float mat[9]; - wlr_matrix_projection(mat, 1, 1, WL_OUTPUT_TRANSFORM_FLIPPED_180); + wlr_matrix_projection(mat, 1, 1, WL_OUTPUT_TRANSFORM_NORMAL); struct wlr_renderer *renderer = dest->renderer->wlr_rend; wlr_renderer_begin(renderer, dest->width, dest->height); diff --git a/backend/drm/util.c b/backend/drm/util.c index baacbfa8..050da2a6 100644 --- a/backend/drm/util.c +++ b/backend/drm/util.c @@ -144,6 +144,9 @@ const char *conn_get_name(uint32_t type_id) { case DRM_MODE_CONNECTOR_eDP: return "eDP"; case DRM_MODE_CONNECTOR_VIRTUAL: return "Virtual"; case DRM_MODE_CONNECTOR_DSI: return "DSI"; +#ifdef DRM_MODE_CONNECTOR_DPI + case DRM_MODE_CONNECTOR_DPI: return "DPI"; +#endif default: return "Unknown"; } } @@ -225,9 +228,6 @@ static bool match_obj_(struct match_state *st, size_t skips, size_t score, size_ st->replaced = replaced; memcpy(st->best, st->res, sizeof(st->best[0]) * st->num_res); - if (st->score == st->num_objs && st->replaced == 0) { - st->exit_early = true; - } st->exit_early = (st->score == st->num_res - skips || st->score == st->num_objs) && st->replaced == 0; @@ -247,37 +247,44 @@ static bool match_obj_(struct match_state *st, size_t skips, size_t score, size_ * Attempt to use the current solution first, to try and avoid * recalculating everything */ - if (st->orig[i] != UNMATCHED && !is_taken(i, st->res, st->orig[i])) { st->res[i] = st->orig[i]; if (match_obj_(st, skips, score + 1, replaced, i + 1)) { return true; } } + if (st->orig[i] == UNMATCHED) { + st->res[i] = UNMATCHED; + match_obj_(st, skips, score, replaced, i + 1); + if (st->exit_early) { + return true; + } + } if (st->orig[i] != UNMATCHED) { ++replaced; } - bool is_best = false; - for (st->res[i] = 0; st->res[i] < st->num_objs; ++st->res[i]) { + bool has_best = false; + for (size_t candidate = 0; candidate < st->num_objs; ++candidate) { // We tried this earlier - if (st->res[i] == st->orig[i]) { + if (candidate == st->orig[i]) { continue; } // Not compatible - if (!(st->objs[st->res[i]] & (1 << i))) { + if (!(st->objs[candidate] & (1 << i))) { continue; } // Already taken - if (is_taken(i, st->res, st->res[i])) { + if (is_taken(i, st->res, candidate)) { continue; } + st->res[i] = candidate; if (match_obj_(st, skips, score + 1, replaced, i + 1)) { - is_best = true; + has_best = true; } if (st->exit_early) { @@ -285,7 +292,7 @@ static bool match_obj_(struct match_state *st, size_t skips, size_t score, size_ } } - if (is_best) { + if (has_best) { return true; } @@ -298,6 +305,9 @@ size_t match_obj(size_t num_objs, const uint32_t objs[static restrict num_objs], size_t num_res, const uint32_t res[static restrict num_res], uint32_t out[static restrict num_res]) { uint32_t solution[num_res]; + for (size_t i = 0; i < num_res; ++i) { + solution[i] = UNMATCHED; + } struct match_state st = { .num_objs = num_objs, diff --git a/backend/libinput/tablet_pad.c b/backend/libinput/tablet_pad.c index 579a11cf..0642f925 100644 --- a/backend/libinput/tablet_pad.c +++ b/backend/libinput/tablet_pad.c @@ -28,7 +28,7 @@ static void add_pad_group_from_libinput(struct wlr_tablet_pad *pad, ++group->ring_count; } } - group->rings = calloc(sizeof(int), group->ring_count); + group->rings = calloc(sizeof(unsigned int), group->ring_count); size_t ring = 0; for (size_t i = 0; i < pad->ring_count; ++i) { if (libinput_tablet_pad_mode_group_has_ring(li_group, i)) { @@ -41,7 +41,7 @@ static void add_pad_group_from_libinput(struct wlr_tablet_pad *pad, ++group->strip_count; } } - group->strips = calloc(sizeof(int), group->strip_count); + group->strips = calloc(sizeof(unsigned int), group->strip_count); size_t strip = 0; for (size_t i = 0; i < pad->strip_count; ++i) { if (libinput_tablet_pad_mode_group_has_strip(li_group, i)) { @@ -54,7 +54,7 @@ static void add_pad_group_from_libinput(struct wlr_tablet_pad *pad, ++group->button_count; } } - group->buttons = calloc(sizeof(int), group->button_count); + group->buttons = calloc(sizeof(unsigned int), group->button_count); size_t button = 0; for (size_t i = 0; i < pad->button_count; ++i) { if (libinput_tablet_pad_mode_group_has_button(li_group, i)) { diff --git a/backend/meson.build b/backend/meson.build index 52abe64d..dd1f4df3 100644 --- a/backend/meson.build +++ b/backend/meson.build @@ -1,3 +1,4 @@ +backend_parts = [] backend_files = files( 'backend.c', 'drm/atomic.c', @@ -44,28 +45,17 @@ else backend_files += files('session/direct.c') endif -if conf_data.get('WLR_HAS_SYSTEMD', false) +if logind.found() backend_files += files('session/logind.c') - backend_deps += systemd + backend_deps += logind endif -if conf_data.get('WLR_HAS_X11_BACKEND', false) - backend_files += files( - 'x11/backend.c', - 'x11/input_device.c', - 'x11/output.c', - ) - backend_deps += xcb_xkb -endif - -if conf_data.get('WLR_HAS_ELOGIND', false) - backend_files += files('session/logind.c') - backend_deps += elogind -endif +subdir('x11') lib_wlr_backend = static_library( 'wlr_backend', backend_files, include_directories: wlr_inc, + link_whole: backend_parts, dependencies: backend_deps, ) diff --git a/backend/multi/backend.c b/backend/multi/backend.c index f1d50347..e0038955 100644 --- a/backend/multi/backend.c +++ b/backend/multi/backend.c @@ -143,7 +143,7 @@ bool wlr_multi_backend_add(struct wlr_backend *_multi, struct wlr_renderer *multi_renderer = multi_backend_get_renderer(&multi->backend); struct wlr_renderer *backend_renderer = wlr_backend_get_renderer(backend); - if (multi_renderer != NULL && backend_renderer != NULL) { + if (multi_renderer != NULL && backend_renderer != NULL && multi_renderer != backend_renderer) { wlr_log(WLR_ERROR, "Could not add backend: multiple renderers at the " "same time aren't supported"); return false; diff --git a/backend/session/direct-freebsd.c b/backend/session/direct-freebsd.c index 63e1be01..cecfb0c1 100644 --- a/backend/session/direct-freebsd.c +++ b/backend/session/direct-freebsd.c @@ -15,6 +15,7 @@ #include <wayland-server.h> #include <wlr/backend/session/interface.h> #include <wlr/util/log.h> +#include <xf86drm.h> #include "backend/session/direct-ipc.h" #include "util/signal.h" @@ -23,6 +24,7 @@ const struct session_impl session_direct; struct direct_session { struct wlr_session base; int tty_fd; + int old_tty; int old_kbmode; int sock; pid_t child; @@ -40,23 +42,18 @@ static int direct_session_open(struct wlr_session *base, const char *path) { return fd; } - struct stat st; - if (fstat(fd, &st) < 0) { - close(fd); - return -errno; - } - return fd; } static void direct_session_close(struct wlr_session *base, int fd) { struct direct_session *session = wl_container_of(base, session, base); - struct stat st; - if (fstat(fd, &st) < 0) { - wlr_log_errno(WLR_ERROR, "Stat failed"); - close(fd); - return; + int ev; + struct drm_version dv = {0}; + if (ioctl(fd, DRM_IOCTL_VERSION, &dv) == 0) { + direct_ipc_dropmaster(session->sock, fd); + } else if (ioctl(fd, EVIOCGVERSION, &ev) == 0) { + ioctl(fd, EVIOCREVOKE, 0); } close(fd); @@ -79,6 +76,8 @@ static void direct_session_destroy(struct wlr_session *base) { ioctl(session->tty_fd, KDSETMODE, KD_TEXT); ioctl(session->tty_fd, VT_SETMODE, &mode); + ioctl(session->tty_fd, VT_ACTIVATE, session->old_tty); + if (errno) { wlr_log(WLR_ERROR, "Failed to restore tty"); } @@ -93,13 +92,29 @@ static void direct_session_destroy(struct wlr_session *base) { static int vt_handler(int signo, void *data) { struct direct_session *session = data; + struct drm_version dv = {0}; + struct wlr_device *dev; if (session->base.active) { session->base.active = false; wlr_signal_emit_safe(&session->base.session_signal, session); + + wl_list_for_each(dev, &session->base.devices, link) { + if (ioctl(dev->fd, DRM_IOCTL_VERSION, &dv) == 0) { + direct_ipc_dropmaster(session->sock, dev->fd); + } + } + ioctl(session->tty_fd, VT_RELDISP, 1); } else { ioctl(session->tty_fd, VT_RELDISP, VT_ACKACQ); + + wl_list_for_each(dev, &session->base.devices, link) { + if (ioctl(dev->fd, DRM_IOCTL_VERSION, &dv) == 0) { + direct_ipc_setmaster(session->sock, dev->fd); + } + } + session->base.active = true; wlr_signal_emit_safe(&session->base.session_signal, session); } @@ -108,11 +123,15 @@ static int vt_handler(int signo, void *data) { } static bool setup_tty(struct direct_session *session, struct wl_display *display) { - int fd = -1, tty = -1, tty0_fd = -1; + int fd = -1, tty = -1, tty0_fd = -1, old_tty = 1; if ((tty0_fd = open("/dev/ttyv0", O_RDWR | O_CLOEXEC)) < 0) { wlr_log_errno(WLR_ERROR, "Could not open /dev/ttyv0 to find a free vt"); goto error; } + if (ioctl(tty0_fd, VT_GETACTIVE, &old_tty) != 0) { + wlr_log_errno(WLR_ERROR, "Could not get active vt"); + goto error; + } if (ioctl(tty0_fd, VT_OPENQRY, &tty) != 0) { wlr_log_errno(WLR_ERROR, "Could not find a free vt"); goto error; @@ -168,13 +187,16 @@ static bool setup_tty(struct direct_session *session, struct wl_display *display session->base.vtnr = tty; session->tty_fd = fd; + session->old_tty = old_tty; session->old_kbmode = old_kbmode; return true; error: - // Drop back to tty 1, better than hanging in a useless blank console - ioctl(fd, VT_ACTIVATE, 1); + // In case we could not get the last active one, drop back to tty 1, + // better than hanging in a useless blank console. Otherwise activate the + // last active. + ioctl(fd, VT_ACTIVATE, old_tty); close(fd); return false; } diff --git a/backend/session/direct-ipc.c b/backend/session/direct-ipc.c index 5fdb95ac..3abce46a 100644 --- a/backend/session/direct-ipc.c +++ b/backend/session/direct-ipc.c @@ -1,7 +1,7 @@ #define _POSIX_C_SOURCE 200809L #ifdef __FreeBSD__ #define __BSD_VISIBLE 1 -#define INPUT_MAJOR 0 +#include <dev/evdev/input.h> #endif #include <errno.h> #include <fcntl.h> @@ -142,6 +142,7 @@ static void communicate(int sock) { goto error; } +#ifndef __FreeBSD__ struct stat st; if (fstat(fd, &st) < 0) { ret = errno; @@ -157,6 +158,20 @@ static void communicate(int sock) { if (maj == DRM_MAJOR && drmSetMaster(fd)) { ret = errno; } +#else + int ev; + struct drm_version dv = {0}; + if (ioctl(fd, EVIOCGVERSION, &ev) == -1 && + ioctl(fd, DRM_IOCTL_VERSION, &dv) == -1) { + ret = ENOTSUP; + goto error; + } + + if (dv.version_major != 0 && drmSetMaster(fd)) { + ret = errno; + } +#endif + error: send_msg(sock, ret ? -1 : fd, &ret, sizeof(ret)); if (fd >= 0) { @@ -193,8 +208,11 @@ int direct_ipc_open(int sock, const char *path) { send_msg(sock, -1, &msg, sizeof(msg)); - int fd, err; - recv_msg(sock, &fd, &err, sizeof(err)); + int fd, err, ret; + int retry = 0; + do { + ret = recv_msg(sock, &fd, &err, sizeof(err)); + } while (ret == 0 && retry++ < 3); return err ? -err : fd; } diff --git a/backend/session/session.c b/backend/session/session.c index 8d74bafe..3fcac3e3 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -79,6 +79,7 @@ struct wlr_session *wlr_session_create(struct wl_display *disp) { session->active = true; wl_signal_init(&session->session_signal); + wl_signal_init(&session->events.destroy); wl_list_init(&session->devices); session->udev = udev_new(); @@ -125,6 +126,7 @@ void wlr_session_destroy(struct wlr_session *session) { return; } + wlr_signal_emit_safe(&session->events.destroy, session); wl_list_remove(&session->display_destroy.link); wl_event_source_remove(session->udev_event); @@ -220,17 +222,9 @@ static int open_if_kms(struct wlr_session *restrict session, const char *restric goto out_fd; } - if (res->count_crtcs <= 0 || res->count_connectors <= 0 || - res->count_encoders <= 0) { - - goto out_res; - } - drmModeFreeResources(res); return fd; -out_res: - drmModeFreeResources(res); out_fd: wlr_session_close_file(session, fd); return -1; diff --git a/backend/wayland/wl_seat.c b/backend/wayland/wl_seat.c index 5163e804..8fb4aa5f 100644 --- a/backend/wayland/wl_seat.c +++ b/backend/wayland/wl_seat.c @@ -1,4 +1,4 @@ -#define _XOPEN_SOURCE 500 +#define _POSIX_C_SOURCE 200809L #include <assert.h> #include <stdint.h> #include <stdlib.h> diff --git a/backend/x11/backend.c b/backend/x11/backend.c index e0f5d6e7..0ff2925d 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -163,6 +163,8 @@ static bool backend_start(struct wlr_backend *backend) { 0, 0, 0); + + free(reply); } } #endif diff --git a/backend/x11/meson.build b/backend/x11/meson.build new file mode 100644 index 00000000..1164df1e --- /dev/null +++ b/backend/x11/meson.build @@ -0,0 +1,44 @@ +x11_libs = [] +x11_required = [ + 'xcb', + 'x11-xcb', +] +x11_optional = [ + 'xcb-xkb', +] + +foreach lib : x11_required + dep = dependency(lib, required: get_option('x11-backend')) + if not dep.found() + subdir_done() + endif + + x11_libs += dep +endforeach + +foreach lib : x11_optional + dep = dependency(lib, required: get_option(lib)) + if dep.found() + x11_libs += dep + conf_data.set('WLR_HAS_' + lib.underscorify().to_upper(), true) + endif +endforeach + +lib_wlr_backend_x11 = static_library( + 'wlr_backend_x11', + files( + 'backend.c', + 'input_device.c', + 'output.c', + ), + include_directories: wlr_inc, + dependencies: [ + wayland_server, + pixman, + xkbcommon, + x11_libs, + ], +) + +backend_parts += lib_wlr_backend_x11 +conf_data.set('WLR_HAS_X11_BACKEND', true) diff --git a/backend/x11/output.c b/backend/x11/output.c index 151807dd..b678296d 100644 --- a/backend/x11/output.c +++ b/backend/x11/output.c @@ -121,6 +121,9 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) { struct wlr_output *wlr_output = &output->wlr_output; wlr_output_init(wlr_output, &x11->backend, &output_impl, x11->wl_display); + wlr_output->width = 1024; + wlr_output->height = 768; + output_set_refresh(&output->wlr_output, 0); snprintf(wlr_output->name, sizeof(wlr_output->name), "X11-%d", @@ -137,8 +140,8 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) { }; output->win = xcb_generate_id(x11->xcb_conn); xcb_create_window(x11->xcb_conn, XCB_COPY_FROM_PARENT, output->win, - x11->screen->root, 0, 0, 1024, 768, 1, XCB_WINDOW_CLASS_INPUT_OUTPUT, - x11->screen->root_visual, mask, values); + x11->screen->root, 0, 0, wlr_output->width, wlr_output->height, 1, + XCB_WINDOW_CLASS_INPUT_OUTPUT, x11->screen->root_visual, mask, values); output->surf = wlr_egl_create_surface(&x11->egl, &output->win); if (!output->surf) { @@ -187,11 +190,17 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) { void handle_x11_configure_notify(struct wlr_x11_output *output, xcb_configure_notify_event_t *ev) { - wlr_output_update_custom_mode(&output->wlr_output, ev->width, - ev->height, output->wlr_output.refresh); - - // Move the pointer to its new location - update_x11_pointer_position(output, output->x11->time); + // ignore events that set an invalid size: + if (ev->width > 0 && ev->height > 0) { + wlr_output_update_custom_mode(&output->wlr_output, ev->width, + ev->height, output->wlr_output.refresh); + + // Move the pointer to its new location + update_x11_pointer_position(output, output->x11->time); + } else { + wlr_log(WLR_DEBUG,"Ignoring X11 configure event for height=%d, width=%d", + ev->width, ev->height); + } } bool wlr_output_is_x11(struct wlr_output *wlr_output) { diff --git a/docs/env_vars.md b/docs/env_vars.md index 3f1926d3..b28849cc 100644 --- a/docs/env_vars.md +++ b/docs/env_vars.md @@ -12,6 +12,8 @@ wlroots specific wayland, x11, headless) * *WLR_WL_OUTPUTS*: when using the wayland backend specifies the number of outputs * *WLR_X11_OUTPUTS*: when using the X11 backend specifies the number of outputs +* *WLR_HEADLESS_OUTPUTS*: when using the headless backend specifies the number + of outputs rootston specific ------------------ diff --git a/examples/gamma-control.c b/examples/gamma-control.c new file mode 100644 index 00000000..a060b883 --- /dev/null +++ b/examples/gamma-control.c @@ -0,0 +1,195 @@ +#define _POSIX_C_SOURCE 200809L +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <wayland-client-protocol.h> +#include <wayland-client.h> +#include "wlr-gamma-control-unstable-v1-client-protocol.h" + +struct output { + struct wl_output *wl_output; + struct zwlr_gamma_control_v1 *gamma_control; + uint32_t ramp_size; + int table_fd; + uint16_t *table; + struct wl_list link; +}; + +static struct wl_list outputs; +static struct zwlr_gamma_control_manager_v1 *gamma_control_manager = NULL; + +static int create_anonymous_file(off_t size) { + char template[] = "/tmp/wlroots-shared-XXXXXX"; + int fd = mkstemp(template); + if (fd < 0) { + return -1; + } + + int ret; + do { + errno = 0; + ret = ftruncate(fd, size); + } while (errno == EINTR); + if (ret < 0) { + close(fd); + return -1; + } + + unlink(template); + return fd; +} + +static int create_gamma_table(uint32_t ramp_size, uint16_t **table) { + size_t table_size = ramp_size * 3 * sizeof(uint16_t); + int fd = create_anonymous_file(table_size); + if (fd < 0) { + fprintf(stderr, "failed to create anonymous file\n"); + return -1; + } + + void *data = + mmap(NULL, table_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) { + fprintf(stderr, "failed to mmap()\n"); + close(fd); + return -1; + } + + *table = data; + return fd; +} + +static void gamma_control_handle_gamma_size(void *data, + struct zwlr_gamma_control_v1 *gamma_control, uint32_t ramp_size) { + struct output *output = data; + output->ramp_size = ramp_size; + output->table_fd = create_gamma_table(ramp_size, &output->table); + if (output->table_fd < 0) { + exit(EXIT_FAILURE); + } +} + +static void gamma_control_handle_failed(void *data, + struct zwlr_gamma_control_v1 *gamma_control) { + fprintf(stderr, "failed to set gamma table\n"); + exit(EXIT_FAILURE); +} + +static const struct zwlr_gamma_control_v1_listener gamma_control_listener = { + .gamma_size = gamma_control_handle_gamma_size, + .failed = gamma_control_handle_failed, +}; + +static void registry_handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) { + if (strcmp(interface, wl_output_interface.name) == 0) { + struct output *output = calloc(1, sizeof(struct output)); + output->wl_output = wl_registry_bind(registry, name, + &wl_output_interface, 1); + wl_list_insert(&outputs, &output->link); + } else if (strcmp(interface, + zwlr_gamma_control_manager_v1_interface.name) == 0) { + gamma_control_manager = wl_registry_bind(registry, name, + &zwlr_gamma_control_manager_v1_interface, 1); + } +} + +static void registry_handle_global_remove(void *data, + struct wl_registry *registry, uint32_t name) { + // Who cares? +} + +static const struct wl_registry_listener registry_listener = { + .global = registry_handle_global, + .global_remove = registry_handle_global_remove, +}; + +static void fill_gamma_table(uint16_t *table, uint32_t ramp_size, + double contrast, double brightness, double gamma) { + uint16_t *r = table; + uint16_t *g = table + ramp_size; + uint16_t *b = table + 2 * ramp_size; + for (uint32_t i = 0; i < ramp_size; ++i) { + double val = (double)i / (ramp_size - 1); + val = contrast * pow(val, 1.0 / gamma) + (brightness - 1); + if (val > 1.0) { + val = 1.0; + } else if (val < 0.0) { + val = 0.0; + } + r[i] = g[i] = b[i] = (uint16_t)(UINT16_MAX * val); + } +} + +static const char usage[] = "usage: gamma-control [options]\n" + " -h show this help message\n" + " -c <value> set contrast (default: 1)\n" + " -b <value> set brightness (default: 1)\n" + " -g <value> set gamma (default: 1)\n"; + +int main(int argc, char *argv[]) { + wl_list_init(&outputs); + + double contrast = 1, brightness = 1, gamma = 1; + int opt; + while ((opt = getopt(argc, argv, "hc:b:g:")) != -1) { + switch (opt) { + case 'c': + contrast = strtod(optarg, NULL); + break; + case 'b': + brightness = strtod(optarg, NULL); + break; + case 'g': + gamma = strtod(optarg, NULL); + break; + case 'h': + default: + fprintf(stderr, usage); + return opt == 'h' ? EXIT_SUCCESS : EXIT_FAILURE; + } + } + + struct wl_display *display = wl_display_connect(NULL); + if (display == NULL) { + fprintf(stderr, "failed to create display\n"); + return -1; + } + + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_dispatch(display); + wl_display_roundtrip(display); + + if (gamma_control_manager == NULL) { + fprintf(stderr, + "compositor doesn't support wlr-gamma-control-unstable-v1\n"); + return EXIT_FAILURE; + } + + struct output *output; + wl_list_for_each(output, &outputs, link) { + output->gamma_control = zwlr_gamma_control_manager_v1_get_gamma_control( + gamma_control_manager, output->wl_output); + zwlr_gamma_control_v1_add_listener(output->gamma_control, + &gamma_control_listener, output); + } + wl_display_roundtrip(display); + + wl_list_for_each(output, &outputs, link) { + fill_gamma_table(output->table, output->ramp_size, + contrast, brightness, gamma); + zwlr_gamma_control_v1_set_gamma(output->gamma_control, + output->table_fd); + } + + while (wl_display_dispatch(display) != -1) { + // This space is intentionnally left blank + } + + return EXIT_SUCCESS; +} diff --git a/examples/idle-inhibit.c b/examples/idle-inhibit.c index 348892ab..48c812e8 100644 --- a/examples/idle-inhibit.c +++ b/examples/idle-inhibit.c @@ -8,7 +8,11 @@ #include "idle-inhibit-unstable-v1-client-protocol.h" #include "xdg-shell-client-protocol.h" +#ifdef __linux__ #include <linux/input-event-codes.h> +#elif __FreeBSD__ +#include <dev/evdev/input-event-codes.h> +#endif /** * Usage: idle-inhibit diff --git a/examples/idle.c b/examples/idle.c index 30e106db..3e1565ca 100644 --- a/examples/idle.c +++ b/examples/idle.c @@ -129,6 +129,7 @@ int main(int argc, char *argv[]) { wl_registry_add_listener(registry, ®istry_listener, NULL); wl_display_dispatch(display); wl_display_roundtrip(display); + free(registry); if (idle_manager == NULL) { fprintf(stderr, "display doesn't support idle protocol\n"); @@ -152,14 +153,20 @@ int main(int argc, char *argv[]) { .display = display, }; - if (simulate_activity_timeout != 0 && simulate_activity_timeout < close_timeout) { + bool create_t1 = (simulate_activity_timeout != 0) && + (simulate_activity_timeout < close_timeout); + + if (create_t1) { if (pthread_create(&t1, NULL, &simulate_activity, (void *)&arg) != 0) { return -1; } } - if (close_timeout != 0) { + + bool create_t2 = (close_timeout != 0); + + if (create_t2) { if (pthread_create(&t2, NULL, &close_program, (void *)&arg) != 0) { - if (simulate_activity_timeout != 0) { + if (create_t1) { pthread_cancel(t1); } return -1; @@ -170,18 +177,19 @@ int main(int argc, char *argv[]) { fprintf(stdout, "waiting\n"); if (pthread_create(&t3, NULL, &main_loop, (void *)display) != 0) { - if (simulate_activity_timeout != 0) { + if (create_t1) { pthread_cancel(t1); } - if (close_timeout != 0 ) { + if (create_t2) { pthread_cancel(t2); } + return -1; } - if (simulate_activity_timeout != 0) { + if (create_t1) { pthread_join(t1, NULL); } - if (close_timeout != 0) { + if (create_t2) { pthread_join(t2, NULL); } pthread_cancel(t3); diff --git a/examples/layer-shell.c b/examples/layer-shell.c index 70ae21f0..f56825c3 100644 --- a/examples/layer-shell.c +++ b/examples/layer-shell.c @@ -1,4 +1,4 @@ -#define _POSIX_C_SOURCE 199309L +#define _POSIX_C_SOURCE 200112L #ifdef __linux__ #include <linux/input-event-codes.h> #elif __FreeBSD__ diff --git a/examples/meson.build b/examples/meson.build index 18f44fde..b5ad6c98 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -1,68 +1,110 @@ threads = dependency('threads') wayland_cursor = dependency('wayland-cursor') - libpng = dependency('libpng', required: false) - # These versions correspond to ffmpeg 4.0 libavutil = dependency('libavutil', version: '>=56.14.100', required: false) libavcodec = dependency('libavcodec', version: '>=58.18.100', required: false) libavformat = dependency('libavformat', version: '>=58.12.100', required: false) +# Small hack until https://github.com/mesonbuild/meson/pull/3386/ is merged +foreach dep : ['libpng', 'libavutil', 'libavcodec', 'libavformat'] + if not get_variable(dep).found() + set_variable(dep, disabler()) + endif +endforeach + if not cc.has_header('libavutil/hwcontext_drm.h', dependencies: libavutil) - libavutil = disabler() + libavutil = disabler() endif -executable('simple', 'simple.c', dependencies: wlroots) -executable('pointer', 'pointer.c', dependencies: wlroots) -executable('touch', 'touch.c', 'cat.c', dependencies: wlroots) -executable('tablet', 'tablet.c', dependencies: wlroots) -executable('rotation', 'rotation.c', 'cat.c', dependencies: wlroots) -executable('multi-pointer', 'multi-pointer.c', dependencies: wlroots) -executable('output-layout', 'output-layout.c', 'cat.c', dependencies: wlroots) - -executable( - 'screenshot', - 'screenshot.c', - dependencies: [wayland_client, wlr_protos, wlroots] -) - -executable( - 'idle', - 'idle.c', - dependencies: [wayland_client, wlr_protos, wlroots, threads] -) - -executable( - 'idle-inhibit', - 'idle-inhibit.c', - dependencies: [wayland_client, wlr_protos, wlroots, threads] -) +examples = { + 'simple': { + 'src': 'simple.c', + 'dep': [wlroots], + }, + 'pointer': { + 'src': 'pointer.c', + 'dep': [wlroots], + }, + 'touch': { + 'src': ['touch.c', 'cat.c'], + 'dep': [wlroots], + }, + 'tablet': { + 'src': 'tablet.c', + 'dep': [wlroots], + }, + 'rotation': { + 'src': ['rotation.c', 'cat.c'], + 'dep': [wlroots], + }, + 'multi-pointer': { + 'src': 'multi-pointer.c', + 'dep': [wlroots], + }, + 'output-layout': { + 'src': ['output-layout.c', 'cat.c'], + 'dep': [wlroots], + }, + 'screenshot': { + 'src': 'screenshot.c', + 'dep': [wayland_client, wlr_protos, wlroots], + }, + 'idle': { + 'src': 'idle.c', + 'dep': [wayland_client, wlr_protos, wlroots, threads], + }, + 'idle-inhibit': { + 'src': 'idle-inhibit.c', + 'dep': [wayland_client, wlr_protos, wlroots], + }, + 'layer-shell': { + 'src': 'layer-shell.c', + 'dep': [wayland_client, wayland_cursor, wlr_protos, wlroots], + }, + 'input-inhibitor': { + 'src': 'input-inhibitor.c', + 'dep': [wayland_client, wayland_cursor, wlr_protos, wlroots], + }, + 'gamma-control': { + 'src': 'gamma-control.c', + 'dep': [wayland_client, wayland_cursor, wlr_protos, wlroots], + }, + 'dmabuf-capture': { + 'src': 'dmabuf-capture.c', + 'dep': [ + libavcodec, + libavformat, + libavutil, + threads, + wayland_client, + wlr_protos, + wlroots, + ], + }, + 'screencopy': { + 'src': 'screencopy.c', + 'dep': [libpng, wayland_client, wlr_protos, wlroots], + }, + 'toplevel-decoration': { + 'src': 'toplevel-decoration.c', + 'dep': [wayland_client, wlr_protos, wlroots], + }, +} -executable( - 'layer-shell', - 'layer-shell.c', - dependencies: [wayland_cursor, wayland_client, wlr_protos, wlroots] -) - -executable( - 'input-inhibitor', - 'input-inhibitor.c', - dependencies: [wayland_cursor, wayland_client, wlr_protos, wlroots] -) - -if libavutil.found() and libavcodec.found() and libavformat.found() - executable( - 'dmabuf-capture', - 'dmabuf-capture.c', - dependencies: [wayland_client, wlr_protos, libavutil, libavcodec, - libavformat, wlroots, threads ] - ) -endif - -if libpng.found() - executable( - 'screencopy', - 'screencopy.c', - dependencies: [wayland_client, wlr_protos, wlroots, libpng] - ) -endif +foreach name, info : examples + all_dep_found = true + foreach d : info.get('dep') + all_dep_found = all_dep_found and d.found() + endforeach + if all_dep_found + executable( + name, + info.get('src'), + dependencies: info.get('dep'), + build_by_default: get_option('examples'), + ) + else + warning('Dependencies not satisfied for ' + name) + endif +endforeach diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c index 58689649..49670c39 100644 --- a/examples/multi-pointer.c +++ b/examples/multi-pointer.c @@ -1,5 +1,4 @@ #define _POSIX_C_SOURCE 200112L -#define _XOPEN_SOURCE 500 #include <assert.h> #include <GLES2/gl2.h> #include <math.h> @@ -240,15 +239,21 @@ void new_input_notify(struct wl_listener *listener, void *data) { wlr_log(WLR_ERROR, "Failed to create XKB context"); exit(1); } - wlr_keyboard_set_keymap(device->keyboard, xkb_map_new_from_names(context, - &rules, XKB_KEYMAP_COMPILE_NO_FLAGS)); + struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) { + wlr_log(WLR_ERROR, "Failed to create XKB keymap"); + exit(1); + } + wlr_keyboard_set_keymap(device->keyboard, keymap); + xkb_keymap_unref(keymap); xkb_context_unref(context); break; case WLR_INPUT_DEVICE_POINTER:; - struct sample_cursor *cursor = calloc(1, sizeof(struct sample_cursor)); + struct sample_cursor *cursor = calloc(1, sizeof(struct sample_cursor)); struct sample_pointer *pointer = calloc(1, sizeof(struct sample_pointer)); pointer->device = device; - cursor->sample = sample; + cursor->sample = sample; cursor->device = device; cursor->cursor = wlr_cursor_create(); @@ -325,6 +330,11 @@ int main(int argc, char *argv[]) { cursor_destroy(cursor); } + struct sample_pointer *pointer, *tmp_pointer; + wl_list_for_each_safe(pointer, tmp_pointer, &state.pointers, link) { + free(pointer); + } + wlr_xcursor_theme_destroy(theme); wlr_output_layout_destroy(state.layout); } diff --git a/examples/output-layout.c b/examples/output-layout.c index 2bfc5923..2d1bc58b 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -239,8 +239,14 @@ void new_input_notify(struct wl_listener *listener, void *data) { wlr_log(WLR_ERROR, "Failed to create XKB context"); exit(1); } - wlr_keyboard_set_keymap(device->keyboard, xkb_map_new_from_names(context, - &rules, XKB_KEYMAP_COMPILE_NO_FLAGS)); + struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) { + wlr_log(WLR_ERROR, "Failed to create XKB keymap"); + exit(1); + } + wlr_keyboard_set_keymap(device->keyboard, keymap); + xkb_keymap_unref(keymap); xkb_context_unref(context); break; default: @@ -285,6 +291,6 @@ int main(int argc, char *argv[]) { wlr_texture_destroy(state.cat_texture); - wlr_output_layout_destroy(state.layout); wl_display_destroy(state.display); + wlr_output_layout_destroy(state.layout); } diff --git a/examples/pointer.c b/examples/pointer.c index e0f009b3..cc58c223 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -1,5 +1,4 @@ #define _POSIX_C_SOURCE 200112L -#define _XOPEN_SOURCE 500 #include <assert.h> #include <math.h> #include <stdio.h> @@ -305,8 +304,14 @@ void new_input_notify(struct wl_listener *listener, void *data) { wlr_log(WLR_ERROR, "Failed to create XKB context"); exit(1); } - wlr_keyboard_set_keymap(device->keyboard, xkb_map_new_from_names(context, - &rules, XKB_KEYMAP_COMPILE_NO_FLAGS)); + struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) { + wlr_log(WLR_ERROR, "Failed to create XKB keymap"); + exit(1); + } + wlr_keyboard_set_keymap(device->keyboard, keymap); + xkb_keymap_unref(keymap); xkb_context_unref(context); break; default: diff --git a/examples/rotation.c b/examples/rotation.c index 2d2fb179..7cf5727b 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -1,5 +1,4 @@ #define _POSIX_C_SOURCE 200112L -#define _XOPEN_SOURCE 500 #include <GLES2/gl2.h> #include <getopt.h> #include <math.h> @@ -189,8 +188,14 @@ void new_input_notify(struct wl_listener *listener, void *data) { wlr_log(WLR_ERROR, "Failed to create XKB context"); exit(1); } - wlr_keyboard_set_keymap(device->keyboard, xkb_map_new_from_names(context, - &rules, XKB_KEYMAP_COMPILE_NO_FLAGS)); + struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) { + wlr_log(WLR_ERROR, "Failed to create XKB keymap"); + exit(1); + } + wlr_keyboard_set_keymap(device->keyboard, keymap); + xkb_keymap_unref(keymap); xkb_context_unref(context); break; default: diff --git a/examples/simple.c b/examples/simple.c index f161dc22..e1c10906 100644 --- a/examples/simple.c +++ b/examples/simple.c @@ -37,8 +37,8 @@ struct sample_keyboard { }; void output_frame_notify(struct wl_listener *listener, void *data) { - wlr_log(WLR_DEBUG, "Output removed"); - struct sample_output *sample_output = wl_container_of(listener, sample_output, frame); + struct sample_output *sample_output = + wl_container_of(listener, sample_output, frame); struct sample_state *sample = sample_output->sample; struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -66,7 +66,9 @@ void output_frame_notify(struct wl_listener *listener, void *data) { } void output_remove_notify(struct wl_listener *listener, void *data) { - struct sample_output *sample_output = wl_container_of(listener, sample_output, destroy); + struct sample_output *sample_output = + wl_container_of(listener, sample_output, destroy); + wlr_log(WLR_DEBUG, "Output removed"); wl_list_remove(&sample_output->frame.link); wl_list_remove(&sample_output->destroy.link); free(sample_output); @@ -74,10 +76,13 @@ void output_remove_notify(struct wl_listener *listener, void *data) { void new_output_notify(struct wl_listener *listener, void *data) { struct wlr_output *output = data; - struct sample_state *sample = wl_container_of(listener, sample, new_output); - struct sample_output *sample_output = calloc(1, sizeof(struct sample_output)); + struct sample_state *sample = + wl_container_of(listener, sample, new_output); + struct sample_output *sample_output = + calloc(1, sizeof(struct sample_output)); if (!wl_list_empty(&output->modes)) { - struct wlr_output_mode *mode = wl_container_of(output->modes.prev, mode, link); + struct wlr_output_mode *mode = + wl_container_of(output->modes.prev, mode, link); wlr_output_set_mode(output, mode); } sample_output->output = output; @@ -105,7 +110,8 @@ void keyboard_key_notify(struct wl_listener *listener, void *data) { } void keyboard_destroy_notify(struct wl_listener *listener, void *data) { - struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, destroy); + struct sample_keyboard *keyboard = + wl_container_of(listener, keyboard, destroy); wl_list_remove(&keyboard->destroy.link); wl_list_remove(&keyboard->key.link); free(keyboard); @@ -116,7 +122,8 @@ void new_input_notify(struct wl_listener *listener, void *data) { struct sample_state *sample = wl_container_of(listener, sample, new_input); switch (device->type) { case WLR_INPUT_DEVICE_KEYBOARD:; - struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); + struct sample_keyboard *keyboard = + calloc(1, sizeof(struct sample_keyboard)); keyboard->device = device; keyboard->sample = sample; wl_signal_add(&device->events.destroy, &keyboard->destroy); @@ -134,8 +141,14 @@ void new_input_notify(struct wl_listener *listener, void *data) { wlr_log(WLR_ERROR, "Failed to create XKB context"); exit(1); } - wlr_keyboard_set_keymap(device->keyboard, xkb_map_new_from_names(context, - &rules, XKB_KEYMAP_COMPILE_NO_FLAGS)); + struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) { + wlr_log(WLR_ERROR, "Failed to create XKB keymap"); + exit(1); + } + wlr_keyboard_set_keymap(device->keyboard, keymap); + xkb_keymap_unref(keymap); xkb_context_unref(context); break; default: @@ -152,19 +165,19 @@ int main(void) { .last_frame = { 0 }, .display = display }; - struct wlr_backend *wlr = wlr_backend_autocreate(display, NULL); - if (!wlr) { + struct wlr_backend *backend = wlr_backend_autocreate(display, NULL); + if (!backend) { exit(1); } - wl_signal_add(&wlr->events.new_output, &state.new_output); + wl_signal_add(&backend->events.new_output, &state.new_output); state.new_output.notify = new_output_notify; - wl_signal_add(&wlr->events.new_input, &state.new_input); + wl_signal_add(&backend->events.new_input, &state.new_input); state.new_input.notify = new_input_notify; clock_gettime(CLOCK_MONOTONIC, &state.last_frame); - if (!wlr_backend_start(wlr)) { + if (!wlr_backend_start(backend)) { wlr_log(WLR_ERROR, "Failed to start backend"); - wlr_backend_destroy(wlr); + wlr_backend_destroy(backend); exit(1); } wl_display_run(display); diff --git a/examples/tablet.c b/examples/tablet.c index 4a27d0e1..fad30d52 100644 --- a/examples/tablet.c +++ b/examples/tablet.c @@ -1,5 +1,4 @@ -#define _POSIX_C_SOURCE 200112L -#define _XOPEN_SOURCE 500 +#define _XOPEN_SOURCE 600 #include <GLES2/gl2.h> #include <math.h> #include <stdio.h> @@ -298,8 +297,14 @@ void new_input_notify(struct wl_listener *listener, void *data) { wlr_log(WLR_ERROR, "Failed to create XKB context"); exit(1); } - wlr_keyboard_set_keymap(device->keyboard, xkb_map_new_from_names(context, - &rules, XKB_KEYMAP_COMPILE_NO_FLAGS)); + struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) { + wlr_log(WLR_ERROR, "Failed to create XKB keymap"); + exit(1); + } + wlr_keyboard_set_keymap(device->keyboard, keymap); + xkb_keymap_unref(keymap); xkb_context_unref(context); break; case WLR_INPUT_DEVICE_TABLET_PAD:; diff --git a/examples/toplevel-decoration.c b/examples/toplevel-decoration.c new file mode 100644 index 00000000..e930c417 --- /dev/null +++ b/examples/toplevel-decoration.c @@ -0,0 +1,253 @@ +#include <GLES2/gl2.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wayland-client.h> +#include <wayland-egl.h> +#include <wlr/render/egl.h> +#include "xdg-shell-client-protocol.h" +#include "xdg-decoration-unstable-v1-client-protocol.h" + +/** + * Usage: toplevel-decoration [mode] + * Creates an xdg-toplevel supporting decoration negotiation. If `mode` is + * specified, the client will prefer this decoration mode. + */ + +static int width = 500, height = 300; + +static struct wl_compositor *compositor = NULL; +static struct xdg_wm_base *wm_base = NULL; +static struct zxdg_decoration_manager_v1 *decoration_manager = NULL; + +struct wlr_egl egl; +struct wl_egl_window *egl_window; +struct wlr_egl_surface *egl_surface; + +struct zxdg_toplevel_decoration_v1 *decoration; +enum zxdg_toplevel_decoration_v1_mode client_preferred_mode, current_mode; + +static const char *get_mode_name(enum zxdg_toplevel_decoration_v1_mode mode) { + switch (mode) { + case ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE: + return "client-side decorations"; + case ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE: + return "server-side decorations"; + } + abort(); +} + +static void request_preferred_mode(void) { + enum zxdg_toplevel_decoration_v1_mode mode = client_preferred_mode; + if (mode == 0) { + printf("Requesting compositor preferred mode\n"); + zxdg_toplevel_decoration_v1_unset_mode(decoration); + return; + } + if (mode == current_mode) { + return; + } + + printf("Requesting %s\n", get_mode_name(mode)); + zxdg_toplevel_decoration_v1_set_mode(decoration, mode); +} + +static void draw(void) { + eglMakeCurrent(egl.display, egl_surface, egl_surface, egl.context); + + float color[] = {1.0, 1.0, 0.0, 1.0}; + if (current_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE) { + color[0] = 0.0; + } + + glViewport(0, 0, width, height); + glClearColor(color[0], color[1], color[2], 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + eglSwapBuffers(egl.display, egl_surface); +} + +static void xdg_surface_handle_configure(void *data, + struct xdg_surface *xdg_surface, uint32_t serial) { + xdg_surface_ack_configure(xdg_surface, serial); + wl_egl_window_resize(egl_window, width, height, 0, 0); + draw(); +} + +static const struct xdg_surface_listener xdg_surface_listener = { + .configure = xdg_surface_handle_configure, +}; + +static void xdg_toplevel_handle_configure(void *data, + struct xdg_toplevel *xdg_toplevel, int32_t w, int32_t h, + struct wl_array *states) { + width = w; + height = h; +} + +static const struct xdg_toplevel_listener xdg_toplevel_listener = { + .configure = xdg_toplevel_handle_configure, +}; + +static void decoration_handle_configure(void *data, + struct zxdg_toplevel_decoration_v1 *decoration, + enum zxdg_toplevel_decoration_v1_mode mode) { + printf("Using %s\n", get_mode_name(mode)); + current_mode = mode; +} + +static const struct zxdg_toplevel_decoration_v1_listener decoration_listener = { + .configure = decoration_handle_configure, +}; + +static void pointer_handle_enter(void *data, struct wl_pointer *pointer, + uint32_t serial, struct wl_surface *surface, + wl_fixed_t sx, wl_fixed_t sy) { + // No-op +} + +static void pointer_handle_leave(void *data, struct wl_pointer *pointer, + uint32_t serial, struct wl_surface *surface) { + // No-op +} + +static void pointer_handle_motion(void *data, struct wl_pointer *pointer, + uint32_t time, wl_fixed_t sx, wl_fixed_t sy) { + // No-op +} + +static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, uint32_t time, uint32_t button, + enum wl_pointer_button_state state) { + if (state == WL_POINTER_BUTTON_STATE_PRESSED) { + // Toggle mode + if (client_preferred_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE) { + client_preferred_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; + } else { + client_preferred_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; + } + request_preferred_mode(); + } +} + +static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, + uint32_t time, enum wl_pointer_axis axis, wl_fixed_t value) { + // No-op +} + +static const struct wl_pointer_listener pointer_listener = { + .enter = pointer_handle_enter, + .leave = pointer_handle_leave, + .motion = pointer_handle_motion, + .button = pointer_handle_button, + .axis = pointer_handle_axis, +}; + +static void seat_handle_capabilities(void *data, struct wl_seat *seat, + enum wl_seat_capability caps) { + if (caps & WL_SEAT_CAPABILITY_POINTER) { + struct wl_pointer *pointer = wl_seat_get_pointer(seat); + wl_pointer_add_listener(pointer, &pointer_listener, NULL); + } +} + +static const struct wl_seat_listener seat_listener = { + .capabilities = seat_handle_capabilities, +}; + +static void handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) { + if (strcmp(interface, wl_compositor_interface.name) == 0) { + compositor = wl_registry_bind(registry, name, &wl_compositor_interface, + 1); + } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { + wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); + } else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) { + decoration_manager = wl_registry_bind(registry, name, + &zxdg_decoration_manager_v1_interface, 1); + } else if (strcmp(interface, wl_seat_interface.name) == 0) { + struct wl_seat *seat = + wl_registry_bind(registry, name, &wl_seat_interface, 1); + wl_seat_add_listener(seat, &seat_listener, NULL); + } +} + +static void handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) { + // Who cares? +} + +static const struct wl_registry_listener registry_listener = { + .global = handle_global, + .global_remove = handle_global_remove, +}; + +int main(int argc, char **argv) { + if (argc == 2) { + char *mode = argv[1]; + if (strcmp(mode, "client") == 0) { + client_preferred_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; + } else if (strcmp(mode, "server") == 0) { + client_preferred_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; + } else { + fprintf(stderr, "Invalid decoration mode\n"); + return EXIT_FAILURE; + } + } + + struct wl_display *display = wl_display_connect(NULL); + if (display == NULL) { + fprintf(stderr, "Failed to create display\n"); + return EXIT_FAILURE; + } + + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_dispatch(display); + wl_display_roundtrip(display); + + if (compositor == NULL) { + fprintf(stderr, "wl-compositor not available\n"); + return EXIT_FAILURE; + } + if (wm_base == NULL) { + fprintf(stderr, "xdg-shell not available\n"); + return EXIT_FAILURE; + } + if (decoration_manager == NULL) { + fprintf(stderr, "xdg-decoration not available\n"); + return EXIT_FAILURE; + } + + wlr_egl_init(&egl, EGL_PLATFORM_WAYLAND_EXT, display, NULL, + WL_SHM_FORMAT_ARGB8888); + + struct wl_surface *surface = wl_compositor_create_surface(compositor); + struct xdg_surface *xdg_surface = + xdg_wm_base_get_xdg_surface(wm_base, surface); + struct xdg_toplevel *xdg_toplevel = xdg_surface_get_toplevel(xdg_surface); + decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( + decoration_manager, xdg_toplevel); + + wl_display_roundtrip(display); + request_preferred_mode(); + + xdg_surface_add_listener(xdg_surface, &xdg_surface_listener, NULL); + xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, NULL); + zxdg_toplevel_decoration_v1_add_listener(decoration, &decoration_listener, + NULL); + wl_surface_commit(surface); + + egl_window = wl_egl_window_create(surface, width, height); + egl_surface = wlr_egl_create_surface(&egl, egl_window); + + wl_display_roundtrip(display); + + draw(); + + while (wl_display_dispatch(display) != -1) { + // This space is intentionally left blank + } + + return EXIT_SUCCESS; +} diff --git a/examples/touch.c b/examples/touch.c index 9954cdbd..9ed20a28 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -1,5 +1,4 @@ #define _POSIX_C_SOURCE 200112L -#define _XOPEN_SOURCE 500 #include <GLES2/gl2.h> #include <math.h> #include <stdint.h> @@ -211,8 +210,14 @@ void new_input_notify(struct wl_listener *listener, void *data) { wlr_log(WLR_ERROR, "Failed to create XKB context"); exit(1); } - wlr_keyboard_set_keymap(device->keyboard, xkb_map_new_from_names(context, - &rules, XKB_KEYMAP_COMPILE_NO_FLAGS)); + struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) { + wlr_log(WLR_ERROR, "Failed to create XKB keymap"); + exit(1); + } + wlr_keyboard_set_keymap(device->keyboard, keymap); + xkb_keymap_unref(keymap); xkb_context_unref(context); break; case WLR_INPUT_DEVICE_TOUCH:; @@ -7,16 +7,15 @@ # to fail if it can't load the function. You'll need to check if that function # is NULL before using it. -if [ $# -ne 3 ]; then +if [ $# -ne 2 ]; then exit 1 fi SPEC=$1 -OUT_C=$2 -OUT_H=$3 +OUTDIR=$2 BASE=$(basename "$SPEC" .txt) -INCLUDE_GUARD=$(printf %s "$OUT_H" | tr -c [:alnum:] _ | tr [:lower:] [:upper:]) +INCLUDE_GUARD=$(printf %s_%s_H "$OUTDIR" "$BASE" | tr -c [:alnum:] _ | tr [:lower:] [:upper:]) DECL="" DEFN="" @@ -56,9 +55,9 @@ while read -r COMMAND; do if [ $OPTIONAL -eq 0 ]; then LOADER="$LOADER$(printf "\n$CHECK_FMT" "$COMMAND" "$COMMAND")" fi -done < $SPEC +done < "$SPEC" -cat > $OUT_H << EOF +cat > "$OUTDIR/$BASE.h" << EOF #ifndef $INCLUDE_GUARD #define $INCLUDE_GUARD @@ -66,7 +65,6 @@ cat > $OUT_H << EOF #include <EGL/egl.h> #include <EGL/eglext.h> -#include <EGL/eglmesaext.h> #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> @@ -76,9 +74,9 @@ $DECL #endif EOF -cat > $OUT_C << EOF +cat > "$OUTDIR/$BASE.c" << EOF #include <wlr/util/log.h> -#include "$OUT_H" +#include "$BASE.h" $DEFN bool load_$BASE(void) { diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 416507ea..fe279917 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -119,6 +119,7 @@ struct wlr_drm_connector { struct wlr_output output; enum wlr_drm_connector_state state; + struct wlr_output_mode *desired_mode; uint32_t id; struct wlr_drm_crtc *crtc; @@ -143,9 +144,5 @@ void restore_drm_outputs(struct wlr_drm_backend *drm); void scan_drm_connectors(struct wlr_drm_backend *state); int handle_drm_event(int fd, uint32_t mask, void *data); void enable_drm_connector(struct wlr_output *output, bool enable); -/** - * Add mode to the list of available modes - */ -bool wlr_drm_connector_add_mode(struct wlr_output *output, const drmModeModeInfo *mode); #endif diff --git a/include/render/gles2.h b/include/render/gles2.h index 8b036f80..f649f3e2 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -88,7 +88,7 @@ const struct wlr_gles2_pixel_format *get_gles2_format_from_wl( enum wl_shm_format fmt); const enum wl_shm_format *get_gles2_formats(size_t *len); -struct wlr_gles2_texture *get_gles2_texture_in_context( +struct wlr_gles2_texture *gles2_get_texture( struct wlr_texture *wlr_texture); void push_gles2_marker(const char *file, const char *func); diff --git a/include/rootston/cursor.h b/include/rootston/cursor.h index f7410dec..2c687a39 100644 --- a/include/rootston/cursor.h +++ b/include/rootston/cursor.h @@ -80,4 +80,7 @@ void roots_cursor_handle_tool_tip(struct roots_cursor *cursor, void roots_cursor_handle_request_set_cursor(struct roots_cursor *cursor, struct wlr_seat_pointer_request_set_cursor_event *event); +void roots_cursor_update_position(struct roots_cursor *cursor, + uint32_t time); + #endif diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index d9add26a..3496fb43 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -4,26 +4,24 @@ #include <wayland-server.h> #include <wlr/config.h> #include <wlr/types/wlr_compositor.h> +#include <wlr/types/wlr_gamma_control_v1.h> #include <wlr/types/wlr_gamma_control.h> +#include <wlr/types/wlr_idle_inhibit_v1.h> #include <wlr/types/wlr_idle.h> #include <wlr/types/wlr_input_inhibitor.h> #include <wlr/types/wlr_layer_shell.h> -#include <wlr/types/wlr_linux_dmabuf.h> #include <wlr/types/wlr_list.h> #include <wlr/types/wlr_output_layout.h> #include <wlr/types/wlr_output.h> #include <wlr/types/wlr_primary_selection.h> +#include <wlr/types/wlr_screencopy_v1.h> #include <wlr/types/wlr_screenshooter.h> #include <wlr/types/wlr_virtual_keyboard_v1.h> #include <wlr/types/wlr_wl_shell.h> #include <wlr/types/wlr_xcursor_manager.h> +#include <wlr/types/wlr_xdg_decoration_v1.h> #include <wlr/types/wlr_xdg_shell_v6.h> #include <wlr/types/wlr_xdg_shell.h> -#include <wlr/types/wlr_list.h> -#include <wlr/types/wlr_idle.h> -#include <wlr/types/wlr_idle_inhibit_v1.h> -#include <wlr/types/wlr_screencopy_v1.h> -#include "rootston/view.h" #include "rootston/config.h" #include "rootston/output.h" #include "rootston/view.h" @@ -45,14 +43,15 @@ struct roots_desktop { struct wlr_xdg_shell_v6 *xdg_shell_v6; struct wlr_xdg_shell *xdg_shell; struct wlr_gamma_control_manager *gamma_control_manager; + struct wlr_gamma_control_manager_v1 *gamma_control_manager_v1; struct wlr_screenshooter *screenshooter; struct wlr_export_dmabuf_manager_v1 *export_dmabuf_manager_v1; struct wlr_server_decoration_manager *server_decoration_manager; + struct wlr_xdg_decoration_manager_v1 *xdg_decoration_manager; struct wlr_primary_selection_device_manager *primary_selection_device_manager; struct wlr_idle *idle; struct wlr_idle_inhibit_manager_v1 *idle_inhibit; struct wlr_input_inhibit_manager *input_inhibit; - struct wlr_linux_dmabuf *linux_dmabuf; struct wlr_layer_shell *layer_shell; struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard; struct wlr_screencopy_manager_v1 *screencopy; @@ -64,7 +63,7 @@ struct roots_desktop { struct wl_listener xdg_shell_surface; struct wl_listener wl_shell_surface; struct wl_listener layer_shell_surface; - struct wl_listener decoration_new; + struct wl_listener xdg_toplevel_decoration; struct wl_listener input_inhibit_activate; struct wl_listener input_inhibit_deactivate; struct wl_listener virtual_keyboard_new; @@ -94,6 +93,7 @@ void view_apply_damage(struct roots_view *view); void view_damage_whole(struct roots_view *view); void view_update_position(struct roots_view *view, double x, double y); void view_update_size(struct roots_view *view, uint32_t width, uint32_t height); +void view_update_decorated(struct roots_view *view, bool decorated); void view_initial_focus(struct roots_view *view); void view_map(struct roots_view *view, struct wlr_surface *surface); void view_unmap(struct roots_view *view); @@ -101,6 +101,7 @@ void view_arrange_maximized(struct roots_view *view); void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); void handle_xdg_shell_surface(struct wl_listener *listener, void *data); +void handle_xdg_toplevel_decoration(struct wl_listener *listener, void *data); void handle_wl_shell_surface(struct wl_listener *listener, void *data); void handle_layer_shell_surface(struct wl_listener *listener, void *data); void handle_xwayland_surface(struct wl_listener *listener, void *data); diff --git a/include/rootston/input.h b/include/rootston/input.h index ef46fab2..2cdb13e6 100644 --- a/include/rootston/input.h +++ b/include/rootston/input.h @@ -32,4 +32,6 @@ struct roots_seat *input_get_seat(struct roots_input *input, char *name); struct roots_seat *input_last_active_seat(struct roots_input *input); +void input_update_cursor_focus(struct roots_input *input); + #endif diff --git a/include/rootston/view.h b/include/rootston/view.h index 4e3859d5..14448fc6 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -4,6 +4,7 @@ #include <wlr/config.h> #include <wlr/types/wlr_box.h> #include <wlr/types/wlr_surface.h> +#include <wlr/types/wlr_xdg_decoration_v1.h> #include <wlr/types/wlr_xdg_shell_v6.h> #include <wlr/types/wlr_xdg_shell.h> @@ -38,6 +39,8 @@ struct roots_xdg_surface_v6 { uint32_t pending_move_resize_configure_serial; }; +struct roots_xdg_toplevel_decoration; + struct roots_xdg_surface { struct roots_view *view; @@ -53,6 +56,8 @@ struct roots_xdg_surface { struct wl_listener surface_commit; uint32_t pending_move_resize_configure_serial; + + struct roots_xdg_toplevel_decoration *xdg_toplevel_decoration; }; struct roots_xwayland_surface { @@ -190,6 +195,14 @@ struct roots_xdg_popup { struct wl_listener new_popup; }; +struct roots_xdg_toplevel_decoration { + struct wlr_xdg_toplevel_decoration_v1 *wlr_decoration; + struct roots_xdg_surface *surface; + struct wl_listener destroy; + struct wl_listener request_mode; + struct wl_listener surface_commit; +}; + void view_get_box(const struct roots_view *view, struct wlr_box *box); void view_activate(struct roots_view *view, bool active); void view_move(struct roots_view *view, double x, double y); diff --git a/include/types/wlr_xdg_shell.h b/include/types/wlr_xdg_shell.h index 7a17d286..93fdc670 100644 --- a/include/types/wlr_xdg_shell.h +++ b/include/types/wlr_xdg_shell.h @@ -19,7 +19,8 @@ struct wlr_xdg_surface *create_xdg_surface( uint32_t id); void unmap_xdg_surface(struct wlr_xdg_surface *surface); void destroy_xdg_surface(struct wlr_xdg_surface *surface); -void handle_xdg_surface_committed(struct wlr_surface *wlr_surface); +void handle_xdg_surface_commit(struct wlr_surface *wlr_surface); +void handle_xdg_surface_precommit(struct wlr_surface *wlr_surface); void create_xdg_positioner(struct wlr_xdg_client *client, uint32_t id); struct wlr_xdg_positioner_resource *get_xdg_positioner_from_resource( diff --git a/include/types/wlr_xdg_shell_v6.h b/include/types/wlr_xdg_shell_v6.h index 030c10e4..59fca667 100644 --- a/include/types/wlr_xdg_shell_v6.h +++ b/include/types/wlr_xdg_shell_v6.h @@ -19,7 +19,8 @@ struct wlr_xdg_surface_v6 *create_xdg_surface_v6( uint32_t id); void unmap_xdg_surface_v6(struct wlr_xdg_surface_v6 *surface); void destroy_xdg_surface_v6(struct wlr_xdg_surface_v6 *surface); -void handle_xdg_surface_v6_committed(struct wlr_surface *wlr_surface); +void handle_xdg_surface_v6_commit(struct wlr_surface *wlr_surface); +void handle_xdg_surface_v6_precommit(struct wlr_surface *wlr_surface); void create_xdg_positioner_v6(struct wlr_xdg_client_v6 *client, uint32_t id); struct wlr_xdg_positioner_v6_resource *get_xdg_positioner_v6_from_resource( diff --git a/include/wlr/backend.h b/include/wlr/backend.h index f40f5353..39d072e2 100644 --- a/include/wlr/backend.h +++ b/include/wlr/backend.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_BACKEND_H #define WLR_BACKEND_H diff --git a/include/wlr/backend/drm.h b/include/wlr/backend/drm.h index 7f41ca15..5d47647d 100644 --- a/include/wlr/backend/drm.h +++ b/include/wlr/backend/drm.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_BACKEND_DRM_H #define WLR_BACKEND_DRM_H @@ -20,6 +28,12 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, bool wlr_backend_is_drm(struct wlr_backend *backend); bool wlr_output_is_drm(struct wlr_output *output); +/** + * Add mode to the list of available modes + */ +typedef struct _drmModeModeInfo drmModeModeInfo; +bool wlr_drm_connector_add_mode(struct wlr_output *output, const drmModeModeInfo *mode); + struct wlr_session *wlr_drm_backend_get_session(struct wlr_backend *backend); #endif diff --git a/include/wlr/backend/headless.h b/include/wlr/backend/headless.h index 02c7cd11..eab102e2 100644 --- a/include/wlr/backend/headless.h +++ b/include/wlr/backend/headless.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_BACKEND_HEADLESS_H #define WLR_BACKEND_HEADLESS_H diff --git a/include/wlr/backend/interface.h b/include/wlr/backend/interface.h index 42b39a16..f3dee69b 100644 --- a/include/wlr/backend/interface.h +++ b/include/wlr/backend/interface.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_BACKEND_INTERFACE_H #define WLR_BACKEND_INTERFACE_H diff --git a/include/wlr/backend/libinput.h b/include/wlr/backend/libinput.h index 92d31415..1a2ab294 100644 --- a/include/wlr/backend/libinput.h +++ b/include/wlr/backend/libinput.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_BACKEND_LIBINPUT_H #define WLR_BACKEND_LIBINPUT_H diff --git a/include/wlr/backend/meson.build b/include/wlr/backend/meson.build new file mode 100644 index 00000000..e005b854 --- /dev/null +++ b/include/wlr/backend/meson.build @@ -0,0 +1,16 @@ +install_headers( + 'drm.h', + 'headless.h', + 'interface.h', + 'libinput.h', + 'multi.h', + 'session.h', + 'wayland.h', + subdir: 'wlr/backend', +) + +if conf_data.get('WLR_HAS_X11_BACKEND', false) + install_headers('x11.h', subdir: 'wlr/backend') +endif + +subdir('session') diff --git a/include/wlr/backend/multi.h b/include/wlr/backend/multi.h index 1e04dba4..7137b075 100644 --- a/include/wlr/backend/multi.h +++ b/include/wlr/backend/multi.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_BACKEND_MULTI_H #define WLR_BACKEND_MULTI_H diff --git a/include/wlr/backend/session.h b/include/wlr/backend/session.h index 1cf41939..7b26f34c 100644 --- a/include/wlr/backend/session.h +++ b/include/wlr/backend/session.h @@ -39,6 +39,10 @@ struct wlr_session { struct wl_list devices; struct wl_listener display_destroy; + + struct { + struct wl_signal destroy; + } events; }; /* diff --git a/include/wlr/backend/session/interface.h b/include/wlr/backend/session/interface.h index b35ed71d..5ccf9c8a 100644 --- a/include/wlr/backend/session/interface.h +++ b/include/wlr/backend/session/interface.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_BACKEND_SESSION_INTERFACE_H #define WLR_BACKEND_SESSION_INTERFACE_H diff --git a/include/wlr/backend/session/meson.build b/include/wlr/backend/session/meson.build new file mode 100644 index 00000000..21b5a96b --- /dev/null +++ b/include/wlr/backend/session/meson.build @@ -0,0 +1 @@ +install_headers('interface.h', subdir: 'wlr/backend/session') diff --git a/include/wlr/config.h.in b/include/wlr/config.h.in new file mode 100644 index 00000000..750ad3b7 --- /dev/null +++ b/include/wlr/config.h.in @@ -0,0 +1,19 @@ +#ifndef WLR_CONFIG_H +#define WLR_CONFIG_H + +#mesondefine WLR_HAS_LIBCAP + +#mesondefine WLR_HAS_SYSTEMD +#mesondefine WLR_HAS_ELOGIND + +#mesondefine WLR_HAS_X11_BACKEND + +#mesondefine WLR_HAS_XWAYLAND + +#mesondefine WLR_HAS_XCB_ERRORS +#mesondefine WLR_HAS_XCB_ICCCM +#mesondefine WLR_HAS_XCB_XKB + +#mesondefine WLR_HAS_POSIX_FALLOCATE + +#endif diff --git a/include/wlr/interfaces/meson.build b/include/wlr/interfaces/meson.build new file mode 100644 index 00000000..207896b5 --- /dev/null +++ b/include/wlr/interfaces/meson.build @@ -0,0 +1,10 @@ +install_headers( + 'wlr_input_device.h', + 'wlr_keyboard.h', + 'wlr_output.h', + 'wlr_pointer.h', + 'wlr_tablet_pad.h', + 'wlr_tablet_tool.h', + 'wlr_touch.h', + subdir: 'wlr/interfaces', +) diff --git a/include/wlr/interfaces/wlr_input_device.h b/include/wlr/interfaces/wlr_input_device.h index a5c513b7..05248bf6 100644 --- a/include/wlr/interfaces/wlr_input_device.h +++ b/include/wlr/interfaces/wlr_input_device.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_INTERFACES_WLR_INPUT_DEVICE_H #define WLR_INTERFACES_WLR_INPUT_DEVICE_H diff --git a/include/wlr/interfaces/wlr_keyboard.h b/include/wlr/interfaces/wlr_keyboard.h index c9a13fd7..5d537827 100644 --- a/include/wlr/interfaces/wlr_keyboard.h +++ b/include/wlr/interfaces/wlr_keyboard.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_INTERFACES_WLR_KEYBOARD_H #define WLR_INTERFACES_WLR_KEYBOARD_H diff --git a/include/wlr/interfaces/wlr_output.h b/include/wlr/interfaces/wlr_output.h index 8f87408a..4860a5b6 100644 --- a/include/wlr/interfaces/wlr_output.h +++ b/include/wlr/interfaces/wlr_output.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_INTERFACES_WLR_OUTPUT_H #define WLR_INTERFACES_WLR_OUTPUT_H @@ -20,7 +28,7 @@ struct wlr_output_impl { void (*destroy)(struct wlr_output *output); bool (*make_current)(struct wlr_output *output, int *buffer_age); bool (*swap_buffers)(struct wlr_output *output, pixman_region32_t *damage); - void (*set_gamma)(struct wlr_output *output, + bool (*set_gamma)(struct wlr_output *output, uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b); uint32_t (*get_gamma_size)(struct wlr_output *output); bool (*export_dmabuf)(struct wlr_output *output, diff --git a/include/wlr/interfaces/wlr_pointer.h b/include/wlr/interfaces/wlr_pointer.h index f0cf9081..fd3ab102 100644 --- a/include/wlr/interfaces/wlr_pointer.h +++ b/include/wlr/interfaces/wlr_pointer.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_INTERFACES_WLR_POINTER_H #define WLR_INTERFACES_WLR_POINTER_H diff --git a/include/wlr/interfaces/wlr_tablet_pad.h b/include/wlr/interfaces/wlr_tablet_pad.h index 5ec1e3eb..86bbe9c3 100644 --- a/include/wlr/interfaces/wlr_tablet_pad.h +++ b/include/wlr/interfaces/wlr_tablet_pad.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_INTERFACES_WLR_TABLET_PAD_H #define WLR_INTERFACES_WLR_TABLET_PAD_H diff --git a/include/wlr/interfaces/wlr_tablet_tool.h b/include/wlr/interfaces/wlr_tablet_tool.h index 12b2e32e..9cfc3ca0 100644 --- a/include/wlr/interfaces/wlr_tablet_tool.h +++ b/include/wlr/interfaces/wlr_tablet_tool.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_INTERFACES_WLR_TABLET_TOOL_H #define WLR_INTERFACES_WLR_TABLET_TOOL_H diff --git a/include/wlr/interfaces/wlr_touch.h b/include/wlr/interfaces/wlr_touch.h index 63bac6b8..cc426332 100644 --- a/include/wlr/interfaces/wlr_touch.h +++ b/include/wlr/interfaces/wlr_touch.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_INTERFACES_WLR_TOUCH_H #define WLR_INTERFACES_WLR_TOUCH_H diff --git a/include/wlr/meson.build b/include/wlr/meson.build index 6259c311..43b5aec9 100644 --- a/include/wlr/meson.build +++ b/include/wlr/meson.build @@ -4,11 +4,23 @@ version_data.set_quoted('WLR_VERSION_STR', meson.project_version()) version_data.set('WLR_VERSION_MAJOR', version_array[0]) version_data.set('WLR_VERSION_MINOR', version_array[1]) version_data.set('WLR_VERSION_MICRO', version_array[2]) -version_data.set('WLR_VERSION_NUM', '(WLR_VERSION_MAJOR << 16) | (WLR_VERSION_MINOR << 8) | WLR_VERSION_MICRO') version_data.set('WLR_VERSION_API_CURRENT', so_version[0]) version_data.set('WLR_VERSION_API_REVISION', so_version[1]) version_data.set('WLR_VERSION_API_AGE', so_version[2]) -wlr_inc_dest = join_paths(get_option('includedir'), 'wlr') -configure_file(output: 'config.h', install_dir: wlr_inc_dest, configuration: conf_data) -configure_file(output: 'version.h', install_dir: wlr_inc_dest, configuration: version_data) +install_headers( + configure_file(input: 'config.h.in', output: 'config.h',configuration: conf_data), + configure_file(input: 'version.h.in', output: 'version.h', configuration: version_data), + 'backend.h', + 'xcursor.h', + subdir: 'wlr' +) +if conf_data.get('WLR_HAS_XWAYLAND', false) + install_headers('xwayland.h', subdir: 'wlr') +endif + +subdir('backend') +subdir('interfaces') +subdir('render') +subdir('types') +subdir('util') diff --git a/include/wlr/render/dmabuf.h b/include/wlr/render/dmabuf.h index 78f8c2eb..33c3a129 100644 --- a/include/wlr/render/dmabuf.h +++ b/include/wlr/render/dmabuf.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_RENDER_DMABUF_H #define WLR_RENDER_DMABUF_H diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index 6b887f4f..c42b0325 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_RENDER_EGL_H #define WLR_RENDER_EGL_H diff --git a/include/wlr/render/gles2.h b/include/wlr/render/gles2.h index 866c6658..fca11ab8 100644 --- a/include/wlr/render/gles2.h +++ b/include/wlr/render/gles2.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_RENDER_GLES2_H #define WLR_RENDER_GLES2_H diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index f4565ad5..63f4265c 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_RENDER_INTERFACE_H #define WLR_RENDER_INTERFACE_H diff --git a/include/wlr/render/meson.build b/include/wlr/render/meson.build new file mode 100644 index 00000000..05127bb7 --- /dev/null +++ b/include/wlr/render/meson.build @@ -0,0 +1,9 @@ +install_headers( + 'dmabuf.h', + 'egl.h', + 'gles2.h', + 'interface.h', + 'wlr_renderer.h', + 'wlr_texture.h', + subdir: 'wlr/render' +) diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index 0650bf1b..9c031b7f 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_RENDER_WLR_RENDERER_H #define WLR_RENDER_WLR_RENDERER_H diff --git a/include/wlr/render/wlr_texture.h b/include/wlr/render/wlr_texture.h index 9370fa25..dbfabfee 100644 --- a/include/wlr/render/wlr_texture.h +++ b/include/wlr/render/wlr_texture.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_RENDER_WLR_TEXTURE_H #define WLR_RENDER_WLR_TEXTURE_H diff --git a/include/wlr/types/meson.build b/include/wlr/types/meson.build new file mode 100644 index 00000000..8c81cb0e --- /dev/null +++ b/include/wlr/types/meson.build @@ -0,0 +1,42 @@ +install_headers( + 'wlr_box.h', + 'wlr_buffer.h', + 'wlr_compositor.h', + 'wlr_cursor.h', + 'wlr_data_device.h', + 'wlr_export_dmabuf_v1.h', + 'wlr_gamma_control.h', + 'wlr_gamma_control_v1.h', + 'wlr_idle.h', + 'wlr_idle_inhibit_v1.h', + 'wlr_input_device.h', + 'wlr_input_inhibitor.h', + 'wlr_keyboard.h', + 'wlr_layer_shell.h', + 'wlr_linux_dmabuf_v1.h', + 'wlr_list.h', + 'wlr_matrix.h', + 'wlr_output.h', + 'wlr_output_damage.h', + 'wlr_output_layout.h', + 'wlr_pointer.h', + 'wlr_primary_selection.h', + 'wlr_region.h', + 'wlr_screencopy_v1.h', + 'wlr_screenshooter.h', + 'wlr_seat.h', + 'wlr_server_decoration.h', + 'wlr_surface.h', + 'wlr_tablet_pad.h', + 'wlr_tablet_tool.h', + 'wlr_tablet_v2.h', + 'wlr_touch.h', + 'wlr_virtual_keyboard_v1.h', + 'wlr_wl_shell.h', + 'wlr_xcursor_manager.h', + 'wlr_xdg_decoration_v1.h', + 'wlr_xdg_output.h', + 'wlr_xdg_shell.h', + 'wlr_xdg_shell_v6.h', + subdir: 'wlr/types', +) diff --git a/include/wlr/types/wlr_box.h b/include/wlr/types/wlr_box.h index 0e586a18..11a53b56 100644 --- a/include/wlr/types/wlr_box.h +++ b/include/wlr/types/wlr_box.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_BOX_H #define WLR_TYPES_WLR_BOX_H diff --git a/include/wlr/types/wlr_buffer.h b/include/wlr/types/wlr_buffer.h index eabc8b51..0c987b17 100644 --- a/include/wlr/types/wlr_buffer.h +++ b/include/wlr/types/wlr_buffer.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_BUFFER_H #define WLR_TYPES_WLR_BUFFER_H diff --git a/include/wlr/types/wlr_compositor.h b/include/wlr/types/wlr_compositor.h index 0d79b0bb..1772e54b 100644 --- a/include/wlr/types/wlr_compositor.h +++ b/include/wlr/types/wlr_compositor.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_COMPOSITOR_H #define WLR_TYPES_WLR_COMPOSITOR_H diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index 998c6f0d..ba582be9 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_CURSOR_H #define WLR_TYPES_WLR_CURSOR_H diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index 8b7b374c..c45e8d1c 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_DATA_DEVICE_H #define WLR_TYPES_WLR_DATA_DEVICE_H @@ -85,8 +93,6 @@ struct wlr_drag_icon { bool is_pointer; int32_t touch_id; - int32_t sx, sy; - struct { struct wl_signal map; struct wl_signal unmap; diff --git a/include/wlr/types/wlr_export_dmabuf_v1.h b/include/wlr/types/wlr_export_dmabuf_v1.h index a094b3de..56767540 100644 --- a/include/wlr/types/wlr_export_dmabuf_v1.h +++ b/include/wlr/types/wlr_export_dmabuf_v1.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_EXPORT_DMABUF_V1_H #define WLR_TYPES_WLR_EXPORT_DMABUF_V1_H diff --git a/include/wlr/types/wlr_gamma_control.h b/include/wlr/types/wlr_gamma_control.h index f195c8ef..912a413c 100644 --- a/include/wlr/types/wlr_gamma_control.h +++ b/include/wlr/types/wlr_gamma_control.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_GAMMA_CONTROL_H #define WLR_TYPES_WLR_GAMMA_CONTROL_H @@ -9,6 +17,10 @@ struct wlr_gamma_control_manager { struct wl_listener display_destroy; + struct { + struct wl_signal destroy; + } events; + void *data; }; diff --git a/include/wlr/types/wlr_gamma_control_v1.h b/include/wlr/types/wlr_gamma_control_v1.h new file mode 100644 index 00000000..f186aa81 --- /dev/null +++ b/include/wlr/types/wlr_gamma_control_v1.h @@ -0,0 +1,35 @@ +#ifndef WLR_TYPES_WLR_GAMMA_CONTROL_V1_H +#define WLR_TYPES_WLR_GAMMA_CONTROL_V1_H + +#include <wayland-server.h> + +struct wlr_gamma_control_manager_v1 { + struct wl_global *global; + struct wl_list resources; + struct wl_list controls; // wlr_gamma_control_v1::link + + struct wl_listener display_destroy; + + struct { + struct wl_signal destroy; + } events; + + void *data; +}; + +struct wlr_gamma_control_v1 { + struct wl_resource *resource; + struct wlr_output *output; + struct wl_list link; + + struct wl_listener output_destroy_listener; + + void *data; +}; + +struct wlr_gamma_control_manager_v1 *wlr_gamma_control_manager_v1_create( + struct wl_display *display); +void wlr_gamma_control_manager_v1_destroy( + struct wlr_gamma_control_manager_v1 *manager); + +#endif diff --git a/include/wlr/types/wlr_idle.h b/include/wlr/types/wlr_idle.h index 53fc6b98..d8c81a60 100644 --- a/include/wlr/types/wlr_idle.h +++ b/include/wlr/types/wlr_idle.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_IDLE_H #define WLR_TYPES_WLR_IDLE_H @@ -22,6 +30,7 @@ struct wlr_idle { struct wl_listener display_destroy; struct { struct wl_signal activity_notify; + struct wl_signal destroy; } events; void *data; diff --git a/include/wlr/types/wlr_idle_inhibit_v1.h b/include/wlr/types/wlr_idle_inhibit_v1.h index 011abbe5..2093eafe 100644 --- a/include/wlr/types/wlr_idle_inhibit_v1.h +++ b/include/wlr/types/wlr_idle_inhibit_v1.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_IDLE_INHIBIT_V1_H #define WLR_TYPES_WLR_IDLE_INHIBIT_V1_H @@ -19,11 +27,12 @@ struct wlr_idle_inhibit_manager_v1 { struct wl_list resources; // wl_resource_get_link struct wl_list inhibitors; // wlr_idle_inhibit_inhibitor_v1::link struct wl_global *global; - + struct wl_listener display_destroy; struct { struct wl_signal new_inhibitor; + struct wl_signal destroy; } events; void *data; diff --git a/include/wlr/types/wlr_input_device.h b/include/wlr/types/wlr_input_device.h index cce15d90..ab0aecb6 100644 --- a/include/wlr/types/wlr_input_device.h +++ b/include/wlr/types/wlr_input_device.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_INPUT_DEVICE_H #define WLR_TYPES_WLR_INPUT_DEVICE_H diff --git a/include/wlr/types/wlr_input_inhibitor.h b/include/wlr/types/wlr_input_inhibitor.h index 2f333f3b..f3187540 100644 --- a/include/wlr/types/wlr_input_inhibitor.h +++ b/include/wlr/types/wlr_input_inhibitor.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_INPUT_INHIBITOR_H #define WLR_TYPES_INPUT_INHIBITOR_H #include <wayland-server.h> @@ -12,6 +20,7 @@ struct wlr_input_inhibit_manager { struct { struct wl_signal activate; // struct wlr_input_inhibit_manager * struct wl_signal deactivate; // struct wlr_input_inhibit_manager * + struct wl_signal destroy; } events; void *data; diff --git a/include/wlr/types/wlr_keyboard.h b/include/wlr/types/wlr_keyboard.h index 67d4e5be..3e207523 100644 --- a/include/wlr/types/wlr_keyboard.h +++ b/include/wlr/types/wlr_keyboard.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_KEYBOARD_H #define WLR_TYPES_WLR_KEYBOARD_H diff --git a/include/wlr/types/wlr_layer_shell.h b/include/wlr/types/wlr_layer_shell.h index 2848a115..c7ddd180 100644 --- a/include/wlr/types/wlr_layer_shell.h +++ b/include/wlr/types/wlr_layer_shell.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_LAYER_SHELL_H #define WLR_TYPES_WLR_LAYER_SHELL_H #include <stdbool.h> @@ -31,6 +39,7 @@ struct wlr_layer_shell { // Note: the output may be NULL. In this case, it is your // responsibility to assign an output before returning. struct wl_signal new_surface; + struct wl_signal destroy; } events; void *data; diff --git a/include/wlr/types/wlr_linux_dmabuf.h b/include/wlr/types/wlr_linux_dmabuf_v1.h index 4a03170c..f21b0b3a 100644 --- a/include/wlr/types/wlr_linux_dmabuf.h +++ b/include/wlr/types/wlr_linux_dmabuf_v1.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_LINUX_DMABUF_H #define WLR_TYPES_WLR_LINUX_DMABUF_H @@ -5,7 +13,7 @@ #include <wayland-server-protocol.h> #include <wlr/render/dmabuf.h> -struct wlr_dmabuf_buffer { +struct wlr_dmabuf_v1_buffer { struct wlr_renderer *renderer; struct wl_resource *buffer_resource; struct wl_resource *params_resource; @@ -17,24 +25,24 @@ struct wlr_dmabuf_buffer { * Returns true if the given resource was created via the linux-dmabuf * buffer protocol, false otherwise */ -bool wlr_dmabuf_resource_is_buffer(struct wl_resource *buffer_resource); +bool wlr_dmabuf_v1_resource_is_buffer(struct wl_resource *buffer_resource); /** * Returns the wlr_dmabuf_buffer if the given resource was created * via the linux-dmabuf buffer protocol */ -struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_buffer_resource( +struct wlr_dmabuf_v1_buffer *wlr_dmabuf_v1_buffer_from_buffer_resource( struct wl_resource *buffer_resource); /** * Returns the wlr_dmabuf_buffer if the given resource was created * via the linux-dmabuf params protocol */ -struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_params_resource( +struct wlr_dmabuf_v1_buffer *wlr_dmabuf_v1_buffer_from_params_resource( struct wl_resource *params_resource); /* the protocol interface */ -struct wlr_linux_dmabuf { +struct wlr_linux_dmabuf_v1 { struct wl_global *global; struct wlr_renderer *renderer; struct wl_list resources; @@ -50,18 +58,18 @@ struct wlr_linux_dmabuf { /** * Create linux-dmabuf interface */ -struct wlr_linux_dmabuf *wlr_linux_dmabuf_create(struct wl_display *display, +struct wlr_linux_dmabuf_v1 *wlr_linux_dmabuf_v1_create(struct wl_display *display, struct wlr_renderer *renderer); /** * Destroy the linux-dmabuf interface */ -void wlr_linux_dmabuf_destroy(struct wlr_linux_dmabuf *linux_dmabuf); +void wlr_linux_dmabuf_v1_destroy(struct wlr_linux_dmabuf_v1 *linux_dmabuf); /** * Returns the wlr_linux_dmabuf if the given resource was created * via the linux_dmabuf protocol */ -struct wlr_linux_dmabuf *wlr_linux_dmabuf_from_resource( +struct wlr_linux_dmabuf_v1 *wlr_linux_dmabuf_v1_from_resource( struct wl_resource *resource); #endif diff --git a/include/wlr/types/wlr_list.h b/include/wlr/types/wlr_list.h index 23bf53b7..60f388f9 100644 --- a/include/wlr/types/wlr_list.h +++ b/include/wlr/types/wlr_list.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_LIST_H #define WLR_TYPES_WLR_LIST_H diff --git a/include/wlr/types/wlr_matrix.h b/include/wlr/types/wlr_matrix.h index 02111db8..a3961c35 100644 --- a/include/wlr/types/wlr_matrix.h +++ b/include/wlr/types/wlr_matrix.h @@ -1,20 +1,57 @@ +/* + * This is a stable interface of wlroots. Future changes will be limited to: + * + * - New functions + * - New struct members + * - New enum members + * + * Note that wlroots does not make an ABI compatibility promise - in the future, + * the layout and size of structs used by wlroots may change, requiring code + * depending on this header to be recompiled (but not edited). + * + * Breaking changes are announced by email and follow a 1-year deprecation + * schedule. Send an email to ~sircmpwn/wlroots-announce+subscribe@lists.sr.ht + * to receive these announcements. + */ + #ifndef WLR_TYPES_WLR_MATRIX_H #define WLR_TYPES_WLR_MATRIX_H #include <wayland-server.h> #include <wlr/types/wlr_box.h> +/** Writes the identity matrix into mat */ void wlr_matrix_identity(float mat[static 9]); + +/** mat ← a × b */ void wlr_matrix_multiply(float mat[static 9], const float a[static 9], const float b[static 9]); + void wlr_matrix_transpose(float mat[static 9], const float a[static 9]); + +/** Writes a 2D translation matrix to mat of magnitude (x, y) */ void wlr_matrix_translate(float mat[static 9], float x, float y); + +/** Writes a 2D scale matrix to mat of magnitude (x, y) */ void wlr_matrix_scale(float mat[static 9], float x, float y); + +/** Writes a 2D rotation matrix to mat at an angle of rad radians */ void wlr_matrix_rotate(float mat[static 9], float rad); + +/** Writes a transformation matrix which applies the specified + * wl_output_transform to mat */ void wlr_matrix_transform(float mat[static 9], enum wl_output_transform transform); + +/** Writes a 2D orthographic projection matrix to mat of (width, height) with a + * specified wl_output_transform*/ void wlr_matrix_projection(float mat[static 9], int width, int height, enum wl_output_transform transform); + +/** Shortcut for the various matrix operations involved in projecting the + * specified wlr_box onto a given orthographic projection with a given + * rotation. The result is written to mat, which can be applied to each + * coordinate of the box to get a new coordinate from [-1,1]. */ void wlr_matrix_project_box(float mat[static 9], const struct wlr_box *box, enum wl_output_transform transform, float rotation, const float projection[static 9]); diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 5084eb5a..3a9f3c41 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_OUTPUT_H #define WLR_TYPES_WLR_OUTPUT_H @@ -6,7 +14,7 @@ #include <time.h> #include <wayland-server.h> #include <wayland-util.h> -#include <wlr/types/wlr_linux_dmabuf.h> +#include <wlr/render/dmabuf.h> struct wlr_output_mode { uint32_t flags; // enum wl_output_mode @@ -166,9 +174,19 @@ bool wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, * it is a no-op. */ void wlr_output_schedule_frame(struct wlr_output *output); -void wlr_output_set_gamma(struct wlr_output *output, - uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b); +/** + * Returns the maximum length of each gamma ramp, or 0 if unsupported. + */ uint32_t wlr_output_get_gamma_size(struct wlr_output *output); +/** + * Sets the gamma table for this output. `r`, `g` and `b` are gamma ramps for + * red, green and blue. `size` is the length of the ramps and must not exceed + * the value returned by `wlr_output_get_gamma_size`. + * + * Providing zero-sized ramps resets the gamma table. + */ +bool wlr_output_set_gamma(struct wlr_output *output, + uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b); bool wlr_output_export_dmabuf(struct wlr_output *output, struct wlr_dmabuf_attributes *attribs); void wlr_output_set_fullscreen_surface(struct wlr_output *output, diff --git a/include/wlr/types/wlr_output_damage.h b/include/wlr/types/wlr_output_damage.h index a4333c1a..d614e6d6 100644 --- a/include/wlr/types/wlr_output_damage.h +++ b/include/wlr/types/wlr_output_damage.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_OUTPUT_DAMAGE_H #define WLR_TYPES_WLR_OUTPUT_DAMAGE_H diff --git a/include/wlr/types/wlr_output_layout.h b/include/wlr/types/wlr_output_layout.h index 759c8ccf..cc9d2328 100644 --- a/include/wlr/types/wlr_output_layout.h +++ b/include/wlr/types/wlr_output_layout.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_OUTPUT_LAYOUT_H #define WLR_TYPES_WLR_OUTPUT_LAYOUT_H @@ -118,5 +126,8 @@ enum wlr_direction { struct wlr_output *wlr_output_layout_adjacent_output( struct wlr_output_layout *layout, enum wlr_direction direction, struct wlr_output *reference, double ref_lx, double ref_ly); +struct wlr_output *wlr_output_layout_farthest_output( + struct wlr_output_layout *layout, enum wlr_direction direction, + struct wlr_output *reference, double ref_lx, double ref_ly); #endif diff --git a/include/wlr/types/wlr_pointer.h b/include/wlr/types/wlr_pointer.h index 48c89151..7dc643ae 100644 --- a/include/wlr/types/wlr_pointer.h +++ b/include/wlr/types/wlr_pointer.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_POINTER_H #define WLR_TYPES_WLR_POINTER_H diff --git a/include/wlr/types/wlr_primary_selection.h b/include/wlr/types/wlr_primary_selection.h index 78f23ad6..f33f6368 100644 --- a/include/wlr/types/wlr_primary_selection.h +++ b/include/wlr/types/wlr_primary_selection.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_PRIMARY_SELECTION_H #define WLR_TYPES_WLR_PRIMARY_SELECTION_H @@ -9,6 +17,10 @@ struct wlr_primary_selection_device_manager { struct wl_listener display_destroy; + struct { + struct wl_signal destroy; + } events; + void *data; }; diff --git a/include/wlr/types/wlr_region.h b/include/wlr/types/wlr_region.h index be2f8b84..3c4a0532 100644 --- a/include/wlr/types/wlr_region.h +++ b/include/wlr/types/wlr_region.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_REGION_H #define WLR_TYPES_WLR_REGION_H diff --git a/include/wlr/types/wlr_screencopy_v1.h b/include/wlr/types/wlr_screencopy_v1.h index 892687aa..aba32a45 100644 --- a/include/wlr/types/wlr_screencopy_v1.h +++ b/include/wlr/types/wlr_screencopy_v1.h @@ -1,7 +1,16 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_SCREENCOPY_V1_H #define WLR_TYPES_WLR_SCREENCOPY_V1_H #include <wayland-server.h> +#include <wlr/types/wlr_box.h> struct wlr_screencopy_manager_v1 { struct wl_global *global; @@ -10,6 +19,10 @@ struct wlr_screencopy_manager_v1 { struct wl_listener display_destroy; + struct { + struct wl_signal destroy; + } events; + void *data; }; diff --git a/include/wlr/types/wlr_screenshooter.h b/include/wlr/types/wlr_screenshooter.h index 916c8942..b7b87b39 100644 --- a/include/wlr/types/wlr_screenshooter.h +++ b/include/wlr/types/wlr_screenshooter.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_SCREENSHOOTER_H #define WLR_TYPES_WLR_SCREENSHOOTER_H @@ -9,6 +17,10 @@ struct wlr_screenshooter { struct wl_listener display_destroy; + struct { + struct wl_signal destroy; + } events; + void *data; }; diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 92d0a233..b3c02cf2 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_SEAT_H #define WLR_TYPES_WLR_SEAT_H diff --git a/include/wlr/types/wlr_server_decoration.h b/include/wlr/types/wlr_server_decoration.h index 23387968..ff8d1369 100644 --- a/include/wlr/types/wlr_server_decoration.h +++ b/include/wlr/types/wlr_server_decoration.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_SERVER_DECORATION_H #define WLR_TYPES_WLR_SERVER_DECORATION_H @@ -37,6 +45,7 @@ struct wlr_server_decoration_manager { struct { struct wl_signal new_decoration; + struct wl_signal destroy; } events; void *data; diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 0e3b5ff4..063f9e26 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_SURFACE_H #define WLR_TYPES_WLR_SURFACE_H @@ -39,6 +47,7 @@ struct wlr_surface_state { struct wlr_surface_role { const char *name; void (*commit)(struct wlr_surface *surface); + void (*precommit)(struct wlr_surface *surface); }; struct wlr_surface { diff --git a/include/wlr/types/wlr_tablet_pad.h b/include/wlr/types/wlr_tablet_pad.h index 23ac464d..d9bb284f 100644 --- a/include/wlr/types/wlr_tablet_pad.h +++ b/include/wlr/types/wlr_tablet_pad.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_TABLET_PAD_H #define WLR_TYPES_WLR_TABLET_PAD_H diff --git a/include/wlr/types/wlr_tablet_tool.h b/include/wlr/types/wlr_tablet_tool.h index bfa2e1f7..cb516ed9 100644 --- a/include/wlr/types/wlr_tablet_tool.h +++ b/include/wlr/types/wlr_tablet_tool.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_TABLET_TOOL_H #define WLR_TYPES_TABLET_TOOL_H diff --git a/include/wlr/types/wlr_tablet_v2.h b/include/wlr/types/wlr_tablet_v2.h index e2a39392..d6fd646d 100644 --- a/include/wlr/types/wlr_tablet_v2.h +++ b/include/wlr/types/wlr_tablet_v2.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_TABLET_V2_H #define WLR_TYPES_WLR_TABLET_V2_H @@ -37,6 +45,10 @@ struct wlr_tablet_manager_v2 { struct wl_listener display_destroy; + struct { + struct wl_signal destroy; + } events; + void *data; }; diff --git a/include/wlr/types/wlr_touch.h b/include/wlr/types/wlr_touch.h index 70070f84..99316ae0 100644 --- a/include/wlr/types/wlr_touch.h +++ b/include/wlr/types/wlr_touch.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_TOUCH_H #define WLR_TYPES_WLR_TOUCH_H diff --git a/include/wlr/types/wlr_virtual_keyboard_v1.h b/include/wlr/types/wlr_virtual_keyboard_v1.h index 1236ae24..e75ed8ec 100644 --- a/include/wlr/types/wlr_virtual_keyboard_v1.h +++ b/include/wlr/types/wlr_virtual_keyboard_v1.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_VIRTUAL_KEYBOARD_V1_H #define WLR_TYPES_WLR_VIRTUAL_KEYBOARD_V1_H @@ -14,6 +22,7 @@ struct wlr_virtual_keyboard_manager_v1 { struct { struct wl_signal new_virtual_keyboard; // struct wlr_virtual_keyboard_v1* + struct wl_signal destroy; } events; }; diff --git a/include/wlr/types/wlr_wl_shell.h b/include/wlr/types/wlr_wl_shell.h index c4cc1999..dffbb4d7 100644 --- a/include/wlr/types/wlr_wl_shell.h +++ b/include/wlr/types/wlr_wl_shell.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_WL_SHELL_H #define WLR_TYPES_WLR_WL_SHELL_H @@ -16,6 +24,7 @@ struct wlr_wl_shell { struct { struct wl_signal new_surface; + struct wl_signal destroy; } events; void *data; diff --git a/include/wlr/types/wlr_xcursor_manager.h b/include/wlr/types/wlr_xcursor_manager.h index c7fa83be..285006bf 100644 --- a/include/wlr/types/wlr_xcursor_manager.h +++ b/include/wlr/types/wlr_xcursor_manager.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_XCURSOR_MANAGER_H #define WLR_TYPES_WLR_XCURSOR_MANAGER_H diff --git a/include/wlr/types/wlr_xdg_decoration_v1.h b/include/wlr/types/wlr_xdg_decoration_v1.h new file mode 100644 index 00000000..ba1ad84b --- /dev/null +++ b/include/wlr/types/wlr_xdg_decoration_v1.h @@ -0,0 +1,69 @@ +#ifndef WLR_TYPES_WLR_XDG_DECORATION_V1 +#define WLR_TYPES_WLR_XDG_DECORATION_V1 + +#include <wayland-server.h> +#include <wlr/types/wlr_xdg_shell.h> + +enum wlr_xdg_toplevel_decoration_v1_mode { + WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_NONE = 0, + WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE = 1, + WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE = 2, +}; + +struct wlr_xdg_decoration_manager_v1 { + struct wl_global *global; + struct wl_list resources; + struct wl_list decorations; // wlr_xdg_toplevel_decoration::link + + struct wl_listener display_destroy; + + struct { + struct wl_signal new_toplevel_decoration; // struct wlr_xdg_toplevel_decoration * + struct wl_signal destroy; + } events; + + void *data; +}; + +struct wlr_xdg_toplevel_decoration_v1_configure { + struct wl_list link; // wlr_xdg_toplevel_decoration::configure_list + struct wlr_xdg_surface_configure *surface_configure; + enum wlr_xdg_toplevel_decoration_v1_mode mode; +}; + +struct wlr_xdg_toplevel_decoration_v1 { + struct wl_resource *resource; + struct wlr_xdg_surface *surface; + struct wlr_xdg_decoration_manager_v1 *manager; + struct wl_list link; // wlr_xdg_decoration_manager_v1::link + + bool added; + enum wlr_xdg_toplevel_decoration_v1_mode current_mode; + enum wlr_xdg_toplevel_decoration_v1_mode client_pending_mode; + enum wlr_xdg_toplevel_decoration_v1_mode server_pending_mode; + + struct wl_list configure_list; // wlr_xdg_toplevel_decoration_v1_configure::link + + struct { + struct wl_signal destroy; + struct wl_signal request_mode; + } events; + + struct wl_listener surface_destroy; + struct wl_listener surface_configure; + struct wl_listener surface_ack_configure; + struct wl_listener surface_commit; + + void *data; +}; + +struct wlr_xdg_decoration_manager_v1 * + wlr_xdg_decoration_manager_v1_create(struct wl_display *display); +void wlr_xdg_decoration_manager_v1_destroy( + struct wlr_xdg_decoration_manager_v1 *manager); + +uint32_t wlr_xdg_toplevel_decoration_v1_set_mode( + struct wlr_xdg_toplevel_decoration_v1 *decoration, + enum wlr_xdg_toplevel_decoration_v1_mode mode); + +#endif diff --git a/include/wlr/types/wlr_xdg_output.h b/include/wlr/types/wlr_xdg_output.h index 81566ab9..60611307 100644 --- a/include/wlr/types/wlr_xdg_output.h +++ b/include/wlr/types/wlr_xdg_output.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_XDG_OUTPUT_H #define WLR_TYPES_WLR_XDG_OUTPUT_H #include <wayland-server.h> @@ -26,6 +34,10 @@ struct wlr_xdg_output_manager { struct wl_listener layout_add; struct wl_listener layout_change; struct wl_listener layout_destroy; + + struct { + struct wl_signal destroy; + } events; }; struct wlr_xdg_output_manager *wlr_xdg_output_manager_create( diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index 9c0e6adc..1bca9ef3 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_XDG_SHELL_H #define WLR_TYPES_WLR_XDG_SHELL_H #include <wlr/types/wlr_box.h> @@ -21,6 +29,7 @@ struct wlr_xdg_shell { * surface will be ready to be managed on the `map` event. */ struct wl_signal new_surface; + struct wl_signal destroy; } events; void *data; @@ -119,10 +128,13 @@ struct wlr_xdg_toplevel { struct wl_signal request_resize; struct wl_signal request_show_window_menu; struct wl_signal set_parent; + struct wl_signal set_title; + struct wl_signal set_app_id; } events; }; struct wlr_xdg_surface_configure { + struct wlr_xdg_surface *surface; struct wl_list link; // wlr_xdg_surface::configure_list uint32_t serial; @@ -186,6 +198,10 @@ struct wlr_xdg_surface { * surface has been hidden or is about to be destroyed. */ struct wl_signal unmap; + + // for protocol extensions + struct wl_signal configure; // wlr_xdg_surface_configure + struct wl_signal ack_configure; // wlr_xdg_surface_configure } events; void *data; @@ -224,6 +240,8 @@ struct wlr_xdg_surface *wlr_xdg_surface_from_resource( struct wl_resource *resource); struct wlr_xdg_surface *wlr_xdg_surface_from_popup_resource( struct wl_resource *resource); +struct wlr_xdg_surface *wlr_xdg_surface_from_toplevel_resource( + struct wl_resource *resource); struct wlr_box wlr_xdg_positioner_get_geometry( struct wlr_xdg_positioner *positioner); @@ -283,13 +301,6 @@ uint32_t wlr_xdg_toplevel_set_tiled(struct wlr_xdg_surface *surface, void wlr_xdg_surface_send_close(struct wlr_xdg_surface *surface); /** - * Compute the popup position in its parent's surface-local coordinate system. - * This aborts if called for popups whose parent is not an xdg_surface. - */ -void wlr_xdg_surface_popup_get_position(struct wlr_xdg_surface *surface, - double *popup_sx, double *popup_sy); - -/** * Get the geometry for this positioner based on the anchor rect, gravity, and * size of this positioner. */ @@ -350,7 +361,8 @@ struct wlr_xdg_surface *wlr_xdg_surface_from_wlr_surface( * * The x and y value can be <0 */ -void wlr_xdg_surface_get_geometry(struct wlr_xdg_surface *surface, struct wlr_box *box); +void wlr_xdg_surface_get_geometry(struct wlr_xdg_surface *surface, + struct wlr_box *box); /** * Call `iterator` on each surface and popup in the xdg-surface tree, with the @@ -358,7 +370,13 @@ void wlr_xdg_surface_get_geometry(struct wlr_xdg_surface *surface, struct wlr_bo * from root to leaves (in rendering order). */ void wlr_xdg_surface_for_each_surface(struct wlr_xdg_surface *surface, - wlr_surface_iterator_func_t iterator, void *user_data); + wlr_surface_iterator_func_t iterator, void *user_data); + +/** + * Schedule a surface configuration. This should only be called by protocols + * extending the shell. + */ +uint32_t wlr_xdg_surface_schedule_configure(struct wlr_xdg_surface *surface); /** * Call `iterator` on each popup in the xdg-surface tree, with the popup's diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 2e1b6f11..a69e488f 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_TYPES_WLR_XDG_SHELL_V6_H #define WLR_TYPES_WLR_XDG_SHELL_V6_H @@ -22,6 +30,7 @@ struct wlr_xdg_shell_v6 { * surface will be ready to be managed on the `map` event. */ struct wl_signal new_surface; + struct wl_signal destroy; } events; void *data; @@ -127,6 +136,8 @@ struct wlr_xdg_toplevel_v6 { struct wl_signal request_resize; struct wl_signal request_show_window_menu; struct wl_signal set_parent; + struct wl_signal set_title; + struct wl_signal set_app_id; } events; }; diff --git a/include/wlr/util/edges.h b/include/wlr/util/edges.h index 53268323..bf1eb1e7 100644 --- a/include/wlr/util/edges.h +++ b/include/wlr/util/edges.h @@ -1,3 +1,19 @@ +/* + * This is a stable interface of wlroots. Future changes will be limited to: + * + * - New functions + * - New struct members + * - New enum members + * + * Note that wlroots does not make an ABI compatibility promise - in the future, + * the layout and size of structs used by wlroots may change, requiring code + * depending on this header to be recompiled (but not edited). + * + * Breaking changes are announced by email and follow a 1-year deprecation + * schedule. Send an email to ~sircmpwn/wlroots-announce+subscribe@lists.sr.ht + * to receive these announcements. + */ + #ifndef WLR_UTIL_EDGES_H #define WLR_UTIL_EDGES_H diff --git a/include/wlr/util/log.h b/include/wlr/util/log.h index 098a020d..2c441180 100644 --- a/include/wlr/util/log.h +++ b/include/wlr/util/log.h @@ -1,3 +1,19 @@ +/* + * This is a stable interface of wlroots. Future changes will be limited to: + * + * - New functions + * - New struct members + * - New enum members + * + * Note that wlroots does not make an ABI compatibility promise - in the future, + * the layout and size of structs used by wlroots may change, requiring code + * depending on this header to be recompiled (but not edited). + * + * Breaking changes are announced by email and follow a 1-year deprecation + * schedule. Send an email to ~sircmpwn/wlroots-announce+subscribe@lists.sr.ht + * to receive these announcements. + */ + #ifndef WLR_UTIL_LOG_H #define WLR_UTIL_LOG_H @@ -19,8 +35,13 @@ typedef void (*wlr_log_func_t)(enum wlr_log_importance importance, // Will log all messages less than or equal to `verbosity` // If `callback` is NULL, wlr will use its default logger. +// The function can be called multiple times to update the verbosity or +// callback function. void wlr_log_init(enum wlr_log_importance verbosity, wlr_log_func_t callback); +// Returns the log verbosity provided to wlr_log_init +enum wlr_log_importance wlr_log_get_verbosity(void); + #ifdef __GNUC__ #define _WLR_ATTRIB_PRINTF(start, end) __attribute__((format(printf, start, end))) #else diff --git a/include/wlr/util/meson.build b/include/wlr/util/meson.build new file mode 100644 index 00000000..ee72cbd6 --- /dev/null +++ b/include/wlr/util/meson.build @@ -0,0 +1,6 @@ +install_headers( + 'edges.h', + 'log.h', + 'region.h', + subdir: 'wlr/util', +) diff --git a/include/wlr/util/region.h b/include/wlr/util/region.h index c0fe6063..32387bfb 100644 --- a/include/wlr/util/region.h +++ b/include/wlr/util/region.h @@ -1,6 +1,21 @@ +/* + * This is a stable interface of wlroots. Future changes will be limited to: + * + * - New functions + * - New struct members + * - New enum members + * + * Note that wlroots does not make an ABI compatibility promise - in the future, + * the layout and size of structs used by wlroots may change, requiring code + * depending on this header to be recompiled (but not edited). + * + * Breaking changes are announced by email and follow a 1-year deprecation + * schedule. Send an email to ~sircmpwn/wlroots-announce+subscribe@lists.sr.ht + * to receive these announcements. + */ + #ifndef WLR_UTIL_REGION_H #define WLR_UTIL_REGION_H - #include <pixman.h> #include <wayland-server.h> diff --git a/include/wlr/version.h.in b/include/wlr/version.h.in new file mode 100644 index 00000000..cdc0fd75 --- /dev/null +++ b/include/wlr/version.h.in @@ -0,0 +1,16 @@ +#ifndef WLR_VERSION_H +#define WLR_VERSION_H + +#mesondefine WLR_VERSION_STR + +#mesondefine WLR_VERSION_MAJOR +#mesondefine WLR_VERSION_MINOR +#mesondefine WLR_VERSION_MICRO + +#define WLR_VERSION_NUM ((WLR_VERSION_MAJOR << 16) | (WLR_VERSION_MINOR << 8) | WLR_VERSION_MICRO) + +#mesondefine WLR_VERSION_API_CURRENT +#mesondefine WLR_VERSION_API_REVISION +#mesondefine WLR_VERSION_API_AGE + +#endif diff --git a/include/wlr/xcursor.h b/include/wlr/xcursor.h index d97469f8..39874f39 100644 --- a/include/wlr/xcursor.h +++ b/include/wlr/xcursor.h @@ -24,8 +24,19 @@ */ /* - * This is adapted from wayland-cursor, but with the wl_shm client stuff removed - * so we can use it on the compositor, too. + * This is a stable interface of wlroots. Future changes will be limited to: + * + * - New functions + * - New struct members + * - New enum members + * + * Note that wlroots does not make an ABI compatibility promise - in the future, + * the layout and size of structs used by wlroots may change, requiring code + * depending on this header to be recompiled (but not edited). + * + * Breaking changes are announced by email and follow a 1-year deprecation + * schedule. Send an email to ~sircmpwn/wlroots-announce+subscribe@lists.sr.ht + * to receive these announcements. */ #ifndef WLR_XCURSOR_H diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h index 7471bbc6..eb5d6985 100644 --- a/include/wlr/xwayland.h +++ b/include/wlr/xwayland.h @@ -1,3 +1,11 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + #ifndef WLR_XWAYLAND_H #define WLR_XWAYLAND_H @@ -108,6 +116,7 @@ struct wlr_xwayland_surface { char *title; char *class; char *instance; + char *role; pid_t pid; bool has_utf8_title; @@ -130,6 +139,7 @@ struct wlr_xwayland_surface { struct wl_event_source *ping_timer; // _NET_WM_STATE + bool modal; bool fullscreen; bool maximized_vert, maximized_horz; @@ -142,14 +152,18 @@ struct wlr_xwayland_surface { struct wl_signal request_resize; struct wl_signal request_maximize; struct wl_signal request_fullscreen; + struct wl_signal request_activate; struct wl_signal map; struct wl_signal unmap; struct wl_signal set_title; struct wl_signal set_class; + struct wl_signal set_role; struct wl_signal set_parent; struct wl_signal set_pid; struct wl_signal set_window_type; + struct wl_signal set_hints; + struct wl_signal set_override_redirect; struct wl_signal ping_timeout; } events; @@ -174,6 +188,14 @@ struct wlr_xwayland_resize_event { uint32_t edges; }; +/** Create an Xwayland server. + * + * The server supports a lazy mode in which Xwayland is only started when a + * client tries to connect. + * + * Note: wlr_xwayland will setup a global SIGUSR1 handler on the compositor + * process. + */ struct wlr_xwayland *wlr_xwayland_create(struct wl_display *wl_display, struct wlr_compositor *compositor, bool lazy); @@ -200,9 +222,6 @@ void wlr_xwayland_surface_set_fullscreen(struct wlr_xwayland_surface *surface, void wlr_xwayland_set_seat(struct wlr_xwayland *xwayland, struct wlr_seat *seat); -bool wlr_xwayland_surface_is_unmanaged( - const struct wlr_xwayland_surface *surface); - bool wlr_surface_is_xwayland_surface(struct wlr_surface *surface); struct wlr_xwayland_surface *wlr_xwayland_surface_from_wlr_surface( @@ -210,4 +229,29 @@ struct wlr_xwayland_surface *wlr_xwayland_surface_from_wlr_surface( void wlr_xwayland_surface_ping(struct wlr_xwayland_surface *surface); +/** Metric to guess if an OR window should "receive" focus + * + * In the pure X setups, window managers usually straight up ignore override + * redirect windows, and never touch them. (we have to handle them for mapping) + * + * When such a window wants to receive keyboard input (e.g. rofi/dzen) it will + * use mechanics we don't support (sniffing/grabbing input). + * [Sadly this is unrelated to xwayland-keyboard-grab] + * + * To still support these windows, while keeping general OR semantics as is, we + * need to hand a subset of windows focus. + * The dirty truth is, we need to hand focus to any Xwayland window, though + * pretending this window has focus makes it easier to handle unmap. + * + * This function provides a handy metric based on the window type to guess if + * the OR window wants focus. + * It's probably not perfect, nor exactly intended but works in practice. + * + * Returns: true if the window should receive focus + * false if it should be ignored + */ +bool wlr_xwayland_or_surface_wants_focus( + const struct wlr_xwayland_surface *surface); + + #endif diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index 08d37736..3536bbc8 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -25,6 +25,7 @@ enum atom_name { WM_HINTS, WM_NORMAL_HINTS, WM_SIZE_HINTS, + WM_WINDOW_ROLE, MOTIF_WM_HINTS, UTF8_STRING, WM_S0, @@ -40,6 +41,7 @@ enum atom_name { _NET_WM_MOVERESIZE, _NET_WM_NAME, _NET_SUPPORTING_WM_CHECK, + _NET_WM_STATE_MODAL, _NET_WM_STATE_FULLSCREEN, _NET_WM_STATE_MAXIMIZED_VERT, _NET_WM_STATE_MAXIMIZED_HORZ, diff --git a/meson.build b/meson.build index b65cd51a..ff4e5e5f 100644 --- a/meson.build +++ b/meson.build @@ -3,7 +3,7 @@ project( 'c', version: '0.0.1', license: 'MIT', - meson_version: '>=0.44.0', + meson_version: '>=0.47.1', default_options: [ 'c_std=c11', 'warning_level=2', @@ -18,21 +18,17 @@ so_version = ['0', '0', '0'] add_project_arguments('-Wno-unused-parameter', language: 'c') add_project_arguments( - '-DWLR_SRC_DIR="@0@"'.format(meson.source_root()), + '-DWLR_SRC_DIR="@0@"'.format(meson.current_source_dir()), language: 'c', ) add_project_arguments( - '-I@0@'.format(meson.build_root()), - language: 'c', -) -add_project_link_arguments( - '-Wl,-rpath,@0@'.format(meson.build_root()), + '-DWLR_USE_UNSTABLE', language: 'c', ) conf_data = configuration_data() -wlr_inc = include_directories('include') +wlr_inc = include_directories('.', 'include') cc = meson.get_compiler('c') @@ -49,7 +45,7 @@ add_project_arguments('-DWL_HIDE_DEPRECATED', language: 'c') wayland_server = dependency('wayland-server', version: '>=1.15') wayland_client = dependency('wayland-client') wayland_egl = dependency('wayland-egl') -wayland_protos = dependency('wayland-protocols', version: '>=1.14') +wayland_protos = dependency('wayland-protocols', version: '>=1.15') egl = dependency('egl') glesv2 = dependency('glesv2') drm = dependency('libdrm') @@ -58,86 +54,37 @@ libinput = dependency('libinput', version: '>=1.7.0') xkbcommon = dependency('xkbcommon') udev = dependency('libudev') pixman = dependency('pixman-1') -libcap = dependency('libcap', required: get_option('enable-libcap') == 'true') -systemd = dependency('libsystemd', required: get_option('enable-systemd') == 'true') -elogind = dependency('libelogind', required: get_option('enable-elogind') == 'true') +libcap = dependency('libcap', required: get_option('libcap')) +logind = dependency('lib' + get_option('logind-provider'), required: get_option('logind')) math = cc.find_library('m', required: false) -exclude_headers = [] wlr_parts = [] wlr_deps = [] -if libcap.found() and get_option('enable-libcap') != 'false' +if libcap.found() conf_data.set('WLR_HAS_LIBCAP', true) wlr_deps += libcap endif -if systemd.found() and get_option('enable-systemd') != 'false' - conf_data.set('WLR_HAS_SYSTEMD', true) - wlr_deps += systemd -endif - -if elogind.found() and get_option('enable-elogind') != 'false' - conf_data.set('WLR_HAS_ELOGIND', true) -endif - -if get_option('enable-x11_backend') or get_option('enable-xwayland') - xcb = dependency('xcb') - xcb_composite = dependency('xcb-composite') - xcb_xfixes = dependency('xcb-xfixes') - xcb_image = dependency('xcb-image') - xcb_render = dependency('xcb-render') - x11_xcb = dependency('x11-xcb') - - xcb_icccm = dependency('xcb-icccm', required: false) - xcb_xkb = dependency('xcb-xkb', required: false) - xcb_errors = dependency('xcb-errors', required: get_option('enable-xcb_errors') == 'true') - - if xcb_icccm.found() - conf_data.set('WLR_HAS_XCB_ICCCM', true) - endif - - if xcb_xkb.found() - conf_data.set('WLR_HAS_XCB_XKB', true) - endif - - if xcb_errors.found() and get_option('enable-xcb_errors') != 'false' - conf_data.set('WLR_HAS_XCB_ERRORS', true) - endif - - wlr_deps += [ - xcb, - xcb_composite, - x11_xcb, - ] -else - add_project_arguments('-DMESA_EGL_NO_X11_HEADERS', language: 'c') +if logind.found() + conf_data.set('WLR_HAS_' + get_option('logind-provider').to_upper(), true) + wlr_deps += logind endif -if get_option('enable-x11_backend') - conf_data.set('WLR_HAS_X11_BACKEND', true) +if cc.has_header_symbol('fcntl.h', 'posix_fallocate', prefix: '#define _POSIX_C_SOURCE 200112L') + conf_data.set('WLR_HAS_POSIX_FALLOCATE', true) endif -if get_option('enable-xwayland') - subdir('xwayland') - wlr_parts += [lib_wlr_xwayland] - conf_data.set('WLR_HAS_XWAYLAND', true) -else - exclude_headers += 'xwayland.h' -endif - -includedir = get_option('includedir') -exclude_headers += 'meson.build' -install_subdir('include/wlr', install_dir: includedir, exclude_files: exclude_headers) - - -subdir('include') subdir('protocol') subdir('render') + subdir('backend') subdir('types') subdir('util') subdir('xcursor') +subdir('xwayland') + +subdir('include') wlr_parts += [ lib_wl_protos, @@ -174,6 +121,7 @@ lib_wlr = library( include_directories: wlr_inc, install: true, link_args : symbols_flag, + link_depends: symbols_file, ) wlroots = declare_dependency( @@ -182,7 +130,6 @@ wlroots = declare_dependency( include_directories: wlr_inc, ) - summary = [ '', '----------------', @@ -200,14 +147,8 @@ summary = [ ] message('\n'.join(summary)) - -if get_option('enable-rootston') - subdir('rootston') -endif - -if get_option('enable-examples') - subdir('examples') -endif +subdir('examples') +subdir('rootston') pkgconfig = import('pkgconfig') pkgconfig.generate( @@ -222,26 +163,31 @@ git = find_program('git', required: false) if git.found() all_files = run_command( git, - ['--git-dir=@0@/.git'.format(meson.current_source_dir()), - 'ls-files', - ':/*.[ch]']) + '--git-dir=@0@/.git'.format(meson.current_source_dir()), + 'ls-files', + ':/*.[ch]', + ) all_files = files(all_files.stdout().split()) etags = find_program('etags', required: false) if etags.found() and all_files.length() > 0 - custom_target('etags', + custom_target( + 'etags', build_by_default: true, input: all_files, output: 'TAGS', - command: [etags.path(), '-o', 'TAGS'] + all_files) + command: [etags, '-o', '@OUTPUT@', '@INPUT@'], + ) endif ctags = find_program('ctags', required: false) if ctags.found() and all_files.length() > 0 - custom_target('ctags', + custom_target( + 'ctags', build_by_default: true, input: all_files, output: 'tags', - command: [ctags.path(), '-o', 'tags'] + all_files) + command: [ctags, '-f', '@OUTPUT@', '@INPUT@'], + ) endif endif diff --git a/meson_options.txt b/meson_options.txt index e474b8aa..360c6f6a 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,8 +1,10 @@ -option('enable-libcap', type: 'combo', choices: ['auto', 'true', 'false'], value: 'auto', description: 'Enable support for capabilities') -option('enable-systemd', type: 'combo', choices: ['auto', 'true', 'false'], value: 'auto', description: 'Enable support for logind') -option('enable-elogind', type: 'combo', choices: ['auto', 'true', 'false'], value: 'auto', description: 'Enable support for logind') -option('enable-xcb_errors', type: 'combo', choices: ['auto', 'true', 'false'], value: 'auto', description: 'Use xcb-errors util library') -option('enable-xwayland', type: 'boolean', value: true, description: 'Enable support X11 applications') -option('enable-x11_backend', type: 'boolean', value: true, description: 'Enable X11 backend') -option('enable-rootston', type: 'boolean', value: true, description: 'Build the rootston example compositor') -option('enable-examples', type: 'boolean', value: true, description: 'Build example applications') +option('libcap', type: 'feature', value: 'auto', description: 'Enable support for rootless session via capabilities (cap_sys_admin)') +option('logind', type: 'feature', value: 'auto', description: 'Enable support for rootless session via logind') +option('logind-provider', type: 'combo', choices: ['systemd', 'elogind'], value: 'systemd', description: 'Provider of logind support library') +option('xcb-errors', type: 'feature', value: 'auto', description: 'Use xcb-errors util library') +option('xcb-icccm', type: 'feature', value: 'auto', description: 'Use xcb-icccm util library') +option('xcb-xkb', type: 'feature', value: 'auto', description: 'Use xcb-xkb util library') +option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications') +option('x11-backend', type: 'feature', value: 'auto', description: 'Enable X11 backend') +option('rootston', type: 'boolean', value: true, description: 'Build the rootston example compositor') +option('examples', type: 'boolean', value: true, description: 'Build example applications') diff --git a/protocol/meson.build b/protocol/meson.build index b7a6e80a..2d2a73ed 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -1,39 +1,23 @@ wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir') -wayland_scanner = find_program('wayland-scanner') - -wayland_scanner_server = generator( - wayland_scanner, - output: '@BASENAME@-protocol.h', - arguments: ['server-header', '@INPUT@', '@OUTPUT@'], -) - -# should check wayland_scanner's version, but it is hard to get -if wayland_server.version().version_compare('>=1.14.91') - code_type = 'private-code' +wayland_scanner_dep = dependency('wayland-scanner', required: false, native: true) +if wayland_scanner_dep.found() + wayland_scanner = find_program( + wayland_scanner_dep.get_pkgconfig_variable('wayland_scanner'), + native: true, + ) else - code_type = 'code' + wayland_scanner = find_program('wayland-scanner', native: true) endif -wayland_scanner_code = generator( - wayland_scanner, - output: '@BASENAME@-protocol.c', - arguments: [code_type, '@INPUT@', '@OUTPUT@'], -) - -wayland_scanner_client = generator( - wayland_scanner, - output: '@BASENAME@-client-protocol.h', - arguments: ['client-header', '@INPUT@', '@OUTPUT@'], -) - protocols = [ [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], [wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'], [wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'], - [wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'], - [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], [wl_protocol_dir, 'unstable/tablet/tablet-unstable-v2.xml'], + [wl_protocol_dir, 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml'], + [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], + [wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'], 'gamma-control.xml', 'gtk-primary-selection.xml', 'idle.xml', @@ -41,18 +25,21 @@ protocols = [ 'server-decoration.xml', 'virtual-keyboard-unstable-v1.xml', 'wlr-export-dmabuf-unstable-v1.xml', + 'wlr-gamma-control-unstable-v1.xml', 'wlr-input-inhibitor-unstable-v1.xml', 'wlr-layer-shell-unstable-v1.xml', 'wlr-screencopy-unstable-v1.xml', ] client_protocols = [ - [wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'], [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], [wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'], + [wl_protocol_dir, 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml'], + [wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'], 'idle.xml', 'screenshooter.xml', 'wlr-export-dmabuf-unstable-v1.xml', + 'wlr-gamma-control-unstable-v1.xml', 'wlr-input-inhibitor-unstable-v1.xml', 'wlr-layer-shell-unstable-v1.xml', 'wlr-screencopy-unstable-v1.xml', @@ -63,17 +50,35 @@ wl_protos_headers = [] foreach p : protocols xml = join_paths(p) - wl_protos_src += wayland_scanner_code.process(xml) - wl_protos_headers += wayland_scanner_server.process(xml) + wl_protos_src += custom_target( + xml.underscorify() + '_server_c', + input: xml, + output: '@BASENAME@-protocol.c', + command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'], + ) + wl_protos_headers += custom_target( + xml.underscorify() + '_server_h', + input: xml, + output: '@BASENAME@-protocol.h', + command: [wayland_scanner, 'server-header', '@INPUT@', '@OUTPUT@'], + ) endforeach foreach p : client_protocols xml = join_paths(p) - wl_protos_headers += wayland_scanner_client.process(xml) + wl_protos_headers += custom_target( + xml.underscorify() + '_client_h', + input: xml, + output: '@BASENAME@-client-protocol.h', + command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'], + ) endforeach -lib_wl_protos = static_library('wl_protos', wl_protos_src + wl_protos_headers, - dependencies: [wayland_client]) # for the include directory +lib_wl_protos = static_library( + 'wl_protos', + wl_protos_src + wl_protos_headers, + dependencies: wayland_client.partial_dependency(includes: true), +) wlr_protos = declare_dependency( link_with: lib_wl_protos, diff --git a/protocol/wlr-gamma-control-unstable-v1.xml b/protocol/wlr-gamma-control-unstable-v1.xml new file mode 100644 index 00000000..f55f3fe5 --- /dev/null +++ b/protocol/wlr-gamma-control-unstable-v1.xml @@ -0,0 +1,126 @@ +<?xml version="1.0" encoding="UTF-8"?> +<protocol name="wlr_gamma_control_unstable_v1"> + <copyright> + Copyright © 2015 Giulio camuffo + Copyright © 2018 Simon Ser + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + </copyright> + + <description summary="manage gamma tables of outputs"> + This protocol allows a privileged client to set the gamma tables for + outputs. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible changes + may be added together with the corresponding interface version bump. + Backward incompatible changes are done by bumping the version number in + the protocol and interface names and resetting the interface version. + Once the protocol is to be declared stable, the 'z' prefix and the + version number in the protocol and interface names are removed and the + interface version number is reset. + </description> + + <interface name="zwlr_gamma_control_manager_v1" version="1"> + <description summary="manager to create per-output gamma controls"> + This interface is a manager that allows creating per-output gamma + controls. + </description> + + <request name="get_gamma_control"> + <description summary="get a gamma control for an output"> + Create a gamma control that can be used to adjust gamma tables for the + provided output. + </description> + <arg name="id" type="new_id" interface="zwlr_gamma_control_v1"/> + <arg name="output" type="object" interface="wl_output"/> + </request> + + <request name="destroy" type="destructor"> + <description summary="destroy the manager"> + All objects created by the manager will still remain valid, until their + appropriate destroy request has been called. + </description> + </request> + </interface> + + <interface name="zwlr_gamma_control_v1" version="1"> + <description summary="adjust gamma tables for an output"> + This interface allows a client to adjust gamma tables for a particular + output. + + The client will receive the gamma size, and will then be able to set gamma + tables. At any time the compositor can send a failed event indicating that + this object is no longer valid. + + There must always be at most one gamma control object per output, which + has exclusive access to this particular output. When the gamma control + object is destroyed, the gamma table is restored to its original value. + </description> + + <event name="gamma_size"> + <description summary="size of gamma ramps"> + Advertise the size of each gamma ramp. + + This event is sent immediately when the gamma control object is created. + </description> + <arg name="size" type="uint" summary="number of elements in a ramp"/> + </event> + + <enum name="error"> + <entry name="invalid_gamma" value="1" summary="invalid gamma tables"/> + </enum> + + <request name="set_gamma"> + <description summary="set the gamma table"> + Set the gamma table. The file descriptor can be memory-mapped to provide + the raw gamma table, which contains successive gamma ramps for the red, + green and blue channels. Each gamma ramp is an array of 16-byte unsigned + integers which has the same length as the gamma size. + + The file descriptor data must have the same length as three times the + gamma size. + </description> + <arg name="fd" type="fd" summary="gamma table file descriptor"/> + </request> + + <event name="failed"> + <description summary="object no longer valid"> + This event indicates that the gamma control is no longer valid. This + can happen for a number of reasons, including: + - The output doesn't support gamma tables + - Setting the gamma tables failed + - Another client already has exclusive gamma control for this output + - The compositor has transfered gamma control to another client + + Upon receiving this event, the client should destroy this object. + </description> + </event> + + <request name="destroy" type="destructor"> + <description summary="destroy this control"> + Destroys the gamma control object. If the object is still valid, this + restores the original gamma tables. + </description> + </request> + </interface> +</protocol> diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 27c16e52..b6e97041 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -116,7 +116,7 @@ static bool gles2_render_texture_with_matrix(struct wlr_renderer *wlr_renderer, struct wlr_gles2_renderer *renderer = gles2_get_renderer_in_context(wlr_renderer); struct wlr_gles2_texture *texture = - get_gles2_texture_in_context(wlr_texture); + gles2_get_texture(wlr_texture); struct wlr_gles2_tex_shader *shader = NULL; GLenum target = 0; @@ -213,7 +213,7 @@ static const enum wl_shm_format *gles2_renderer_formats( static bool gles2_resource_is_wl_drm_buffer(struct wlr_renderer *wlr_renderer, struct wl_resource *resource) { struct wlr_gles2_renderer *renderer = - gles2_get_renderer_in_context(wlr_renderer); + gles2_get_renderer(wlr_renderer); if (!eglQueryWaylandBufferWL) { return false; @@ -227,7 +227,7 @@ static bool gles2_resource_is_wl_drm_buffer(struct wlr_renderer *wlr_renderer, static void gles2_wl_drm_buffer_get_size(struct wlr_renderer *wlr_renderer, struct wl_resource *buffer, int *width, int *height) { struct wlr_gles2_renderer *renderer = - gles2_get_renderer_in_context(wlr_renderer); + gles2_get_renderer(wlr_renderer); if (!eglQueryWaylandBufferWL) { return; @@ -323,7 +323,7 @@ static struct wlr_texture *gles2_texture_from_dmabuf( static void gles2_init_wl_display(struct wlr_renderer *wlr_renderer, struct wl_display *wl_display) { struct wlr_gles2_renderer *renderer = - gles2_get_renderer_in_context(wlr_renderer); + gles2_get_renderer(wlr_renderer); if (!wlr_egl_bind_display(renderer->egl, wl_display)) { wlr_log(WLR_INFO, "failed to bind wl_display to EGL"); } diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 1e55f4c4..22d02cde 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -16,7 +16,7 @@ static const struct wlr_texture_impl texture_impl; -static struct wlr_gles2_texture *gles2_get_texture( +struct wlr_gles2_texture *gles2_get_texture( struct wlr_texture *wlr_texture) { assert(wlr_texture->impl == &texture_impl); return (struct wlr_gles2_texture *)wlr_texture; @@ -25,7 +25,9 @@ static struct wlr_gles2_texture *gles2_get_texture( struct wlr_gles2_texture *get_gles2_texture_in_context( struct wlr_texture *wlr_texture) { struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); - assert(wlr_egl_is_current(texture->egl)); + if (!wlr_egl_is_current(texture->egl)) { + wlr_egl_make_current(texture->egl, EGL_NO_SURFACE, NULL); + } return texture; } @@ -143,7 +145,9 @@ static const struct wlr_texture_impl texture_impl = { struct wlr_texture *wlr_gles2_texture_from_pixels(struct wlr_egl *egl, enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height, const void *data) { - assert(wlr_egl_is_current(egl)); + if (!wlr_egl_is_current(egl)) { + wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL); + } const struct wlr_gles2_pixel_format *fmt = get_gles2_format_from_wl(wl_fmt); if (fmt == NULL) { @@ -180,7 +184,9 @@ struct wlr_texture *wlr_gles2_texture_from_pixels(struct wlr_egl *egl, struct wlr_texture *wlr_gles2_texture_from_wl_drm(struct wlr_egl *egl, struct wl_resource *data) { - assert(wlr_egl_is_current(egl)); + if (!wlr_egl_is_current(egl)) { + wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL); + } if (!glEGLImageTargetTexture2DOES) { return NULL; @@ -239,7 +245,9 @@ struct wlr_texture *wlr_gles2_texture_from_wl_drm(struct wlr_egl *egl, struct wlr_texture *wlr_gles2_texture_from_dmabuf(struct wlr_egl *egl, struct wlr_dmabuf_attributes *attribs) { - assert(wlr_egl_is_current(egl)); + if (!wlr_egl_is_current(egl)) { + wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL); + } if (!glEGLImageTargetTexture2DOES) { return NULL; diff --git a/render/meson.build b/render/meson.build index 4b90c229..ab66eab0 100644 --- a/render/meson.build +++ b/render/meson.build @@ -1,9 +1,10 @@ glgen = find_program('../glgen.sh') -glapi = custom_target('glapi', +glapi = custom_target( + 'glapi', input: 'glapi.txt', output: ['@BASENAME@.c', '@BASENAME@.h'], - command: [glgen, '@INPUT@', '@OUTPUT0@', '@OUTPUT1@'], + command: [glgen, '@INPUT@', '@OUTDIR@'], ) lib_wlr_render = static_library( @@ -19,8 +20,7 @@ lib_wlr_render = static_library( 'wlr_renderer.c', 'wlr_texture.c', ), - glapi[0], - glapi[1], + glapi, include_directories: wlr_inc, dependencies: [egl, glesv2, pixman, wayland_server], ) diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 6c2b9fbb..31bf2b18 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -1,10 +1,11 @@ #include <assert.h> #include <stdbool.h> #include <stdlib.h> +#include <wlr/render/gles2.h> #include <wlr/render/interface.h> #include <wlr/render/wlr_renderer.h> +#include <wlr/types/wlr_linux_dmabuf_v1.h> #include <wlr/types/wlr_matrix.h> -#include <wlr/render/gles2.h> #include <wlr/util/log.h> #include "util/signal.h" @@ -176,6 +177,10 @@ void wlr_renderer_init_wl_display(struct wlr_renderer *r, } } + if (r->impl->texture_from_dmabuf) { + wlr_linux_dmabuf_v1_create(wl_display, r); + } + if (r->impl->init_wl_display) { r->impl->init_wl_display(r, wl_display); } diff --git a/rootston/config.c b/rootston/config.c index 0c0ad055..92d90de1 100644 --- a/rootston/config.c +++ b/rootston/config.c @@ -26,7 +26,10 @@ static void usage(const char *name, int ret) { " See `rootston.ini.example` for config\n" " file documentation.\n" " -E <COMMAND> Command that will be ran at startup.\n" - " -D Enable damage tracking debugging.\n", + " -D Enable damage tracking debugging.\n" + " -l <LEVEL> Set log verbosity, where,\n" + " 0:SILENT, 1:ERROR, 2:INFO, 3+:DEBUG\n" + " (default: DEBUG)\n", name); exit(ret); @@ -455,7 +458,8 @@ struct roots_config *roots_config_create_from_args(int argc, char *argv[]) { wl_list_init(&config->bindings); int c; - while ((c = getopt(argc, argv, "C:E:hD")) != -1) { + unsigned int log_verbosity = WLR_DEBUG; + while ((c = getopt(argc, argv, "C:E:hDl:")) != -1) { switch (c) { case 'C': config->config_path = strdup(optarg); @@ -466,11 +470,18 @@ struct roots_config *roots_config_create_from_args(int argc, char *argv[]) { case 'D': config->debug_damage_tracking = true; break; + case 'l': + log_verbosity = strtoul(optarg, NULL, 10); + if (log_verbosity >= WLR_LOG_IMPORTANCE_LAST) { + log_verbosity = WLR_LOG_IMPORTANCE_LAST - 1; + } + break; case 'h': case '?': usage(argv[0], c != 'h'); } } + wlr_log_init(log_verbosity, NULL); if (!config->config_path) { // get the config path from the current directory diff --git a/rootston/cursor.c b/rootston/cursor.c index 94f5520e..9a9f9af6 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -101,6 +101,7 @@ static void seat_view_deco_button(struct roots_seat_view *view, double sx, static void roots_passthrough_cursor(struct roots_cursor *cursor, uint32_t time) { + bool focus_changed; double sx, sy; struct roots_view *view = NULL; struct roots_seat *seat = cursor->seat; @@ -136,8 +137,11 @@ static void roots_passthrough_cursor(struct roots_cursor *cursor, } if (surface) { + focus_changed = (seat->seat->pointer_state.focused_surface != surface); wlr_seat_pointer_notify_enter(seat->seat, surface, sx, sy); - wlr_seat_pointer_notify_motion(seat->seat, time, sx, sy); + if (!focus_changed) { + wlr_seat_pointer_notify_motion(seat->seat, time, sx, sy); + } } else { wlr_seat_pointer_clear_focus(seat->seat); } @@ -148,8 +152,8 @@ static void roots_passthrough_cursor(struct roots_cursor *cursor, } } -static void roots_cursor_update_position( - struct roots_cursor *cursor, uint32_t time) { +void roots_cursor_update_position(struct roots_cursor *cursor, + uint32_t time) { struct roots_seat *seat = cursor->seat; struct roots_view *view; switch (cursor->mode) { @@ -266,13 +270,7 @@ static void roots_cursor_press_button(struct roots_cursor *cursor, cursor->mode = ROOTS_CURSOR_PASSTHROUGH; } - switch (state) { - case WLR_BUTTON_RELEASED: - if (!is_touch) { - roots_cursor_update_position(cursor, time); - } - break; - case WLR_BUTTON_PRESSED: + if (state == WLR_BUTTON_PRESSED) { if (view) { roots_seat_set_focus(seat, view); } @@ -283,7 +281,6 @@ static void roots_cursor_press_button(struct roots_cursor *cursor, roots_seat_set_focus_layer(seat, layer); } } - break; } } diff --git a/rootston/desktop.c b/rootston/desktop.c index 3f9faf24..efb7581a 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -9,11 +9,11 @@ #include <wlr/types/wlr_cursor.h> #include <wlr/types/wlr_export_dmabuf_v1.h> #include <wlr/types/wlr_gamma_control.h> +#include <wlr/types/wlr_gamma_control_v1.h> #include <wlr/types/wlr_idle_inhibit_v1.h> #include <wlr/types/wlr_idle.h> #include <wlr/types/wlr_input_inhibitor.h> #include <wlr/types/wlr_layer_shell.h> -#include <wlr/types/wlr_linux_dmabuf.h> #include <wlr/types/wlr_output_layout.h> #include <wlr/types/wlr_primary_selection.h> #include <wlr/types/wlr_server_decoration.h> @@ -423,6 +423,7 @@ 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); return subsurface; } @@ -468,6 +469,7 @@ void view_map(struct roots_view *view, struct wlr_surface *surface) { wl_list_insert(&view->desktop->views, &view->link); view_damage_whole(view); + input_update_cursor_focus(view->desktop->server->input); } void view_unmap(struct roots_view *view) { @@ -550,6 +552,23 @@ void view_update_size(struct roots_view *view, uint32_t width, uint32_t height) view_damage_whole(view); } +void view_update_decorated(struct roots_view *view, bool decorated) { + if (view->decorated == decorated) { + return; + } + + view_damage_whole(view); + view->decorated = decorated; + if (decorated) { + view->border_width = 4; + view->titlebar_height = 12; + } else { + view->border_width = 0; + view->titlebar_height = 0; + } + view_damage_whole(view); +} + 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 && @@ -849,6 +868,8 @@ struct roots_desktop *desktop_create(struct roots_server *server, desktop->gamma_control_manager = wlr_gamma_control_manager_create( server->wl_display); + desktop->gamma_control_manager_v1 = wlr_gamma_control_manager_v1_create( + server->wl_display); desktop->screenshooter = wlr_screenshooter_create(server->wl_display); desktop->export_dmabuf_manager_v1 = wlr_export_dmabuf_manager_v1_create(server->wl_display); @@ -871,9 +892,6 @@ struct roots_desktop *desktop_create(struct roots_server *server, wl_signal_add(&desktop->input_inhibit->events.deactivate, &desktop->input_inhibit_deactivate); - desktop->linux_dmabuf = wlr_linux_dmabuf_create(server->wl_display, - server->renderer); - desktop->virtual_keyboard = wlr_virtual_keyboard_manager_v1_create( server->wl_display); wl_signal_add(&desktop->virtual_keyboard->events.new_virtual_keyboard, @@ -882,6 +900,12 @@ struct roots_desktop *desktop_create(struct roots_server *server, desktop->screencopy = wlr_screencopy_manager_v1_create(server->wl_display); + desktop->xdg_decoration_manager = + wlr_xdg_decoration_manager_v1_create(server->wl_display); + wl_signal_add(&desktop->xdg_decoration_manager->events.new_toplevel_decoration, + &desktop->xdg_toplevel_decoration); + desktop->xdg_toplevel_decoration.notify = handle_xdg_toplevel_decoration; + return desktop; } diff --git a/rootston/input.c b/rootston/input.c index 84b5acae..b7a5f1ba 100644 --- a/rootston/input.c +++ b/rootston/input.c @@ -1,5 +1,7 @@ +#define _POSIX_C_SOURCE 200112L #include <assert.h> #include <stdlib.h> +#include <time.h> #include <wayland-server.h> #include <wlr/backend/libinput.h> #include <wlr/config.h> @@ -126,3 +128,16 @@ bool input_view_has_focus(struct roots_input *input, struct roots_view *view) { return false; } + +static inline int64_t timespec_to_msec(const struct timespec *a) { + return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000; +} + +void input_update_cursor_focus(struct roots_input *input) { + struct roots_seat *seat; + struct timespec now; + wl_list_for_each(seat, &input->seats, link) { + clock_gettime(CLOCK_MONOTONIC, &now); + roots_cursor_update_position(seat->cursor, timespec_to_msec(&now)); + } +} diff --git a/rootston/keyboard.c b/rootston/keyboard.c index 6697ca83..b5a8093b 100644 --- a/rootston/keyboard.c +++ b/rootston/keyboard.c @@ -2,6 +2,7 @@ #include <stdbool.h> #include <stdint.h> #include <stdlib.h> +#include <sys/wait.h> #include <unistd.h> #include <wayland-server.h> #include <wlr/backend/multi.h> @@ -84,6 +85,39 @@ static void pressed_keysyms_update(xkb_keysym_t *pressed_keysyms, } } +static void double_fork_shell_cmd(const char *shell_cmd) { + pid_t pid = fork(); + if (pid < 0) { + wlr_log(WLR_ERROR, "cannot execute binding command: fork() failed"); + return; + } + + if (pid == 0) { + pid = fork(); + if (pid == 0) { + execl("/bin/sh", "/bin/sh", "-c", shell_cmd, NULL); + _exit(EXIT_FAILURE); + } else { + _exit(pid == -1); + } + } + + int status; + while (waitpid(pid, &status, 0) < 0) { + if (errno == EINTR) { + continue; + } + wlr_log_errno(WLR_ERROR, "waitpid() on first child failed"); + return; + } + + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { + return; + } + + wlr_log(WLR_ERROR, "first child failed to fork command"); +} + static const char *exec_prefix = "exec "; static bool outputs_enabled = true; @@ -113,13 +147,7 @@ static void keyboard_binding_execute(struct roots_keyboard *keyboard, } } else if (strncmp(exec_prefix, command, strlen(exec_prefix)) == 0) { const char *shell_cmd = command + strlen(exec_prefix); - pid_t pid = fork(); - if (pid < 0) { - wlr_log(WLR_ERROR, "cannot execute binding command: fork() failed"); - return; - } else if (pid == 0) { - execl("/bin/sh", "/bin/sh", "-c", shell_cmd, (void *)NULL); - } + double_fork_shell_cmd(shell_cmd); } else if (strcmp(command, "maximize") == 0) { struct roots_view *focus = roots_seat_get_focus(seat); if (focus != NULL) { @@ -133,6 +161,21 @@ static void keyboard_binding_execute(struct roots_keyboard *keyboard, wl_list_for_each(output, &keyboard->input->server->desktop->outputs, link) { wlr_output_enable(output->wlr_output, outputs_enabled); } + } else if (strcmp(command, "toggle_decoration_mode") == 0) { + struct roots_view *focus = roots_seat_get_focus(seat); + if (focus != NULL && focus->type == ROOTS_XDG_SHELL_VIEW) { + struct roots_xdg_toplevel_decoration *decoration = + focus->roots_xdg_surface->xdg_toplevel_decoration; + if (decoration != NULL) { + enum wlr_xdg_toplevel_decoration_v1_mode mode = + decoration->wlr_decoration->current_mode; + mode = mode == WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE + ? WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE + : WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; + wlr_xdg_toplevel_decoration_v1_set_mode( + decoration->wlr_decoration, mode); + } + } } else { wlr_log(WLR_ERROR, "unknown binding command: %s", command); } diff --git a/rootston/layer_shell.c b/rootston/layer_shell.c index ba69c3db..39054079 100644 --- a/rootston/layer_shell.c +++ b/rootston/layer_shell.c @@ -1,6 +1,12 @@ +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L +#endif #include <assert.h> +#include <errno.h> #include <stdbool.h> #include <stdlib.h> +#include <string.h> +#include <time.h> #include <wayland-server.h> #include <wlr/types/wlr_box.h> #include <wlr/types/wlr_surface.h> @@ -73,13 +79,38 @@ static void apply_exclusive(struct wlr_box *usable_area, } } -static void arrange_layer(struct wlr_output *output, struct wl_list *list, +static void update_cursors(struct roots_layer_surface *roots_surface, + struct wl_list *seats /* struct roots_seat */) { + struct roots_seat *seat; + wl_list_for_each(seat, seats, link) { + double sx, sy; + + struct wlr_surface *surface = desktop_surface_at( + seat->input->server->desktop, + seat->cursor->cursor->x, seat->cursor->cursor->y, &sx, &sy, NULL); + + if (surface == roots_surface->layer_surface->surface) { + struct timespec time; + if (clock_gettime(CLOCK_MONOTONIC, &time) == 0) { + roots_cursor_update_position(seat->cursor, + time.tv_sec * 1000 + time.tv_nsec / 1000000); + } else { + wlr_log(WLR_ERROR, "Failed to get time, not updating" + "position. Errno: %s\n", strerror(errno)); + } + } + } +} + +static void arrange_layer(struct wlr_output *output, + struct wl_list *seats /* struct *roots_seat */, + struct wl_list *list /* struct *roots_layer_surface */, struct wlr_box *usable_area, bool exclusive) { struct roots_layer_surface *roots_surface; struct wlr_box full_area = { 0 }; wlr_output_effective_resolution(output, &full_area.width, &full_area.height); - wl_list_for_each(roots_surface, list, link) { + wl_list_for_each_reverse(roots_surface, list, link) { struct wlr_layer_surface *layer = roots_surface->layer_surface; struct wlr_layer_surface_state *state = &layer->current; if (exclusive != (state->exclusive_zone > 0)) { @@ -143,12 +174,25 @@ static void arrange_layer(struct wlr_output *output, struct wl_list *list, wlr_layer_surface_close(layer); continue; } + // Apply + struct wlr_box old_geo = roots_surface->geo; roots_surface->geo = box; apply_exclusive(usable_area, state->anchor, state->exclusive_zone, state->margin.top, state->margin.right, state->margin.bottom, state->margin.left); wlr_layer_surface_configure(layer, box.width, box.height); + + // Having a cursor newly end up over the moved layer will not + // automatically send a motion event to the surface. The event needs to + // be synthesized. + // Only update layer surfaces which kept their size (and so buffers) the + // same, because those with resized buffers will be handled separately. + + if (roots_surface->geo.x != old_geo.x + || roots_surface->geo.y != old_geo.y) { + update_cursors(roots_surface, seats); + } } } @@ -158,16 +202,16 @@ void arrange_layers(struct roots_output *output) { &usable_area.width, &usable_area.height); // Arrange exclusive surfaces from top->bottom - arrange_layer(output->wlr_output, + arrange_layer(output->wlr_output, &output->desktop->server->input->seats, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &usable_area, true); - arrange_layer(output->wlr_output, + arrange_layer(output->wlr_output, &output->desktop->server->input->seats, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &usable_area, true); - arrange_layer(output->wlr_output, + arrange_layer(output->wlr_output, &output->desktop->server->input->seats, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &usable_area, true); - arrange_layer(output->wlr_output, + arrange_layer(output->wlr_output, &output->desktop->server->input->seats, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &usable_area, true); memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box)); @@ -180,16 +224,16 @@ void arrange_layers(struct roots_output *output) { } // Arrange non-exlusive surfaces from top->bottom - arrange_layer(output->wlr_output, + arrange_layer(output->wlr_output, &output->desktop->server->input->seats, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &usable_area, false); - arrange_layer(output->wlr_output, + arrange_layer(output->wlr_output, &output->desktop->server->input->seats, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &usable_area, false); - arrange_layer(output->wlr_output, + arrange_layer(output->wlr_output, &output->desktop->server->input->seats, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &usable_area, false); - arrange_layer(output->wlr_output, + arrange_layer(output->wlr_output, &output->desktop->server->input->seats, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &usable_area, false); @@ -238,6 +282,20 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { struct roots_output *output = wlr_output->data; struct wlr_box old_geo = layer->geo; arrange_layers(output); + + // Cursor changes which happen as a consequence of resizing a layer + // surface are applied in arrange_layers. Because the resize happens + // before the underlying surface changes, it will only receive a cursor + // update if the new cursor position crosses the *old* sized surface in + // the *new* layer surface. + // Another cursor move event is needed when the surface actually + // changes. + struct wlr_surface *surface = layer_surface->surface; + if (surface->previous.width != surface->current.width || + surface->previous.height != surface->current.height) { + update_cursors(layer, &output->desktop->server->input->seats); + } + if (memcmp(&old_geo, &layer->geo, sizeof(struct wlr_box)) != 0) { output_damage_whole_local_surface(output, layer_surface->surface, old_geo.x, old_geo.y, 0); @@ -291,7 +349,10 @@ static void handle_map(struct wl_listener *listener, void *data) { static void handle_unmap(struct wl_listener *listener, void *data) { struct roots_layer_surface *layer = wl_container_of( listener, layer, unmap); + struct wlr_output *wlr_output = layer->layer_surface->output; + struct roots_output *output = wlr_output->data; unmap(layer->layer_surface); + input_update_cursor_focus(output->desktop->server->input); } static void popup_handle_map(struct wl_listener *listener, void *data) { @@ -303,6 +364,7 @@ static void popup_handle_map(struct wl_listener *listener, void *data) { int oy = popup->wlr_popup->geometry.y + layer->geo.y; output_damage_whole_local_surface(output, popup->wlr_popup->base->surface, ox, oy, 0); + input_update_cursor_focus(output->desktop->server->input); } static void popup_handle_unmap(struct wl_listener *listener, void *data) { diff --git a/rootston/meson.build b/rootston/meson.build index 8ab872b5..9d1decce 100644 --- a/rootston/meson.build +++ b/rootston/meson.build @@ -11,12 +11,17 @@ sources = [ 'seat.c', 'virtual_keyboard.c', 'wl_shell.c', - 'xdg_shell_v6.c', 'xdg_shell.c', + 'xdg_shell_v6.c', ] -if get_option('enable-xwayland') - sources += ['xwayland.c'] + +if conf_data.get('WLR_HAS_XWAYLAND', false) + sources += 'xwayland.c' endif + executable( - 'rootston', sources, dependencies: [wlroots, wlr_protos, pixman] + 'rootston', + sources, + dependencies: [wlroots, wlr_protos, pixman], + build_by_default: get_option('rootston'), ) diff --git a/rootston/output.c b/rootston/output.c index 71ccf8bc..8677f491 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -3,6 +3,7 @@ #include <stdbool.h> #include <stdlib.h> #include <time.h> +#include <wlr/backend/drm.h> #include <wlr/config.h> #include <wlr/types/wlr_matrix.h> #include <wlr/types/wlr_compositor.h> @@ -16,7 +17,6 @@ #include "rootston/layers.h" #include "rootston/output.h" #include "rootston/server.h" -#include "backend/drm/drm.h" /** * Rotate a child's position relative to a parent. The parent size is (pw, ph), @@ -822,12 +822,6 @@ void handle_new_output(struct wl_listener *listener, void *data) { wlr_output->model, wlr_output->serial, wlr_output->phys_width, wlr_output->phys_height); - if (!wl_list_empty(&wlr_output->modes)) { - struct wlr_output_mode *mode = - wl_container_of((&wlr_output->modes)->prev, mode, link); - wlr_output_set_mode(wlr_output, mode); - } - struct roots_output *output = calloc(1, sizeof(struct roots_output)); clock_gettime(CLOCK_MONOTONIC, &output->last_frame); output->desktop = desktop; @@ -856,22 +850,28 @@ void handle_new_output(struct wl_listener *listener, void *data) { struct roots_output_config *output_config = roots_config_get_output(config, wlr_output); + + if ((!output_config || output_config->enable) && !wl_list_empty(&wlr_output->modes)) { + struct wlr_output_mode *mode = + wl_container_of(wlr_output->modes.prev, mode, link); + wlr_output_set_mode(wlr_output, mode); + } + if (output_config) { if (output_config->enable) { - struct roots_output_mode_config *mode_config; - if (wlr_output_is_drm(wlr_output)) { + struct roots_output_mode_config *mode_config; wl_list_for_each(mode_config, &output_config->modes, link) { wlr_drm_connector_add_mode(wlr_output, &mode_config->info); } - } else { - if (!wl_list_empty(&output_config->modes)) { - wlr_log(WLR_ERROR, "Can only add modes for DRM backend"); - } + } else if (!wl_list_empty(&output_config->modes)) { + wlr_log(WLR_ERROR, "Can only add modes for DRM backend"); } + if (output_config->mode.width) { set_mode(wlr_output, output_config); } + wlr_output_set_scale(wlr_output, output_config->scale); wlr_output_set_transform(wlr_output, output_config->transform); wlr_output_layout_add(desktop->layout, wlr_output, output_config->x, diff --git a/rootston/seat.c b/rootston/seat.c index f308da52..1ae098bc 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -1,4 +1,4 @@ -#define _POSIX_C_SOURCE 199309L +#define _POSIX_C_SOURCE 200112L #include <assert.h> #include <libinput.h> #include <stdlib.h> @@ -127,13 +127,13 @@ static void handle_tablet_tool_position(struct roots_cursor *cursor, struct wlr_surface *surface = desktop_surface_at(desktop, cursor->cursor->x, cursor->cursor->y, &sx, &sy, &view); struct roots_tablet_tool *roots_tool = tool->data; - + if (!surface) { wlr_tablet_v2_tablet_tool_notify_proximity_out(roots_tool->tablet_v2_tool); /* XXX: TODO: Fallback pointer semantics */ return; } - + if (!wlr_surface_accepts_tablet_v2(tablet->tablet_v2, surface)) { wlr_tablet_v2_tablet_tool_notify_proximity_out(roots_tool->tablet_v2_tool); /* XXX: TODO: Fallback pointer semantics */ @@ -218,7 +218,7 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) { static void handle_tablet_tool_destroy(struct wl_listener *listener, void *data) { struct roots_tablet_tool *tool = wl_container_of(listener, tool, tool_destroy); - + wl_list_remove(&tool->link); wl_list_remove(&tool->tool_link); @@ -503,16 +503,16 @@ void roots_drag_icon_update_position(struct roots_drag_icon *icon) { struct roots_seat *seat = icon->seat; struct wlr_cursor *cursor = seat->cursor->cursor; if (wlr_icon->is_pointer) { - icon->x = cursor->x + wlr_icon->sx; - icon->y = cursor->y + wlr_icon->sy; + icon->x = cursor->x; + icon->y = cursor->y; } else { struct wlr_touch_point *point = wlr_seat_touch_get_point(seat->seat, wlr_icon->touch_id); if (point == NULL) { return; } - icon->x = seat->touch_x + wlr_icon->sx; - icon->y = seat->touch_y + wlr_icon->sy; + icon->x = seat->touch_x; + icon->y = seat->touch_y; } roots_drag_icon_damage_whole(icon); @@ -746,6 +746,7 @@ static void attach_tablet_pad(struct roots_tablet_pad *pad, pad->tablet = tool; + wl_list_remove(&pad->tablet_destroy.link); pad->tablet_destroy.notify = handle_pad_tool_destroy; wl_signal_add(&tool->device->events.destroy, &pad->tablet_destroy); } @@ -813,7 +814,8 @@ static void seat_add_tablet_pad(struct roots_seat *seat, &tablet_pad->device_destroy); tablet_pad->attach.notify = handle_tablet_pad_attach; - wl_signal_add(&tablet_pad->device->tablet_pad->events.attach_tablet, &tablet_pad->attach); + wl_signal_add(&tablet_pad->device->tablet_pad->events.attach_tablet, + &tablet_pad->attach); tablet_pad->button.notify = handle_tablet_pad_button; wl_signal_add(&tablet_pad->device->tablet_pad->events.button, &tablet_pad->button); @@ -824,6 +826,8 @@ static void seat_add_tablet_pad(struct roots_seat *seat, tablet_pad->ring.notify = handle_tablet_pad_ring; wl_signal_add(&tablet_pad->device->tablet_pad->events.ring, &tablet_pad->ring); + wl_list_init(&tablet_pad->tablet_destroy.link); + struct roots_desktop *desktop = seat->input->server->desktop; tablet_pad->tablet_v2_pad = wlr_tablet_pad_create(desktop->tablet_v2, seat->seat, device); @@ -1125,7 +1129,8 @@ void roots_seat_set_focus(struct roots_seat *seat, struct roots_view *view) { #ifdef WLR_HAS_XWAYLAND if (view && view->type == ROOTS_XWAYLAND_VIEW && - wlr_xwayland_surface_is_unmanaged(view->xwayland_surface)) { + !wlr_xwayland_or_surface_wants_focus( + view->xwayland_surface)) { return; } #endif diff --git a/rootston/xdg_shell.c b/rootston/xdg_shell.c index d04d37e1..2cf2081e 100644 --- a/rootston/xdg_shell.c +++ b/rootston/xdg_shell.c @@ -6,6 +6,7 @@ #include <wlr/types/wlr_surface.h> #include <wlr/types/wlr_xdg_shell.h> #include <wlr/util/log.h> +#include "rootston/cursor.h" #include "rootston/desktop.h" #include "rootston/input.h" #include "rootston/server.h" @@ -33,6 +34,7 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) { static void popup_handle_map(struct wl_listener *listener, void *data) { struct roots_xdg_popup *popup = wl_container_of(listener, popup, map); view_damage_whole(popup->view_child.view); + input_update_cursor_focus(popup->view_child.view->desktop->server->input); } static void popup_handle_unmap(struct wl_listener *listener, void *data) { @@ -263,6 +265,7 @@ static void destroy(struct roots_view *view) { wl_list_remove(&roots_xdg_surface->request_resize.link); wl_list_remove(&roots_xdg_surface->request_maximize.link); wl_list_remove(&roots_xdg_surface->request_fullscreen.link); + roots_xdg_surface->view->xdg_surface->data = NULL; free(roots_xdg_surface); } @@ -437,6 +440,7 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { &roots_surface->request_fullscreen); roots_surface->new_popup.notify = handle_new_popup; wl_signal_add(&surface->events.new_popup, &roots_surface->new_popup); + surface->data = roots_surface; struct roots_view *view = view_create(desktop); if (!view) { @@ -463,3 +467,71 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { view_set_fullscreen(view, true, NULL); } } + + + +static void decoration_handle_destroy(struct wl_listener *listener, + void *data) { + struct roots_xdg_toplevel_decoration *decoration = + wl_container_of(listener, decoration, destroy); + + decoration->surface->xdg_toplevel_decoration = NULL; + view_update_decorated(decoration->surface->view, false); + wl_list_remove(&decoration->destroy.link); + wl_list_remove(&decoration->request_mode.link); + wl_list_remove(&decoration->surface_commit.link); + free(decoration); +} + +static void decoration_handle_request_mode(struct wl_listener *listener, + void *data) { + struct roots_xdg_toplevel_decoration *decoration = + wl_container_of(listener, decoration, request_mode); + + enum wlr_xdg_toplevel_decoration_v1_mode mode = + decoration->wlr_decoration->client_pending_mode; + if (mode == WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_NONE) { + mode = WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; + } + wlr_xdg_toplevel_decoration_v1_set_mode(decoration->wlr_decoration, mode); +} + +static void decoration_handle_surface_commit(struct wl_listener *listener, + void *data) { + struct roots_xdg_toplevel_decoration *decoration = + wl_container_of(listener, decoration, surface_commit); + + bool decorated = decoration->wlr_decoration->current_mode == + WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; + view_update_decorated(decoration->surface->view, decorated); +} + +void handle_xdg_toplevel_decoration(struct wl_listener *listener, void *data) { + struct wlr_xdg_toplevel_decoration_v1 *wlr_decoration = data; + + wlr_log(WLR_DEBUG, "new xdg toplevel decoration"); + + struct roots_xdg_surface *xdg_surface = wlr_decoration->surface->data; + assert(xdg_surface != NULL); + struct wlr_xdg_surface *wlr_xdg_surface = xdg_surface->view->xdg_surface; + + struct roots_xdg_toplevel_decoration *decoration = + calloc(1, sizeof(struct roots_xdg_toplevel_decoration)); + if (decoration == NULL) { + return; + } + decoration->wlr_decoration = wlr_decoration; + decoration->surface = xdg_surface; + xdg_surface->xdg_toplevel_decoration = decoration; + + decoration->destroy.notify = decoration_handle_destroy; + wl_signal_add(&wlr_decoration->events.destroy, &decoration->destroy); + decoration->request_mode.notify = decoration_handle_request_mode; + wl_signal_add(&wlr_decoration->events.request_mode, + &decoration->request_mode); + decoration->surface_commit.notify = decoration_handle_surface_commit; + wl_signal_add(&wlr_xdg_surface->surface->events.commit, + &decoration->surface_commit); + + decoration_handle_request_mode(&decoration->request_mode, wlr_decoration); +} diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index 219be2b0..1201ba68 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -34,6 +34,7 @@ static void popup_handle_map(struct wl_listener *listener, void *data) { struct roots_xdg_popup_v6 *popup = wl_container_of(listener, popup, map); view_damage_whole(popup->view_child.view); + input_update_cursor_focus(popup->view_child.view->desktop->server->input); } static void popup_handle_unmap(struct wl_listener *listener, void *data) { diff --git a/types/data_device/wlr_drag.c b/types/data_device/wlr_drag.c index 7f3b346d..fcde7b3e 100644 --- a/types/data_device/wlr_drag.c +++ b/types/data_device/wlr_drag.c @@ -345,9 +345,6 @@ static void drag_icon_surface_role_commit(struct wlr_surface *surface) { return; } - icon->sx += icon->surface->current.dx; - icon->sy += icon->surface->current.dy; - drag_icon_set_mapped(icon, wlr_surface_has_buffer(surface)); } diff --git a/types/meson.build b/types/meson.build index 0b8584f8..23c6cd13 100644 --- a/types/meson.build +++ b/types/meson.build @@ -25,13 +25,14 @@ lib_wlr_types = static_library( 'wlr_cursor.c', 'wlr_export_dmabuf_v1.c', 'wlr_gamma_control.c', + 'wlr_gamma_control_v1.c', 'wlr_idle_inhibit_v1.c', 'wlr_idle.c', 'wlr_input_device.c', 'wlr_input_inhibitor.c', 'wlr_keyboard.c', 'wlr_layer_shell.c', - 'wlr_linux_dmabuf.c', + 'wlr_linux_dmabuf_v1.c', 'wlr_list.c', 'wlr_matrix.c', 'wlr_output_damage.c', @@ -53,9 +54,10 @@ lib_wlr_types = static_library( 'wlr_virtual_keyboard_v1.c', 'wlr_wl_shell.c', 'wlr_xcursor_manager.c', + 'wlr_xdg_decoration_v1.c', 'wlr_xdg_output.c', 'wlr_screencopy_v1.c', ), include_directories: wlr_inc, - dependencies: [pixman, xkbcommon, wayland_server, wlr_protos], + dependencies: [pixman, xkbcommon, wayland_server, wlr_protos, libinput], ) diff --git a/types/seat/wlr_seat_keyboard.c b/types/seat/wlr_seat_keyboard.c index 8c1b56e1..e8ea300e 100644 --- a/types/seat/wlr_seat_keyboard.c +++ b/types/seat/wlr_seat_keyboard.c @@ -110,7 +110,7 @@ static void handle_keyboard_repeat_info(struct wl_listener *listener, static void handle_keyboard_destroy(struct wl_listener *listener, void *data) { struct wlr_seat_keyboard_state *state = wl_container_of(listener, state, keyboard_destroy); - state->keyboard = NULL; + wlr_seat_set_keyboard(state->seat, NULL); } void wlr_seat_set_keyboard(struct wlr_seat *seat, diff --git a/types/tablet_v2/wlr_tablet_v2.c b/types/tablet_v2/wlr_tablet_v2.c index fa058e79..7f3d5f30 100644 --- a/types/tablet_v2/wlr_tablet_v2.c +++ b/types/tablet_v2/wlr_tablet_v2.c @@ -14,6 +14,7 @@ #include <wlr/types/wlr_tablet_v2.h> #include <wlr/util/log.h> #include "tablet-unstable-v2-protocol.h" +#include "util/signal.h" #define TABLET_MANAGER_VERSION 1 @@ -162,7 +163,7 @@ static void get_tablet_seat(struct wl_client *wl_client, struct wl_resource *res struct wlr_tablet_seat_client_v2 *seat_client = calloc(1, sizeof(struct wlr_tablet_seat_client_v2)); - if (tablet_seat == NULL) { + if (seat_client == NULL) { wl_client_post_no_memory(wl_client); return; } @@ -281,6 +282,8 @@ void wlr_tablet_v2_destroy(struct wlr_tablet_manager_v2 *manager) { wlr_tablet_manager_v2_destroy(pos->resource); } + wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_list_remove(&manager->display_destroy.link); wl_global_destroy(manager->wl_global); free(manager); } @@ -292,12 +295,6 @@ struct wlr_tablet_manager_v2 *wlr_tablet_v2_create(struct wl_display *display) { return NULL; } - wl_list_init(&tablet->clients); - wl_list_init(&tablet->seats); - - tablet->display_destroy.notify = handle_display_destroy; - wl_display_add_destroy_listener(display, &tablet->display_destroy); - tablet->wl_global = wl_global_create(display, &zwp_tablet_manager_v2_interface, TABLET_MANAGER_VERSION, tablet, tablet_v2_bind); @@ -306,5 +303,12 @@ struct wlr_tablet_manager_v2 *wlr_tablet_v2_create(struct wl_display *display) { return NULL; } + wl_signal_init(&tablet->events.destroy); + wl_list_init(&tablet->clients); + wl_list_init(&tablet->seats); + + tablet->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &tablet->display_destroy); + return tablet; } diff --git a/types/tablet_v2/wlr_tablet_v2_pad.c b/types/tablet_v2/wlr_tablet_v2_pad.c index 74444708..185abfe8 100644 --- a/types/tablet_v2/wlr_tablet_v2_pad.c +++ b/types/tablet_v2/wlr_tablet_v2_pad.c @@ -373,7 +373,7 @@ struct wlr_tablet_v2_tablet_pad *wlr_tablet_pad_create( pad->grab = &pad->default_grab; pad->group_count = wl_list_length(&wlr_pad->groups); - pad->groups = calloc(pad->group_count, sizeof(int)); + pad->groups = calloc(pad->group_count, sizeof(uint32_t)); if (!pad->groups) { free(pad); return NULL; diff --git a/types/wlr_buffer.c b/types/wlr_buffer.c index 5e4aedac..55ed4792 100644 --- a/types/wlr_buffer.c +++ b/types/wlr_buffer.c @@ -1,8 +1,8 @@ #include <assert.h> #include <stdlib.h> -#include <wlr/types/wlr_buffer.h> -#include <wlr/types/wlr_linux_dmabuf.h> #include <wlr/render/wlr_renderer.h> +#include <wlr/types/wlr_buffer.h> +#include <wlr/types/wlr_linux_dmabuf_v1.h> #include <wlr/util/log.h> bool wlr_resource_is_buffer(struct wl_resource *resource) { @@ -21,9 +21,9 @@ bool wlr_buffer_get_resource_size(struct wl_resource *resource, resource)) { wlr_renderer_wl_drm_buffer_get_size(renderer, resource, width, height); - } else if (wlr_dmabuf_resource_is_buffer(resource)) { - struct wlr_dmabuf_buffer *dmabuf = - wlr_dmabuf_buffer_from_buffer_resource(resource); + } else if (wlr_dmabuf_v1_resource_is_buffer(resource)) { + struct wlr_dmabuf_v1_buffer *dmabuf = + wlr_dmabuf_v1_buffer_from_buffer_resource(resource); *width = dmabuf->attributes.width; *height = dmabuf->attributes.height; } else { @@ -77,9 +77,9 @@ struct wlr_buffer *wlr_buffer_create(struct wlr_renderer *renderer, released = true; } else if (wlr_renderer_resource_is_wl_drm_buffer(renderer, resource)) { texture = wlr_texture_from_wl_drm(renderer, resource); - } else if (wlr_dmabuf_resource_is_buffer(resource)) { - struct wlr_dmabuf_buffer *dmabuf = - wlr_dmabuf_buffer_from_buffer_resource(resource); + } else if (wlr_dmabuf_v1_resource_is_buffer(resource)) { + struct wlr_dmabuf_v1_buffer *dmabuf = + wlr_dmabuf_v1_buffer_from_buffer_resource(resource); texture = wlr_texture_from_dmabuf(renderer, &dmabuf->attributes); // We have imported the DMA-BUF, but we need to prevent the client from diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 82ad1a4a..49f11b20 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -332,7 +332,7 @@ static void handle_pointer_motion(struct wl_listener *listener, void *data) { static void apply_output_transform(double *x, double *y, enum wl_output_transform transform) { - double dx = *x, dy = *y; + double dx = 0.0, dy = 0.0; double width = 1.0, height = 1.0; switch (transform) { diff --git a/types/wlr_export_dmabuf_v1.c b/types/wlr_export_dmabuf_v1.c index 060f4afa..72c9bcec 100644 --- a/types/wlr_export_dmabuf_v1.c +++ b/types/wlr_export_dmabuf_v1.c @@ -2,8 +2,8 @@ #include <stdlib.h> #include <unistd.h> #include <wlr/interfaces/wlr_output.h> +#include <wlr/render/dmabuf.h> #include <wlr/types/wlr_export_dmabuf_v1.h> -#include <wlr/types/wlr_linux_dmabuf.h> #include <wlr/types/wlr_output.h> #include "wlr-export-dmabuf-unstable-v1-protocol.h" #include <wlr/util/log.h> diff --git a/types/wlr_gamma_control.c b/types/wlr_gamma_control.c index 5b871335..40ca2aca 100644 --- a/types/wlr_gamma_control.c +++ b/types/wlr_gamma_control.c @@ -25,7 +25,7 @@ static void gamma_control_destroy(struct wlr_gamma_control *gamma_control) { static const struct gamma_control_interface gamma_control_impl; -struct wlr_gamma_control *gamma_control_from_resource( +static struct wlr_gamma_control *gamma_control_from_resource( struct wl_resource *resource) { assert(wl_resource_instance_of(resource, &gamma_control_interface, &gamma_control_impl)); @@ -83,7 +83,7 @@ static const struct gamma_control_interface gamma_control_impl = { static const struct gamma_control_manager_interface gamma_control_manager_impl; -struct wlr_gamma_control_manager *gamma_control_manager_from_resource( +static struct wlr_gamma_control_manager *gamma_control_manager_from_resource( struct wl_resource *resource) { assert(wl_resource_instance_of(resource, &gamma_control_manager_interface, &gamma_control_manager_impl)); @@ -155,11 +155,12 @@ void wlr_gamma_control_manager_destroy( if (!manager) { return; } - wl_list_remove(&manager->display_destroy.link); struct wlr_gamma_control *gamma_control, *tmp; wl_list_for_each_safe(gamma_control, tmp, &manager->controls, link) { gamma_control_destroy(gamma_control); } + wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_list_remove(&manager->display_destroy.link); wl_global_destroy(manager->global); free(manager); } @@ -186,6 +187,7 @@ struct wlr_gamma_control_manager *wlr_gamma_control_manager_create( } manager->global = global; + wl_signal_init(&manager->events.destroy); wl_list_init(&manager->controls); manager->display_destroy.notify = handle_display_destroy; diff --git a/types/wlr_gamma_control_v1.c b/types/wlr_gamma_control_v1.c new file mode 100644 index 00000000..9f049a0b --- /dev/null +++ b/types/wlr_gamma_control_v1.c @@ -0,0 +1,266 @@ +#include <assert.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> +#include <wayland-server.h> +#include <wlr/interfaces/wlr_output.h> +#include <wlr/types/wlr_gamma_control_v1.h> +#include <wlr/types/wlr_output.h> +#include <wlr/util/log.h> +#include "util/signal.h" +#include "wlr-gamma-control-unstable-v1-protocol.h" + +#define GAMMA_CONTROL_MANAGER_V1_VERSION 1 + +static void gamma_control_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static void gamma_control_destroy(struct wlr_gamma_control_v1 *gamma_control) { + if (gamma_control == NULL) { + return; + } + wlr_output_set_gamma(gamma_control->output, 0, NULL, NULL, NULL); + wl_resource_set_user_data(gamma_control->resource, NULL); + wl_list_remove(&gamma_control->output_destroy_listener.link); + wl_list_remove(&gamma_control->link); + free(gamma_control); +} + +static void gamma_control_send_failed( + struct wlr_gamma_control_v1 *gamma_control) { + zwlr_gamma_control_v1_send_failed(gamma_control->resource); + gamma_control_destroy(gamma_control); +} + +static const struct zwlr_gamma_control_v1_interface gamma_control_impl; + +static struct wlr_gamma_control_v1 *gamma_control_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &zwlr_gamma_control_v1_interface, + &gamma_control_impl)); + return wl_resource_get_user_data(resource); +} + +static void gamma_control_handle_resource_destroy(struct wl_resource *resource) { + struct wlr_gamma_control_v1 *gamma_control = + gamma_control_from_resource(resource); + gamma_control_destroy(gamma_control); +} + +static void gamma_control_handle_output_destroy(struct wl_listener *listener, + void *data) { + struct wlr_gamma_control_v1 *gamma_control = + wl_container_of(listener, gamma_control, output_destroy_listener); + gamma_control_destroy(gamma_control); +} + +static void gamma_control_handle_set_gamma(struct wl_client *client, + struct wl_resource *gamma_control_resource, int fd) { + struct wlr_gamma_control_v1 *gamma_control = + gamma_control_from_resource(gamma_control_resource); + if (gamma_control == NULL) { + goto error_fd; + } + + uint32_t ramp_size = wlr_output_get_gamma_size(gamma_control->output); + size_t table_size = ramp_size * 3 * sizeof(uint16_t); + + // Refuse to block when reading + int fd_flags = fcntl(fd, F_GETFL, 0); + if (fd_flags == -1) { + wlr_log_errno(WLR_ERROR, "failed to get FD flags"); + gamma_control_send_failed(gamma_control); + goto error_fd; + } + if (fcntl(fd, F_SETFL, fd_flags | O_NONBLOCK) == -1) { + wlr_log_errno(WLR_ERROR, "failed to set FD flags"); + gamma_control_send_failed(gamma_control); + goto error_fd; + } + + // Use the heap since gamma tables can be large + uint16_t *table = malloc(table_size); + if (table == NULL) { + wl_resource_post_no_memory(gamma_control_resource); + goto error_fd; + } + + ssize_t n_read = read(fd, table, table_size); + if (n_read < 0) { + wlr_log_errno(WLR_ERROR, "failed to read gamma table"); + gamma_control_send_failed(gamma_control); + goto error_table; + } else if ((size_t)n_read != table_size) { + wl_resource_post_error(gamma_control_resource, + ZWLR_GAMMA_CONTROL_V1_ERROR_INVALID_GAMMA, + "The gamma ramps don't have the correct size"); + goto error_table; + } + close(fd); + fd = -1; + + uint16_t *r = table; + uint16_t *g = table + ramp_size; + uint16_t *b = table + 2 * ramp_size; + + bool ok = wlr_output_set_gamma(gamma_control->output, ramp_size, r, g, b); + if (!ok) { + gamma_control_send_failed(gamma_control); + goto error_table; + } + free(table); + + return; + +error_table: + free(table); +error_fd: + close(fd); +} + +static const struct zwlr_gamma_control_v1_interface gamma_control_impl = { + .destroy = gamma_control_handle_destroy, + .set_gamma = gamma_control_handle_set_gamma, +}; + +static const struct zwlr_gamma_control_manager_v1_interface + gamma_control_manager_impl; + +static struct wlr_gamma_control_manager_v1 *gamma_control_manager_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &zwlr_gamma_control_manager_v1_interface, &gamma_control_manager_impl)); + return wl_resource_get_user_data(resource); +} + +static void gamma_control_manager_get_gamma_control(struct wl_client *client, + struct wl_resource *manager_resource, uint32_t id, + struct wl_resource *output_resource) { + struct wlr_gamma_control_manager_v1 *manager = + gamma_control_manager_from_resource(manager_resource); + struct wlr_output *output = wlr_output_from_resource(output_resource); + + struct wlr_gamma_control_v1 *gamma_control = + calloc(1, sizeof(struct wlr_gamma_control_v1)); + if (gamma_control == NULL) { + wl_client_post_no_memory(client); + return; + } + gamma_control->output = output; + + uint32_t version = wl_resource_get_version(manager_resource); + gamma_control->resource = wl_resource_create(client, + &zwlr_gamma_control_v1_interface, version, id); + if (gamma_control->resource == NULL) { + free(gamma_control); + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(gamma_control->resource, &gamma_control_impl, + gamma_control, gamma_control_handle_resource_destroy); + + wl_signal_add(&output->events.destroy, + &gamma_control->output_destroy_listener); + gamma_control->output_destroy_listener.notify = + gamma_control_handle_output_destroy; + + wl_list_init(&gamma_control->link); + + if (!output->impl->set_gamma) { + zwlr_gamma_control_v1_send_failed(gamma_control->resource); + gamma_control_destroy(gamma_control); + return; + } + + struct wlr_gamma_control_v1 *gc; + wl_list_for_each(gc, &manager->controls, link) { + if (gc->output == output) { + zwlr_gamma_control_v1_send_failed(gc->resource); + gamma_control_destroy(gc); + return; + } + } + + wl_list_remove(&gamma_control->link); + wl_list_insert(&manager->controls, &gamma_control->link); + zwlr_gamma_control_v1_send_gamma_size(gamma_control->resource, + wlr_output_get_gamma_size(output)); +} + +static const struct zwlr_gamma_control_manager_v1_interface + gamma_control_manager_impl = { + .get_gamma_control = gamma_control_manager_get_gamma_control, +}; + +static void gamma_control_manager_handle_resource_destroy( + struct wl_resource *resource) { + wl_list_remove(wl_resource_get_link(resource)); +} + +static void gamma_control_manager_bind(struct wl_client *client, void *data, + uint32_t version, uint32_t id) { + struct wlr_gamma_control_manager_v1 *manager = data; + + struct wl_resource *resource = wl_resource_create(client, + &zwlr_gamma_control_manager_v1_interface, version, id); + if (resource == NULL) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(resource, &gamma_control_manager_impl, + manager, gamma_control_manager_handle_resource_destroy); + wl_list_insert(&manager->resources, wl_resource_get_link(resource)); +} + +void wlr_gamma_control_manager_v1_destroy( + struct wlr_gamma_control_manager_v1 *manager) { + if (!manager) { + return; + } + struct wlr_gamma_control_v1 *gamma_control, *tmp; + wl_list_for_each_safe(gamma_control, tmp, &manager->controls, link) { + wl_resource_destroy(gamma_control->resource); + } + wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_list_remove(&manager->display_destroy.link); + struct wl_resource *resource, *resource_tmp; + wl_resource_for_each_safe(resource, resource_tmp, &manager->resources) { + wl_resource_destroy(resource); + } + wl_global_destroy(manager->global); + free(manager); +} + +static void handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_gamma_control_manager_v1 *manager = + wl_container_of(listener, manager, display_destroy); + wlr_gamma_control_manager_v1_destroy(manager); +} + +struct wlr_gamma_control_manager_v1 *wlr_gamma_control_manager_v1_create( + struct wl_display *display) { + struct wlr_gamma_control_manager_v1 *manager = + calloc(1, sizeof(struct wlr_gamma_control_manager_v1)); + if (!manager) { + return NULL; + } + + manager->global = wl_global_create(display, + &zwlr_gamma_control_manager_v1_interface, + GAMMA_CONTROL_MANAGER_V1_VERSION, manager, gamma_control_manager_bind); + if (manager->global == NULL) { + free(manager); + return NULL; + } + + wl_signal_init(&manager->events.destroy); + wl_list_init(&manager->resources); + wl_list_init(&manager->controls); + + manager->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &manager->display_destroy); + + return manager; +} diff --git a/types/wlr_idle.c b/types/wlr_idle.c index b4e00451..2d0e8eed 100644 --- a/types/wlr_idle.c +++ b/types/wlr_idle.c @@ -187,6 +187,7 @@ void wlr_idle_destroy(struct wlr_idle *idle) { if (!idle) { return; } + wlr_signal_emit_safe(&idle->events.destroy, idle); wl_list_remove(&idle->display_destroy.link); struct wlr_idle_timeout *timer, *tmp; wl_list_for_each_safe(timer, tmp, &idle->idle_timers, link) { @@ -208,6 +209,7 @@ struct wlr_idle *wlr_idle_create(struct wl_display *display) { } wl_list_init(&idle->idle_timers); wl_signal_init(&idle->events.activity_notify); + wl_signal_init(&idle->events.destroy); idle->enabled = true; idle->event_loop = wl_display_get_event_loop(display); diff --git a/types/wlr_idle_inhibit_v1.c b/types/wlr_idle_inhibit_v1.c index 4cee3029..5f3d3d40 100644 --- a/types/wlr_idle_inhibit_v1.c +++ b/types/wlr_idle_inhibit_v1.c @@ -144,14 +144,15 @@ void wlr_idle_inhibit_v1_destroy(struct wlr_idle_inhibit_manager_v1 *idle_inhibi return; } - wl_list_remove(&idle_inhibit->display_destroy.link); - struct wlr_idle_inhibitor_v1 *inhibitor; struct wlr_idle_inhibitor_v1 *tmp; wl_list_for_each_safe(inhibitor, tmp, &idle_inhibit->inhibitors, link) { idle_inhibitor_v1_destroy(inhibitor); } + wlr_signal_emit_safe(&idle_inhibit->events.destroy, idle_inhibit); + wl_list_remove(&idle_inhibit->display_destroy.link); + struct wl_resource *resource; struct wl_resource *tmp_resource; wl_resource_for_each_safe(resource, tmp_resource, &idle_inhibit->resources) { @@ -175,6 +176,7 @@ struct wlr_idle_inhibit_manager_v1 *wlr_idle_inhibit_v1_create(struct wl_display idle_inhibit->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &idle_inhibit->display_destroy); wl_signal_init(&idle_inhibit->events.new_inhibitor); + wl_signal_init(&idle_inhibit->events.destroy); idle_inhibit->global = wl_global_create(display, &zwp_idle_inhibit_manager_v1_interface, 1, diff --git a/types/wlr_input_inhibitor.c b/types/wlr_input_inhibitor.c index dc5175f8..fa692d6c 100644 --- a/types/wlr_input_inhibitor.c +++ b/types/wlr_input_inhibitor.c @@ -112,6 +112,7 @@ void wlr_input_inhibit_manager_destroy( input_inhibitor_destroy(manager->active_client, manager->active_inhibitor); } + wlr_signal_emit_safe(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); wl_global_destroy(manager->global); free(manager); @@ -143,6 +144,7 @@ struct wlr_input_inhibit_manager *wlr_input_inhibit_manager_create( wl_signal_init(&manager->events.activate); wl_signal_init(&manager->events.deactivate); + wl_signal_init(&manager->events.destroy); manager->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &manager->display_destroy); diff --git a/types/wlr_layer_shell.c b/types/wlr_layer_shell.c index 5d610ece..52e5088e 100644 --- a/types/wlr_layer_shell.c +++ b/types/wlr_layer_shell.c @@ -449,6 +449,7 @@ struct wlr_layer_shell *wlr_layer_shell_create(struct wl_display *display) { layer_shell->global = global; wl_signal_init(&layer_shell->events.new_surface); + wl_signal_init(&layer_shell->events.destroy); layer_shell->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &layer_shell->display_destroy); @@ -464,6 +465,7 @@ void wlr_layer_shell_destroy(struct wlr_layer_shell *layer_shell) { wl_resource_for_each_safe(client, tmp, &layer_shell->client_resources) { wl_resource_destroy(client); } + wlr_signal_emit_safe(&layer_shell->events.destroy, layer_shell); wl_list_remove(&layer_shell->display_destroy.link); wl_global_destroy(layer_shell->global); free(layer_shell); diff --git a/types/wlr_linux_dmabuf.c b/types/wlr_linux_dmabuf_v1.c index 2d5259d8..f72e7c07 100644 --- a/types/wlr_linux_dmabuf.c +++ b/types/wlr_linux_dmabuf_v1.c @@ -4,7 +4,7 @@ #include <unistd.h> #include <wayland-server.h> #include <wlr/render/wlr_renderer.h> -#include <wlr/types/wlr_linux_dmabuf.h> +#include <wlr/types/wlr_linux_dmabuf_v1.h> #include <wlr/util/log.h> #include "linux-dmabuf-unstable-v1-protocol.h" #include "util/signal.h" @@ -20,13 +20,13 @@ static const struct wl_buffer_interface buffer_impl = { .destroy = buffer_handle_destroy, }; -bool wlr_dmabuf_resource_is_buffer(struct wl_resource *buffer_resource) { +bool wlr_dmabuf_v1_resource_is_buffer(struct wl_resource *buffer_resource) { if (!wl_resource_instance_of(buffer_resource, &wl_buffer_interface, &buffer_impl)) { return false; } - struct wlr_dmabuf_buffer *buffer = + struct wlr_dmabuf_v1_buffer *buffer = wl_resource_get_user_data(buffer_resource); if (buffer && buffer->buffer_resource && !buffer->params_resource && buffer->buffer_resource == buffer_resource) { @@ -36,12 +36,12 @@ bool wlr_dmabuf_resource_is_buffer(struct wl_resource *buffer_resource) { return false; } -struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_buffer_resource( +struct wlr_dmabuf_v1_buffer *wlr_dmabuf_v1_buffer_from_buffer_resource( struct wl_resource *buffer_resource) { assert(wl_resource_instance_of(buffer_resource, &wl_buffer_interface, &buffer_impl)); - struct wlr_dmabuf_buffer *buffer = + struct wlr_dmabuf_v1_buffer *buffer = wl_resource_get_user_data(buffer_resource); assert(buffer); assert(buffer->buffer_resource); @@ -51,7 +51,7 @@ struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_buffer_resource( return buffer; } -static void linux_dmabuf_buffer_destroy(struct wlr_dmabuf_buffer *buffer) { +static void linux_dmabuf_buffer_destroy(struct wlr_dmabuf_v1_buffer *buffer) { wlr_dmabuf_attributes_finish(&buffer->attributes); free(buffer); } @@ -65,8 +65,8 @@ static void params_add(struct wl_client *client, struct wl_resource *params_resource, int32_t fd, uint32_t plane_idx, uint32_t offset, uint32_t stride, uint32_t modifier_hi, uint32_t modifier_lo) { - struct wlr_dmabuf_buffer *buffer = - wlr_dmabuf_buffer_from_params_resource(params_resource); + struct wlr_dmabuf_v1_buffer *buffer = + wlr_dmabuf_v1_buffer_from_params_resource(params_resource); if (!buffer) { wl_resource_post_error(params_resource, @@ -113,12 +113,12 @@ static void params_add(struct wl_client *client, } static void buffer_handle_resource_destroy(struct wl_resource *buffer_resource) { - struct wlr_dmabuf_buffer *buffer = - wlr_dmabuf_buffer_from_buffer_resource(buffer_resource); + struct wlr_dmabuf_v1_buffer *buffer = + wlr_dmabuf_v1_buffer_from_buffer_resource(buffer_resource); linux_dmabuf_buffer_destroy(buffer); } -static bool check_import_dmabuf(struct wlr_dmabuf_buffer *buffer) { +static bool check_import_dmabuf(struct wlr_dmabuf_v1_buffer *buffer) { struct wlr_texture *texture = wlr_texture_from_dmabuf(buffer->renderer, &buffer->attributes); if (texture == NULL) { @@ -140,8 +140,8 @@ static void params_create_common(struct wl_client *client, "params was already used to create a wl_buffer"); return; } - struct wlr_dmabuf_buffer *buffer = - wlr_dmabuf_buffer_from_params_resource(params_resource); + struct wlr_dmabuf_v1_buffer *buffer = + wlr_dmabuf_v1_buffer_from_params_resource(params_resource); /* Switch the linux_dmabuf_buffer object from params resource to * eventually wl_buffer resource. */ @@ -302,13 +302,13 @@ static const struct zwp_linux_buffer_params_v1_interface .create_immed = params_create_immed, }; -struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_params_resource( +struct wlr_dmabuf_v1_buffer *wlr_dmabuf_v1_buffer_from_params_resource( struct wl_resource *params_resource) { assert(wl_resource_instance_of(params_resource, &zwp_linux_buffer_params_v1_interface, &linux_buffer_params_impl)); - struct wlr_dmabuf_buffer *buffer = + struct wlr_dmabuf_v1_buffer *buffer = wl_resource_get_user_data(params_resource); assert(buffer); assert(buffer->params_resource); @@ -319,24 +319,24 @@ struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_params_resource( } static void handle_params_destroy(struct wl_resource *params_resource) { - /* Check for NULL since wlr_dmabuf_buffer_from_params_resource will choke */ + /* Check for NULL since wlr_dmabuf_v1_buffer_from_params_resource will choke */ if (!wl_resource_get_user_data(params_resource)) { return; } - struct wlr_dmabuf_buffer *buffer = - wlr_dmabuf_buffer_from_params_resource(params_resource); + struct wlr_dmabuf_v1_buffer *buffer = + wlr_dmabuf_v1_buffer_from_params_resource(params_resource); linux_dmabuf_buffer_destroy(buffer); } static void linux_dmabuf_create_params(struct wl_client *client, struct wl_resource *linux_dmabuf_resource, uint32_t params_id) { - struct wlr_linux_dmabuf *linux_dmabuf = - wlr_linux_dmabuf_from_resource(linux_dmabuf_resource); + struct wlr_linux_dmabuf_v1 *linux_dmabuf = + wlr_linux_dmabuf_v1_from_resource(linux_dmabuf_resource); uint32_t version = wl_resource_get_version(linux_dmabuf_resource); - struct wlr_dmabuf_buffer *buffer = calloc(1, sizeof *buffer); + struct wlr_dmabuf_v1_buffer *buffer = calloc(1, sizeof *buffer); if (!buffer) { goto err; } @@ -372,17 +372,17 @@ static const struct zwp_linux_dmabuf_v1_interface linux_dmabuf_impl = { .create_params = linux_dmabuf_create_params, }; -struct wlr_linux_dmabuf *wlr_linux_dmabuf_from_resource( +struct wlr_linux_dmabuf_v1 *wlr_linux_dmabuf_v1_from_resource( struct wl_resource *resource) { assert(wl_resource_instance_of(resource, &zwp_linux_dmabuf_v1_interface, &linux_dmabuf_impl)); - struct wlr_linux_dmabuf *dmabuf = wl_resource_get_user_data(resource); + struct wlr_linux_dmabuf_v1 *dmabuf = wl_resource_get_user_data(resource); assert(dmabuf); return dmabuf; } -static void linux_dmabuf_send_modifiers(struct wlr_linux_dmabuf *linux_dmabuf, +static void linux_dmabuf_send_modifiers(struct wlr_linux_dmabuf_v1 *linux_dmabuf, struct wl_resource *resource) { struct wlr_renderer *renderer = linux_dmabuf->renderer; /* @@ -428,7 +428,7 @@ static void linux_dmabuf_resource_destroy(struct wl_resource *resource) { static void linux_dmabuf_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) { - struct wlr_linux_dmabuf *linux_dmabuf = data; + struct wlr_linux_dmabuf_v1 *linux_dmabuf = data; struct wl_resource *resource = wl_resource_create(client, &zwp_linux_dmabuf_v1_interface, version, id); @@ -445,7 +445,7 @@ static void linux_dmabuf_bind(struct wl_client *client, void *data, } } -void wlr_linux_dmabuf_destroy(struct wlr_linux_dmabuf *linux_dmabuf) { +void wlr_linux_dmabuf_v1_destroy(struct wlr_linux_dmabuf_v1 *linux_dmabuf) { if (!linux_dmabuf) { return; } @@ -465,21 +465,21 @@ void wlr_linux_dmabuf_destroy(struct wlr_linux_dmabuf *linux_dmabuf) { } static void handle_display_destroy(struct wl_listener *listener, void *data) { - struct wlr_linux_dmabuf *linux_dmabuf = + struct wlr_linux_dmabuf_v1 *linux_dmabuf = wl_container_of(listener, linux_dmabuf, display_destroy); - wlr_linux_dmabuf_destroy(linux_dmabuf); + wlr_linux_dmabuf_v1_destroy(linux_dmabuf); } static void handle_renderer_destroy(struct wl_listener *listener, void *data) { - struct wlr_linux_dmabuf *linux_dmabuf = + struct wlr_linux_dmabuf_v1 *linux_dmabuf = wl_container_of(listener, linux_dmabuf, renderer_destroy); - wlr_linux_dmabuf_destroy(linux_dmabuf); + wlr_linux_dmabuf_v1_destroy(linux_dmabuf); } -struct wlr_linux_dmabuf *wlr_linux_dmabuf_create(struct wl_display *display, +struct wlr_linux_dmabuf_v1 *wlr_linux_dmabuf_v1_create(struct wl_display *display, struct wlr_renderer *renderer) { - struct wlr_linux_dmabuf *linux_dmabuf = - calloc(1, sizeof(struct wlr_linux_dmabuf)); + struct wlr_linux_dmabuf_v1 *linux_dmabuf = + calloc(1, sizeof(struct wlr_linux_dmabuf_v1)); if (linux_dmabuf == NULL) { wlr_log(WLR_ERROR, "could not create simple dmabuf manager"); return NULL; diff --git a/types/wlr_output.c b/types/wlr_output.c index a1d00c0c..abbdab9c 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -552,11 +552,12 @@ void wlr_output_schedule_frame(struct wlr_output *output) { wl_event_loop_add_idle(ev, schedule_frame_handle_idle_timer, output); } -void wlr_output_set_gamma(struct wlr_output *output, - uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b) { - if (output->impl->set_gamma) { - output->impl->set_gamma(output, size, r, g, b); +bool wlr_output_set_gamma(struct wlr_output *output, uint32_t size, + uint16_t *r, uint16_t *g, uint16_t *b) { + if (!output->impl->set_gamma) { + return false; } + return output->impl->set_gamma(output, size, r, g, b); } uint32_t wlr_output_get_gamma_size(struct wlr_output *output) { @@ -767,7 +768,8 @@ bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor, return true; } - wlr_log(WLR_DEBUG, "Falling back to software cursor"); + wlr_log(WLR_DEBUG, "Falling back to software cursor on output '%s'", + cursor->output->name); output_cursor_damage_whole(cursor); return true; } diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index 5ad0c99e..e634d2b2 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -430,15 +430,20 @@ struct wlr_output *wlr_output_layout_get_center_output( return wlr_output_layout_output_at(layout, dest_x, dest_y); } +enum distance_selection_method { + NEAREST, + FARTHEST +}; -struct wlr_output *wlr_output_layout_adjacent_output( +struct wlr_output *wlr_output_layout_output_in_direction( struct wlr_output_layout *layout, enum wlr_direction direction, - struct wlr_output *reference, double ref_lx, double ref_ly) { + struct wlr_output *reference, double ref_lx, double ref_ly, + enum distance_selection_method distance_method) { assert(reference); struct wlr_box *ref_box = wlr_output_layout_get_box(layout, reference); - double min_distance = DBL_MAX; + double min_distance = (distance_method == NEAREST) ? DBL_MAX : DBL_MIN; struct wlr_output *closest_output = NULL; struct wlr_output_layout_output *l_output; wl_list_for_each(l_output, &layout->outputs, link) { @@ -471,10 +476,28 @@ struct wlr_output *wlr_output_layout_adjacent_output( ref_lx, ref_ly, &x, &y); double distance = (x - ref_lx) * (x - ref_lx) + (y - ref_ly) * (y - ref_ly); - if (distance < min_distance) { + + if ((distance_method == NEAREST) + ? distance < min_distance + : distance > min_distance) { min_distance = distance; closest_output = l_output->output; } } return closest_output; } + +struct wlr_output *wlr_output_layout_adjacent_output( + struct wlr_output_layout *layout, enum wlr_direction direction, + struct wlr_output *reference, double ref_lx, double ref_ly) { + return wlr_output_layout_output_in_direction(layout, direction, + reference, ref_lx, ref_ly, NEAREST); +} + +struct wlr_output *wlr_output_layout_farthest_output( + struct wlr_output_layout *layout, enum wlr_direction direction, + struct wlr_output *reference, double ref_lx, double ref_ly) { + return wlr_output_layout_output_in_direction(layout, direction, + reference, ref_lx, ref_ly, FARTHEST); +} + diff --git a/types/wlr_primary_selection.c b/types/wlr_primary_selection.c index 750f9ab4..e561852f 100644 --- a/types/wlr_primary_selection.c +++ b/types/wlr_primary_selection.c @@ -408,6 +408,8 @@ struct wlr_primary_selection_device_manager * return NULL; } + wl_signal_init(&manager->events.destroy); + manager->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &manager->display_destroy); @@ -419,6 +421,7 @@ void wlr_primary_selection_device_manager_destroy( if (manager == NULL) { return; } + wlr_signal_emit_safe(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); // TODO: free resources wl_global_destroy(manager->global); diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c index bd3dfe9a..4f044eba 100644 --- a/types/wlr_screencopy_v1.c +++ b/types/wlr_screencopy_v1.c @@ -5,6 +5,7 @@ #include <wlr/types/wlr_screencopy_v1.h> #include <wlr/backend.h> #include "wlr-screencopy-unstable-v1-protocol.h" +#include "util/signal.h" #define SCREENCOPY_MANAGER_VERSION 1 @@ -295,6 +296,8 @@ struct wlr_screencopy_manager_v1 *wlr_screencopy_manager_v1_create( wl_list_init(&manager->resources); wl_list_init(&manager->frames); + wl_signal_init(&manager->events.destroy); + manager->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &manager->display_destroy); @@ -306,6 +309,7 @@ void wlr_screencopy_manager_v1_destroy( if (manager == NULL) { return; } + wlr_signal_emit_safe(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); struct wlr_screencopy_frame_v1 *frame, *tmp_frame; wl_list_for_each_safe(frame, tmp_frame, &manager->frames, link) { diff --git a/types/wlr_screenshooter.c b/types/wlr_screenshooter.c index 37b70538..c85e6ba5 100644 --- a/types/wlr_screenshooter.c +++ b/types/wlr_screenshooter.c @@ -8,6 +8,7 @@ #include <wlr/types/wlr_screenshooter.h> #include <wlr/util/log.h> #include "screenshooter-protocol.h" +#include "util/signal.h" static struct wlr_screenshot *screenshot_from_resource( struct wl_resource *resource) { @@ -177,6 +178,7 @@ void wlr_screenshooter_destroy(struct wlr_screenshooter *screenshooter) { wl_list_for_each_safe(screenshot, tmp, &screenshooter->screenshots, link) { screenshot_destroy(screenshot); } + wlr_signal_emit_safe(&screenshooter->events.destroy, screenshooter); wl_global_destroy(screenshooter->global); free(screenshooter); } @@ -195,6 +197,7 @@ struct wlr_screenshooter *wlr_screenshooter_create(struct wl_display *display) { } wl_list_init(&screenshooter->screenshots); + wl_signal_init(&screenshooter->events.destroy); screenshooter->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &screenshooter->display_destroy); diff --git a/types/wlr_server_decoration.c b/types/wlr_server_decoration.c index fceb1638..fd92fd04 100644 --- a/types/wlr_server_decoration.c +++ b/types/wlr_server_decoration.c @@ -167,12 +167,13 @@ void wlr_server_decoration_manager_destroy( if (manager == NULL) { return; } - wl_list_remove(&manager->display_destroy.link); struct wlr_server_decoration *decoration, *tmp_decoration; wl_list_for_each_safe(decoration, tmp_decoration, &manager->decorations, link) { server_decoration_destroy(decoration); } + wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_list_remove(&manager->display_destroy.link); struct wl_resource *resource, *tmp_resource; wl_resource_for_each_safe(resource, tmp_resource, &manager->resources) { server_decoration_manager_destroy_resource(resource); @@ -205,6 +206,7 @@ struct wlr_server_decoration_manager *wlr_server_decoration_manager_create( wl_list_init(&manager->resources); wl_list_init(&manager->decorations); wl_signal_init(&manager->events.new_decoration); + wl_signal_init(&manager->events.destroy); manager->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &manager->display_destroy); diff --git a/types/wlr_surface.c b/types/wlr_surface.c index f2b248ca..ab1dfc2d 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -360,10 +360,14 @@ static void surface_update_opaque_region(struct wlr_surface *surface) { } static void surface_commit_pending(struct wlr_surface *surface) { - bool invalid_buffer = surface->pending.committed & WLR_SURFACE_STATE_BUFFER; - surface_state_finalize(surface, &surface->pending); + if (surface->role && surface->role->precommit) { + surface->role->precommit(surface); + } + + bool invalid_buffer = surface->pending.committed & WLR_SURFACE_STATE_BUFFER; + surface->sx += surface->pending.dx; surface->sy += surface->pending.dy; surface_update_damage(&surface->buffer_damage, diff --git a/types/wlr_virtual_keyboard_v1.c b/types/wlr_virtual_keyboard_v1.c index cf7be0ee..e5463295 100644 --- a/types/wlr_virtual_keyboard_v1.c +++ b/types/wlr_virtual_keyboard_v1.c @@ -1,4 +1,4 @@ -#define _POSIX_C_SOURCE 1 +#define _POSIX_C_SOURCE 199309L #include <assert.h> #include <stdlib.h> #include <sys/mman.h> @@ -99,7 +99,7 @@ static void virtual_keyboard_destroy_resource(struct wl_resource *resource) { virtual_keyboard_from_resource(resource); wlr_signal_emit_safe(&keyboard->events.destroy, keyboard); wl_list_remove(&keyboard->link); - wlr_keyboard_destroy(keyboard->input_device.keyboard); + wlr_input_device_destroy(&keyboard->input_device); free(keyboard); } @@ -223,6 +223,7 @@ struct wlr_virtual_keyboard_manager_v1* wl_list_init(&manager->virtual_keyboards); wl_signal_init(&manager->events.new_virtual_keyboard); + wl_signal_init(&manager->events.destroy); manager->global = wl_global_create(display, &zwp_virtual_keyboard_manager_v1_interface, 1, manager, virtual_keyboard_manager_bind); @@ -231,6 +232,7 @@ struct wlr_virtual_keyboard_manager_v1* void wlr_virtual_keyboard_manager_v1_destroy( struct wlr_virtual_keyboard_manager_v1 *manager) { + wlr_signal_emit_safe(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); wl_global_destroy(manager->global); struct wl_resource *resource, *resource_tmp; diff --git a/types/wlr_xdg_decoration_v1.c b/types/wlr_xdg_decoration_v1.c new file mode 100644 index 00000000..f5182daa --- /dev/null +++ b/types/wlr_xdg_decoration_v1.c @@ -0,0 +1,304 @@ +#include <assert.h> +#include <stdbool.h> +#include <stdlib.h> +#include <wlr/types/wlr_xdg_decoration_v1.h> +#include <wlr/util/log.h> +#include "util/signal.h" +#include "xdg-decoration-unstable-v1-protocol.h" + +#define DECORATION_MANAGER_VERSION 1 + +static const struct zxdg_toplevel_decoration_v1_interface + toplevel_decoration_impl; + +static struct wlr_xdg_toplevel_decoration_v1 *toplevel_decoration_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &zxdg_toplevel_decoration_v1_interface, &toplevel_decoration_impl)); + return wl_resource_get_user_data(resource); +} + +static void toplevel_decoration_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static void toplevel_decoration_handle_set_mode(struct wl_client *client, + struct wl_resource *resource, + enum zxdg_toplevel_decoration_v1_mode mode) { + struct wlr_xdg_toplevel_decoration_v1 *decoration = + toplevel_decoration_from_resource(resource); + + decoration->client_pending_mode = + (enum wlr_xdg_toplevel_decoration_v1_mode)mode; + wlr_signal_emit_safe(&decoration->events.request_mode, decoration); +} + +static void toplevel_decoration_handle_unset_mode(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_xdg_toplevel_decoration_v1 *decoration = + toplevel_decoration_from_resource(resource); + + decoration->client_pending_mode = WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_NONE; + wlr_signal_emit_safe(&decoration->events.request_mode, decoration); +} + +static const struct zxdg_toplevel_decoration_v1_interface + toplevel_decoration_impl = { + .destroy = toplevel_decoration_handle_destroy, + .set_mode = toplevel_decoration_handle_set_mode, + .unset_mode = toplevel_decoration_handle_unset_mode, +}; + +uint32_t wlr_xdg_toplevel_decoration_v1_set_mode( + struct wlr_xdg_toplevel_decoration_v1 *decoration, + enum wlr_xdg_toplevel_decoration_v1_mode mode) { + assert(mode != WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_NONE); + decoration->server_pending_mode = mode; + return wlr_xdg_surface_schedule_configure(decoration->surface); +} + +static void toplevel_decoration_handle_resource_destroy( + struct wl_resource *resource) { + struct wlr_xdg_toplevel_decoration_v1 *decoration = + toplevel_decoration_from_resource(resource); + wlr_signal_emit_safe(&decoration->events.destroy, decoration); + wl_list_remove(&decoration->surface_commit.link); + wl_list_remove(&decoration->surface_destroy.link); + wl_list_remove(&decoration->surface_configure.link); + wl_list_remove(&decoration->surface_ack_configure.link); + struct wlr_xdg_toplevel_decoration_v1_configure *configure, *tmp; + wl_list_for_each_safe(configure, tmp, &decoration->configure_list, link) { + free(configure); + } + wl_list_remove(&decoration->link); + free(decoration); +} + +static void toplevel_decoration_handle_surface_destroy( + struct wl_listener *listener, void *data) { + struct wlr_xdg_toplevel_decoration_v1 *decoration = + wl_container_of(listener, decoration, surface_destroy); + wl_resource_destroy(decoration->resource); +} + +static void toplevel_decoration_handle_surface_configure( + struct wl_listener *listener, void *data) { + struct wlr_xdg_toplevel_decoration_v1 *decoration = + wl_container_of(listener, decoration, surface_configure); + struct wlr_xdg_surface_configure *surface_configure = data; + + if (decoration->current_mode == decoration->server_pending_mode) { + return; + } + + struct wlr_xdg_toplevel_decoration_v1_configure *configure = + calloc(1, sizeof(struct wlr_xdg_toplevel_decoration_v1_configure)); + if (configure == NULL) { + return; + } + configure->surface_configure = surface_configure; + configure->mode = decoration->server_pending_mode; + wl_list_insert(decoration->configure_list.prev, &configure->link); + + zxdg_toplevel_decoration_v1_send_configure(decoration->resource, + configure->mode); +} + +static void toplevel_decoration_handle_surface_ack_configure( + struct wl_listener *listener, void *data) { + struct wlr_xdg_toplevel_decoration_v1 *decoration = + wl_container_of(listener, decoration, surface_ack_configure); + struct wlr_xdg_surface_configure *surface_configure = data; + + bool found = false; + struct wlr_xdg_toplevel_decoration_v1_configure *configure; + wl_list_for_each(configure, &decoration->configure_list, link) { + if (configure->surface_configure == surface_configure) { + found = true; + break; + } + } + if (!found) { + return; + } + + decoration->current_mode = configure->mode; + + wl_list_remove(&configure->link); + free(configure); +} + +static void toplevel_decoration_handle_surface_commit( + struct wl_listener *listener, void *data) { + struct wlr_xdg_toplevel_decoration_v1 *decoration = + wl_container_of(listener, decoration, surface_commit); + struct wlr_xdg_decoration_manager_v1 *manager = decoration->manager; + + if (decoration->surface->added) { + wl_list_remove(&decoration->surface_commit.link); + wl_list_init(&decoration->surface_commit.link); + + decoration->added = true; + wlr_signal_emit_safe(&manager->events.new_toplevel_decoration, + decoration); + } +} + + +static const struct zxdg_decoration_manager_v1_interface decoration_manager_impl; + +static struct wlr_xdg_decoration_manager_v1 * + decoration_manager_from_resource(struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &zxdg_decoration_manager_v1_interface, + &decoration_manager_impl)); + return wl_resource_get_user_data(resource); +} + +static void decoration_manager_handle_get_toplevel_decoration( + struct wl_client *client, struct wl_resource *manager_resource, + uint32_t id, struct wl_resource *toplevel_resource) { + struct wlr_xdg_decoration_manager_v1 *manager = + decoration_manager_from_resource(manager_resource); + struct wlr_xdg_surface *surface = + wlr_xdg_surface_from_toplevel_resource(toplevel_resource); + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + + if (wlr_surface_has_buffer(surface->surface)) { + wl_resource_post_error(manager_resource, + ZXDG_TOPLEVEL_DECORATION_V1_ERROR_UNCONFIGURED_BUFFER, + "xdg_toplevel_decoration must not have a buffer at creation"); + return; + } + + struct wlr_xdg_toplevel_decoration_v1 *decoration = + calloc(1, sizeof(struct wlr_xdg_toplevel_decoration_v1)); + if (decoration == NULL) { + wl_client_post_no_memory(client); + return; + } + decoration->manager = manager; + decoration->surface = surface; + + uint32_t version = wl_resource_get_version(manager_resource); + decoration->resource = wl_resource_create(client, + &zxdg_toplevel_decoration_v1_interface, version, id); + if (decoration->resource == NULL) { + free(decoration); + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(decoration->resource, + &toplevel_decoration_impl, decoration, + toplevel_decoration_handle_resource_destroy); + + wlr_log(WLR_DEBUG, "new xdg_toplevel_decoration %p (res %p)", decoration, + decoration->resource); + + wl_list_init(&decoration->configure_list); + wl_signal_init(&decoration->events.destroy); + wl_signal_init(&decoration->events.request_mode); + + wl_signal_add(&surface->events.destroy, &decoration->surface_destroy); + decoration->surface_destroy.notify = + toplevel_decoration_handle_surface_destroy; + wl_signal_add(&surface->events.configure, &decoration->surface_configure); + decoration->surface_configure.notify = + toplevel_decoration_handle_surface_configure; + wl_signal_add(&surface->events.ack_configure, + &decoration->surface_ack_configure); + decoration->surface_ack_configure.notify = + toplevel_decoration_handle_surface_ack_configure; + wl_list_init(&decoration->surface_commit.link); + + wl_list_insert(&manager->decorations, &decoration->link); + + if (surface->added) { + decoration->added = true; + wlr_signal_emit_safe(&manager->events.new_toplevel_decoration, + decoration); + } else { + wl_list_remove(&decoration->surface_commit.link); + wl_signal_add(&surface->surface->events.commit, + &decoration->surface_commit); + decoration->surface_commit.notify = + toplevel_decoration_handle_surface_commit; + } +} + +static const struct zxdg_decoration_manager_v1_interface + decoration_manager_impl = { + .get_toplevel_decoration = decoration_manager_handle_get_toplevel_decoration, +}; + +void decoration_manager_handle_resource_destroy(struct wl_resource *resource) { + wl_list_remove(wl_resource_get_link(resource)); +} + +static void decoration_manager_bind(struct wl_client *client, void *data, + uint32_t version, uint32_t id) { + struct wlr_xdg_decoration_manager_v1 *manager = data; + + struct wl_resource *resource = wl_resource_create(client, + &zxdg_decoration_manager_v1_interface, version, id); + if (resource == NULL) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(resource, &decoration_manager_impl, + manager, decoration_manager_handle_resource_destroy); + + wl_list_insert(&manager->resources, wl_resource_get_link(resource)); +} + +static void handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_xdg_decoration_manager_v1 *manager = + wl_container_of(listener, manager, display_destroy); + wlr_xdg_decoration_manager_v1_destroy(manager); +} + +struct wlr_xdg_decoration_manager_v1 * + wlr_xdg_decoration_manager_v1_create(struct wl_display *display) { + struct wlr_xdg_decoration_manager_v1 *manager = + calloc(1, sizeof(struct wlr_xdg_decoration_manager_v1)); + if (manager == NULL) { + return NULL; + } + manager->global = wl_global_create(display, + &zxdg_decoration_manager_v1_interface, DECORATION_MANAGER_VERSION, + manager, decoration_manager_bind); + if (manager->global == NULL) { + free(manager); + return NULL; + } + wl_list_init(&manager->resources); + wl_list_init(&manager->decorations); + wl_signal_init(&manager->events.new_toplevel_decoration); + wl_signal_init(&manager->events.destroy); + + manager->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &manager->display_destroy); + + return manager; +} + +void wlr_xdg_decoration_manager_v1_destroy( + struct wlr_xdg_decoration_manager_v1 *manager) { + if (manager == NULL) { + return; + } + wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_list_remove(&manager->display_destroy.link); + struct wlr_xdg_toplevel_decoration_v1 *decoration, *tmp_decoration; + wl_list_for_each_safe(decoration, tmp_decoration, &manager->decorations, + link) { + wl_resource_destroy(decoration->resource); + } + struct wl_resource *resource, *tmp_resource; + wl_resource_for_each_safe(resource, tmp_resource, &manager->resources) { + wl_resource_destroy(resource); + } + wl_global_destroy(manager->global); + free(manager); +} diff --git a/types/wlr_xdg_output.c b/types/wlr_xdg_output.c index 1a3bba2c..8c7a1fcb 100644 --- a/types/wlr_xdg_output.c +++ b/types/wlr_xdg_output.c @@ -6,6 +6,7 @@ #include <wlr/types/wlr_xdg_output.h> #include <wlr/util/log.h> #include "xdg-output-unstable-v1-protocol.h" +#include "util/signal.h" #define OUTPUT_MANAGER_VERSION 2 @@ -199,7 +200,7 @@ static void handle_layout_change(struct wl_listener *listener, void *data) { static void handle_layout_destroy(struct wl_listener *listener, void *data) { struct wlr_xdg_output_manager *manager = - wl_container_of(listener, manager, layout_change); + wl_container_of(listener, manager, layout_destroy); wlr_xdg_output_manager_destroy(manager); } @@ -227,6 +228,8 @@ struct wlr_xdg_output_manager *wlr_xdg_output_manager_create( add_output(manager, layout_output); } + wl_signal_init(&manager->events.destroy); + manager->layout_add.notify = handle_layout_add; wl_signal_add(&layout->events.add, &manager->layout_add); manager->layout_change.notify = handle_layout_change; @@ -245,6 +248,7 @@ void wlr_xdg_output_manager_destroy(struct wlr_xdg_output_manager *manager) { wl_resource_for_each_safe(resource, resource_tmp, &manager->resources) { wl_resource_destroy(resource); } + wlr_signal_emit_safe(&manager->events.destroy, manager); wl_list_remove(&manager->layout_add.link); wl_list_remove(&manager->layout_change.link); wl_list_remove(&manager->layout_destroy.link); diff --git a/types/xdg_shell/wlr_xdg_popup.c b/types/xdg_shell/wlr_xdg_popup.c index 26d248e1..b3409261 100644 --- a/types/xdg_shell/wlr_xdg_popup.c +++ b/types/xdg_shell/wlr_xdg_popup.c @@ -214,7 +214,8 @@ static void xdg_popup_handle_resource_destroy(struct wl_resource *resource) { const struct wlr_surface_role xdg_popup_surface_role = { .name = "xdg_popup", - .commit = handle_xdg_surface_committed, + .commit = handle_xdg_surface_commit, + .precommit = handle_xdg_surface_precommit, }; void create_xdg_popup(struct wlr_xdg_surface *xdg_surface, diff --git a/types/xdg_shell/wlr_xdg_shell.c b/types/xdg_shell/wlr_xdg_shell.c index 601e728c..58dc376c 100644 --- a/types/xdg_shell/wlr_xdg_shell.c +++ b/types/xdg_shell/wlr_xdg_shell.c @@ -155,6 +155,7 @@ struct wlr_xdg_shell *wlr_xdg_shell_create(struct wl_display *display) { xdg_shell->global = global; wl_signal_init(&xdg_shell->events.new_surface); + wl_signal_init(&xdg_shell->events.destroy); xdg_shell->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &xdg_shell->display_destroy); @@ -166,6 +167,7 @@ void wlr_xdg_shell_destroy(struct wlr_xdg_shell *xdg_shell) { if (!xdg_shell) { return; } + wlr_signal_emit_safe(&xdg_shell->events.destroy, xdg_shell); wl_list_remove(&xdg_shell->display_destroy.link); wl_global_destroy(xdg_shell->global); free(xdg_shell); diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index dc98a3a5..e32b7f18 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -111,6 +111,7 @@ static void xdg_surface_handle_ack_configure(struct wl_client *client, struct wlr_xdg_surface_configure *configure, *tmp; wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { if (configure->serial < serial) { + wlr_signal_emit_safe(&surface->events.ack_configure, configure); xdg_surface_configure_destroy(configure); } else if (configure->serial == serial) { found = true; @@ -140,6 +141,7 @@ static void xdg_surface_handle_ack_configure(struct wl_client *client, surface->configured = true; surface->configure_serial = serial; + wlr_signal_emit_safe(&surface->events.ack_configure, configure); xdg_surface_configure_destroy(configure); } @@ -157,6 +159,7 @@ static void surface_send_configure(void *user_data) { wl_list_insert(surface->configure_list.prev, &configure->link); configure->serial = surface->configure_next_serial; + configure->surface = surface; switch (surface->role) { case WLR_XDG_SURFACE_ROLE_NONE: @@ -174,26 +177,15 @@ static void surface_send_configure(void *user_data) { break; } + wlr_signal_emit_safe(&surface->events.configure, configure); + xdg_surface_send_configure(surface->resource, configure->serial); } -uint32_t schedule_xdg_surface_configure( - struct wlr_xdg_surface *surface) { +static uint32_t schedule_configure(struct wlr_xdg_surface *surface, + bool pending_same) { struct wl_display *display = wl_client_get_display(surface->client->client); struct wl_event_loop *loop = wl_display_get_event_loop(display); - bool pending_same = false; - - switch (surface->role) { - case WLR_XDG_SURFACE_ROLE_NONE: - assert(0 && "not reached"); - break; - case WLR_XDG_SURFACE_ROLE_TOPLEVEL: - pending_same = - compare_xdg_surface_toplevel_state(surface->toplevel); - break; - case WLR_XDG_SURFACE_ROLE_POPUP: - break; - } if (surface->configure_idle != NULL) { if (!pending_same) { @@ -218,6 +210,27 @@ uint32_t schedule_xdg_surface_configure( } } +uint32_t schedule_xdg_surface_configure(struct wlr_xdg_surface *surface) { + bool pending_same = false; + + switch (surface->role) { + case WLR_XDG_SURFACE_ROLE_NONE: + assert(0 && "not reached"); + break; + case WLR_XDG_SURFACE_ROLE_TOPLEVEL: + pending_same = compare_xdg_surface_toplevel_state(surface->toplevel); + break; + case WLR_XDG_SURFACE_ROLE_POPUP: + break; + } + + return schedule_configure(surface, pending_same); +} + +uint32_t wlr_xdg_surface_schedule_configure(struct wlr_xdg_surface *surface) { + return schedule_configure(surface, false); +} + static void xdg_surface_handle_get_popup(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *parent_resource, @@ -313,7 +326,7 @@ static void xdg_surface_handle_surface_commit(struct wl_listener *listener, } } -void handle_xdg_surface_committed(struct wlr_surface *wlr_surface) { +void handle_xdg_surface_commit(struct wlr_surface *wlr_surface) { struct wlr_xdg_surface *surface = wlr_xdg_surface_from_wlr_surface(wlr_surface); if (surface == NULL) { @@ -355,6 +368,22 @@ void handle_xdg_surface_committed(struct wlr_surface *wlr_surface) { } } +void handle_xdg_surface_precommit(struct wlr_surface *wlr_surface) { + struct wlr_xdg_surface *surface = + wlr_xdg_surface_from_wlr_surface(wlr_surface); + if (surface == NULL) { + return; + } + + if (wlr_surface->pending.committed & WLR_SURFACE_STATE_BUFFER && + wlr_surface->pending.buffer_resource == NULL) { + // This is a NULL commit + if (surface->configured && surface->mapped) { + unmap_xdg_surface(surface); + } + } +} + static void xdg_surface_handle_surface_destroy(struct wl_listener *listener, void *data) { struct wlr_xdg_surface *xdg_surface = @@ -401,6 +430,8 @@ struct wlr_xdg_surface *create_xdg_surface( wl_signal_init(&xdg_surface->events.new_popup); wl_signal_init(&xdg_surface->events.map); wl_signal_init(&xdg_surface->events.unmap); + wl_signal_init(&xdg_surface->events.configure); + wl_signal_init(&xdg_surface->events.ack_configure); wl_signal_add(&xdg_surface->surface->events.destroy, &xdg_surface->surface_destroy); diff --git a/types/xdg_shell/wlr_xdg_toplevel.c b/types/xdg_shell/wlr_xdg_toplevel.c index f04aa654..77398c7e 100644 --- a/types/xdg_shell/wlr_xdg_toplevel.c +++ b/types/xdg_shell/wlr_xdg_toplevel.c @@ -200,7 +200,7 @@ void handle_xdg_surface_toplevel_committed(struct wlr_xdg_surface *surface) { static const struct xdg_toplevel_interface xdg_toplevel_implementation; -static struct wlr_xdg_surface *xdg_surface_from_xdg_toplevel_resource( +struct wlr_xdg_surface *wlr_xdg_surface_from_toplevel_resource( struct wl_resource *resource) { assert(wl_resource_instance_of(resource, &xdg_toplevel_interface, &xdg_toplevel_implementation)); @@ -210,11 +210,11 @@ static struct wlr_xdg_surface *xdg_surface_from_xdg_toplevel_resource( static void xdg_toplevel_handle_set_parent(struct wl_client *client, struct wl_resource *resource, struct wl_resource *parent_resource) { struct wlr_xdg_surface *surface = - xdg_surface_from_xdg_toplevel_resource(resource); + wlr_xdg_surface_from_toplevel_resource(resource); struct wlr_xdg_surface *parent = NULL; if (parent_resource != NULL) { - parent = xdg_surface_from_xdg_toplevel_resource(parent_resource); + parent = wlr_xdg_surface_from_toplevel_resource(parent_resource); } surface->toplevel->parent = parent; @@ -224,7 +224,7 @@ static void xdg_toplevel_handle_set_parent(struct wl_client *client, static void xdg_toplevel_handle_set_title(struct wl_client *client, struct wl_resource *resource, const char *title) { struct wlr_xdg_surface *surface = - xdg_surface_from_xdg_toplevel_resource(resource); + wlr_xdg_surface_from_toplevel_resource(resource); char *tmp; tmp = strdup(title); @@ -234,12 +234,13 @@ static void xdg_toplevel_handle_set_title(struct wl_client *client, free(surface->toplevel->title); surface->toplevel->title = tmp; + wlr_signal_emit_safe(&surface->toplevel->events.set_title, surface); } static void xdg_toplevel_handle_set_app_id(struct wl_client *client, struct wl_resource *resource, const char *app_id) { struct wlr_xdg_surface *surface = - xdg_surface_from_xdg_toplevel_resource(resource); + wlr_xdg_surface_from_toplevel_resource(resource); char *tmp; tmp = strdup(app_id); @@ -249,13 +250,14 @@ static void xdg_toplevel_handle_set_app_id(struct wl_client *client, free(surface->toplevel->app_id); surface->toplevel->app_id = tmp; + wlr_signal_emit_safe(&surface->toplevel->events.set_app_id, surface); } static void xdg_toplevel_handle_show_window_menu(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, int32_t x, int32_t y) { struct wlr_xdg_surface *surface = - xdg_surface_from_xdg_toplevel_resource(resource); + wlr_xdg_surface_from_toplevel_resource(resource); struct wlr_seat_client *seat = wlr_seat_client_from_resource(seat_resource); @@ -286,7 +288,7 @@ static void xdg_toplevel_handle_move(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial) { struct wlr_xdg_surface *surface = - xdg_surface_from_xdg_toplevel_resource(resource); + wlr_xdg_surface_from_toplevel_resource(resource); struct wlr_seat_client *seat = wlr_seat_client_from_resource(seat_resource); @@ -315,7 +317,7 @@ static void xdg_toplevel_handle_resize(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, uint32_t edges) { struct wlr_xdg_surface *surface = - xdg_surface_from_xdg_toplevel_resource(resource); + wlr_xdg_surface_from_toplevel_resource(resource); struct wlr_seat_client *seat = wlr_seat_client_from_resource(seat_resource); @@ -344,7 +346,7 @@ static void xdg_toplevel_handle_resize(struct wl_client *client, static void xdg_toplevel_handle_set_max_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { struct wlr_xdg_surface *surface = - xdg_surface_from_xdg_toplevel_resource(resource); + wlr_xdg_surface_from_toplevel_resource(resource); surface->toplevel->client_pending.max_width = width; surface->toplevel->client_pending.max_height = height; } @@ -352,7 +354,7 @@ static void xdg_toplevel_handle_set_max_size(struct wl_client *client, static void xdg_toplevel_handle_set_min_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { struct wlr_xdg_surface *surface = - xdg_surface_from_xdg_toplevel_resource(resource); + wlr_xdg_surface_from_toplevel_resource(resource); surface->toplevel->client_pending.min_width = width; surface->toplevel->client_pending.min_height = height; } @@ -360,7 +362,7 @@ static void xdg_toplevel_handle_set_min_size(struct wl_client *client, static void xdg_toplevel_handle_set_maximized(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface *surface = - xdg_surface_from_xdg_toplevel_resource(resource); + wlr_xdg_surface_from_toplevel_resource(resource); surface->toplevel->client_pending.maximized = true; wlr_signal_emit_safe(&surface->toplevel->events.request_maximize, surface); } @@ -368,7 +370,7 @@ static void xdg_toplevel_handle_set_maximized(struct wl_client *client, static void xdg_toplevel_handle_unset_maximized(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface *surface = - xdg_surface_from_xdg_toplevel_resource(resource); + wlr_xdg_surface_from_toplevel_resource(resource); surface->toplevel->client_pending.maximized = false; wlr_signal_emit_safe(&surface->toplevel->events.request_maximize, surface); } @@ -376,7 +378,7 @@ static void xdg_toplevel_handle_unset_maximized(struct wl_client *client, static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client, struct wl_resource *resource, struct wl_resource *output_resource) { struct wlr_xdg_surface *surface = - xdg_surface_from_xdg_toplevel_resource(resource); + wlr_xdg_surface_from_toplevel_resource(resource); struct wlr_output *output = NULL; if (output_resource != NULL) { @@ -397,7 +399,7 @@ static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client, static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface *surface = - xdg_surface_from_xdg_toplevel_resource(resource); + wlr_xdg_surface_from_toplevel_resource(resource); surface->toplevel->client_pending.fullscreen = false; @@ -413,7 +415,7 @@ static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client, static void xdg_toplevel_handle_set_minimized(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface *surface = - xdg_surface_from_xdg_toplevel_resource(resource); + wlr_xdg_surface_from_toplevel_resource(resource); wlr_signal_emit_safe(&surface->toplevel->events.request_minimize, surface); } @@ -441,7 +443,7 @@ static const struct xdg_toplevel_interface xdg_toplevel_implementation = { static void xdg_toplevel_handle_resource_destroy(struct wl_resource *resource) { struct wlr_xdg_surface *surface = - xdg_surface_from_xdg_toplevel_resource(resource); + wlr_xdg_surface_from_toplevel_resource(resource); if (surface != NULL) { destroy_xdg_toplevel(surface); } @@ -449,7 +451,8 @@ static void xdg_toplevel_handle_resource_destroy(struct wl_resource *resource) { const struct wlr_surface_role xdg_toplevel_surface_role = { .name = "xdg_toplevel", - .commit = handle_xdg_surface_committed, + .commit = handle_xdg_surface_commit, + .precommit = handle_xdg_surface_precommit, }; void create_xdg_toplevel(struct wlr_xdg_surface *xdg_surface, @@ -471,6 +474,8 @@ void create_xdg_toplevel(struct wlr_xdg_surface *xdg_surface, wl_signal_init(&xdg_surface->toplevel->events.request_resize); wl_signal_init(&xdg_surface->toplevel->events.request_show_window_menu); wl_signal_init(&xdg_surface->toplevel->events.set_parent); + wl_signal_init(&xdg_surface->toplevel->events.set_title); + wl_signal_init(&xdg_surface->toplevel->events.set_app_id); xdg_surface->role = WLR_XDG_SURFACE_ROLE_TOPLEVEL; xdg_surface->toplevel->base = xdg_surface; diff --git a/types/xdg_shell_v6/wlr_xdg_popup_v6.c b/types/xdg_shell_v6/wlr_xdg_popup_v6.c index 59af020f..097e0253 100644 --- a/types/xdg_shell_v6/wlr_xdg_popup_v6.c +++ b/types/xdg_shell_v6/wlr_xdg_popup_v6.c @@ -251,7 +251,8 @@ void handle_xdg_surface_v6_popup_committed(struct wlr_xdg_surface_v6 *surface) { const struct wlr_surface_role xdg_popup_v6_surface_role = { .name = "xdg_popup_v6", - .commit = handle_xdg_surface_v6_committed, + .commit = handle_xdg_surface_v6_commit, + .precommit = handle_xdg_surface_v6_precommit, }; void create_xdg_popup_v6(struct wlr_xdg_surface_v6 *xdg_surface, diff --git a/types/xdg_shell_v6/wlr_xdg_shell_v6.c b/types/xdg_shell_v6/wlr_xdg_shell_v6.c index d61b5dc2..fce8e96a 100644 --- a/types/xdg_shell_v6/wlr_xdg_shell_v6.c +++ b/types/xdg_shell_v6/wlr_xdg_shell_v6.c @@ -156,6 +156,7 @@ struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display) { xdg_shell->global = global; wl_signal_init(&xdg_shell->events.new_surface); + wl_signal_init(&xdg_shell->events.destroy); xdg_shell->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &xdg_shell->display_destroy); @@ -167,6 +168,7 @@ void wlr_xdg_shell_v6_destroy(struct wlr_xdg_shell_v6 *xdg_shell) { if (!xdg_shell) { return; } + wlr_signal_emit_safe(&xdg_shell->events.destroy, xdg_shell); wl_list_remove(&xdg_shell->display_destroy.link); wl_global_destroy(xdg_shell->global); free(xdg_shell); diff --git a/types/xdg_shell_v6/wlr_xdg_surface_v6.c b/types/xdg_shell_v6/wlr_xdg_surface_v6.c index ca729c48..c4007c71 100644 --- a/types/xdg_shell_v6/wlr_xdg_surface_v6.c +++ b/types/xdg_shell_v6/wlr_xdg_surface_v6.c @@ -371,7 +371,7 @@ static void xdg_surface_handle_surface_commit(struct wl_listener *listener, } } -void handle_xdg_surface_v6_committed(struct wlr_surface *wlr_surface) { +void handle_xdg_surface_v6_commit(struct wlr_surface *wlr_surface) { struct wlr_xdg_surface_v6 *surface = wlr_xdg_surface_v6_from_wlr_surface(wlr_surface); if (surface == NULL) { @@ -407,9 +407,21 @@ void handle_xdg_surface_v6_committed(struct wlr_surface *wlr_surface) { surface->mapped = true; wlr_signal_emit_safe(&surface->events.map, surface); } - if (surface->configured && !wlr_surface_has_buffer(surface->surface) && - surface->mapped) { - unmap_xdg_surface_v6(surface); +} + +void handle_xdg_surface_v6_precommit(struct wlr_surface *wlr_surface) { + struct wlr_xdg_surface_v6 *surface = + wlr_xdg_surface_v6_from_wlr_surface(wlr_surface); + if (surface == NULL) { + return; + } + + if (wlr_surface->pending.committed & WLR_SURFACE_STATE_BUFFER && + wlr_surface->pending.buffer_resource == NULL) { + // This is a NULL commit + if (surface->configured && surface->mapped) { + unmap_xdg_surface_v6(surface); + } } } diff --git a/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c b/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c index 43ca99f0..297f49f5 100644 --- a/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c +++ b/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c @@ -57,6 +57,7 @@ static void xdg_toplevel_handle_set_title(struct wl_client *client, free(surface->toplevel->title); surface->toplevel->title = tmp; + wlr_signal_emit_safe(&surface->toplevel->events.set_title, surface); } static void xdg_toplevel_handle_set_app_id(struct wl_client *client, @@ -71,6 +72,7 @@ static void xdg_toplevel_handle_set_app_id(struct wl_client *client, free(surface->toplevel->app_id); surface->toplevel->app_id = tmp; + wlr_signal_emit_safe(&surface->toplevel->events.set_app_id, surface); } static void xdg_toplevel_handle_show_window_menu(struct wl_client *client, @@ -419,7 +421,8 @@ static void xdg_toplevel_handle_resource_destroy(struct wl_resource *resource) { const struct wlr_surface_role xdg_toplevel_v6_surface_role = { .name = "xdg_toplevel_v6", - .commit = handle_xdg_surface_v6_committed, + .commit = handle_xdg_surface_v6_commit, + .precommit = handle_xdg_surface_v6_precommit, }; void create_xdg_toplevel_v6(struct wlr_xdg_surface_v6 *xdg_surface, @@ -441,6 +444,8 @@ void create_xdg_toplevel_v6(struct wlr_xdg_surface_v6 *xdg_surface, wl_signal_init(&xdg_surface->toplevel->events.request_resize); wl_signal_init(&xdg_surface->toplevel->events.request_show_window_menu); wl_signal_init(&xdg_surface->toplevel->events.set_parent); + wl_signal_init(&xdg_surface->toplevel->events.set_title); + wl_signal_init(&xdg_surface->toplevel->events.set_app_id); xdg_surface->role = WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; xdg_surface->toplevel->base = xdg_surface; @@ -85,3 +85,7 @@ const char *_wlr_strip_path(const char *filepath) { } return filepath; } + +enum wlr_log_importance wlr_log_get_verbosity(void) { + return log_importance; +} diff --git a/util/os-compatibility.c b/util/os-compatibility.c index 38333605..bd39705d 100644 --- a/util/os-compatibility.c +++ b/util/os-compatibility.c @@ -23,7 +23,7 @@ * SOFTWARE. */ -#define _XOPEN_SOURCE 700 +#define _POSIX_C_SOURCE 200809L #include <errno.h> #include <fcntl.h> #include <stdlib.h> @@ -32,20 +32,22 @@ #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> +#include <wlr/config.h> #include "util/os-compatibility.h" int os_fd_set_cloexec(int fd) { - long flags; - - if (fd == -1) + if (fd == -1) { return -1; + } - flags = fcntl(fd, F_GETFD); - if (flags == -1) + long flags = fcntl(fd, F_GETFD); + if (flags == -1) { return -1; + } - if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) + if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) { return -1; + } return 0; } @@ -58,15 +60,14 @@ int set_cloexec_or_close(int fd) { return fd; } -int create_tmpfile_cloexec(char *tmpname) -{ +int create_tmpfile_cloexec(char *tmpname) { int fd; - mode_t prev_umask = umask(0066); #ifdef HAVE_MKOSTEMP fd = mkostemp(tmpname, O_CLOEXEC); - if (fd >= 0) + if (fd >= 0) { unlink(tmpname); + } #else fd = mkstemp(tmpname); if (fd >= 0) { @@ -102,32 +103,29 @@ int create_tmpfile_cloexec(char *tmpname) */ int os_create_anonymous_file(off_t size) { static const char template[] = "/wlroots-shared-XXXXXX"; - const char *path; - char *name; - int fd; - int ret; - path = getenv("XDG_RUNTIME_DIR"); + const char *path = getenv("XDG_RUNTIME_DIR"); if (!path) { errno = ENOENT; return -1; } - name = malloc(strlen(path) + sizeof(template)); - if (!name) + char *name = malloc(strlen(path) + sizeof(template)); + if (!name) { return -1; + } strcpy(name, path); strcat(name, template); - fd = create_tmpfile_cloexec(name); - + int fd = create_tmpfile_cloexec(name); free(name); - - if (fd < 0) + if (fd < 0) { return -1; + } -#ifdef HAVE_POSIX_FALLOCATE +#ifdef WLR_HAS_POSIX_FALLOCATE + int ret; do { ret = posix_fallocate(fd, 0, size); } while (ret == EINTR); @@ -137,6 +135,7 @@ int os_create_anonymous_file(off_t size) { return -1; } #else + int ret; do { ret = ftruncate(fd, size); } while (ret < 0 && errno == EINTR); diff --git a/wlroots.syms b/wlroots.syms index ba085d0f..3176f874 100644 --- a/wlroots.syms +++ b/wlroots.syms @@ -1,4 +1,4 @@ -WLROOTS_0_0_0 { +{ global: wlr_*; _wlr_log; diff --git a/xwayland/meson.build b/xwayland/meson.build index ec486f58..0bd88924 100644 --- a/xwayland/meson.build +++ b/xwayland/meson.build @@ -1,3 +1,32 @@ +xwayland_libs = [] +xwayland_required = [ + 'xcb', + 'xcb-composite', + 'xcb-render', + 'xcb-xfixes', +] +xwayland_optional = [ + 'xcb-errors', + 'xcb-icccm', +] + +foreach lib : xwayland_required + dep = dependency(lib, required: get_option('xwayland')) + if not dep.found() + subdir_done() + endif + + xwayland_libs += dep +endforeach + +foreach lib : xwayland_optional + dep = dependency(lib, required: get_option(lib)) + if dep.found() + xwayland_libs += dep + conf_data.set('WLR_HAS_' + lib.underscorify().to_upper(), true) + endif +endforeach + lib_wlr_xwayland = static_library( 'wlr_xwayland', files( @@ -12,14 +41,11 @@ lib_wlr_xwayland = static_library( include_directories: wlr_inc, dependencies: [ wayland_server, - xcb, - xcb_composite, - xcb_xfixes, - xcb_image, - xcb_render, - xcb_icccm, - xcb_errors, + xwayland_libs, xkbcommon, pixman, ], ) + +wlr_parts += lib_wlr_xwayland +conf_data.set('WLR_HAS_XWAYLAND', true) diff --git a/xwayland/xwayland.c b/xwayland/xwayland.c index 1068b942..fe09ea5e 100644 --- a/xwayland/xwayland.c +++ b/xwayland/xwayland.c @@ -74,6 +74,7 @@ static int fill_arg(char ***argv, const char *fmt, ...) { return len; } +_Noreturn static void exec_xwayland(struct wlr_xwayland *wlr_xwayland) { if (unset_cloexec(wlr_xwayland->x_fd[0]) || unset_cloexec(wlr_xwayland->x_fd[1]) || @@ -123,9 +124,26 @@ static void exec_xwayland(struct wlr_xwayland *wlr_xwayland) { wlr_xwayland->wl_fd[1], wlr_xwayland->display, wlr_xwayland->x_fd[0], wlr_xwayland->x_fd[1], wlr_xwayland->wm_fd[1]); - // TODO: close stdout/err depending on log level + // Closes stdout/stderr depending on log verbosity + enum wlr_log_importance verbosity = wlr_log_get_verbosity(); + int devnull = open("/dev/null", O_WRONLY | O_CREAT, 0666); + if (devnull < 0) { + wlr_log_errno(WLR_ERROR, "XWayland: failed to open /dev/null"); + _exit(EXIT_FAILURE); + } + if (verbosity < WLR_INFO) { + dup2(devnull, STDOUT_FILENO); + } + if (verbosity < WLR_ERROR) { + dup2(devnull, STDERR_FILENO); + } + // This returns if and only if the call fails execvp("Xwayland", argv); + + wlr_log_errno(WLR_ERROR, "failed to exec Xwayland"); + close(devnull); + _exit(EXIT_FAILURE); } static void xwayland_finish_server(struct wlr_xwayland *wlr_xwayland) { @@ -346,8 +364,6 @@ static bool xwayland_start_server(struct wlr_xwayland *wlr_xwayland) { sigprocmask(SIG_BLOCK, &sigset, NULL); if ((pid = fork()) == 0) { exec_xwayland(wlr_xwayland); - wlr_log_errno(WLR_ERROR, "failed to exec Xwayland"); - _exit(EXIT_FAILURE); } if (pid < 0) { wlr_log_errno(WLR_ERROR, "second fork failed"); @@ -390,6 +406,10 @@ static bool xwayland_start_server_lazy(struct wlr_xwayland *wlr_xwayland) { } void wlr_xwayland_destroy(struct wlr_xwayland *wlr_xwayland) { + if (!wlr_xwayland) { + return; + } + wlr_xwayland_set_seat(wlr_xwayland, NULL); xwayland_finish_server(wlr_xwayland); xwayland_finish_display(wlr_xwayland); diff --git a/xwayland/xwm.c b/xwayland/xwm.c index bee3a005..9c803543 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -24,6 +24,7 @@ const char *atom_map[ATOM_LAST] = { "WM_HINTS", "WM_NORMAL_HINTS", "WM_SIZE_HINTS", + "WM_WINDOW_ROLE", "_MOTIF_WM_HINTS", "UTF8_STRING", "WM_S0", @@ -39,6 +40,7 @@ const char *atom_map[ATOM_LAST] = { "_NET_WM_MOVERESIZE", "_NET_WM_NAME", "_NET_SUPPORTING_WM_CHECK", + "_NET_WM_STATE_MODAL", "_NET_WM_STATE_FULLSCREEN", "_NET_WM_STATE_MAXIMIZED_VERT", "_NET_WM_STATE_MAXIMIZED_HORZ", @@ -147,13 +149,17 @@ static struct wlr_xwayland_surface *xwayland_surface_create( wl_signal_init(&surface->events.request_resize); wl_signal_init(&surface->events.request_maximize); wl_signal_init(&surface->events.request_fullscreen); + wl_signal_init(&surface->events.request_activate); wl_signal_init(&surface->events.map); wl_signal_init(&surface->events.unmap); wl_signal_init(&surface->events.set_class); + wl_signal_init(&surface->events.set_role); wl_signal_init(&surface->events.set_title); wl_signal_init(&surface->events.set_parent); wl_signal_init(&surface->events.set_pid); wl_signal_init(&surface->events.set_window_type); + wl_signal_init(&surface->events.set_hints); + wl_signal_init(&surface->events.set_override_redirect); wl_signal_init(&surface->events.ping_timeout); xcb_get_geometry_reply_t *geometry_reply = @@ -240,8 +246,7 @@ static void xwm_send_focus_window(struct wlr_xwm *xwm, XCB_CONFIG_WINDOW_STACK_MODE, values); } - -void xwm_surface_activate(struct wlr_xwm *xwm, +static void xwm_surface_activate(struct wlr_xwm *xwm, struct wlr_xwayland_surface *xsurface) { if (xwm->focus_surface == xsurface || (xsurface && xsurface->override_redirect)) { @@ -267,6 +272,9 @@ static void xsurface_set_net_wm_state(struct wlr_xwayland_surface *xsurface) { int i; i = 0; + if (xsurface->modal) { + property[i++] = xwm->atoms[_NET_WM_STATE_MODAL]; + } if (xsurface->fullscreen) { property[i++] = xwm->atoms[_NET_WM_STATE_FULLSCREEN]; } @@ -321,6 +329,7 @@ static void xwayland_surface_destroy( free(xsurface->title); free(xsurface->class); free(xsurface->instance); + free(xsurface->role); free(xsurface->window_type); free(xsurface->protocols); free(xsurface->hints); @@ -359,6 +368,28 @@ static void read_surface_class(struct wlr_xwm *xwm, wlr_signal_emit_safe(&surface->events.set_class, surface); } +static void read_surface_role(struct wlr_xwm *xwm, + struct wlr_xwayland_surface *xsurface, + xcb_get_property_reply_t *reply) { + if (reply->type != XCB_ATOM_STRING && + reply->type != xwm->atoms[UTF8_STRING]) { + return; + } + + size_t len = xcb_get_property_value_length(reply); + char *role = xcb_get_property_value(reply); + + free(xsurface->role); + if (len > 0) { + xsurface->role = strndup(role, len); + } else { + xsurface->role = NULL; + } + + wlr_log(WLR_DEBUG, "XCB_ATOM_WM_WINDOW_ROLE: %s", xsurface->role); + wlr_signal_emit_safe(&xsurface->events.set_role, xsurface); +} + static void read_surface_title(struct wlr_xwm *xwm, struct wlr_xwayland_surface *xsurface, xcb_get_property_reply_t *reply) { @@ -492,6 +523,7 @@ static void read_surface_hints(struct wlr_xwm *xwm, xsurface->hints_urgency = xcb_icccm_wm_hints_get_urgency(&hints); wlr_log(WLR_DEBUG, "WM_HINTS (%d)", reply->value_len); + wlr_signal_emit_safe(&xsurface->events.set_hints, xsurface); } #else static void read_surface_hints(struct wlr_xwm *xwm, @@ -573,7 +605,9 @@ static void read_surface_net_wm_state(struct wlr_xwm *xwm, xsurface->fullscreen = 0; xcb_atom_t *atom = xcb_get_property_value(reply); for (uint32_t i = 0; i < reply->value_len; i++) { - if (atom[i] == xwm->atoms[_NET_WM_STATE_FULLSCREEN]) { + if (atom[i] == xwm->atoms[_NET_WM_STATE_MODAL]) { + xsurface->modal = true; + } else if (atom[i] == xwm->atoms[_NET_WM_STATE_FULLSCREEN]) { xsurface->fullscreen = true; } else if (atom[i] == xwm->atoms[_NET_WM_STATE_MAXIMIZED_VERT]) { xsurface->maximized_vert = true; @@ -629,6 +663,8 @@ static void read_surface_property(struct wlr_xwm *xwm, read_surface_normal_hints(xwm, xsurface, reply); } else if (property == xwm->atoms[MOTIF_WM_HINTS]) { read_surface_motif_hints(xwm, xsurface, reply); + } else if (property == xwm->atoms[WM_WINDOW_ROLE]) { + read_surface_role(xwm, xsurface, reply); } else { char *prop_name = xwm_get_atom_name(xwm, property); wlr_log(WLR_DEBUG, "unhandled X11 property %u (%s) for window %u", @@ -652,9 +688,27 @@ static void xwayland_surface_role_commit(struct wlr_surface *wlr_surface) { } } +static void xwayland_surface_role_precommit(struct wlr_surface *wlr_surface) { + assert(wlr_surface->role == &xwayland_surface_role); + struct wlr_xwayland_surface *surface = wlr_surface->role_data; + if (surface == NULL) { + return; + } + + if (wlr_surface->pending.committed & WLR_SURFACE_STATE_BUFFER && + wlr_surface->pending.buffer_resource == NULL) { + // This is a NULL commit + if (surface->mapped) { + wlr_signal_emit_safe(&surface->events.unmap, surface); + surface->mapped = false; + } + } +} + static const struct wlr_surface_role xwayland_surface_role = { .name = "wlr_xwayland_surface", .commit = xwayland_surface_role_commit, + .precommit = xwayland_surface_role_precommit, }; static void handle_surface_destroy(struct wl_listener *listener, void *data) { @@ -764,9 +818,7 @@ static void xwm_handle_configure_request(struct wlr_xwm *xwm, static void xwm_handle_configure_notify(struct wlr_xwm *xwm, xcb_configure_notify_event_t *ev) { - struct wlr_xwayland_surface *xsurface = - lookup_surface(xwm, ev->window); - + struct wlr_xwayland_surface *xsurface = lookup_surface(xwm, ev->window); if (!xsurface) { return; } @@ -775,6 +827,11 @@ static void xwm_handle_configure_notify(struct wlr_xwm *xwm, xsurface->y = ev->y; xsurface->width = ev->width; xsurface->height = ev->height; + + if (xsurface->override_redirect != ev->override_redirect) { + xsurface->override_redirect = ev->override_redirect; + wlr_signal_emit_safe(&xsurface->events.set_override_redirect, xsurface); + } } #define ICCCM_WITHDRAWN_STATE 0 @@ -814,6 +871,15 @@ static void xwm_handle_map_request(struct wlr_xwm *xwm, static void xwm_handle_map_notify(struct wlr_xwm *xwm, xcb_map_notify_event_t *ev) { wlr_log(WLR_DEBUG, "XCB_MAP_NOTIFY (%u)", ev->window); + struct wlr_xwayland_surface *xsurface = lookup_surface(xwm, ev->window); + if (!xsurface) { + return; + } + + if (xsurface->override_redirect != ev->override_redirect) { + xsurface->override_redirect = ev->override_redirect; + wlr_signal_emit_safe(&xsurface->events.set_override_redirect, xsurface); + } } static void xwm_handle_unmap_notify(struct wlr_xwm *xwm, @@ -996,7 +1062,10 @@ static void xwm_handle_net_wm_state_message(struct wlr_xwm *xwm, for (size_t i = 0; i < 2; ++i) { uint32_t property = client_message->data.data32[1 + i]; - if (property == xwm->atoms[_NET_WM_STATE_FULLSCREEN] && + if (property == xwm->atoms[_NET_WM_STATE_MODAL] && + update_state(action, &xsurface->modal)) { + xsurface_set_net_wm_state(xsurface); + } else if (property == xwm->atoms[_NET_WM_STATE_FULLSCREEN] && update_state(action, &xsurface->fullscreen)) { xsurface_set_net_wm_state(xsurface); } else if (property == xwm->atoms[_NET_WM_STATE_MAXIMIZED_VERT] && @@ -1055,6 +1124,15 @@ static void xwm_handle_wm_protocols_message(struct wlr_xwm *xwm, } } +static void xwm_handle_net_active_window_message(struct wlr_xwm *xwm, + xcb_client_message_event_t *ev) { + struct wlr_xwayland_surface *surface = lookup_surface(xwm, ev->window); + if (surface == NULL) { + return; + } + wlr_signal_emit_safe(&surface->events.request_activate, surface); +} + static void xwm_handle_client_message(struct wlr_xwm *xwm, xcb_client_message_event_t *ev) { wlr_log(WLR_DEBUG, "XCB_CLIENT_MESSAGE (%u)", ev->window); @@ -1067,6 +1145,8 @@ static void xwm_handle_client_message(struct wlr_xwm *xwm, xwm_handle_net_wm_moveresize_message(xwm, ev); } else if (ev->type == xwm->atoms[WM_PROTOCOLS]) { xwm_handle_wm_protocols_message(xwm, ev); + } else if (ev->type == xwm->atoms[_NET_ACTIVE_WINDOW]) { + xwm_handle_net_active_window_message(xwm, ev); } else if (!xwm_handle_selection_client_message(xwm, ev)) { char *type_name = xwm_get_atom_name(xwm, ev->type); wlr_log(WLR_DEBUG, "unhandled x11 client message %u (%s)", ev->type, @@ -1598,6 +1678,7 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland) { xwm->atoms[NET_WM_STATE], xwm->atoms[_NET_ACTIVE_WINDOW], xwm->atoms[_NET_WM_MOVERESIZE], + xwm->atoms[_NET_WM_STATE_MODAL], xwm->atoms[_NET_WM_STATE_FULLSCREEN], xwm->atoms[_NET_WM_STATE_MAXIMIZED_VERT], xwm->atoms[_NET_WM_STATE_MAXIMIZED_HORZ], @@ -1659,8 +1740,22 @@ bool xwm_atoms_contains(struct wlr_xwm *xwm, xcb_atom_t *atoms, return false; } -bool wlr_xwayland_surface_is_unmanaged( +void wlr_xwayland_surface_ping(struct wlr_xwayland_surface *surface) { + xcb_client_message_data_t data = { 0 }; + data.data32[0] = surface->xwm->atoms[_NET_WM_PING]; + data.data32[1] = XCB_CURRENT_TIME; + data.data32[2] = surface->window_id; + + xwm_send_wm_message(surface, &data, XCB_EVENT_MASK_NO_EVENT); + + wl_event_source_timer_update(surface->ping_timer, + surface->xwm->ping_timeout); + surface->pinging = true; +} + +bool wlr_xwayland_or_surface_wants_focus( const struct wlr_xwayland_surface *surface) { + bool ret = true; static enum atom_name needles[] = { NET_WM_WINDOW_TYPE_COMBO, NET_WM_WINDOW_TYPE_DND, @@ -1672,26 +1767,12 @@ bool wlr_xwayland_surface_is_unmanaged( NET_WM_WINDOW_TYPE_TOOLTIP, NET_WM_WINDOW_TYPE_UTILITY, }; - for (size_t i = 0; i < sizeof(needles) / sizeof(needles[0]); ++i) { if (xwm_atoms_contains(surface->xwm, surface->window_type, surface->window_type_len, needles[i])) { - return true; + ret = false; } } - return false; -} - -void wlr_xwayland_surface_ping(struct wlr_xwayland_surface *surface) { - xcb_client_message_data_t data = { 0 }; - data.data32[0] = surface->xwm->atoms[_NET_WM_PING]; - data.data32[1] = XCB_CURRENT_TIME; - data.data32[2] = surface->window_id; - - xwm_send_wm_message(surface, &data, XCB_EVENT_MASK_NO_EVENT); - - wl_event_source_timer_update(surface->ping_timer, - surface->xwm->ping_timeout); - surface->pinging = true; + return ret; } |