aboutsummaryrefslogtreecommitdiff
path: root/mu_x11.c
diff options
context:
space:
mode:
Diffstat (limited to 'mu_x11.c')
-rw-r--r--mu_x11.c177
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);
- }
-}