diff --git a/app.c b/app.c index 77f1103..82c157f 100644 --- a/app.c +++ b/app.c @@ -9,10 +9,9 @@ #include #include -#include -int appInit(App *app) { +int appInit(App *app, const char *touch_dev) { LOGDBG("app: init"); CLEARFROM(app, dpy); @@ -26,7 +25,8 @@ int appInit(App *app) { app->screen = DefaultScreen(app->dpy); app->sw = DisplayWidth(app->dpy, app->screen); app->sh = DisplayHeight(app->dpy, app->screen); - LOGDBG("app: init: screen=%d sw=%d sh=%d", app->screen, app->sw, app->sh); + XRRRotations(app->dpy, app->screen, &app->sr); + LOGDBG("app: init: screen=%d sw=%d sh=%d sr=%02x", app->screen, app->sw, app->sh, app->sr); LOGDBG("app: init: get root window"); app->root = RootWindow(app->dpy, app->screen); @@ -49,7 +49,7 @@ int appInit(App *app) { #else app->y = app->sh - app->h; #endif - + XSetWindowAttributes attr = {}; #ifdef NOBORDER attr.override_redirect = 1; @@ -144,6 +144,7 @@ int appInit(App *app) { #endif // init submodules + touchInit(&app->touch, app, touch_dev); // touch is optional if (graphInit(&app->graph, app)) { graphResize(&app->graph); if (inputInit(&app->input, app)) { @@ -179,7 +180,10 @@ int appRun(App *app) { LOGDBG("app: run: show window"); XMapWindow(app->dpy, app->win); + XFlush(app->dpy); + appUpdateStrut(app); + XFlush(app->dpy); LOGDBG("app: run: get connection file descriptor"); int fd = ConnectionNumber(app->dpy); @@ -190,7 +194,10 @@ int appRun(App *app) { int buttonDown = 0; unsigned int buttonDownMs = 0; fd_set fds = {}; - int maxFd = fd > app->stopFd ? fd : app->stopFd; + int maxFd = fd; + if (maxFd < app->stopFd) maxFd = app->stopFd; + if (app->touch.app && maxFd < app->touch.fd) maxFd = app->touch.fd; + XFlush(app->dpy); while(1) { int hasEvent = 0; @@ -199,6 +206,7 @@ int appRun(App *app) { FD_ZERO(&fds); FD_SET(fd, &fds); FD_SET(app->stopFd, &fds); + if (app->touch.app) FD_SET(app->touch.fd, &fds); // wait for next event if (XPending(app->dpy)) { @@ -229,7 +237,29 @@ int appRun(App *app) { hasEvent = 1; } + if (app->touch.app) { + // handle direct touch events + int x, y, p; + while(touchGet(&app->touch, &x, &y, &p)) { + if (p && !buttonDown) { + LOGDBG("app: touch pressed: x=%d, y=%d", x, y); + buttonDown = 1; buttonDownMs = monotonicMs(); + keyboardMouseDown(&app->keyboard, x, y); + } else + if (!p && buttonDown) { + LOGDBG("app: touch released"); + buttonDown = 0; + keyboardMouseUp(&app->keyboard); + } else + if (p) { + LOGDBG("app: touch motion: x=%d, y=%d", x, y); + keyboardMouseMotion(&app->keyboard, x, y); + } + } + } + if (hasEvent) { + // handle X11 events switch(event.type) { case Expose: { LOGDBG( "app: expose: x=%d, y=%d, w=%d, h=%d", @@ -252,7 +282,7 @@ int appRun(App *app) { app->y = event.xconfigure.y; app->w = event.xconfigure.width; app->h = event.xconfigure.height; - appUpdateStrut(app); + //appUpdateStrut(app); if (resized) graphResize(&app->graph); } break; @@ -304,7 +334,7 @@ int appRun(App *app) { if (app->xron && event.type == app->xrev + RRScreenChangeNotify) { LOGDBG("app: screen change event"); XRRScreenChangeNotifyEvent *ev = (XRRScreenChangeNotifyEvent*)&event; - appUpdateScreenSize(app, ev->width, ev->height); + appUpdateScreenSize(app, ev->width, ev->height, ev->rotation); } break; } @@ -354,7 +384,7 @@ void appStop(App *app, int err) { void appUpdateStrut(App *app) { - unsigned int v[4] = {}; + unsigned int v[12] = {0, 0, 0, 0, 0, app->sh, 0, app->sh, 0, app->sw, 0, app->sw}; #ifdef DOCK if (app->y == 0) v[2] = app->h; else @@ -366,19 +396,26 @@ void appUpdateStrut(App *app) { app->dockt = v[2]; app->dockb = v[3]; + LOGDBG("app: update strut: %u %u %u %u", v[0], v[1], v[2], v[3]); + Atom k = XInternAtom(app->dpy, "_NET_WM_STRUT", False); - if (!k) return; + if (k != None) + XChangeProperty(app->dpy, app->win, k, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)v, 4); - LOGDBG("app: update strut: %u %u %u %u", v[0], v[1], v[2], v[3]); - XChangeProperty(app->dpy, app->win, k, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)v, 4); + k = XInternAtom(app->dpy, "_NET_WM_STRUT_PARTIAL", False); + if (k != None) + XChangeProperty(app->dpy, app->win, k, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)v, 12); } -void appUpdateScreenSize(App *app, int sw, int sh) { +void appUpdateScreenSize(App *app, int sw, int sh, Rotation sr) { if (sw <= 0 || sh <= 0) return; + if (sw == app->sw && sh == app->sh && sr == app->sr) return; + LOGDBG("app: update screen size: w=%d, h=%d, r=%d", sw, sh, sr); + + app->sr = sr; if (sw == app->sw && sh == app->sh) return; - LOGDBG("app: update screen size: w=%d, h=%d", sw, sh); #if defined(DOCK) || (defined(LOCK_SIZE) && defined(NOBORDER) && defined(NOTITLE)) // static size case diff --git a/app.h b/app.h index 56d3e0f..00b2eb9 100644 --- a/app.h +++ b/app.h @@ -3,16 +3,20 @@ #include "common.h" +#include "touch.h" #include "graph.h" #include "input.h" #include "keyboard.h" +#include + struct App { // keep these filds at the begining for easyest static initialization Keyboard keyboard; Input input; Graph graph; + Touch touch; // these fields will be set while initialization Display *dpy; @@ -25,6 +29,7 @@ struct App { // dynamic fields int run; int sw, sh; + Rotation sr; int x, y, w, h; int dockt, dockb; int irx, iry, irw, irh; @@ -32,12 +37,12 @@ struct App { }; -int appInit(App *app); +int appInit(App *app, const char *touch_dev); void appDeinit(App *app); int appRun(App *app); void appStop(App *app, int err); void appUpdateStrut(App *app); -void appUpdateScreenSize(App *app, int sw, int sh); +void appUpdateScreenSize(App *app, int sw, int sh, Rotation sr); void appMove(App *app, int x, int y, int w, int h); void appInvalidateRect(App *app, int x, int y, int w, int h); diff --git a/build.sh b/build.sh index 4035ff9..6eca25d 100755 --- a/build.sh +++ b/build.sh @@ -8,19 +8,24 @@ FLAGS="$(pkg-config --cflags --libs x11 xft xtst xrandr)" FLAGS="$FLAGS -Wall -lm" MODE_FLAGS="-O3 -DNDEBUG" - -if [ "$1" = "-debug" ]; then - echo "debug mode" - MODE_FLAGS="-g -O0" - shift -elif [ "$1" = "-release" ]; then +while [ "$#" != "0" ]; do + if [ "$1" = "-release" ]; then + true + elif [ "$1" = "-debug" ]; then + echo "debug mode" + MODE_FLAGS="-g -O0" + elif [ "$1" = "-direct-touch" ]; then + FLAGS="$FLAGS -DDIRECT_TOUCH $(pkg-config --cflags --libs mtdev)" + elif [ "$1" = "-target" ] && [ -n "$2" ]; then + TARGET="$2" + shift + else + echo "usage: ./build.sh [-debug|-release] [-direct-touch] [-target TARGET]" + exit 1 + fi shift -fi +done -if [ ! -z "$1" ]; then - TARGET="$1" - shift -fi if [ ! -f "config.h" ]; then echo "copy config.h from example" diff --git a/config.h.example b/config.h.example index 5e4bb9e..11579bc 100644 --- a/config.h.example +++ b/config.h.example @@ -26,6 +26,9 @@ #define FONT_SIZES { 2, 3, 4, 6, 8, 10, 12, 16, 18, 24, 32, 40, 48 } #define FONT_MAX_SIZES 16 +#define TOUCH_THRESHOLD0 0.3 // threshold for detect a touch should be a bit greater +#define TOUCH_THRESHOLD1 0.2 // then threshold to detect resease + #define LABEL_MAXLEN 32 #define KEY_BORDER 2 // see also S in layout.defs.h diff --git a/maemo/build.sh b/maemo/build.sh index 9e9a0b2..1696ddb 100755 --- a/maemo/build.sh +++ b/maemo/build.sh @@ -12,7 +12,8 @@ MODE="-release" function build() { echo "copy config $BUILD_DIR/$1 -> config.h" cp "$BUILD_DIR/$1" "config.h" - ./build.sh "$MODE" "$BUILD_DIR/$2" + echo ./build.sh "$MODE" -target "$BUILD_DIR/$2" + ./build.sh "$MODE" -target "$BUILD_DIR/$2" } diff --git a/maemo/config.h.bottom b/maemo/config.h.bottom index 8da8fa1..705e73e 100644 --- a/maemo/config.h.bottom +++ b/maemo/config.h.bottom @@ -25,6 +25,9 @@ #define FONT_SIZES { 2, 3, 4, 6, 8, 10, 12, 16, 18, 24, 32, 40, 48 } #define FONT_MAX_SIZES 16 +#define TOUCH_THRESHOLD0 0.3 // threshold for detect a touch should be a bit greater +#define TOUCH_THRESHOLD1 0.2 // then threshold to detect resease + #define LABEL_MAXLEN 32 #define KEY_BORDER 2 // see also S in layout.defs.h diff --git a/maemo/config.h.dock b/maemo/config.h.dock index 679aa8a..fe1ff98 100644 --- a/maemo/config.h.dock +++ b/maemo/config.h.dock @@ -25,6 +25,9 @@ #define FONT_SIZES { 2, 3, 4, 6, 8, 10, 12, 16, 18, 24, 32, 40, 48 } #define FONT_MAX_SIZES 16 +#define TOUCH_THRESHOLD0 0.3 // threshold for detect a touch should be a bit greater +#define TOUCH_THRESHOLD1 0.2 // then threshold to detect resease + #define LABEL_MAXLEN 32 #define KEY_BORDER 2 // see also S in layout.defs.h diff --git a/maemo/config.h.top b/maemo/config.h.top index 1fba283..5719e87 100644 --- a/maemo/config.h.top +++ b/maemo/config.h.top @@ -25,6 +25,9 @@ #define FONT_SIZES { 2, 3, 4, 6, 8, 10, 12, 16, 18, 24, 32, 40, 48 } #define FONT_MAX_SIZES 16 +#define TOUCH_THRESHOLD0 0.3 // threshold for detect a touch should be a bit greater +#define TOUCH_THRESHOLD1 0.2 // then threshold to detect resease + #define LABEL_MAXLEN 32 #define KEY_BORDER 2 // see also S in layout.defs.h diff --git a/main.c b/main.c index b80c646..2e96be3 100644 --- a/main.c +++ b/main.c @@ -3,6 +3,7 @@ #include "common.c" #include "app.c" +#include "touch.c" #include "graph.c" #include "input.c" #include "keyboard.c" @@ -32,8 +33,10 @@ void terminate(int s) { appStop(&app, 1); } -int main() { - if (!appInit(&app)) +int main(int argc, char **argv) { + const char *touch_dev = argc > 1 ? argv[1] : NULL; + + if (!appInit(&app, touch_dev)) return 1; struct sigaction act = {}; diff --git a/touch.c b/touch.c new file mode 100644 index 0000000..fb28bba --- /dev/null +++ b/touch.c @@ -0,0 +1,128 @@ + +#include "touch.h" + + +#ifndef DIRECT_TOUCH + + +int touchInit(Touch *touch, App *app, const char *dev) { return 0; } +void touchDeinit(Touch *touch) { } +int touchGet(Touch *touch, int *x, int *y, int *p) { return 0; } + + +#else // DIRECT_TOUCH + + +#include +#include +#include +#include +#include + + + +static int touch_field_codes[TOUCH_FIELDS] = + { ABS_MT_POSITION_X, ABS_MT_POSITION_Y, ABS_MT_PRESSURE }; + + +int touchInit(Touch *touch, App *app, const char *dev) { + if (!app || !dev) return 0; + + LOGDBG("touch: init"); + touch->app = app; + touch->slot = 0; + touch->id = -1; + touch->pressed = 0; + + touch->fd = open(dev, O_RDONLY | O_NONBLOCK); + if (touch->fd < 0) + return LOGERR("touch: init: cannot open file: %s", dev); + + int ret = mtdev_open(&touch->dev, touch->fd); + if (ret) { + close(touch->fd); + touch->fd = 0; + return LOGERR("touch: init: cannot open device: %s", dev); + } + + for(int i = 0; i < TOUCH_FIELDS; ++i) { + int *f = touch->fields[i]; + f[0] = mtdev_get_abs_minimum(&touch->dev, touch_field_codes[i]); + f[1] = mtdev_get_abs_maximum(&touch->dev, touch_field_codes[i]); + if (f[0] >= f[1]) { + mtdev_close(&touch->dev); + close(touch->fd); + return LOGERR("touch: init: cannot get field bounds for device: %s (field %d:%d)", dev, i, touch_field_codes[i]); + } + f[2] = 0; + if (f[2] > f[1]) f[2] = f[1]; + if (f[2] < f[0]) f[2] = f[0]; + } + + return 1; +} + + +void touchDeinit(Touch *touch) { + if (touch->app) { + mtdev_close(&touch->dev); + close(touch->fd); + } + touch->app = NULL; +} + + +int touchGet(Touch *touch, int *x, int *y, int *p) { + if (!touch->app) return 0; + + struct input_event ev; + while(mtdev_get(&touch->dev, touch->fd, &ev, 1) > 0) { + if (ev.type == EV_SYN) { + // return event + double f[TOUCH_FIELDS]; + for(int i = 0; i < TOUCH_FIELDS; ++i) { + int *tf = touch->fields[i]; + f[i] = (tf[2] - tf[0])/(double)(tf[1] - tf[0]); + } + double fx = f[0], fy = f[1], fp = f[2]; + + App *app = touch->app; + if (app->sr & RR_Rotate_90) + { double v = fx; fx = fy; fy = 1-v; } + if (app->sr & RR_Rotate_180) + { fx = 1-fx; fy = 1-fy; } + if (app->sr & RR_Rotate_270) + { double v = fx; fx = 1-fy; fy = v; } + if (app->sr & RR_Reflect_X) + fx = 1-fx; + if (app->sr & RR_Reflect_Y) + fy = 1-fy; + + *x = (int)round(fx*app->sw - app->x); + *y = (int)round(fy*app->sh - app->y); + *p = touch->id >= 0 && fp > (touch->pressed ? TOUCH_THRESHOLD0 : TOUCH_THRESHOLD1); + touch->pressed = *p; + return 1; + } + + if (ev.type != EV_ABS) + continue; // ignore non ABS events + + if (ev.code == ABS_MT_SLOT) + { touch->slot = ev.value; continue; } // switch slot + if (touch->slot != 0) + continue; // handle only first slot + + if (ev.code == ABS_MT_TRACKING_ID) + { touch->id = ev.value; continue; } // set track id + + for(int i = 0; i < TOUCH_FIELDS; ++i) + if (ev.code == touch_field_codes[i]) + touch->fields[i][2] = ev.value; + } + + return 0; +} + + +#endif // DIRECT_TOUCH diff --git a/touch.h b/touch.h new file mode 100644 index 0000000..fd8f258 --- /dev/null +++ b/touch.h @@ -0,0 +1,32 @@ +#ifndef TOUCH_H +#define TOUCH_H + + +#include "common.h" + +#ifdef DIRECT_TOUCH +#include +#endif + + +#define TOUCH_FIELDS 3 + + +typedef struct Touch { + App *app; + int fd; + #ifdef DIRECT_TOUCH + struct mtdev dev; + #endif + + int slot, id, pressed; + int fields[TOUCH_FIELDS][3]; +} Touch; + + +int touchInit(Touch *touch, App *app, const char *dev); +void touchDeinit(Touch *touch); +int touchGet(Touch *touch, int *x, int *y, int *p); + + +#endif