static void view_paint(struct ctx *context, struct wlc_view *view) { assert(context && view); struct wlc_surface *surface; if (!(surface = convert_from_wlc_resource(view->surface, "surface"))) return; struct paint settings; memset(&settings, 0, sizeof(settings)); settings.dim = ((view->commit.state & WLC_BIT_ACTIVATED) || (view->type & (WLC_BIT_UNMANAGED|WLC_BIT_SPLASH|WLC_BIT_OVERRIDE_REDIRECT)) ? 1.0f : DIM); settings.program = (enum program_type)surface->format; struct wlc_geometry geometry; wlc_view_get_bounds(view, &geometry, &settings.visible); surface_paint_internal(context, surface, &geometry, &settings); if (DRAW_OPAQUE) { wlc_view_get_opaque(view, &geometry); settings.visible = geometry; settings.program = PROGRAM_CURSOR; GL_CALL(glBlendFunc(GL_ONE, GL_DST_COLOR)); texture_paint(context, &context->textures[TEXTURE_BLACK], 1, &geometry, &settings); GL_CALL(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); } }
void wlc_view_get_bounds(struct wlc_view *view, struct wlc_geometry *out_bounds, struct wlc_geometry *out_visible) { assert(view && out_bounds); memcpy(out_bounds, &view->commit.geometry, sizeof(struct wlc_geometry)); struct wlc_surface *surface; if (!(surface = convert_from_wlc_resource(view->surface, "surface"))) return; if (should_be_transformed_by_parent(view)) { for (struct wlc_view *parent = convert_from_wlc_handle(view->parent, "view"); parent; parent = convert_from_wlc_handle(parent->parent, "view")) { out_bounds->origin.x += parent->commit.geometry.origin.x; out_bounds->origin.y += parent->commit.geometry.origin.y; } } if (view->xdg_surface && view->commit.visible.size.w > 0 && view->commit.visible.size.h > 0) { // xdg-surface client that draws drop shadows or other stuff. // Only obey visible hints when not maximized or fullscreen. if (!(view->commit.state & WLC_BIT_MAXIMIZED) && !(view->commit.state & WLC_BIT_FULLSCREEN)) { out_bounds->origin.x -= view->commit.visible.origin.x; out_bounds->origin.y -= view->commit.visible.origin.y; // Make sure size is at least what we want, but may be bigger (shadows etc...) out_bounds->size.w = chck_maxu32(surface->size.w, view->commit.geometry.size.w); out_bounds->size.h = chck_maxu32(surface->size.h, view->commit.geometry.size.h); } } // Make sure bounds is never 0x0 w/h wlc_size_max(&out_bounds->size, &(struct wlc_size){ 1, 1 }, &out_bounds->size);
void wlc_view_get_input(struct wlc_view *view, struct wlc_geometry *out_input) { assert(view && out_input); struct wlc_geometry b, v; wlc_view_get_bounds(view, &b, &v); wlc_surface_get_input(convert_from_wlc_resource(view->surface, "surface"), &v.origin, out_input); }
struct wlc_output* wlc_view_get_output_ptr(struct wlc_view *view) { struct wlc_surface *surface; if (!view || !(surface = convert_from_wlc_resource(view->surface, "surface"))) return NULL; return convert_from_wlc_handle(surface->output, "output"); }
bool wlc_view_get_opaque(struct wlc_view *view, struct wlc_geometry *out_opaque) { assert(view && out_opaque); struct wlc_geometry b, v; wlc_view_get_bounds(view, &b, &v); return wlc_surface_get_opaque(convert_from_wlc_resource(view->surface, "surface"), &v.origin, out_opaque); }
static void surface_tree_update_coordinate_transform(struct wlc_surface *surface, const struct wlc_geometry *area) { assert(surface && area); surface_update_coordinate_transform(surface, area); wlc_resource *s; chck_iter_pool_for_each(&surface->subsurface_list, s) surface_update_coordinate_transform(convert_from_wlc_resource(*s, "surface"), area); }
void wlc_view_ack_surface_attach(struct wlc_view *view, struct wlc_surface *surface) { assert(view && surface); if (view->x11.id) { surface->pending.opaque.extents = (pixman_box32_t){ 0, 0, surface->size.w, surface->size.h }; view->surface_pending.visible = (struct wlc_geometry){ wlc_origin_zero, surface->size }; } const bool resizing = (view->pending.state & WLC_BIT_RESIZING || view->commit.state & WLC_BIT_RESIZING); if (!resizing && !wlc_geometry_equals(&view->surface_pending.visible, &view->surface_commit.visible)) { struct wlc_geometry g = (struct wlc_geometry){ view->pending.geometry.origin, view->surface_pending.visible.size }; wlc_view_request_geometry(view, &g); } view->surface_commit = view->surface_pending; wlc_dlog(WLC_DBG_COMMIT, "=> surface view %" PRIuWLC, convert_to_wlc_handle(view)); } static bool should_be_transformed_by_parent(struct wlc_view *view) { return !(view->type & WLC_BIT_OVERRIDE_REDIRECT) && !(view->type & WLC_BIT_UNMANAGED); } void wlc_view_get_bounds(struct wlc_view *view, struct wlc_geometry *out_bounds, struct wlc_geometry *out_visible) { assert(view && out_bounds && out_bounds != out_visible); memcpy(out_bounds, &view->commit.geometry, sizeof(struct wlc_geometry)); struct wlc_surface *surface; if (!(surface = convert_from_wlc_resource(view->surface, "surface"))) return; if (should_be_transformed_by_parent(view)) { for (struct wlc_view *parent = convert_from_wlc_handle(view->parent, "view"); parent; parent = convert_from_wlc_handle(parent->parent, "view")) { out_bounds->origin.x += parent->commit.geometry.origin.x; out_bounds->origin.y += parent->commit.geometry.origin.y; } } if (view->xdg_surface && view->surface_commit.visible.size.w > 0 && view->surface_commit.visible.size.h > 0) { // xdg-surface client that draws drop shadows or other stuff. out_bounds->origin.x -= view->surface_commit.visible.origin.x; out_bounds->origin.y -= view->surface_commit.visible.origin.y; out_bounds->size.w += surface->size.w - view->surface_commit.visible.size.w; out_bounds->size.h += surface->size.h - view->surface_commit.visible.size.h; } // Make sure bounds is never 0x0 w/h wlc_size_max(&out_bounds->size, &(struct wlc_size){ 1, 1 }, &out_bounds->size);
static void wl_cb_shell_surface_pong(struct wl_client *client, struct wl_resource *resource, uint32_t serial) { (void)client, (void)serial; struct wlc_view *view; struct wlc_surface *surface; if (!(view = convert_from_wlc_handle((wlc_handle)wl_resource_get_user_data(resource), "view")) || !(surface = convert_from_wlc_resource(view->surface, "surface"))) return; STUBL(resource); }
void wlc_buffer_release(struct wlc_buffer *buffer) { struct wlc_surface *surface; if ((surface = convert_from_wlc_resource(buffer->surface, "surface"))) { if (surface->commit.buffer == convert_to_wlc_resource(buffer)) surface->commit.buffer = 0; if (surface->pending.buffer == convert_to_wlc_resource(buffer)) surface->pending.buffer = 0; } struct wl_resource *resource; if ((resource = convert_to_wl_resource(buffer, "buffer"))) { wlc_resource_invalidate(convert_to_wlc_resource(buffer)); wl_resource_queue_event(resource, WL_BUFFER_RELEASE); } }
void wlc_view_set_surface(struct wlc_view *view, struct wlc_surface *surface) { if (!view || view->surface == convert_to_wlc_resource(surface)) return; wlc_handle old = view->surface; view->surface = convert_to_wlc_resource(surface); wlc_surface_attach_to_view(convert_from_wlc_resource(old, "surface"), NULL); wlc_surface_attach_to_view(surface, view); if (surface && surface->commit.attached) { wlc_view_map(view); } else { wlc_view_unmap(view); } wlc_dlog(WLC_DBG_RENDER, "-> Linked surface (%" PRIuWLC ") to view (%" PRIuWLC ")", convert_to_wlc_resource(surface), convert_to_wlc_handle(view)); }
void wlc_view_release(struct wlc_view *view) { if (!view) return; wlc_view_unmap(view); wlc_view_set_parent_ptr(view, NULL); wlc_resource_release(view->shell_surface); wlc_resource_release(view->xdg_surface); wlc_resource_release(view->xdg_popup); chck_string_release(&view->data.title); chck_string_release(&view->data._class); chck_string_release(&view->data.app_id); wlc_surface_attach_to_view(convert_from_wlc_resource(view->surface, "surface"), NULL); chck_iter_pool_release(&view->wl_state); }
void wlc_view_commit_state(struct wlc_view *view, struct wlc_view_state *pending, struct wlc_view_state *out) { struct wlc_surface *surface; if (!(surface = convert_from_wlc_resource(view->surface, "surface"))) return; // FIXME: handle ping #if 0 struct wl_resource *r; if (view->shell_surface && (r = wl_resource_from_wlc_resource(view->shell_surface, "shell-surface"))) wl_shell_surface_send_ping(r, wl_display_next_serial(wlc_display())); wlc_dlog(WLC_DBG_COMMIT, "=> ping view %zu", convert_to_wlc_handle(view)); return; #endif if (!view->state.created) { // Initial size of the view view->pending.geometry.size = surface->size; view->state.created = true; if (WLC_INTERFACE_EMIT_EXCEPT(view.created, false, convert_to_wlc_handle(view))) { wlc_view_close_ptr(view); return; } } if (!memcmp(pending, out, sizeof(struct wlc_view_state))) return; if (pending->state != out->state) { const struct { uint32_t bit; uint32_t state; } map[] = { { WLC_BIT_MAXIMIZED, XDG_SURFACE_STATE_MAXIMIZED }, { WLC_BIT_FULLSCREEN, XDG_SURFACE_STATE_FULLSCREEN }, { WLC_BIT_RESIZING, XDG_SURFACE_STATE_RESIZING }, { WLC_BIT_ACTIVATED, XDG_SURFACE_STATE_ACTIVATED }, { 0, 0 }, }; chck_iter_pool_flush(&view->wl_state); for (uint32_t i = 0; map[i].state != 0; ++i) { if (pending->state & map[i].bit) chck_iter_pool_push_back(&view->wl_state, &map[i].state); } } const bool size_changed = (!wlc_size_equals(&pending->geometry.size, &out->geometry.size) || !wlc_size_equals(&pending->geometry.size, &surface->size)); wlc_dlog(WLC_DBG_COMMIT, "=> pending commit %zu (%d) pending: %ux%u commited: %ux%u surface: %ux%u", convert_to_wlc_handle(view), size_changed, pending->geometry.size.w, pending->geometry.size.h, out->geometry.size.w, out->geometry.size.h, surface->size.w, surface->size.h); if (pending->state != out->state || size_changed) { struct wl_resource *r; if (view->xdg_surface && (r = wl_resource_from_wlc_resource(view->xdg_surface, "xdg-surface"))) { const uint32_t serial = wl_display_next_serial(wlc_display()); struct wl_array states = { .size = view->wl_state.items.used, .alloc = view->wl_state.items.allocated, .data = view->wl_state.items.buffer }; xdg_surface_send_configure(r, pending->geometry.size.w, pending->geometry.size.h, &states, serial); } else if (view->shell_surface && (r = wl_resource_from_wlc_resource(view->shell_surface, "shell-surface"))) { wl_shell_surface_send_configure(r, pending->edges, pending->geometry.size.w, pending->geometry.size.h); } } if (view->x11.id) { if (!wlc_origin_equals(&pending->geometry.origin, &out->geometry.origin)) wlc_x11_window_position(&view->x11, pending->geometry.origin.x, pending->geometry.origin.y); if (size_changed) wlc_x11_window_resize(&view->x11, pending->geometry.size.w, pending->geometry.size.h); } memcpy(out, pending, sizeof(struct wlc_view_state)); wlc_dlog(WLC_DBG_COMMIT, "=> commit %zu", convert_to_wlc_handle(view)); }
void wlc_view_commit_state(struct wlc_view *view, struct wlc_view_state *pending, struct wlc_view_state *out) { assert(view && pending && out); struct wlc_surface *surface; if (!(surface = convert_from_wlc_resource(view->surface, "surface"))) return; // FIXME: handle ping #if 0 struct wl_resource *r; if (view->shell_surface && (r = wl_resource_from_wlc_resource(view->shell_surface, "shell-surface"))) wl_shell_surface_send_ping(r, wl_display_next_serial(wlc_display())); wlc_dlog(WLC_DBG_COMMIT, "=> ping view %" PRIuWLC, convert_to_wlc_handle(view)); return; #endif if (!view->state.created) { // Initial size of the view view->pending.geometry.size = surface->size; view->state.created = true; if (WLC_INTERFACE_EMIT_EXCEPT(view.created, false, convert_to_wlc_handle(view))) { wlc_view_close_ptr(view); return; } } if (!memcmp(pending, out, sizeof(struct wlc_view_state))) return; if (pending->state != out->state) { const struct { enum wlc_view_state_bit bit; uint32_t state; } map[] = { { WLC_BIT_MAXIMIZED, XDG_SURFACE_STATE_MAXIMIZED }, { WLC_BIT_FULLSCREEN, XDG_SURFACE_STATE_FULLSCREEN }, { WLC_BIT_RESIZING, XDG_SURFACE_STATE_RESIZING }, { WLC_BIT_ACTIVATED, XDG_SURFACE_STATE_ACTIVATED }, }; chck_iter_pool_flush(&view->wl_state); for (uint32_t i = 0; i < LENGTH(map); ++i) { if (pending->state & map[i].bit) chck_iter_pool_push_back(&view->wl_state, &map[i].state); } } const bool size_changed = (!wlc_size_equals(&pending->geometry.size, &out->geometry.size) || !wlc_size_equals(&pending->geometry.size, &surface->size)); wlc_dlog(WLC_DBG_COMMIT, "=> pending view commit %" PRIuWLC " (%d) pending: %ux%u commited: %ux%u surface: %ux%u", convert_to_wlc_handle(view), size_changed, pending->geometry.size.w, pending->geometry.size.h, out->geometry.size.w, out->geometry.size.h, surface->size.w, surface->size.h); if (pending->state != out->state || size_changed) configure_view(view, pending->edges, &pending->geometry); *out = *pending; wlc_dlog(WLC_DBG_COMMIT, "=> commit view %" PRIuWLC, convert_to_wlc_handle(view)); }
void wlc_view_ack_surface_attach(struct wlc_view *view, struct wlc_surface *surface) { assert(view && surface); if (is_x11_view(view)) { surface->pending.opaque.extents = (pixman_box32_t){ 0, 0, surface->size.w, surface->size.h }; view->surface_pending.visible = (struct wlc_geometry){ wlc_point_zero, surface->size }; } const bool resizing = (view->pending.state & WLC_BIT_RESIZING || view->commit.state & WLC_BIT_RESIZING); if (!resizing && !wlc_geometry_equals(&view->surface_pending.visible, &view->surface_commit.visible)) { struct wlc_geometry g = (struct wlc_geometry){ view->pending.geometry.origin, view->surface_pending.visible.size }; wlc_view_request_geometry(view, &g); } view->surface_commit = view->surface_pending; } void wlc_view_get_bounds(struct wlc_view *view, struct wlc_geometry *out_bounds, struct wlc_geometry *out_visible) { assert(view && out_bounds && out_bounds != out_visible); memcpy(out_bounds, &view->commit.geometry, sizeof(struct wlc_geometry)); struct wlc_surface *surface; if (!(surface = convert_from_wlc_resource(view->surface, "surface"))) return; if (view->xdg_surface && !wlc_size_equals(&view->surface_commit.visible.size, &wlc_size_zero)) { // xdg-surface client that draws drop shadows or other stuff. struct wlc_geometry v = view->surface_commit.visible; v.origin.x = chck_clamp32(v.origin.x, 0, surface->size.w); v.origin.y = chck_clamp32(v.origin.y, 0, surface->size.h); v.size.w = chck_clampu32(surface->size.w - v.size.w, 0, surface->size.w); v.size.h = chck_clampu32(surface->size.h - v.size.h, 0, surface->size.h); assert(surface->size.w > 0 && surface->size.h > 0); const float wa = (float)out_bounds->size.w / surface->size.w, ha = (float)out_bounds->size.h / surface->size.h; out_bounds->origin.x -= v.origin.x * wa; out_bounds->origin.y -= v.origin.y * ha; out_bounds->size.w += v.size.w * wa; out_bounds->size.h += v.size.h * ha; } // Make sure bounds is never 0x0 w/h wlc_size_max(&out_bounds->size, &(struct wlc_size){ 1, 1 }, &out_bounds->size); if (!out_visible) return; // Actual visible area of the view // The idea is to draw black borders to the bounds area, while centering the visible area. if ((is_x11_view(view) || view->shell_surface) && !wlc_size_equals(&surface->size, &out_bounds->size)) { out_visible->size = surface->size; // Scale visible area retaining aspect assert(surface->size.w > 0 && surface->size.h > 0); const float ba = (float)out_bounds->size.w / (float)out_bounds->size.h; const float sa = (float)surface->size.w / (float)surface->size.h; if (ba < sa) { out_visible->size.w *= (float)out_bounds->size.w / surface->size.w; out_visible->size.h *= (float)out_bounds->size.w / surface->size.w; } else { out_visible->size.w *= (float)out_bounds->size.h / surface->size.h; out_visible->size.h *= (float)out_bounds->size.h / surface->size.h; } // Center visible area out_visible->origin.x = out_bounds->origin.x + out_bounds->size.w * 0.5 - out_visible->size.w * 0.5; out_visible->origin.y = out_bounds->origin.y + out_bounds->size.h * 0.5 - out_visible->size.h * 0.5; // Make sure visible is never 0x0 w/h out_visible->size.w = chck_maxu32(out_visible->size.w, 1); out_visible->size.h = chck_maxu32(out_visible->size.h, 1); } else { // For non wl_shell or x11 surfaces, just memcpy memcpy(out_visible, out_bounds, sizeof(struct wlc_geometry)); } }