--- /dev/null
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xft/Xft.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <locale.h>
+
+typedef struct XConf {
+ int fd, screen, width, height;
+ Window root;
+ Display* display;
+ Visual* visual;
+ Colormap colormap;
+ unsigned depth;
+ Window self;
+ XftDraw* xft;
+ Pixmap pixmap;
+ XIC xic;
+ XIM xim;
+ GC gc;
+ void (*eventfns[LASTEvent])(struct XConf*, XEvent*);
+} XConf;
+
+static int x11_init(XConf* x) {
+ signal(SIGPIPE, SIG_IGN); // Ignore the SIGPIPE signal
+ setlocale(LC_CTYPE, "");
+ XSetLocaleModifiers("");
+ /* open the X display and get basic attributes */
+ if (!(x->display = XOpenDisplay(0)))
+ return -1;
+ x->root = DefaultRootWindow(x->display);
+ XWindowAttributes wa;
+ XGetWindowAttributes(x->display, x->root, &wa);
+ x->visual = wa.visual;
+ x->colormap = wa.colormap;
+ x->screen = DefaultScreen(x->display);
+ x->depth = DefaultDepth(x->display, x->screen);
+ return 0;
+}
+
+static void x11_mkwin(XConf* x, int width, int height, int evmask) {
+ /* create the main window */
+ x->width = width, x->height = height;
+ x->self = XCreateSimpleWindow(
+ x->display, x->root, 0, 0, x->width, x->height, 0, x->depth, -1);
+ /* register interest in the delete window message */
+ Atom wmDeleteMessage = XInternAtom(x->display, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(x->display, x->self, &wmDeleteMessage, 1);
+ /* setup window attributes and events */
+ XSetWindowAttributes swa;
+ swa.backing_store = WhenMapped;
+ swa.bit_gravity = NorthWestGravity;
+ XChangeWindowAttributes(x->display, x->self, CWBackingStore|CWBitGravity, &swa);
+ XSelectInput(x->display, x->self, evmask);
+}
+
+static void x11_init_gc(XConf* x) {
+ /* set input methods */
+ if ((x->xim = XOpenIM(x->display, 0, 0, 0)))
+ x->xic = XCreateIC(x->xim, XNInputStyle, XIMPreeditNothing|XIMStatusNothing, XNClientWindow, x->self, XNFocusWindow, x->self, NULL);
+ /* initialize pixmap and drawing context */
+ x->pixmap = XCreatePixmap(x->display, x->self, x->width, x->height, x->depth);
+ x->xft = XftDrawCreate(x->display, x->pixmap, x->visual, x->colormap);
+ /* initialize the graphics context */
+ XGCValues gcv;
+ gcv.foreground = WhitePixel(x->display, x->screen);
+ gcv.graphics_exposures = False;
+ x->gc = XCreateGC(x->display, x->self, GCForeground|GCGraphicsExposures, &gcv);
+}
+
+static void x11_show(XConf* x) {
+ /* simulate an initial resize and map the window */
+ XConfigureEvent ce;
+ ce.type = ConfigureNotify;
+ ce.width = x->width;
+ ce.height = x->height;
+ XSendEvent(x->display, x->self, False, StructureNotifyMask, (XEvent *)&ce);
+ XMapWindow(x->display, x->self);
+}
+
+static void x11_event_loop(XConf* x) {
+ for (XEvent e;;) {
+ XNextEvent(x->display, &e);
+ if (x->eventfns[e.type])
+ x->eventfns[e.type](x, &e);
+ for (int status; waitpid(-1, &status, WNOHANG) > 0;);
+ }
+}
--- /dev/null
+#include <stdc.h>
+#include <utf.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xft/Xft.h>
+#include <unistd.h>
+
+int main(int argc, char** argv) {
+ return 0;
+}
+
+#if 0
+struct {
+ Display* display;
+ Window root;
+ Window self;
+ int error;
+} X;
+
+size_t WinCount;
+Window* Windows;
+char** WinFiles;
+
+static void get_windows(Window** wins, char*** files, size_t* nwins);
+static int error_handler(Display* disp, XErrorEvent* ev);
+static void* prop_get(Window win, char* propname, Atom type, unsigned long* nitems);
+static void prop_set(Window win, char* propname, Atom type, int format, void* items, unsigned long nitems);
+static void edit(char* path);
+static Window win_byfile(char* path);
+static void focus_window(Window w, char* addr);
+static void get_abspath(char* path, char** abspath, char** addr);
+
+/* Main Routine
+ ******************************************************************************/
+int main(int argc, char** argv) {
+ if (!(X.display = XOpenDisplay(0)))
+ die("could not open display");
+ X.root = DefaultRootWindow(X.display);
+ X.self = XCreateSimpleWindow(X.display, X.root, 0, 0, 1, 1, 0, 0, 0);
+ XSetErrorHandler(error_handler);
+ get_windows(&Windows, &WinFiles, &WinCount);
+
+ for (int i = 1; i < argc; i++) {
+ bool last = (i == argc-1);
+ char *orig = argv[i], *path = NULL, *addr = NULL;
+ get_abspath(orig, &path, &addr);
+
+ Window win = win_byfile(path);
+ if (!win) {
+ fprintf(stderr, "edit(%s)\n", argv[i]);
+ edit(argv[i]);
+ } else if (last) {
+ fprintf(stderr, "focus(%#x,%s)\n", (int)win, addr);
+ focus_window(win, addr);
+ }
+ free(path);
+ }
+
+ XFlush(X.display);
+ return 0;
+}
+
+static void get_windows(Window** wins, char*** files, size_t* nwins) {
+ XGrabServer(X.display);
+ unsigned long nwindows = 0, nactive = 0, nstrings = 0;
+ Window *windows = prop_get(X.root, "TIDE_WINDOWS", XA_WINDOW, &nwindows);
+ Window *active = calloc(nwindows, sizeof(Window));
+ char **wfiles = calloc(nwindows, sizeof(char*));
+ Atom xa_comm = XInternAtom(X.display, "TIDE_COMM", False);
+ for (int i = 0; i < nwindows; i++) {
+ X.error = 0;
+ int nprops;
+ Atom* props = XListProperties(X.display, windows[i], &nprops);
+ if (!props || X.error) continue;
+ for (int x = 0; x < nprops; x++) {
+ if (props[x] == xa_comm) {
+ active[nactive] = windows[i];
+ wfiles[nactive] = prop_get(windows[i], "TIDE_FILE", XA_STRING, &nstrings);
+ nactive++;
+ break;
+ }
+ }
+ XFree(props);
+ }
+ prop_set(X.root, "TIDE_WINDOWS", XA_WINDOW, 32, active, nactive);
+ XSync(X.display, False);
+ XUngrabServer(X.display);
+ XFree(windows);
+ *wins = active, *files = wfiles, *nwins = nactive;
+}
+
+static int error_handler(Display* disp, XErrorEvent* ev) {
+ X.error = ev->error_code;
+ return 0;
+}
+
+static void* prop_get(Window win, char* propname, Atom type, unsigned long* nitems) {
+ Atom rtype, prop = XInternAtom(X.display, propname, False);
+ unsigned long rformat = 0, nleft = 0;
+ unsigned char* data = NULL;
+ XGetWindowProperty(X.display, win, prop, 0, -1, False, type, &rtype,
+ (int*)&rformat, nitems, &nleft, &data);
+ if (rtype != type)
+ data = NULL, *nitems = 0;
+ return data;
+}
+
+static void prop_set(Window win, char* propname, Atom type, int format, void* items, unsigned long nitems) {
+ Atom prop = XInternAtom(X.display, propname, False);
+ XChangeProperty(X.display, win, prop, type, format, PropModeReplace, items, (int)nitems);
+}
+
+static void edit(char* path) {
+ if (fork() == 0)
+ exit(execvp("tide", (char*[]){ "tide", path, NULL }));
+}
+
+static Window win_byfile(char* path) {
+ for (int i = 0; i < WinCount; i++)
+ if (WinFiles[i] && !strcmp(path, WinFiles[i]))
+ return Windows[i];
+ return (Window)0;
+}
+
+static void focus_window(Window w, char* addr) {
+ XEvent ev = {0};
+ ev.xclient.type = ClientMessage;
+ ev.xclient.send_event = True;
+ ev.xclient.message_type = XInternAtom(X.display, "_NET_ACTIVE_WINDOW", False);
+ ev.xclient.window = w;
+ ev.xclient.format = 32;
+ long mask = SubstructureRedirectMask | SubstructureNotifyMask;
+ XSendEvent(X.display, X.root, False, mask, &ev);
+ XMapRaised(X.display, w);
+ if (addr && *addr)
+ prop_set(w, "TIDE_COMM", XA_STRING, 8, addr, strlen(addr));
+ XFlush(X.display);
+}
+
+void get_abspath(char* path, char** abspath, char** addr) {
+ path = stringdup(path);
+ char* faddr = strrchr(path, ':');
+ if (faddr) *(faddr++) = '\0';
+ char* rpath = realpath(path, NULL);
+ if (!rpath) rpath = path;
+ *abspath = rpath, *addr = faddr;
+}
+#endif
--- /dev/null
+#include <x11.h>
+#include <unistd.h>
+
+typedef struct TWindow {
+ struct TWindow* next;
+ Window win;
+} TWindow;
+
+Atom XA_REGISTRAR, XA_ADD, XA_DEL, XA_OPEN;
+TWindow* Windows = NULL;
+
+static void win_add(Window id) {
+ TWindow* win = calloc(1, sizeof(TWindow));
+ win->win = id;
+ win->next = Windows;
+ Windows = win;
+}
+
+static void win_del(Window id) {
+ if (!Windows) return;
+ if (Windows->win == id) {
+ TWindow* deadite = Windows;
+ Windows = deadite->next;
+ free(deadite);
+ } else {
+ TWindow* w = Windows;
+ for (;w && w->next && (w->next->win != id); w = w->next);
+ if (w && w->next) {
+ TWindow* deadite = w->next;
+ w->next = deadite->next;
+ free(deadite);
+ }
+ }
+}
+
+void selclear(XConf* x, XEvent* e) {
+ exit(0);
+}
+
+void clientmsg(XConf* x, XEvent* e) {
+ if (XA_REGISTRAR != e->xclient.message_type)
+ return;
+ if (XA_ADD == e->xclient.data.l[0])
+ win_add(e->xclient.window);
+ else if (XA_DEL == e->xclient.data.l[0])
+ win_del(e->xclient.window);
+ else if (XA_OPEN == e->xclient.data.l[0])
+ puts("open");
+}
+
+int main(int argc, char** argv) {
+ XConf x;
+ x11_init(&x);
+ x11_mkwin(&x, 1, 1, PropertyChangeMask);
+ XA_REGISTRAR = XInternAtom(x.display, "TIDE_REGISTRAR", 0);
+ XA_ADD = XInternAtom(x.display, "ADD", 0);
+ XA_DEL = XInternAtom(x.display, "DEL", 0);
+ XA_OPEN = XInternAtom(x.display, "OPEN", 0);
+ x.eventfns[SelectionClear] = selclear;
+ x.eventfns[ClientMessage] = clientmsg;
+ if (None == XGetSelectionOwner(x.display, XA_REGISTRAR)) {
+ XSetSelectionOwner(x.display, XA_REGISTRAR, x.self, CurrentTime);
+ if (x.self == XGetSelectionOwner(x.display, XA_REGISTRAR)) {
+ x11_event_loop(&x);
+ }
+ }
+ return 1;
+}