#define WRASTER_NO_XLIB /* Wayland-only file: no libX11 deps */ #include "WINGsP.h" #include #include #include typedef struct { W_Screen *scr; } RenderCtxWL; static void * render_wl_screen_init(W_Screen *scr) { RenderCtxWL *ctx = wmalloc(sizeof(*ctx)); ctx->scr = scr; return ctx; } static void render_wl_screen_fini(void *rctx) { wfree(rctx); } /* Resolve a WMDrawable to a pixman_image_t*. * Synthetic IDs: 0x10000000-0x1FFFFFFF = WM frame_buf windows, * 0x20000000-0x2FFFFFFF = WINGs view windows. * Both registered via W_RegisterBacking. */ extern void *W_GetViewBacking(unsigned long id); static inline pixman_image_t * resolve_drawable(WMDrawable d) { if ((unsigned long)d >= 0x10000000 && (unsigned long)d < 0x30000000) return (pixman_image_t *)W_GetViewBacking((unsigned long)d); return (pixman_image_t *)d; } static WMDrawable render_wl_pixmap_create(void *rctx, unsigned int width, unsigned int height, int depth) { (void)rctx; pixman_format_code_t fmt = (depth == 1) ? PIXMAN_a1 : PIXMAN_a8r8g8b8; pixman_image_t *img = pixman_image_create_bits(fmt, width, height, NULL, 0); return (WMDrawable)img; } static void render_wl_pixmap_free(void *rctx, WMDrawable pm) { (void)rctx; if (pm) pixman_image_unref((pixman_image_t *)pm); } extern W_View *W_GetViewForWindow(WNativeWindow id); extern void (*W_ViewCommitBackingFn)(unsigned long id); static void render_wl_pixmap_copy(void *rctx, WMDrawable src, WMDrawable dst, int sx, int sy, unsigned int w, unsigned int h, int dx, int dy) { (void)rctx; pixman_image_t *s = (pixman_image_t *)src; pixman_image_t *d = resolve_drawable(dst); if (!d) return; pixman_image_composite32(PIXMAN_OP_SRC, s, NULL, d, sx, sy, 0, 0, dx, dy, w, h); /* If dst is a view backing (DOUBLE_BUFFER copy-to-window), composite * up through the parent chain so the change becomes visible. */ if ((unsigned long)dst >= 0x10000000 && (unsigned long)dst < 0x30000000) { W_View *view = W_GetViewForWindow((WNativeWindow)(unsigned long)dst); if (view && view->flags.alreadyDead) return; while (view && view->parent && !view->flags.alreadyDead) { pixman_image_t *vs = (pixman_image_t *)W_GetViewBacking(view->window); pixman_image_t *pd = (pixman_image_t *)W_GetViewBacking(view->parent->window); if (vs && pd) { pixman_image_composite32(PIXMAN_OP_OVER, vs, NULL, pd, 0, 0, 0, 0, view->pos.x, view->pos.y, view->size.width, view->size.height); } view = view->parent; } /* Commit the toplevel surface */ if (view && !view->flags.alreadyDead && W_ViewCommitBackingFn) W_ViewCommitBackingFn((unsigned long)view->window); } } static inline pixman_color_t wm_color_to_pixman(WMColor *color) { pixman_color_t pc; pc.red = color->color.red; pc.green = color->color.green; pc.blue = color->color.blue; pc.alpha = color->alpha ? color->alpha : 0xFFFF; return pc; } static void render_wl_draw_line(void *rctx, WMDrawable d, WMColor *color, int x1, int y1, int x2, int y2) { (void)rctx; pixman_image_t *dst = resolve_drawable(d); if (!dst) return; pixman_color_t pc = wm_color_to_pixman(color); pixman_image_t *fill = pixman_image_create_solid_fill(&pc); /* Bresenham for arbitrary lines; fast paths for h/v */ int dx = abs(x2 - x1), dy = abs(y2 - y1); int sx = x1 < x2 ? 1 : -1; int sy = y1 < y2 ? 1 : -1; int err = dx - dy; while (1) { pixman_image_composite32(PIXMAN_OP_OVER, fill, NULL, dst, 0, 0, 0, 0, x1, y1, 1, 1); if (x1 == x2 && y1 == y2) break; int e2 = 2 * err; if (e2 > -dy) { err -= dy; x1 += sx; } if (e2 < dx) { err += dx; y1 += sy; } } pixman_image_unref(fill); } static void render_wl_draw_rect(void *rctx, WMDrawable d, WMColor *color, int x, int y, unsigned int w, unsigned int h) { (void)rctx; pixman_image_t *dst = resolve_drawable(d); if (!dst) return; pixman_color_t pc = wm_color_to_pixman(color); /* top */ pixman_image_fill_rectangles(PIXMAN_OP_OVER, dst, &pc, 1, &(pixman_rectangle16_t){x, y, w + 1, 1}); /* bottom */ pixman_image_fill_rectangles(PIXMAN_OP_OVER, dst, &pc, 1, &(pixman_rectangle16_t){x, y + h, w + 1, 1}); /* left */ pixman_image_fill_rectangles(PIXMAN_OP_OVER, dst, &pc, 1, &(pixman_rectangle16_t){x, y, 1, h + 1}); /* right */ pixman_image_fill_rectangles(PIXMAN_OP_OVER, dst, &pc, 1, &(pixman_rectangle16_t){x + w, y, 1, h + 1}); } static void render_wl_fill_rect(void *rctx, WMDrawable d, WMColor *color, int x, int y, unsigned int w, unsigned int h) { (void)rctx; pixman_image_t *dst = resolve_drawable(d); if (!dst) return; pixman_color_t pc = wm_color_to_pixman(color); pixman_image_fill_rectangles(PIXMAN_OP_OVER, dst, &pc, 1, &(pixman_rectangle16_t){x, y, w, h}); } static void render_wl_fill_stippled(void *rctx, WMDrawable d, WMColor *color, int x, int y, unsigned int w, unsigned int h) { (void)rctx; pixman_image_t *dst = resolve_drawable(d); if (!dst) return; pixman_color_t pc = wm_color_to_pixman(color); pixman_image_t *fill = pixman_image_create_solid_fill(&pc); /* Draw every other pixel in a checkerboard pattern */ for (unsigned int row = 0; row < h; row++) { for (unsigned int col = (row & 1); col < w; col += 2) { pixman_image_composite32(PIXMAN_OP_OVER, fill, NULL, dst, 0, 0, 0, 0, x + col, y + row, 1, 1); } } pixman_image_unref(fill); } static void render_wl_composite_pixmap(void *rctx, WMDrawable dst, W_Pixmap *src, int sx, int sy, unsigned int w, unsigned int h, int dx, int dy) { (void)rctx; pixman_image_t *d = resolve_drawable(dst); if (!d) return; pixman_image_t *s = (pixman_image_t *)(uintptr_t)src->pixmap; pixman_image_t *m = src->mask ? (pixman_image_t *)(uintptr_t)src->mask : NULL; pixman_image_composite32(PIXMAN_OP_OVER, s, m, d, sx, sy, sx, sy, dx, dy, w, h); } static void render_wl_fill_polygon(void *rctx, WMDrawable d, WMColor *color, void *points_v, int npoints) { WMShortPoint *points = points_v; (void)rctx; if (npoints < 3) return; pixman_image_t *dst = resolve_drawable(d); if (!dst) return; pixman_color_t pc = wm_color_to_pixman(color); /* Find bounding box */ int minY = points[0].y, maxY = points[0].y; for (int i = 1; i < npoints; i++) { if (points[i].y < minY) minY = points[i].y; if (points[i].y > maxY) maxY = points[i].y; } /* Scanline fill for convex polygon */ for (int y = minY; y <= maxY; y++) { int minX = 32767, maxX = -32768; for (int i = 0; i < npoints; i++) { int j = (i + 1) % npoints; int y0 = points[i].y, y1 = points[j].y; int x0 = points[i].x, x1 = points[j].x; if ((y0 <= y && y1 > y) || (y1 <= y && y0 > y)) { int x = x0 + (y - y0) * (x1 - x0) / (y1 - y0); if (x < minX) minX = x; if (x > maxX) maxX = x; } } if (minX <= maxX) { pixman_image_fill_rectangles(PIXMAN_OP_OVER, dst, &pc, 1, &(pixman_rectangle16_t){minX, y, maxX - minX + 1, 1}); } } } static void render_wl_fill_arc(void *rctx, WMDrawable d, WMColor *color, int x, int y, unsigned int w, unsigned int h, int angle1, int angle2) { (void)rctx; pixman_image_t *dst = resolve_drawable(d); if (!dst) return; pixman_color_t pc = wm_color_to_pixman(color); /* X11 angles are in 64ths of a degree */ double a1 = angle1 / (64.0 * 180.0) * 3.14159265358979; double a2 = (angle1 + angle2) / (64.0 * 180.0) * 3.14159265358979; double cx = x + w / 2.0, cy = y + h / 2.0; double rx = w / 2.0, ry = h / 2.0; /* Scanline fill the arc sector */ for (unsigned int row = 0; row < h; row++) { double py = (y + row) - cy; double half_w = rx * sqrt(1.0 - (py * py) / (ry * ry)); if (half_w < 0) continue; int x0 = (int)(cx - half_w); int x1 = (int)(cx + half_w); /* For partial arcs, clip to angle range */ if (angle2 < 360 * 64) { /* Simple: just fill the full ellipse row for now */ /* Full arc clipping would need per-pixel angle checks */ } if (x0 < x1) { pixman_image_fill_rectangles(PIXMAN_OP_OVER, dst, &pc, 1, &(pixman_rectangle16_t){x0, y + row, x1 - x0, 1}); } } } static WMNativePixmap render_wl_create_disabled_mask(void *rctx, WMNativePixmap src_mask, unsigned int width, unsigned int height) { (void)rctx; pixman_image_t *mask = pixman_image_create_bits(PIXMAN_a8, width, height, NULL, 0); pixman_image_t *src = src_mask ? (pixman_image_t *)(uintptr_t)src_mask : NULL; uint8_t *mdata = (uint8_t *)pixman_image_get_data(mask); int stride = pixman_image_get_stride(mask); uint8_t *sdata = src ? (uint8_t *)pixman_image_get_data(src) : NULL; int sstride = src ? pixman_image_get_stride(src) : 0; for (unsigned int y = 0; y < height; y++) { for (unsigned int x = 0; x < width; x++) { int stipple = ((x + y) & 1); int src_opaque = 1; if (sdata) src_opaque = sdata[y * sstride + x] > 0; mdata[y * stride + x] = (stipple && src_opaque) ? 0xFF : 0x00; } } return (WMNativePixmap)(uintptr_t)mask; } const W_RenderBackend W_RenderBackendWL = { .screen_init = render_wl_screen_init, .screen_fini = render_wl_screen_fini, .pixmap_create = render_wl_pixmap_create, .pixmap_free = render_wl_pixmap_free, .pixmap_copy = render_wl_pixmap_copy, .draw_line = render_wl_draw_line, .draw_rect = render_wl_draw_rect, .fill_rect = render_wl_fill_rect, .fill_stippled = render_wl_fill_stippled, .composite_pixmap = render_wl_composite_pixmap, .fill_polygon = render_wl_fill_polygon, .fill_arc = render_wl_fill_arc, .create_disabled_mask = render_wl_create_disabled_mask, };