--- /dev/null
+#include <stdc.h>
+#include <utf.h>
+#include <edit.h>
+#include <win.h>
+#include <x11.h>
+#include <draw.h>
+#include <locale.h>
+#include <sys/wait.h>
+
+#define INCLUDE_DEFS
+#include "config.h"
+
+static struct XConf X;
+static View Tags;
+static int Divider;
+static int FontSel;
+
+/* X11 Window Code
+ ******************************************************************************/
+static void font_load(char* name) {
+ XftFont* font = x11_font_load(&X, name);
+ X.font = (font ? font : X.font); // Update if we found a new font
+}
+
+size_t glyph_width(View* view, int c) {
+ (void)view;
+ FcChar32 rune = (FcChar32)c;
+ XGlyphInfo extents;
+ XftTextExtents32(X.display, X.font, &rune, 1, &extents);
+ if (c == '\t')
+ return (TabWidth * extents.xOff);
+ else
+ return extents.xOff;
+}
+
+Window child_window = 0;
+
+static void xmaprequest(XConf* x, XEvent* e) {
+ (void)x;
+ XMapWindow(e->xmaprequest.display, e->xmaprequest.window);
+ child_window = e->xmaprequest.window;
+}
+
+static void xconfigure(XConf* x, XEvent* e) {
+ if (e->xconfigure.width != x->width || e->xconfigure.height != x->height) {
+ x->width = e->xconfigure.width;
+ x->height = e->xconfigure.height;
+ x->pixmap = XCreatePixmap(x->display, x->self, x->width, x->height, x->depth);
+ x->xft = XftDrawCreate(x->display, x->pixmap, x->visual, x->colormap);
+ }
+
+ if (child_window) {
+ // Get container window attributes
+ XWindowAttributes attrs;
+ XGetWindowAttributes(x->display, x->self, &attrs);
+
+ // Move and resize child
+ XMoveResizeWindow(x->display,
+ child_window,
+ 0, Divider+2, attrs.width, attrs.height - Divider - 2);
+ }
+}
+
+static void xdestroy(XConf* x, XEvent* e) {
+ (void)x, (void)e;
+}
+
+static void xclientmsg(XConf* x, XEvent* e) {
+ if ((Atom)(e->xclient.data.l[0]) == XInternAtom(x->display, "WM_DELETE_WINDOW", False))
+ win_quit();
+}
+
+static void xupdate(Job* job) {
+ int nqueued, nevents;
+ do {
+ nqueued = XEventsQueued(X.display, QueuedAfterFlush);
+ XGetMotionEvents(X.display, X.self, CurrentTime, CurrentTime, &nevents);
+ for (XEvent e; XPending(X.display);) {
+ XNextEvent(X.display, &e);
+ if (!XFilterEvent(&e, None) && X.eventfns[e.type])
+ (X.eventfns[e.type])(&X, &e);
+ for (int status; waitpid(-1, &status, WNOHANG) > 0;);
+ }
+ if (nqueued || !job) {
+ /* determine the size of the regions */
+ size_t maxtagrows = ((X.height/4) / X.font->height);
+ size_t tagrows = view_limitrows(&Tags, maxtagrows);
+ /* draw the regions to the window */
+ drawcsr csr = { .w = X.width, .h = X.height };
+ csr.x += ScrollWidth + 1;
+ draw_statbox(&X, Tags.buffer.status);
+ draw_view(&X, &Tags, X.font, tagrows, &csr, TagsBg, TagsFg, TagsSel, false);
+ Divider = draw_hrule(&X, &csr);
+ draw_rect(&X, EditBg, 0, Divider+2, csr.w, csr.h);
+ XCopyArea(X.display, X.pixmap, X.self, X.gc, 0, 0, X.width, X.height, 0, 0);
+ XFlush(X.display);
+ }
+ } while ((nqueued = XEventsQueued(X.display, QueuedAfterFlush)) > 0);
+}
+
+void win_init(KeyBinding* bindings) {
+ (void)bindings;
+ signal(SIGPIPE, SIG_IGN); // Ignore the SIGPIPE signal
+ setlocale(LC_CTYPE, "");
+ XSetLocaleModifiers("");
+
+ /* open the X display and get basic attributes */
+ x11_init(&X);
+ font_load(Fonts[FontSel = 0]);
+ if (!X.font) {
+ perror("unable to load base font");
+ exit(EXIT_FAILURE);
+ }
+ x11_mkwin(&X, 640, 480, 0
+// | FocusChangeMask
+// | KeyPressMask
+// | ButtonPressMask
+// | ButtonReleaseMask
+// | ButtonMotionMask
+// | PropertyChangeMask
+// | VisibilityChangeMask
+ | SubstructureRedirectMask
+ | SubstructureNotifyMask
+ | StructureNotifyMask
+ | ExposureMask
+ );
+
+ x11_init_gc(&X);
+ x11_sel_init(&X);
+ x11_show(&X);
+
+ /* register event handlers */
+// X.eventfns[KeyPress] = xkeypress;
+// X.eventfns[ButtonPress] = xbtnpress;
+// X.eventfns[ButtonRelease] = xbtnrelease;
+// X.eventfns[MotionNotify] = xbtnmotion;
+
+ X.eventfns[MapRequest] = xmaprequest;
+ X.eventfns[ConfigureNotify] = xconfigure;
+ X.eventfns[DestroyNotify] = xdestroy;
+ X.eventfns[ClientMessage] = xclientmsg;
+}
+
+void win_loop(void) {
+ job_spawn(ConnectionNumber(X.display), xupdate, 0, 0);
+ XSync(X.display, False);
+ while (X.running) {
+ if (job_poll(Timeout))
+ xupdate(NULL);
+ }
+}
+
+void win_quit(void) {
+ X.eventfns[SelectionClear] = x11_sel_quit;
+ XUnmapWindow(X.display, X.self);
+ if (!x11_sel_ready(&X)) {
+ X.running = False;
+ } else {
+ if (fork()) exit(0); /* fork into background if we still have selection */
+ }
+}
+
+/* Main Routine
+ ******************************************************************************/
+int main(void) {
+ /* create the window */
+ win_init(NULL);
+
+ /* Initialize the views */
+ view_init(&Tags, NULL);
+ view_putstr(&Tags, "Newcol Kill Putall Dump Exit");
+ view_resize(&Tags, 640, 1);
+ buf_logclear(&(Tags.buffer));
+
+ char window_id[64];
+ sprintf(window_id, "%lu", X.self);
+ setenv("TIDE_PARENT", window_id, 1);
+
+ if (fork() == 0) {
+ char* tidecmd[] = { "tide", 0 };
+ execvp(tidecmd[0], tidecmd);
+ fprintf(stderr, "error: can't execute child process!\n");
+ exit(1);
+ }
+
+ /* now create the window and start the event loop */
+ xupdate(NULL);
+ win_loop();
+ return 0;
+}