]> git.mdlowis.com Git - projs/tide.git/commitdiff
rework x11 stuff
authorMichael D. Lowis <mike@mdlowis.com>
Sun, 16 Dec 2018 03:25:43 +0000 (22:25 -0500)
committerMichael D. Lowis <mike@mdlowis.com>
Sun, 16 Dec 2018 03:25:43 +0000 (22:25 -0500)
inc/x11.h
src/lib/x11.c
src/pick.c

index 80793bc19ff081e4674ed0f579c3afb703ecdc8e..e2693fc03c1113d3457553ee6a7b5303f46c330c 100644 (file)
--- a/inc/x11.h
+++ b/inc/x11.h
@@ -11,6 +11,7 @@
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 typedef struct XConf {
+    Bool running;
     int fd, screen, width, height;
     Window root;
     Display* display;
@@ -19,6 +20,7 @@ typedef struct XConf {
     unsigned depth;
     Window self;
     XftDraw* xft;
+    XftFont *tagfont, *font;
     Pixmap pixmap;
     XIC xic;
     XIM xim;
@@ -40,6 +42,7 @@ static int x11_init(XConf* x) {
     x->colormap = wa.colormap;
     x->screen   = DefaultScreen(x->display);
     x->depth    = DefaultDepth(x->display, x->screen);
+    x->running = True;
     return 0;
 }
 
@@ -126,4 +129,48 @@ static void x11_event_loop(XConf* x, void (*redraw)(XConf* x)) {
     }
 }
 
+static XftFont* x11_font_load(XConf* x, char* name) {
+    /* init the library and the base font pattern */
+    if (!FcInit()) return NULL;
+    FcPattern* pattern = FcNameParse((FcChar8 *)name);
+    if (!pattern) return NULL;
+    /* load the base font */
+    FcResult result;
+    FcPattern* match = XftFontMatch(x->display, x->screen, pattern, &result);
+    XftFont* font = NULL;
+    if (match)
+        font = XftFontOpenPattern(x->display, match);
+    FcPatternDestroy(pattern);
+    FcPatternDestroy(match);
+    return font;
+}
+
+static void xftcolor(XConf* x, XftColor* xc, unsigned int c) {
+    #define COLOR(c) ((c) | ((c) >> 8))
+    xc->color.alpha = 0xFFFF;
+    xc->color.red   = COLOR((c & 0x00FF0000) >> 8);
+    xc->color.green = COLOR((c & 0x0000FF00));
+    xc->color.blue  = COLOR((c & 0x000000FF) << 8);
+    XftColorAllocValue(x->display, x->visual, x->colormap, &(xc->color), xc);
+}
+
+static void x11_draw_rect(XConf* x, int color, int px, int py, int width, int height) {
+    XftColor clr;
+    xftcolor(x, &clr, color);
+    XftDrawRect(x->xft, &clr, px, py, width, height);
+    XftColorFree(x->display, x->visual, x->colormap, &clr);
+}
+
+static void x11_draw_glyphs(XConf* x, int color, XftFont* font, XftGlyphSpec* specs, long nspecs) {
+    XftColor clr;
+    xftcolor(x, &clr, color);
+    XftDrawGlyphSpec(x->xft, &clr, font, specs, nspecs);
+    XftColorFree(x->display, x->visual, x->colormap, &clr);
+}
+
+static void x11_flip(XConf* x) {
+    XCopyArea(x->display, x->pixmap, x->self, x->gc, 0, 0, x->width, x->height, 0, 0);
+    XFlush(x->display);
+}
+
 #pragma GCC diagnostic pop
index f9f740790e3d1777f40f9b40973e5c6515472aa5..0d3bdffd9afb6d16fb4ecdd881ca2f0b5472e590 100644 (file)
@@ -10,9 +10,8 @@
 #include <sys/time.h>
 #include <sys/types.h>
 #include <ctype.h>
-#include <X11/Xlib.h>
-#include <X11/Xatom.h>
-#include <X11/Xft/Xft.h>
+#include <x11.h>
+
 #include "config.h"
 
 struct XSel {
@@ -22,30 +21,9 @@ struct XSel {
     void (*callback)(char*);
 };
 
-struct XWin {
-    Bool running;
-    Time now;
-    Window root;
-    Display* display;
-    Visual* visual;
-    Colormap colormap;
-    unsigned depth;
-    int screen;
-    /* assume a single window for now. these are its attributes */
-    Window self;
-    XftDraw* xft;
-    Pixmap pixmap;
-    int width;
-    int height;
-    XIC xic;
-    XIM xim;
-    GC gc;
-    XftFont* tagfont;
-    XftFont* font;
-};
-
 /******************************************************************************/
-struct XWin X;
+static Time Now;
+static struct XConf X;
 static int KeyBtnState;
 static WinRegion Focused = EDIT;
 static View Regions[NREGIONS];
@@ -67,29 +45,9 @@ char* SearchTerm = NULL;
 #define PRESSED(btn) \
     ((KeyBtnState & (1 << (btn + 7))) == (1 << (btn + 7)))
 
-static void die(const char* msg) {
-    perror(msg);
-    exit(EXIT_FAILURE);
-}
-
 static void font_load(char* name) {
-    /* init the library and the base font pattern */
-    if (!FcInit())
-        die("Could not init fontconfig.\n");
-    FcPattern* pattern = FcNameParse((FcChar8 *)name);
-    if (!pattern)
-        die("could not parse font name\n");
-    /* load the base font */
-    FcResult result;
-    FcPattern* match = XftFontMatch(X.display, X.screen, pattern, &result);
-    if (match) {
-        XftFont* font = XftFontOpenPattern(X.display, match);
-        X.font = (font ? font : X.font); // Update if we found a new font
-    }
-    if (!X.font)
-        die("could not load base font\n");
-    FcPatternDestroy(pattern);
-    FcPatternDestroy(match);
+    XftFont* font = x11_font_load(&X, name);
+    X.font = (font ? font : X.font); // Update if we found a new font
 }
 
 static void get_position(WinRegion id, int x, int y, size_t* row, size_t* col) {
@@ -112,51 +70,6 @@ static struct XSel* selfetch(Atom atom) {
     return NULL;
 }
 
-static void x11_window(char* name) {
-    /* create the main window */
-    X.width = WinWidth, X.height = WinHeight;
-    XWindowAttributes wa;
-    XGetWindowAttributes(X.display, X.root, &wa);
-    X.self = XCreateSimpleWindow(X.display, X.root,
-        (wa.width  - X.width) / 2,
-        (wa.height - X.height) /2,
-        X.width,
-        X.height,
-        0, X.depth,
-        Palette[EditBg]);
-    /* 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);
-    XStoreName(X.display, X.self, name);
-    XSelectInput(X.display, X.root, PropertyChangeMask);
-    XSelectInput(X.display, X.self, 0
-        | FocusChangeMask
-        | KeyPressMask
-        | ButtonPressMask
-        | ButtonReleaseMask
-        | ButtonMotionMask
-        | StructureNotifyMask
-        | PropertyChangeMask
-        | ExposureMask
-    );
-    /* 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 tide_send(char* type) {
     XEvent ev;
     memset(&ev, 0, sizeof (ev));
@@ -215,8 +128,8 @@ static void mouse_left(WinRegion id, bool pressed, size_t row, size_t col) {
     static int count = 0;
     static Time before = 0;
     if (!pressed) return;
-    count = ((X.now - before) <= (uint64_t)ClickTime ? count+1 : 1);
-    before = X.now;
+    count = ((Now - before) <= (uint64_t)ClickTime ? count+1 : 1);
+    before = Now;
     if (PRESSED(MouseRight)) {
         puts("fetch tag");
     }  else if (PRESSED(MouseMiddle)) {
@@ -280,16 +193,6 @@ static void mouse_click(int btn, bool pressed, int x, int y) {
 
 /******************************************************************************/
 
-static void xftcolor(XftColor* xc, int id) {
-    #define COLOR(c) ((c) | ((c) >> 8))
-    uint32_t c = Palette[id];
-    xc->color.alpha = 0xFFFF;
-    xc->color.red   = COLOR((c & 0x00FF0000) >> 8);
-    xc->color.green = COLOR((c & 0x0000FF00));
-    xc->color.blue  = COLOR((c & 0x000000FF) << 8);
-    XftColorAllocValue(X.display, X.visual, X.colormap, &(xc->color), xc);
-}
-
 size_t glyph_width(View* view, int c) {
     FcChar32 rune = (FcChar32)c;
     XGlyphInfo extents;
@@ -302,10 +205,7 @@ size_t glyph_width(View* view, int c) {
 }
 
 static void draw_rect(int color, int x, int y, int width, int height) {
-    XftColor clr;
-    xftcolor(&clr, color);
-    XftDrawRect(X.xft, &clr, x, y, width, height);
-    XftColorFree(X.display, X.visual, X.colormap, &clr);
+    x11_draw_rect(&X, Palette[color], x, y, width, height);
 }
 
 static void draw_statbox(void) {
@@ -358,7 +258,7 @@ static void draw_view(View* view, XftFont* font, size_t nrows, drawcsr* csr, int
             x += row->cols[i].width;
         }
         XftColor fgc;
-        xftcolor(&fgc, fg);
+        xftcolor(&X, &fgc, Palette[fg]);
         XftDrawGlyphSpec(X.xft, &fgc, font, specs, row->len);
         XftColorFree(X.display, X.visual, X.colormap, &fgc);
     }
@@ -391,13 +291,14 @@ static void draw_scroll(drawcsr* csr) {
 
 /******************************************************************************/
 
-static void xfocus(XEvent* e) {
-    if (X.xic)
-        (e->type == FocusIn ? XSetICFocus : XUnsetICFocus)(X.xic);
+static void xfocus(XConf* x, XEvent* e) {
+    if (x->xic)
+        (e->type == FocusIn ? XSetICFocus : XUnsetICFocus)(x->xic);
 }
 
-static void xkeypress(XEvent* e) {
-    X.now = e->xkey.time;
+static void xkeypress(XConf* x, XEvent* e) {
+    (void)x;
+    Now = e->xkey.time;
     Focused = (e->xkey.y <= Divider ? TAGS : EDIT);
     uint32_t key = getkey(e);
     if (key == RUNE_ERR) return;
@@ -420,43 +321,46 @@ static void xkeypress(XEvent* e) {
         view_insert(win_view(FOCUSED), key);
 }
 
-static void xbtnpress(XEvent* e) {
-    X.now = e->xbutton.time;
+static void xbtnpress(XConf* x, XEvent* e) {
+    (void)x;
+    Now = e->xbutton.time;
     KeyBtnState = (e->xbutton.state | (1 << (e->xbutton.button + 7)));
     mouse_click(e->xbutton.button, true, e->xbutton.x,  e->xbutton.y);
 }
 
-static void xbtnrelease(XEvent* e) {
-    X.now = e->xbutton.time;
+static void xbtnrelease(XConf* x, XEvent* e) {
+    (void)x;
+    Now = e->xbutton.time;
     KeyBtnState = (e->xbutton.state & ~(1 << (e->xbutton.button + 7)));
     mouse_click(e->xbutton.button, false, e->xbutton.x,  e->xbutton.y);
 }
 
-static void xbtnmotion(XEvent* e) {
-    while (XCheckTypedEvent(X.display, MotionNotify, e));
-    X.now = e->xbutton.time;
+static void xbtnmotion(XConf* x, XEvent* e) {
+    while (XCheckTypedEvent(x->display, MotionNotify, e));
+    Now = e->xbutton.time;
     size_t row, col;
     KeyBtnState = e->xbutton.state;
-    int x = e->xbutton.x, y = e->xbutton.y;
-    get_position(Focused, x, y, &row, &col);
+    int xpos = e->xbutton.x, ypos = e->xbutton.y;
+    get_position(Focused, xpos, ypos, &row, &col);
     if (PRESSED(MouseLeft))
         view_setcursor(win_view(Focused), row, col, true);
 }
 
-static void xselclear(XEvent* e) {
+static void xselclear(XConf* x, XEvent* e) {
+    (void)x;
     struct XSel* sel = selfetch(e->xselectionclear.selection);
     if (!sel) return;
     free(sel->text);
     sel->text = NULL;
 }
 
-static void xselquit(XEvent* e) {
-    xselclear(e);
+static void xselquit(XConf* x, XEvent* e) {
+    xselclear(x, e);
     if (!Selections[PRIMARY].text && !Selections[CLIPBOARD].text)
-        X.running = False;
+        x->running = False;
 }
 
-static void xselnotify(XEvent* e) {
+static void xselnotify(XConf* x, XEvent* e) {
     /* bail if the selection cannot be converted */
     if (e->xselection.property == None)
         return;
@@ -464,7 +368,7 @@ static void xselnotify(XEvent* e) {
     Atom rtype;
     unsigned long format = 0, nitems = 0, nleft = 0;
     unsigned char* propdata = NULL;
-    XGetWindowProperty(X.display, X.self, sel->atom, 0, -1, False, AnyPropertyType, &rtype,
+    XGetWindowProperty(x->display, x->self, sel->atom, 0, -1, False, AnyPropertyType, &rtype,
                        (int*)&format, &nitems, &nleft, &propdata);
     if (e->xselection.target == SelTarget) {
         void(*cbfn)(char*) = sel->callback;
@@ -475,7 +379,7 @@ static void xselnotify(XEvent* e) {
     if (propdata) XFree(propdata);
 }
 
-static void xselrequest(XEvent* e) {
+static void xselrequest(XConf* x, XEvent* e) {
     XEvent s;
     struct XSel* sel = selfetch( e->xselectionrequest.selection );
     s.xselection.type      = SelectionNotify;
@@ -485,57 +389,43 @@ static void xselrequest(XEvent* e) {
     s.xselection.target    = e->xselectionrequest.target;
     s.xselection.time      = e->xselectionrequest.time;
     Atom target    = e->xselectionrequest.target;
-    Atom xatargets = XInternAtom(X.display, "TARGETS", 0);
-    Atom xastring  = XInternAtom(X.display, "STRING", 0);
+    Atom xatargets = XInternAtom(x->display, "TARGETS", 0);
+    Atom xastring  = XInternAtom(x->display, "STRING", 0);
     if (target == xatargets) {
         /* respond with the supported type */
         XChangeProperty(
-            X.display,
+            x->display,
             s.xselection.requestor,
             s.xselection.property,
             XA_ATOM, 32, PropModeReplace,
             (unsigned char*)&SelTarget, 1);
     } else if (target == SelTarget || target == xastring) {
         XChangeProperty(
-            X.display,
+            x->display,
             s.xselection.requestor,
             s.xselection.property,
             SelTarget, 8, PropModeReplace,
             (unsigned char*)sel->text, strlen(sel->text));
     }
-    XSendEvent(X.display, s.xselection.requestor, True, 0, &s);
+    XSendEvent(x->display, s.xselection.requestor, True, 0, &s);
 }
 
-static void xclientmsg(XEvent* e) {
-    if ((Atom)(e->xclient.data.l[0]) == XInternAtom(X.display, "WM_DELETE_WINDOW", False))
+static void xclientmsg(XConf* x, XEvent* e) {
+    if ((Atom)(e->xclient.data.l[0]) == XInternAtom(x->display, "WM_DELETE_WINDOW", False))
         win_quit();
-    else if (e->xclient.message_type == XInternAtom(X.display, "GOTO", False))
+    else if (e->xclient.message_type == XInternAtom(x->display, "GOTO", False))
         view_setln(win_view(EDIT), e->xclient.data.l[0]);
 }
 
-static void xresize(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);
+static void xresize(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);
     }
 }
 
-static void (*EventHandlers[LASTEvent])(XEvent*) = {
-    [FocusIn] = xfocus,
-    [FocusOut] = xfocus,
-    [KeyPress] = xkeypress,
-    [ButtonPress] = xbtnpress,
-    [ButtonRelease] = xbtnrelease,
-    [MotionNotify] = xbtnmotion,
-    [SelectionClear] = xselclear,
-    [SelectionNotify] = xselnotify,
-    [SelectionRequest] = xselrequest,
-    [ClientMessage] = xclientmsg,
-    [ConfigureNotify] = xresize,
-};
-
 static void xupdate(Job* job) {
     (void)job;
     int nevents;
@@ -544,8 +434,9 @@ static void xupdate(Job* job) {
     XGetMotionEvents(X.display, X.self, CurrentTime, CurrentTime, &nevents);
     for (XEvent e; XPending(X.display);) {
         XNextEvent(X.display, &e);
-        if (!XFilterEvent(&e, None) && EventHandlers[e.type])
-            (EventHandlers[e.type])(&e);
+        if (!XFilterEvent(&e, None) && X.eventfns[e.type])
+            (X.eventfns[e.type])(&X, &e);
+        for (int status; waitpid(-1, &status, WNOHANG) > 0;);
     }
     /* determine the size of the regions */
     size_t maxtagrows = ((X.height/4) / X.tagfont->height);
@@ -573,20 +464,44 @@ void win_init(KeyBinding* bindings) {
     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)))
-        die("could not open display");
-    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);
+    x11_init(&X);
     font_load(Fonts[FontSel = 0]);
     X.tagfont = X.font;
-    x11_window("unnamed");
-    /* initialize selection atoms */
+    if (!X.font) {
+        perror("unable to load base font");
+        exit(EXIT_FAILURE);
+    }
+    x11_mkwin(&X, 640, 480, 0
+        | FocusChangeMask
+        | KeyPressMask
+        | ButtonPressMask
+        | ButtonReleaseMask
+        | ButtonMotionMask
+        | StructureNotifyMask
+        | PropertyChangeMask
+        | ExposureMask
+    );
+    x11_init_gc(&X);
+    x11_centerwin(&X);
+    x11_show(&X);
+
+    /* register event handlers */
+    X.eventfns[FocusIn] = xfocus;
+    X.eventfns[FocusOut] = xfocus;
+    X.eventfns[KeyPress] = xkeypress;
+    X.eventfns[ButtonPress] = xbtnpress;
+    X.eventfns[ButtonRelease] = xbtnrelease;
+    X.eventfns[MotionNotify] = xbtnmotion;
+    X.eventfns[SelectionClear] = xselclear;
+    X.eventfns[SelectionNotify] = xselnotify;
+    X.eventfns[SelectionRequest] = xselrequest;
+    X.eventfns[ClientMessage] = xclientmsg;
+    X.eventfns[ConfigureNotify] = xresize;
+
+    /* initialize
+selection atoms */
     for (unsigned int i = 0; i < (sizeof(Selections) / sizeof(Selections[0])); i++)
         Selections[i].atom = XInternAtom(X.display, Selections[i].name, 0);
     SelTarget = XInternAtom(X.display, "UTF8_STRING", 0);
@@ -642,9 +557,9 @@ void win_loop(void) {
 
 void win_quit(void) {
     static uint64_t before = 0;
-    if ((win_buf(EDIT)->status != MODIFIED) || (X.now - before) <= (uint64_t)ClickTime) {
+    if ((win_buf(EDIT)->status != MODIFIED) || (Now - before) <= (uint64_t)ClickTime) {
         tide_send("DEL");
-        EventHandlers[SelectionClear] = xselquit;
+        X.eventfns  [SelectionClear] = xselquit;
         XUnmapWindow(X.display, X.self);
         if (!Selections[PRIMARY].text && !Selections[CLIPBOARD].text) {
             X.running = False;
@@ -652,7 +567,7 @@ void win_quit(void) {
             if (fork()) exit(0); /* fork into background if we still have selection */
         }
     }
-    before = X.now;
+    before = Now;
 }
 
 void win_togglefocus(void) {
index c2810a77c3bca3eda39b74bbf7659900a2887e74..2113b6525fa712d8efa032620826564246f9dea3 100644 (file)
@@ -125,26 +125,9 @@ static void xresize(XConf* x, XEvent* e) {
     }
 }
 
-static void xftcolor(XConf* x, XftColor* xc, unsigned int c) {
-    #define COLOR(c) ((c) | ((c) >> 8))
-    xc->color.alpha = 0xFFFF;
-    xc->color.red   = COLOR((c & 0x00FF0000) >> 8);
-    xc->color.green = COLOR((c & 0x0000FF00));
-    xc->color.blue  = COLOR((c & 0x000000FF) << 8);
-    XftColorAllocValue(x->display, x->visual, x->colormap, &(xc->color), xc);
-}
-
-static void draw_rect(XConf* x, int color, int px, int py, int width, int height) {
-    XftColor clr;
-    xftcolor(x, &clr, color);
-    XftDrawRect(x->xft, &clr, px, py, width, height);
-    XftColorFree(x->display, x->visual, x->colormap, &clr);
-}
-
 static void redraw(XConf* x) {
-    draw_rect(x, 0x00, 0, 0, x->width, x->height);
-    XCopyArea(x->display, x->pixmap, x->self, x->gc, 0, 0, x->width, x->height, 0, 0);
-    XFlush(x->display);
+    x11_draw_rect(x, 0x00, 0, 0, x->width, x->height);
+    x11_flip(x);
 }
 
 static void filter(void) {