short y;
} XGlyphSpec;
-/* key definitions */
-enum Keys {
- /* Define some runes in the private use area of unicode to represent
- * special keys */
- KEY_F1 = (0xE000+0),
- KEY_F2 = (0xE000+1),
- KEY_F3 = (0xE000+2),
- KEY_F4 = (0xE000+3),
- KEY_F5 = (0xE000+4),
- KEY_F6 = (0xE000+5),
- KEY_F7 = (0xE000+6),
- KEY_F8 = (0xE000+7),
- KEY_F9 = (0xE000+8),
- KEY_F10 = (0xE000+9),
- KEY_F11 = (0xE000+10),
- KEY_F12 = (0xE000+11),
- KEY_INSERT = (0xE000+12),
- KEY_DELETE = (0xE000+13),
- KEY_HOME = (0xE000+14),
- KEY_END = (0xE000+15),
- KEY_PGUP = (0xE000+16),
- KEY_PGDN = (0xE000+17),
- KEY_UP = (0xE000+18),
- KEY_DOWN = (0xE000+19),
- KEY_RIGHT = (0xE000+20),
- KEY_LEFT = (0xE000+21),
-
- /* ASCII Control Characters */
- KEY_CTRL_TILDE = 0x00,
- KEY_CTRL_2 = 0x00,
- KEY_CTRL_A = 0x01,
- KEY_CTRL_B = 0x02,
- KEY_CTRL_C = 0x03,
- KEY_CTRL_D = 0x04,
- KEY_CTRL_E = 0x05,
- KEY_CTRL_F = 0x06,
- KEY_CTRL_G = 0x07,
- KEY_BACKSPACE = 0x08,
- KEY_CTRL_H = 0x08,
- KEY_TAB = 0x09,
- KEY_CTRL_I = 0x09,
- KEY_CTRL_J = 0x0A,
- KEY_CTRL_K = 0x0B,
- KEY_CTRL_L = 0x0C,
- KEY_ENTER = 0x0D,
- KEY_CTRL_M = 0x0D,
- KEY_CTRL_N = 0x0E,
- KEY_CTRL_O = 0x0F,
- KEY_CTRL_P = 0x10,
- KEY_CTRL_Q = 0x11,
- KEY_CTRL_R = 0x12,
- KEY_CTRL_S = 0x13,
- KEY_CTRL_T = 0x14,
- KEY_CTRL_U = 0x15,
- KEY_CTRL_V = 0x16,
- KEY_CTRL_W = 0x17,
- KEY_CTRL_X = 0x18,
- KEY_CTRL_Y = 0x19,
- KEY_CTRL_Z = 0x1A,
- KEY_ESCAPE = 0x1B,
- KEY_CTRL_LSQ_BRACKET = 0x1B,
- KEY_CTRL_3 = 0x1B,
- KEY_CTRL_4 = 0x1C,
- KEY_CTRL_BACKSLASH = 0x1C,
- KEY_CTRL_5 = 0x1D,
- KEY_CTRL_RSQ_BRACKET = 0x1D,
- KEY_CTRL_6 = 0x1E,
- KEY_CTRL_7 = 0x1F,
- KEY_CTRL_SLASH = 0x1F,
- KEY_CTRL_UNDERSCORE = 0x1F,
-};
-
/* Key modifier masks */
enum {
ModNone = 0,
CLIPBOARD = 1
};
+/* key definitions */
+enum Keys {
+ /* Define some runes in the private use area of unicode to represent
+ * special keys */
+ KEY_F1 = (0xE000+0),
+ KEY_F2 = (0xE000+1),
+ KEY_F3 = (0xE000+2),
+ KEY_F4 = (0xE000+3),
+ KEY_F5 = (0xE000+4),
+ KEY_F6 = (0xE000+5),
+ KEY_F7 = (0xE000+6),
+ KEY_F8 = (0xE000+7),
+ KEY_F9 = (0xE000+8),
+ KEY_F10 = (0xE000+9),
+ KEY_F11 = (0xE000+10),
+ KEY_F12 = (0xE000+11),
+ KEY_INSERT = (0xE000+12),
+ KEY_DELETE = (0xE000+13),
+ KEY_HOME = (0xE000+14),
+ KEY_END = (0xE000+15),
+ KEY_PGUP = (0xE000+16),
+ KEY_PGDN = (0xE000+17),
+ KEY_UP = (0xE000+18),
+ KEY_DOWN = (0xE000+19),
+ KEY_RIGHT = (0xE000+20),
+ KEY_LEFT = (0xE000+21),
+
+ /* ASCII Control Characters */
+ KEY_CTRL_TILDE = 0x00,
+ KEY_CTRL_2 = 0x00,
+ KEY_CTRL_A = 0x01,
+ KEY_CTRL_B = 0x02,
+ KEY_CTRL_C = 0x03,
+ KEY_CTRL_D = 0x04,
+ KEY_CTRL_E = 0x05,
+ KEY_CTRL_F = 0x06,
+ KEY_CTRL_G = 0x07,
+ KEY_BACKSPACE = 0x08,
+ KEY_CTRL_H = 0x08,
+ KEY_TAB = 0x09,
+ KEY_CTRL_I = 0x09,
+ KEY_CTRL_J = 0x0A,
+ KEY_CTRL_K = 0x0B,
+ KEY_CTRL_L = 0x0C,
+ KEY_ENTER = 0x0D,
+ KEY_CTRL_M = 0x0D,
+ KEY_CTRL_N = 0x0E,
+ KEY_CTRL_O = 0x0F,
+ KEY_CTRL_P = 0x10,
+ KEY_CTRL_Q = 0x11,
+ KEY_CTRL_R = 0x12,
+ KEY_CTRL_S = 0x13,
+ KEY_CTRL_T = 0x14,
+ KEY_CTRL_U = 0x15,
+ KEY_CTRL_V = 0x16,
+ KEY_CTRL_W = 0x17,
+ KEY_CTRL_X = 0x18,
+ KEY_CTRL_Y = 0x19,
+ KEY_CTRL_Z = 0x1A,
+ KEY_ESCAPE = 0x1B,
+ KEY_CTRL_LSQ_BRACKET = 0x1B,
+ KEY_CTRL_3 = 0x1B,
+ KEY_CTRL_4 = 0x1C,
+ KEY_CTRL_BACKSLASH = 0x1C,
+ KEY_CTRL_5 = 0x1D,
+ KEY_CTRL_RSQ_BRACKET = 0x1D,
+ KEY_CTRL_6 = 0x1E,
+ KEY_CTRL_7 = 0x1F,
+ KEY_CTRL_SLASH = 0x1F,
+ KEY_CTRL_UNDERSCORE = 0x1F,
+};
+
+
int x11_init(XConf* x);
void x11_error_clear(void);
XErrorEvent* x11_error_get(void);
void x11_mkwin(XConf* x, int width, int height, int evmask);
void x11_mkdialog(XConf* x, int width, int height, int evmask);
+int x11_process_events(XConf* x);
void x11_event_loop(XConf* x, void (*redraw)(XConf* x));
int x11_getptr(XConf* x, int* ptrx, int* ptry);
-KeySym x11_getkey(XConf* x, XEvent* e);
+uint32_t x11_getkey(XConf* x, XEvent* e);
void x11_centerwin(XConf* x);
void x11_init_gc(XConf* x);
#include <x11.h>
+#include <utf.h>
#include <locale.h>
#include <signal.h>
#include <sys/types.h>
/* setup window attributes and events */
XSetWindowAttributes swa;
swa.bit_gravity = NorthWestGravity;
- swa.do_not_propagate_mask = 0; // do not hide any events from child window
+ swa.do_not_propagate_mask = 0; /* do not hide any events from child windows */
XChangeWindowAttributes(x->display, x->self,
- CWBackingStore|CWBitGravity|CWEventMask|NoEventMask|CWBackPixel,
+ CWBackPixel|CWBorderPixel|CWBitGravity|CWEventMask|CWColormap,
&swa);
XSelectInput(x->display, x->self, evmask);
}
XChangeProperty(x->display, x->self, WindowType, XA_ATOM, 32, PropModeReplace, (unsigned char*)&DialogType, 1);
}
+int x11_process_events(XConf* x) {
+ int nqueued, nevents, dirty = false;
+ /* reap zombie background processes */
+ for (int status; waitpid(-1, &status, WNOHANG) > 0;);
+ /* process the entire event queue */
+ 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 (e.type == Expose) dirty = 1;
+ if (!XFilterEvent(&e, None) && x->eventfns[e.type])
+ (x->eventfns[e.type])(x, &e);
+ }
+ dirty = dirty || nqueued;
+ } while ((nqueued = XEventsQueued(x->display, QueuedAfterFlush)) > 0);
+ return dirty;
+}
+
void x11_event_loop(XConf* x, void (*redraw)(XConf* x)) {
if (redraw) redraw(x);
for (XEvent e; x->running;) {
return XQueryPointer(x->display, x->self, &root, &child, ptrx, ptry, &winx, &winy, (unsigned int*)&mask);
}
-KeySym x11_getkey(XConf* x, XEvent* e) {
+static uint32_t special_keys(uint32_t key) {
+ static uint32_t keymap[256] = {
+ /* Function keys */
+ [0xBE] = KEY_F1, [0xBF] = KEY_F2, [0xC0] = KEY_F3, [0xC1] = KEY_F4,
+ [0xC2] = KEY_F5, [0xC3] = KEY_F6, [0xC4] = KEY_F7, [0xC5] = KEY_F8,
+ [0xC6] = KEY_F9, [0xC7] = KEY_F10, [0xC8] = KEY_F11, [0xC9] = KEY_F12,
+ /* Navigation keys */
+ [0x50] = KEY_HOME, [0x51] = KEY_LEFT, [0x52] = KEY_UP,
+ [0x53] = KEY_RIGHT, [0x54] = KEY_DOWN, [0x55] = KEY_PGUP,
+ [0x56] = KEY_PGDN, [0x57] = KEY_END,
+ /* Control keys */
+ [0x08] = '\b', [0x09] = '\t', [0x0d] = '\n', [0x0a] = '\n',
+ /* Miscellaneous */
+ [0x63] = KEY_INSERT, [0x1B] = KEY_ESCAPE, [0xFF] = KEY_DELETE,
+ };
+ /* lookup the key by keysym */
+ key = ((key & 0xFF00) == 0xFF00 ? keymap[key & 0xFF] : key);
+ return (!key ? RUNE_ERR : key);
+}
+
+uint32_t x11_getkey(XConf* x, XEvent* e) {
char buf[8];
KeySym key;
Status status;
Xutf8LookupString(x->xic, &(e->xkey), buf, sizeof(buf), &key, &status);
else
XLookupString(&(e->xkey), buf, sizeof(buf), &key, 0);
- return key;
+ /* if it's ascii, just return it */
+ if (key >= 0x20 && key <= 0x7F)
+ return (uint32_t)key;
+ /* translate special key codes into unicode codepoints */
+ return special_keys(key);
}
-
-
if (e->xconfigure.width != x->width || e->xconfigure.height != x->height) {
x->width = e->xconfigure.width;
x->height = e->xconfigure.height;
+ XFreePixmap(x->display, x->pixmap);
x->pixmap = XCreatePixmap(x->display, x->self, x->width, x->height, x->depth);
- x->xft = XftDrawCreate(x->display, x->pixmap, x->visual, x->colormap);
+ XftDrawChange(x->xft, x->pixmap);
}
}
Window Child = 0;
int retile = 0;
-/* X11 Window Code
+/* X11 Font Code
******************************************************************************/
static void font_load(char* name) {
XftFont* font = x11_font_load(&X, name);
return extents.xOff;
}
+/* X11 Event Code
+ ******************************************************************************/
static void xmaprequest(XConf* x, XEvent* e) {
(void)x;
XMapWindow(e->xmaprequest.display, e->xmaprequest.window);
retile = 1;
}
+static void xkeypress(XConf* x, XEvent* e) {
+ uint32_t key = x11_getkey(x, e);
+ if (key == RUNE_ERR) return;
+// int mods = e->xkey.state & (ModCtrl|ModShift|ModAlt);
+// int32_t mkey = tolower(key);
+// for (KeyBinding* bind = Keys; bind && bind->key; bind++) {
+// bool match = (mkey == bind->key);
+// bool exact = (bind->mods == mods);
+// bool any = (bind->mods == ModAny);
+// bool oneplus = ((bind->mods == ModOneOrMore) && (mods & ModOneOrMore));
+// if (match && (exact || oneplus || any)) {
+// bind->fn(bind->arg);
+// return;
+// }
+// }
+ /* fallback to just inserting the rune if it doesn't fall in the private use area.
+ * the private use area is used to encode special keys */
+ if (key < 0xE000 || key > 0xF8FF)
+ view_insert(&Tags, key);
+}
+
+/* X11 Drawing Code
+ ******************************************************************************/
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, NORMAL);
- draw_view(&X, &Tags, X.font, tagrows, &csr, TagsBg, TagsFg, TagsSel, false);
- int prev_div = Divider;
- 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);
- if ((retile || prev_div != Divider) && Child) {
- XMoveResizeWindow(X.display, Child, -1, Divider, X.width, X.height - Divider);
- retile = 0;
- }
- XFlush(X.display);
- }
- } while ((nqueued = XEventsQueued(X.display, QueuedAfterFlush)) > 0);
+ /* redraw if we have changes */
+ if (!x11_process_events(&X) && job) return;
+ /* 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, NORMAL);
+ draw_view(&X, &Tags, X.font, tagrows, &csr, TagsBg, TagsFg, TagsSel, false);
+ int prev_div = Divider;
+ 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);
+ if ((retile || prev_div != Divider) && Child) {
+ XMoveResizeWindow(X.display, Child, -1, Divider, X.width, X.height - Divider);
+ retile = 0;
+ }
+ XFlush(X.display);
}
void win_init(KeyBinding* bindings) {
}
x11_mkwin(&X, 640, 480, 0
// | FocusChangeMask
-// | KeyPressMask
+ | KeyPressMask
// | ButtonPressMask
// | ButtonReleaseMask
// | ButtonMotionMask
x11_show(&X);
/* register event handlers */
-// X.eventfns[KeyPress] = xkeypress;
// X.eventfns[ButtonPress] = xbtnpress;
// X.eventfns[ButtonRelease] = xbtnrelease;
// X.eventfns[MotionNotify] = xbtnmotion;
X.eventfns[ConfigureNotify] = xconfigure;
X.eventfns[ClientMessage] = xclientmsg;
X.eventfns[Expose] = xexpose;
+ X.eventfns[KeyPress] = xkeypress;
}
void win_loop(void) {
}
}
-static uint32_t special_keys(uint32_t key) {
- static uint32_t keymap[256] = {
- /* Function keys */
- [0xBE] = KEY_F1, [0xBF] = KEY_F2, [0xC0] = KEY_F3, [0xC1] = KEY_F4,
- [0xC2] = KEY_F5, [0xC3] = KEY_F6, [0xC4] = KEY_F7, [0xC5] = KEY_F8,
- [0xC6] = KEY_F9, [0xC7] = KEY_F10, [0xC8] = KEY_F11, [0xC9] = KEY_F12,
- /* Navigation keys */
- [0x50] = KEY_HOME, [0x51] = KEY_LEFT, [0x52] = KEY_UP,
- [0x53] = KEY_RIGHT, [0x54] = KEY_DOWN, [0x55] = KEY_PGUP,
- [0x56] = KEY_PGDN, [0x57] = KEY_END,
- /* Control keys */
- [0x08] = '\b', [0x09] = '\t', [0x0d] = '\n', [0x0a] = '\n',
- /* Miscellaneous */
- [0x63] = KEY_INSERT, [0x1B] = KEY_ESCAPE, [0xFF] = KEY_DELETE,
- };
- /* lookup the key by keysym */
- key = ((key & 0xFF00) == 0xFF00 ? keymap[key & 0xFF] : key);
- return (!key ? RUNE_ERR : key);
-}
-
-static uint32_t getkey(XConf* x, XEvent* e) {
- KeySym key = x11_getkey(x, e);
- /* if it's ascii, just return it */
- if (key >= 0x20 && key <= 0x7F)
- return (uint32_t)key;
- /* translate special key codes into unicode codepoints */
- return special_keys(key);
-}
-
static void mouse_left(WinRegion id, bool pressed, size_t row, size_t col) {
static int count = 0;
static Time before = 0;
(void)x;
Now = e->xkey.time;
Focused = (e->xkey.y <= Divider ? TAGS : EDIT);
- uint32_t key = getkey(x, e);
+ uint32_t key = x11_getkey(x, e);
if (key == RUNE_ERR) return;
KeyBtnState = e->xkey.state;
int mods = KeyBtnState & (ModCtrl|ModShift|ModAlt);
}
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) {
- /* force update the title */
- win_title(NULL);
- /* determine the size of the regions */
- size_t maxtagrows = ((X.height/4) / X.tagfont->height);
- size_t tagrows = view_limitrows(win_view(TAGS), maxtagrows);
- size_t tagregsz = (tagrows * X.tagfont->height) + 7;
- size_t editrows = (X.height - tagregsz) / X.font->height ;
- /* draw the regions to the window */
- drawcsr csr = { .w = X.width, .h = X.height };
- csr.x += ScrollWidth + 1;
- draw_statbox(&X, win_view(EDIT)->buffer.status);
- draw_view(&X, &Regions[TAGS], X.tagfont, tagrows, &csr, TagsBg, TagsFg, TagsSel, false);
- Divider = draw_hrule(&X, &csr);
- draw_view(&X, &Regions[EDIT], X.font, editrows, &csr, EditBg, EditFg, EditSel, SyncMouse);
- draw_scroll(&X, &csr, win_view(EDIT), Divider);
- XCopyArea(X.display, X.pixmap, X.self, X.gc, 0, 0, X.width, X.height, 0, 0);
- SyncMouse = false;
- XFlush(X.display);
- }
- } while ((nqueued = XEventsQueued(X.display, QueuedAfterFlush)) > 0);
+ /* redraw if we have changes */
+ if (!x11_process_events(&X) && job) return;
+ /* force update the title */
+ win_title(NULL);
+ /* determine the size of the regions */
+ size_t maxtagrows = ((X.height/4) / X.tagfont->height);
+ size_t tagrows = view_limitrows(win_view(TAGS), maxtagrows);
+ size_t tagregsz = (tagrows * X.tagfont->height) + 7;
+ size_t editrows = (X.height - tagregsz) / X.font->height ;
+ /* draw the regions to the window */
+ drawcsr csr = { .w = X.width, .h = X.height };
+ csr.x += ScrollWidth + 1;
+ draw_statbox(&X, win_view(EDIT)->buffer.status);
+ draw_view(&X, &Regions[TAGS], X.tagfont, tagrows, &csr, TagsBg, TagsFg, TagsSel, false);
+ Divider = draw_hrule(&X, &csr);
+ draw_view(&X, &Regions[EDIT], X.font, editrows, &csr, EditBg, EditFg, EditSel, SyncMouse);
+ draw_scroll(&X, &csr, win_view(EDIT), Divider);
+ XCopyArea(X.display, X.pixmap, X.self, X.gc, 0, 0, X.width, X.height, 0, 0);
+ SyncMouse = false;
+ XFlush(X.display);
}
void win_init(KeyBinding* bindings) {