]> git.mdlowis.com Git - projs/tide.git/commitdiff
added placeholders for edit and registrar commands.
authorMichael D. Lowis <mike.lowis@gentex.com>
Fri, 12 Oct 2018 15:04:03 +0000 (11:04 -0400)
committerMichael D. Lowis <mike.lowis@gentex.com>
Fri, 12 Oct 2018 15:04:03 +0000 (11:04 -0400)
.gitignore
Makefile
TODO.md
inc/x11.h [new file with mode: 0644]
src/edit.c [new file with mode: 0644]
src/registrar.c [new file with mode: 0644]

index 790cbd66cbbdb01f12a7e95cbba24d344109da5f..57638527a236efb3f990ccc9b802187fa923243e 100644 (file)
@@ -55,3 +55,4 @@ hl-cpp
 pty
 tctl
 flaws.txt
+edit
index f2a4d827fce59434863067d14ea837a50dfd3163..9f509733dc3b2187ae1d8a59d641ac6d3404d9eb 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,5 @@
 INCS = -Iinc/
-MAKEFLAGS = -j4
-BINS = tide
+BINS = tide registrar edit
 MAN1 = docs/tide.1
 
 LIBEDIT_OBJS =       \
@@ -51,6 +50,7 @@ libedit.a: $(LIBEDIT_OBJS)
        $(AR) $(ARFLAGS) $@ $^
 
 tide: src/tide.o libedit.a
+registrar: src/registrar.o
 tests/libedit: tests/libedit.o tests/lib/buf.o tests/lib/utf8.o tests/lib/win.o libedit.a
 
 # define implicit rule for building binaries
diff --git a/TODO.md b/TODO.md
index 23460792f61ab18b5f966b95771b4122603426f2..45dfd2fcd5cd82dad369a47aecb78705e638c11b 100644 (file)
--- a/TODO.md
+++ b/TODO.md
@@ -2,11 +2,11 @@
 
 ## STAGING
 
-* implement new version of tfetch (plumb)
 * implement tide registrar
-* implement tctl command
-* gap buffer does not handle UTF-8 currently
+* implement edit (tctl) command
+* implement new version of tfetch (plumb)
 * Line - Get the current line number(s) containing the selection
+* gap buffer does not handle UTF-8 currently
 
 ## UNCERTAIN
 
diff --git a/inc/x11.h b/inc/x11.h
new file mode 100644 (file)
index 0000000..87ed333
--- /dev/null
+++ b/inc/x11.h
@@ -0,0 +1,89 @@
+#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;);
+    }
+}
diff --git a/src/edit.c b/src/edit.c
new file mode 100644 (file)
index 0000000..3381668
--- /dev/null
@@ -0,0 +1,148 @@
+#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
diff --git a/src/registrar.c b/src/registrar.c
new file mode 100644 (file)
index 0000000..66b50cc
--- /dev/null
@@ -0,0 +1,68 @@
+#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;
+}