diff --git a/app.c b/app.c index 5106673..020f6d7 100644 --- a/app.c +++ b/app.c @@ -90,6 +90,14 @@ int appInit(App *app) { XFree(wmh); } + // subscribe to windows delete message from window manager + app->aWmDel = XInternAtom(app->dpy, "WM_DELETE_WINDOW", False); + XSetWMProtocols(app->dpy, app->win, &app->aWmDel, 1); + + // subscribe to keyboard state and layout changes + XkbSelectEvents(app->dpy, XkbUseCoreKbd, XkbMapNotifyMask | XkbStateNotifyMask, XkbMapNotifyMask | XkbStateNotifyMask); + + // init submodules if (graphInit(&app->graph, app)) { graphResize(&app->graph); @@ -222,6 +230,26 @@ int appRun(App *app) { } break; } + case MappingNotify: { + if ( event.xmapping.request == MappingModifier + || event.xmapping.request == MappingKeyboard ) + { + LOGDBG("app: kayboard layout changed"); + XRefreshKeyboardMapping(&event.xmapping); + inputUpdateLayout( + &app->input, + event.xmapping.first_keycode, + event.xmapping.first_keycode + event.xmapping.count ); + } + break; + } + case ClientMessage: { + if (event.xclient.data.l[0] == app->aWmDel) { + LOGDBG("app: delete window event"); + appStop(app, 0); + } + break; + } default: break; } diff --git a/app.h b/app.h index 8807c71..0c620a9 100644 --- a/app.h +++ b/app.h @@ -19,6 +19,7 @@ struct App { int screen; Window root; Window win; + Atom aWmDel; int sw, sh; // dynamic fields diff --git a/common.h b/common.h index 87454f9..4d030e2 100644 --- a/common.h +++ b/common.h @@ -14,6 +14,9 @@ #include #include +#include +#include +#include diff --git a/config.h b/config.h index e02ea37..5421ed1 100644 --- a/config.h +++ b/config.h @@ -2,7 +2,7 @@ #define CONFIG_H -//#define NOBORDER +#define NOBORDER #define TITLE "coolkbd" #define MIN_WIDTH 200 #define MIN_HEIGHT 100 diff --git a/graph.c b/graph.c index 05a7abd..f80073c 100644 --- a/graph.c +++ b/graph.c @@ -107,6 +107,7 @@ void graphDrawButton(Graph *g, int x, int y, int w, int h, int active) { void textLayoutInit(TextLayout *tl, Graph *g, const char *text) { CLEARFROM(tl, g); tl->g = g; + tl->len = text ? strlen(text) : 0; tl->text = text; if (!tl->len) @@ -115,11 +116,15 @@ void textLayoutInit(TextLayout *tl, Graph *g, const char *text) { for(int i = 0; i < tl->g->fontsCnt; ++i) { XGlyphInfo e = {}; XftTextExtentsUtf8(g->app->dpy, g->fonts[i], (const FcChar8*)tl->text, tl->len, &e); + + int asc = tl->g->fonts[i]->ascent; + int desc = tl->g->fonts[i]->descent; int w = e.width; - int h = tl->g->fonts[i]->ascent; - int minw = h + h/3; - tl->sizes[i].x = -e.x - w/2; - tl->sizes[i].y = h/2; + int minw = asc + asc/3; + int h = asc + 2*desc; + + tl->sizes[i].x = e.x - w/2; + tl->sizes[i].y = asc/2; tl->sizes[i].w = w < minw ? minw : w; tl->sizes[i].h = h; } diff --git a/input.c b/input.c index 01b303a..7321a13 100644 --- a/input.c +++ b/input.c @@ -62,28 +62,17 @@ int inputChooseKeysym(unsigned int modifiers, unsigned int ks0, unsigned int ks1 int inputInit(Input *in, App *app) { LOGDBG("input: init"); + CLEARFROM(in, app); in->app = app; - in->key0 = in->key1 = in->mapKey = 0; - in->mapDown = 0; - in->updated = 0; - in->modifiers = 0; - memset(in->keys, 0, sizeof(in->keys)); - memset(in->masks, 0, sizeof(in->masks)); - - LOGDBG("input: init: connect to X11"); - in->dpy = XOpenDisplay(NULL); - if (!in->dpy) - return LOGERR("input: init: cannot connect to X11"); LOGDBG("input: init: query keycode range"); - XDisplayKeycodes(in->dpy, &in->key0, &in->key1); + XDisplayKeycodes(in->app->dpy, &in->key0, &in->key1); ++in->key1; if (in->key0 < 0) in->key0 = 0; if (in->key1 > IN_MAXKEYS) in->key1 = IN_MAXKEYS; LOGDBG("input: init: keycode range [%d, %d)", in->key0, in->key1); - inputUpdateLayout(in); - inputUpdateModifiers(in); + inputUpdateLayout(in, in->key0, in->key1); return 1; } @@ -96,13 +85,19 @@ void inputDeinit(Input *in) { if (in->mapDown) inputEvent(in, in->mapKey, 0); KeySym ks[4] = {}; - XChangeKeyboardMapping(in->dpy, in->mapKey, 4, ks, 1); + XChangeKeyboardMapping(in->app->dpy, in->mapKey, 4, ks, 1); } - XCloseDisplay(in->dpy); } -void inputUpdateLayout(Input *in) { +void inputUpdateLayout(Input* in, int key0, int key1) { + if (key0 < in->key0) key0 = in->key0; + if (key1 > in->key1) key1 = in->key1; + if (key1 <= key0) + return; + if (in->mapKey && key0 == in->mapKey && key1 - key0 == 1) + return; + LOGDBG("input: update layout"); static const KeySym imKeys[IM_COUNT] = { @@ -113,15 +108,14 @@ void inputUpdateLayout(Input *in) { XK_Mode_switch, XK_Scroll_Lock }; - in->updated = 0; memset(in->masks, 0, sizeof(in->masks)); LOGDBG("input: update layout: read modifiers"); - XModifierKeymap *mods = XGetModifierMapping(in->dpy); + XModifierKeymap *mods = XGetModifierMapping(in->app->dpy); LOGDBG("input: update layout: read keyboard mapping"); int mcnt = 0; - KeySym *ks = XGetKeyboardMapping(in->dpy, in->key0, in->key1 - in->key0, &mcnt); + KeySym *ks = XGetKeyboardMapping(in->app->dpy, in->key0, in->key1 - in->key0, &mcnt); for(int i = in->key0; i < in->key1; ++i, ks += mcnt) { // search key for temporary maps if (!in->mapKey) { @@ -186,13 +180,15 @@ void inputUpdateLayout(Input *in) { for(int i = 0; i < IM_COUNT; ++i) LOGDBG("input: update layout: masks[%d] = %08u", i, in->masks[i]); + + inputUpdateModifiers(in); } void inputUpdateModifiers(Input *in) { LOGDBG("input: update modifiers"); XkbStateRec state = {}; - XkbGetState(in->dpy, XkbUseCoreKbd, &state); + XkbGetState(in->app->dpy, XkbUseCoreKbd, &state); in->modifiers = 0; for(int i = 0; i < IM_COUNT; ++i) if (in->masks[i] & state.mods) @@ -229,9 +225,8 @@ int inputKeycode(Input *in, unsigned int keySym) { for(int i = 0; i < IM_COUNT; ++i) in->keys[in->mapKey][i] = keySym; KeySym ks[4] = { keySym, keySym, keySym, keySym }; - XChangeKeyboardMapping(in->dpy, in->mapKey, 4, ks, 1); - XSync(in->dpy, False); - in->updated = 1; + XChangeKeyboardMapping(in->app->dpy, in->mapKey, 4, ks, 1); + XSync(in->app->dpy, False); return in->mapKey; } @@ -244,8 +239,8 @@ void inputEvent(Input *in, int keycode, int press) { LOGERR("input: event: bad keycode=%d", keycode); return; } - XTestFakeKeyEvent(in->dpy, keycode, press, CurrentTime); - XSync(in->dpy, False); + XTestFakeKeyEvent(in->app->dpy, keycode, press, CurrentTime); + XSync(in->app->dpy, False); inputUpdateModifiers(in); } diff --git a/input.h b/input.h index d725202..eb607b5 100644 --- a/input.h +++ b/input.h @@ -4,10 +4,6 @@ #include "common.h" -#include -#include -#include - #define IN_MAXKEYS 256 @@ -31,14 +27,12 @@ enum { typedef struct Input { App *app; - Display *dpy; int key0, key1; unsigned int keys[IN_MAXKEYS][1 << IM_COUNT]; unsigned int masks[IM_COUNT]; int mapKey; int mapDown; - int updated; unsigned int modifiers; } Input; @@ -48,7 +42,7 @@ int inputChooseKeysym(unsigned int modifiers, unsigned int ks0, unsigned int ks1 int inputInit(Input *in, App *app); void inputDeinit(Input *in); -void inputUpdateLayout(Input *in); +void inputUpdateLayout(Input *in, int key0, int key1); void inputUpdateModifiers(Input *in); int inputKeycode(Input *in, unsigned int keySym); void inputEvent(Input *in, int keycode, int press); diff --git a/keyboard.c b/keyboard.c index 4eb88a9..6a77d72 100644 --- a/keyboard.c +++ b/keyboard.c @@ -4,14 +4,8 @@ int keyInit(Key *k, Layout *l) { + CLEARFROM(k, l); k->l = l; - k->down = k->longDown = 0; - k->downKeycode = 0; - k->mx = k->my = 0; - k->isLetter = k->isKeypad = 0; - k->x = k->y = k->w = k->h = 0; - k->prevHeld = k->nextHeld = NULL; - k->orig = k->clone = NULL; inputPrepareKeysyms(&k->keySym, &k->keySym2, &k->isLetter, &k->isKeypad); if (!k->label[0]) keysymString(k->keySym, k->label); @@ -213,10 +207,9 @@ void keyUp(Key *k, int force) { int layoutInit(Layout *l, Keyboard *kbd) { LOGDBG("layout: init"); + + CLEARFROM(l, kbd); l->kbd = kbd; - l->prev = NULL; - l->downKey = NULL; - l->w = l->h = 0; if (!l->keysCount) return 1; @@ -338,8 +331,10 @@ void layoutMouseUp(Layout *l) { int keyboardInit(Keyboard *kbd, App *app) { LOGDBG("keyboard: init"); + + CLEARFROM(kbd, app); kbd->app = app; - kbd->firstHeld = NULL; + kbd->lastModifiers = kbd->app->input.modifiers; kbd->current = kbd->layoutsCount > 0 ? kbd->layouts : NULL; diff --git a/layout.defs.h b/layout.defs.h index 14ab49a..6e77c8b 100644 --- a/layout.defs.h +++ b/layout.defs.h @@ -5,7 +5,8 @@ #include "app.h" -#define S 10 // spacing +#define S 5 // spacing +#define S2 15 // spacing #define W 50 // width #define W2 70 // more width @@ -17,18 +18,19 @@ #define H2 (H*2+S) // double height #define N (-S-1) // place key next to previos key +#define N2 (-S2-1) #define FW (12*W+2*W2+13*S) // full width #ifdef NOBORDER - #define HH 20 // header height + #define HH 30 // header height #define HEADER(fw) \ { S, S, fw-S-HH, HH, 0, 0, "::: coolkbd :::", "", KF_MOVE }, \ { N, 0, HH, 0, 0, 0, "[X]", "", KF_CLOSE }, #define FOOTER(fw) \ - { S, N, fw, HH, 0, 0, "::: resize handle :::", "", KF_SIZE }, - #define Y (HH+2*S) + { S, N2, fw, HH, 0, 0, "::: resize handle :::", "", KF_SIZE }, + #define Y (HH+S+S2) #else #define Y S #define HEADER(fw) diff --git a/layout.en.full.inc.c b/layout.en.full.inc.c index 7258c02..21eda9c 100644 --- a/layout.en.full.inc.c +++ b/layout.en.full.inc.c @@ -8,12 +8,14 @@ #define LEF_COL2 (FW+S+W/2) #define LEF_COL3 (LEF_COL2+3*S+3*W+W/2) #define LEF_FW (LEF_COL3+2*S+4*W) +#define LEF_N (-(FW-14*W-11*S)-1) + Key keysEnFull[] = { HEADER(LEF_FW) { S, Y, W, H, XK_Escape, 0, "Esc" }, - { N-W, 0, 0, 0, XK_F1, 0, "F1" }, + { LEF_N, 0, 0, 0, XK_F1, 0, "F1" }, { N, 0, 0, 0, XK_F2, 0, "F2" }, { N, 0, 0, 0, XK_F3, 0, "F3" }, { N, 0, 0, 0, XK_F4, 0, "F4" }, @@ -26,7 +28,7 @@ Key keysEnFull[] = { { N, 0, 0, 0, XK_F11, 0, "F11" }, { N, 0, 0, 0, XK_F12, 0, "F12" }, - { S, N-S, W2, H, XK_grave, XK_asciitilde }, + { S, N2, W2, H, XK_grave, XK_asciitilde }, { N, 0, W, 0, XK_1, XK_exclam }, { N, 0, 0, 0, XK_2, XK_at }, { N, 0, 0, 0, XK_3, XK_numbersign }, @@ -56,7 +58,7 @@ Key keysEnFull[] = { { N, 0, 0, 0, XK_bracketright, XK_braceright }, { N, 0, W2, H2, XK_Return, 0, "Enter" }, - { S, Y4+S, W2, H, XK_Caps_Lock, 0, "Caps Lock", "", KF_MOD, IM_CAPSLOCK_BIT }, + { S, Y4+S2-S, W2, H, XK_Caps_Lock, 0, "Caps Lock", "", KF_MOD, IM_CAPSLOCK_BIT }, { N, 0, W, 0, XK_a }, { N, 0, 0, 0, XK_s }, { N, 0, 0, 0, XK_d }, @@ -97,7 +99,7 @@ Key keysEnFull[] = { { N, 0, 0, 0, XK_Scroll_Lock, 0, "ScrLk", "", KF_MOD, IM_SCRLOCK_BIT }, { N, 0, 0, 0, XK_Pause, 0, "Pause" }, - { LEF_COL2, N-S, 0, 0, XK_Insert, 0, "Ins" }, + { LEF_COL2, N2, 0, 0, XK_Insert, 0, "Ins" }, { N, 0, 0, 0, XK_Home, 0, "Home" }, { N, 0, 0, 0, XK_Page_Up, 0, "PgUp" },