#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 {
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];
#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) {
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));
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)) {
/******************************************************************************/
-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;
}
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) {
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);
}
/******************************************************************************/
-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;
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;
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;
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;
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;
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);
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);
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;
if (fork()) exit(0); /* fork into background if we still have selection */
}
}
- before = X.now;
+ before = Now;
}
void win_togglefocus(void) {