diff options
Diffstat (limited to 'mu_x11.c')
| -rw-r--r-- | mu_x11.c | 177 |
1 files changed, 0 insertions, 177 deletions
diff --git a/mu_x11.c b/mu_x11.c deleted file mode 100644 index e672496..0000000 --- a/mu_x11.c +++ /dev/null @@ -1,177 +0,0 @@ -/* mu_x11.c -- an Xlib/Xft backend for microui. - * - * microui is renderer-agnostic: it emits a command list of clipped - * rectangles, text runs and icons, and asks the host two questions about - * font metrics. This answers those and draws the commands into an - * off-screen pixmap, then blits it, so a frame never appears half-drawn. - * - * SPDX-License-Identifier: MIT (matching the vendored microui) - */ -#define _POSIX_C_SOURCE 200809L -#include <X11/Xlib.h> -#include <X11/Xft/Xft.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "vendor/microui.h" -#include "mu_x11.h" - -static Display *dpy; -static Window win; -static Visual *vis; -static Colormap cmap; -static XftFont *fnt; -static XftDraw *xd; -static Pixmap buf; -static GC gc; -static int bw, bh; - -int mux_text_width(mu_Font font, const char *s, int len) -{ - (void)font; - XGlyphInfo gi; - if (len < 0) len = strlen(s); - XftTextExtentsUtf8(dpy, fnt, (const FcChar8 *)s, len, &gi); - return gi.xOff; -} - -int mux_text_height(mu_Font font) -{ - (void)font; - return fnt->ascent + fnt->descent; -} - -void mux_init(Display *d, Window w, const char *fontname) -{ - dpy = d; win = w; - int scr = DefaultScreen(dpy); - vis = DefaultVisual(dpy, scr); - cmap = DefaultColormap(dpy, scr); - fnt = XftFontOpenName(dpy, scr, fontname); - gc = XCreateGC(dpy, win, 0, NULL); - buf = 0; xd = NULL; bw = bh = 0; -} - -static void ensure_buffer(int w, int h) -{ - if (buf && w == bw && h == bh) return; - if (xd) { XftDrawDestroy(xd); xd = NULL; } - if (buf) { XFreePixmap(dpy, buf); buf = 0; } - buf = XCreatePixmap(dpy, win, w, h, DefaultDepth(dpy, DefaultScreen(dpy))); - xd = XftDrawCreate(dpy, buf, vis, cmap); - bw = w; bh = h; -} - -static void xft_of(mu_Color c, XftColor *out) -{ - XRenderColor rc = { c.r * 257, c.g * 257, c.b * 257, c.a * 257 }; - XftColorAllocValue(dpy, vis, cmap, &rc, out); -} - -static const char *icon_glyph(int id) -{ - switch (id) { - case MU_ICON_CLOSE: return "x"; - case MU_ICON_CHECK: return "*"; - case MU_ICON_COLLAPSED: return ">"; - case MU_ICON_EXPANDED: return "v"; - default: return "?"; - } -} - -/* CLAMP BEFORE CONVERTING. XRectangle's w/h are unsigned SHORT, and microui - resets its scissor by emitting an "unclipped" rect of 0x1000000 -- which - truncates to 0 in 16 bits, turning "clip nothing" into "clip everything". - The symptom is that a panel draws its first screenful and the rest - silently vanishes, which reads as a layout or buffer bug and is neither. */ -static void set_clip(mu_Rect r) -{ - int x = r.x, y = r.y, w = r.w, h = r.h; - if (x < 0) { w += x; x = 0; } - if (y < 0) { h += y; y = 0; } - if (w > bw - x) w = bw - x; - if (h > bh - y) h = bh - y; - if (w <= 0 || h <= 0) { w = 0; h = 0; } - XRectangle xr = { (short)x, (short)y, (unsigned short)w, (unsigned short)h }; - Region reg = XCreateRegion(); - XUnionRectWithRegion(&xr, reg, reg); - XftDrawSetClip(xd, reg); - XDestroyRegion(reg); -} - -void mux_present(mu_Context *ctx, int w, int h, mu_Color bg) -{ - ensure_buffer(w, h); - XftDrawSetClip(xd, NULL); - - XftColor col; - xft_of(bg, &col); - XftDrawRect(xd, &col, 0, 0, w, h); - XftColorFree(dpy, vis, cmap, &col); - - mu_Command *cmd = NULL; - while (mu_next_command(ctx, &cmd)) { - switch (cmd->type) { - case MU_COMMAND_RECT: - xft_of(cmd->rect.color, &col); - XftDrawRect(xd, &col, cmd->rect.rect.x, cmd->rect.rect.y, - cmd->rect.rect.w, cmd->rect.rect.h); - XftColorFree(dpy, vis, cmap, &col); - break; - case MU_COMMAND_TEXT: - xft_of(cmd->text.color, &col); - XftDrawStringUtf8(xd, &col, fnt, cmd->text.pos.x, - cmd->text.pos.y + fnt->ascent, - (const FcChar8 *)cmd->text.str, - strlen(cmd->text.str)); - XftColorFree(dpy, vis, cmap, &col); - break; - case MU_COMMAND_ICON: { - const char *g = icon_glyph(cmd->icon.id); - int tw = mux_text_width(NULL, g, 1); - xft_of(cmd->icon.color, &col); - XftDrawStringUtf8(xd, &col, fnt, - cmd->icon.rect.x + (cmd->icon.rect.w - tw) / 2, - cmd->icon.rect.y + fnt->ascent - + (cmd->icon.rect.h - mux_text_height(NULL)) / 2, - (const FcChar8 *)g, 1); - XftColorFree(dpy, vis, cmap, &col); - break; - } - case MU_COMMAND_CLIP: - set_clip(cmd->clip.rect); - break; - } - } - XftDrawSetClip(xd, NULL); - XCopyArea(dpy, buf, win, gc, 0, 0, w, h, 0, 0); - XFlush(dpy); - - /* MUX_DUMP=path writes the frame out as a PPM and exits. Reading back - the off-screen PIXMAP rather than the window is what makes this - reliable: a window's contents are not retained when it is obscured or - on an unfocused tag, so screenshotting one can return black even - though the program is drawing perfectly. A pixmap is always there. */ - { - const char *path = getenv("MUX_DUMP"); - if (!path) return; - XImage *im = XGetImage(dpy, buf, 0, 0, w, h, AllPlanes, ZPixmap); - if (!im) { fprintf(stderr, "MUX_DUMP: XGetImage failed\n"); exit(1); } - FILE *f = fopen(path, "wb"); - if (!f) { fprintf(stderr, "MUX_DUMP: cannot write %s\n", path); exit(1); } - fprintf(f, "P6\n%d %d\n255\n", w, h); - for (int yy = 0; yy < h; yy++) - for (int xx = 0; xx < w; xx++) { - unsigned long px = XGetPixel(im, xx, yy); - unsigned char rgb[3] = { - (unsigned char)((px >> 16) & 0xff), - (unsigned char)((px >> 8) & 0xff), - (unsigned char)(px & 0xff) }; - fwrite(rgb, 1, 3, f); - } - fclose(f); - XDestroyImage(im); - fprintf(stderr, "MUX_DUMP: wrote %s (%dx%d)\n", path, w, h); - exit(0); - } -} |
