Coffee Space


Listen:

Smol Libs: Xgui

Preview Image

What Is?

Smol Libs is:

A series of small C libraries contained within source code of 80x25 characters.

Currently this restriction of 80x25 characters in the source is somewhat loosely followed.

Whilst these projects are not fully baked yet, I think it is about time to share some progress on these libraries.

Xgui

Xgui is a small lightweight wrapper around Xlib that creates windows. Currently the supported features are:

And that’s pretty much it. It was created after I had some real trouble getting existing lightweight GUI libraries to compile, when I really just wanted something incredibly basic.

To do this, we use the following source:

0001 #pragma once          /* xgui - A light wrapper around Xlib that offers */
0002 #include <X11/Xlib.h> /*        text, buttons and images.               */
0003 #include <string.h>   /* Written by B[], 2022                           */
0004 enum type{ TXT, BTN, IMG }; char* xf = "-*-helvetica-*-r-*-*-16-*-*-*-*-*-*-*";
0005 typedef struct{ int i, a, b; enum type t; float x, y, w, h; char* v; Pixmap d; } xobj;
0006 typedef struct{ Display* d; int s, n; Window w; GC g; long b, f; xobj* o[65536]; } xgui;
0007 void xgui_init(xgui* x, int w, int h, long b, long f){ x->b = b; x->f = f;
0008   x->d = XOpenDisplay(NULL); x->s = DefaultScreen(x->d); x->n = 0; x->g = DefaultGC(x->d, x->s);
0009   x->w = XCreateSimpleWindow(x->d, RootWindow(x->d, x->s), 0, 0, w, h, 1, x->f, x->b);
0010   XSelectInput(x->d, x->w, ExposureMask|KeyPressMask|ButtonPressMask); XMapWindow(x->d, x->w); }
0011 void xgui_add(xgui* x, xobj* o){ if(x->n + 1 < 65536) x->o[x->n++] = o; }
0012 void xgui_update(xgui* x, void (*c)(XEvent, xobj*, char, float, float, int, int)){
0013   XEvent e; XNextEvent(x->d, &e); XWindowAttributes a; XGetWindowAttributes(x->d, x->w, &a);
0014   float w = a.width, h = a.height; int l, eks, ekc, i = -1; xobj o;
0015   XFontStruct* f = XLoadQueryFont(x->d, xf); XSetFont(x->d, x->g, f->fid);
0016   while(++i < x->n){ o = *(x->o[i]); eks = e.xkey.state; ekc = e.xkey.keycode; if(o.t != IMG){
0017     XSetForeground(x->d, x->g, o.t == BTN ? x->f : x->b); eks &= ShiftMask; l = strlen(o.v);
0018     XFillRectangle(x->d, x->w, x->g, w * (o.x - o.w/2), h * (o.y - o.h/2), w*o.w, h*o.h);
0019     XSetForeground(x->d, x->g, o.t == BTN ? x->b : x->f); XDrawString(x->d,
0020       x->w, x->g, (w * o.x) - (XTextWidth(f, o.v, l)/2), h*o.y, o.v, l);
0021   }else if(e.type == Expose) XCopyPlane(x->d, o.d, x->w, x->g, 0, 0, o.a, o.b, o.x*w, o.y*h, 1);
0022   (*c)(e, x->o[i], XKeycodeToKeysym(x->d, ekc, eks ? 1 : 0), e.xbutton.x/w, e.xbutton.y/h, w, h);
0023 }} void xgui_close(xgui* x){ XDestroyWindow(x->d, x->w); XCloseDisplay(x->d); }
0024 int xgui_image(xgui* x, char* f, Pixmap* p, int* a, int* b){ int i, j; return
0025   XReadBitmapFile(x->d, x->w, f, a, b, p, &i, &j); } char* XGUI = "1.1.0";

Generally you would setup an xgui object with xgui_init(), add elements using xgui_add() and process updates using xgui_update(). You would need to look at the example programs for more detail, or read the source (it’s very small by design).

It still needs some work, but as you can see, it’s certainly compact! Note the version string XGUI is currently 1.1.0 as of the time of writing.

Examples

The following are examples written in Xgui to demonstrate some of the cape abilities it has.

Calc

In this example we have a simple integer calculator. Values can be entered by either typing or clicking on the buttons.

Basic calculator example

As you resize the window, it resizes the elements automatically and client side code attempts to find a better font size depending on the window size. The corner background images remain in the corner, with the penguin disappearing for very small windows.

xgui_calc weighs in at 19kB (not including image assets).

Scrn

In this example I attempted to write a basic screensaver based on Langton’s Ant. Pressing any key quits the screensaver.

Basic screensaver example

Again as you resize the window, it resizes the elements. It makes use of the libraries ability to change the type of an element during runtime, in this case switching between buttons and text.

xgui_calc weighs in at 19kB.

Future

There isn’t much room to extend this library further, but this is also a good thing. It’s pretty much complete minus some formatting, bug fixes and some tweaks here and there.

For example programs, I really want to build an ultra-lightweight file manager. It turns out to be quite a large undertaking due to file browsers being so complicated, but the one feature I desperately want is history and for tabs to come back after closing the program. I also want to be able to display large numbers of files and not have to wait several minutes for Gnome to figure out what thumbnails it should have, whilst throwing icons all over the place.

There are of course other Smol Lib projects already existing that will be introduced in good time.