static void resolution(struct ctx *context, const struct wlc_size *mode, const struct wlc_size *resolution) { assert(context && resolution); if (!wlc_size_equals(&context->resolution, resolution)) { for (GLuint i = 0; i < PROGRAM_LAST; ++i) { set_program(context, i); GL_CALL(glUniform2fv(context->program->uniforms[UNIFORM_RESOLUTION], 1, (GLfloat[]){ resolution->w, resolution->h })); } GL_CALL(glBindTexture(GL_TEXTURE_2D, context->textures[TEXTURE_FAKEFB])); GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, resolution->w, resolution->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL)); clear_fakefb(context); context->resolution = *resolution; } if (!wlc_size_equals(&context->mode, mode)) { GL_CALL(glViewport(0, 0, mode->w, mode->h)); context->mode = *mode; } }
static void texture_paint(struct ctx *context, GLuint *textures, GLuint nmemb, const struct wlc_geometry *geometry, struct paint *settings) { const GLfloat vertices[8] = { geometry->origin.x + geometry->size.w, geometry->origin.y, geometry->origin.x, geometry->origin.y, geometry->origin.x + geometry->size.w, geometry->origin.y + geometry->size.h, geometry->origin.x, geometry->origin.y + geometry->size.h, }; const GLfloat coords[8] = { 1, 0, 0, 0, 1, 1, 0, 1 }; set_program(context, settings->program); if (settings->dim > 0.0f) { GL_CALL(glUniform1fv(context->program->uniforms[UNIFORM_DIM], 1, &settings->dim)); } for (GLuint i = 0; i < nmemb; ++i) { if (!textures[i]) break; GL_CALL(glActiveTexture(GL_TEXTURE0 + i)); GL_CALL(glBindTexture(GL_TEXTURE_2D, textures[i])); if (settings->filter || !wlc_size_equals(&context->resolution, &context->mode)) { GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); } else { GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); } } GL_CALL(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices)); GL_CALL(glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, coords)); GL_CALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); }
static void surface_paint_internal(struct ctx *context, struct wlc_surface *surface, const struct wlc_geometry *geometry, struct paint *settings) { assert(context && surface && geometry && settings); const struct wlc_geometry *g = geometry; if (!wlc_size_equals(&surface->size, &geometry->size)) { if (wlc_geometry_equals(&settings->visible, geometry)) { settings->filter = true; } else { // black borders are requested struct paint settings2 = *settings; settings2.program = (settings2.program == PROGRAM_RGBA || settings2.program == PROGRAM_RGB ? settings2.program : PROGRAM_RGB); texture_paint(context, &context->textures[TEXTURE_BLACK], 1, geometry, &settings2); g = &settings->visible; } } texture_paint(context, surface->textures, 3, g, settings); }
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)); } }