config.h.in | 6 ++ configure.in | 20 ++++++ xlock/XLock.ad | 4 + xlock/mode.h | 13 ++++ xlock/resource-msg-en.h | 2 + xlock/resource.c | 17 ++++++ xlock/xlock.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 210 insertions(+), 0 deletions(-) diff --git a/.gear/tags/list b/.gear/tags/list new file mode 100644 index 0000000..e69de29 diff --git a/config.h.in b/config.h.in index 10f1fbb..7ae7dce 100644 --- a/config.h.in +++ b/config.h.in @@ -400,3 +400,9 @@ /* Define next line if you do not like the time in password window */ #undef NO_TIME + +/* Define to enable keyboard monitor */ +#undef USE_KBD_MON + +/* Define to enable double buffer rendering */ +#undef USE_DBE diff --git a/configure.ac b/configure.ac index cac489c..bcf4f37 100644 --- a/configure.ac +++ b/configure.ac @@ -4524,6 +4524,26 @@ else AC_MSG_RESULT([no setuid/setgid install]) fi +AC_ARG_ENABLE(kbdmon, [ --enable-kbdmon enable keyboard state monitor (experimental)],kbdmon=$enableval,kbdmon=no) +if test "$kbdmon" = yes; then + AC_CHECK_HEADER(X11/XKBlib.h, + [AC_MSG_RESULT([enabling keyboard state monitor]) + AC_DEFINE(USE_KBD_MON)], + AC_MSG_RESULT([XKB X11 extension not found -- not enabling keyboard state monitor])) +fi + +AC_ARG_ENABLE(dbe, [ --enable-dbe enable X11 double-buffer extension],dbe=$enableval,dbe=yes) +if test "$dbe" = yes; then + AC_CHECK_HEADERS(X11/Xlib.h X11/extensions/Xdbe.h, + [AC_MSG_RESULT([enabling double buffer X11 extension]) + AC_DEFINE(USE_DBE)], + AC_MSG_RESULT([Xdbe X11 extension not found]), + [[#if HAVE_X11_XLIB_H + # include + #endif + ]]) +fi + DEPEND=makedepend DEPEND_FLAGS= DEPEND_DEFINES= diff --git a/xlock/XLock.ad b/xlock/XLock.ad index 0dc2b6b..444a6c5 100644 --- a/xlock/XLock.ad +++ b/xlock/XLock.ad @@ -92,12 +92,16 @@ XLock.logoutAuto: 0 ! 0 defaults to maximum defined value XLock.logoutButton: 0 +! Enables the keyboard monitor. +XLock.enablekbdmon: on + XLock.username: Name: XLock.password: Password: XLock.info: Enter password to unlock; select icon to lock. XLock.validate: Validating login... XLock.invalid: Invalid login. XLock.invalidCapsLock: Invalid login, Caps Lock on. +XLock.kbdmonLabel: Keyboard state: XLock.logoutButtonLabel: Click here to logout XLock.logoutButtonHelp: \ You may log out this session if no terminals are available.\n\ diff --git a/xlock/mode.h b/xlock/mode.h index 9fde092..f2b662d 100644 --- a/xlock/mode.h +++ b/xlock/mode.h @@ -245,6 +245,10 @@ typedef struct { GC mbgc; } mboxInfo; +#ifdef USE_DBE +#include +#endif + typedef struct { Visual *visual; int visualclass; /* visual class name of current window */ @@ -258,6 +262,15 @@ typedef struct { #ifdef USE_BUTTON_LOGOUT Window button; #endif +#ifdef USE_KBD_MON + Window kbdmonw; /* window for keyboard monitor */ + int kbdmonww; /* keyboard monitor window width */ + int kbdmonwh; /* keyboard monitor window height */ +#ifdef USE_DBE + XdbeBackBuffer kbdmonbb; /* keyboard monitor window back buffer */ + XdbeSwapInfo kbdmonswp; /* data for swapping keyboard monitor back buffer */ +#endif +#endif GC gc; /* graphics context for animation */ GC textgc; /* graphics context used for text rendering */ GC plantextgc; /* graphics context for plan message rendering */ diff --git a/xlock/resource-msg-en.h b/xlock/resource-msg-en.h index 61a5782..7a58108 100644 --- a/xlock/resource-msg-en.h +++ b/xlock/resource-msg-en.h @@ -31,4 +31,6 @@ */ #define DEF_FAIL "Auto-logout failed" +#define DEF_KBD_MON "Keyboard state: " + #endif /* __RESOURCE_MSG_EN__ */ diff --git a/xlock/resource.c b/xlock/resource.c index 1f72d73..074d67d 100644 --- a/xlock/resource.c +++ b/xlock/resource.c @@ -398,6 +398,11 @@ static XrmOptionDescRec genTable[] = {(char *) "-invalidCapsLock", (char *) ".invalidCapsLock", XrmoptionSepArg, (caddr_t) NULL}, {(char *) "-geometry", (char *) ".geometry", XrmoptionSepArg, (caddr_t) NULL}, {(char *) "-icongeometry", (char *) ".icongeometry", XrmoptionSepArg, (caddr_t) NULL}, +#ifdef USE_KBD_MON + {(char *) "-enablekbdmon", (char *) ".enablekbdmon", XrmoptionNoArg, (caddr_t) "on"}, + {(char *) "+enablekbdmon", (char *) ".enablekbdmon", XrmoptionNoArg, (caddr_t) "off"}, + {(char *) "-kbdmonLabel", (char *) ".kbdmonLabel", XrmoptionSepArg, (caddr_t) NULL}, +#endif #ifdef FX {(char *) "-glgeometry", (char *) ".glgeometry", XrmoptionSepArg, (caddr_t) NULL}, #endif @@ -826,6 +835,10 @@ char *logoutButtonHelp; char *logoutFailedString; #endif +#ifdef USE_KBD_MON +Bool enable_kbdmon = True; +char *kbdmon_label; +#endif #ifdef USE_DTSAVER Bool dtsaver; @@ -960,6 +973,10 @@ static argtype genvars[] = {(void *) & logoutFailedString, (char *) "logoutFailedString", "LogoutFailedString", (char *) DEF_FAIL, t_String}, #endif +#ifdef USE_KBD_MON + {(void *) & enable_kbdmon, (char *) "enablekbdmon", (char *) "EnableKbdMon", (char *) "off", t_Bool}, + {(void *) & kbdmon_label, (char *) "kbdmonLabel", "kbdmonLabel", (char *) DEF_KBD_MON, t_String}, +#endif #ifdef USE_SOUND {(void *) & locksound, (char *) "locksound", (char *) "LockSound", (char *) DEF_LOCKSOUND, t_String}, {(void *) & infosound, (char *) "infosound", (char *) "InfoSound", (char *) DEF_INFOSOUND, t_String}, diff --git a/xlock/xlock.c b/xlock/xlock.c index 9fa2970..63db08e 100644 --- a/xlock/xlock.c +++ b/xlock/xlock.c @@ -859,6 +859,11 @@ extern char *logoutFailedString; #endif +#ifdef USE_KBD_MON +extern Bool enable_kbdmon; +extern char *kbdmon_label; +#endif + #ifdef USE_DTSAVER extern Bool dtsaver; @@ -994,6 +999,9 @@ extern int checkDynamic(); #endif +#include +#include + #if defined( HAVE_SYSLOG_H ) && defined( USE_SYSLOG ) static void syslogStart(void) @@ -1990,6 +1998,102 @@ runMainLoop(int maxtime, int iconscreen) #endif /* !USE_OLD_EVENT_LOOP */ +#ifdef USE_KBD_MON +void putKeyboardIndicator(const char *name, int *inv, Drawable dr, int *x, int *y) +{ + char delim[] = " + "; + int namelen = strlen(name); + int namew = XTextWidth(planfont, name, strlen(name)); + int delimlen = strlen(delim); + int delimw = XTextWidth(planfont, " + ", strlen(delim)); + + if (*inv) { + XSetForeground(dsp, Scr[screen].plantextgc, Scr[screen].fg_pixel); + XDrawString(dsp, dr, Scr[screen].plantextgc, *x, *y, delim, delimlen); + *x += delimw; + } + XSetForeground(dsp, Scr[screen].gc, Scr[screen].fg_pixel); + XFillRectangle(dsp, dr, Scr[screen].gc, + *x, *y - planFontHeight + 1, namew + 2, planFontHeight + 2); + XSetForeground(dsp, Scr[screen].plantextgc, Scr[screen].bg_pixel); + XDrawString(dsp, dr, Scr[screen].plantextgc, *x + 1, *y, name, namelen); + *x += namew + 2; + *inv = 1; + XSetForeground(dsp, Scr[screen].plantextgc, Scr[screen].fg_pixel); +} + +void updateKeyboardMonitor() +{ + XkbDescPtr kbd_desc = NULL; + XkbStateRec kbd_state; + char *group = NULL; + int lablen = strlen(kbdmon_label); + int x = 0; + int y = planFontHeight - 1; + int inv = 0; + Drawable dr; +#ifdef USE_MB + XFontSet backfontset; +#endif + +#ifdef USE_DBE + if (Scr[screen].kbdmonbb) { + dr = Scr[screen].kbdmonbb; + } else { + dr = Scr[screen].kbdmonw; + } +#else + dr = Scr[screen].kbdmonw; +#endif +#ifdef USE_MB + backfontset = fontset; + fontset = planfontset; +#endif + + { + int opcode_rtrn, error_rtrn, major, minor, event; + XSetForeground(dsp, Scr[screen].gc, Scr[screen].bg_pixel); + XFillRectangle(dsp, dr, Scr[screen].gc, + 0, 0, Scr[screen].kbdmonww, Scr[screen].kbdmonwh); + XDrawString(dsp, dr, Scr[screen].plantextgc, + x, y, kbdmon_label, lablen); + x += XTextWidth(planfont, kbdmon_label, lablen); + if (XkbQueryExtension(dsp, &opcode_rtrn, &event, &error_rtrn, + &major, &minor)) + { + XkbSelectEventDetails(dsp, XkbUseCoreKbd, XkbStateNotify, + XkbGroupStateMask, XkbGroupStateMask); + XkbGetState(dsp, XkbUseCoreKbd, &kbd_state); + kbd_desc = XkbGetKeyboard(dsp, XkbAllComponentsMask, XkbUseCoreKbd); + if (kbd_desc != NULL) { + if (kbd_desc->names != NULL) { + group = XGetAtomName(dsp, kbd_desc->names->groups[kbd_state.group]); + /* TODO: convert county names to codes + * (/usr/share/X11/xkb/rules/xorg.xml might help). */ + } + } + } + if (group != NULL) { + putKeyboardIndicator(group, &inv, dr, &x, &y); + } + if ((kbd_state.mods & LockMask) > 0) { + putKeyboardIndicator("CL", &inv, dr, &x, &y); + } + if (kbd_desc != NULL) { + XkbFreeKeyboard(kbd_desc, 0, 1); + } + } +#ifdef USE_DBE + if (Scr[screen].kbdmonswp.swap_window) { + XdbeSwapBuffers(dsp, &Scr[screen].kbdmonswp, 1); + } +#endif +#ifdef USE_MB + fontset = backfontset; +#endif +} +#endif /* USE_KBD_MON */ + static int ReadXString(char *s, int slen, Bool *capsLock #ifdef GLOBAL_UNLOCK @@ -2238,6 +2342,12 @@ ReadXString(char *s, int slen, Bool *capsLock break; } first_key = 0; +#ifdef USE_KBD_MON + /* If we should indicate keyboard modes */ + if (enable_kbdmon) { + updateKeyboardMonitor(); + } +#endif } } @@ -2448,6 +2558,15 @@ getPassword(void) putText(dsp, Scr[screen].window, Scr[screen].textgc, text_krbinfo, False, left, &x, &y); else #endif /* HAVE_KRB5 */ +#ifdef USE_KBD_MON + if (enable_kbdmon) { + XMoveWindow(dsp, Scr[screen].kbdmonw, x, y - fontHeight + planFontHeight/2 + 1); + y += planFontHeight + 8; + XMapWindow(dsp, Scr[screen].kbdmonw); + XRaiseWindow(dsp, Scr[screen].kbdmonw); + updateKeyboardMonitor(); + } +#endif putText(dsp, Scr[screen].window, Scr[screen].textgc, text_info, False, left, &x, &y); putText(dsp, Scr[screen].window, Scr[screen].textgc, "\n", False, left, &x, &y); if (count_failed > 0) { @@ -2751,6 +2870,11 @@ getPassword(void) #ifdef USE_BUTTON_LOGOUT XUnmapWindow(dsp, Scr[screen].button); #endif +#ifdef USE_KBD_MON + if (enable_kbdmon) { + XUnmapWindow(dsp, Scr[screen].kbdmonw); + } +#endif if (!fullscreen) XConfigureWindow(dsp, Scr[screen].window, sizeconfiguremask, &minisizeconfigure); @@ -3808,6 +3932,30 @@ main(int argc, char **argv) CIMASK, &xswa); } #endif +#ifdef USE_KBD_MON + if (enable_kbdmon) { + Scr[screen].kbdmonww = DisplayWidth(dsp, screen) - Scr[screen].iconpos.x - \ + iconwidth - font->max_bounds.width; + Scr[screen].kbdmonwh = planFontHeight + 2; + Scr[screen].kbdmonw = XCreateWindow(dsp, Scr[screen].window, + Scr[screen].iconpos.x + iconwidth + font->max_bounds.width, + 0, Scr[screen].kbdmonww, Scr[screen].kbdmonwh, 0, (int) CopyFromParent, + InputOutput, CopyFromParent, CIMASK, &xswa); +#ifdef USE_DBE + Scr[screen].kbdmonswp.swap_window = 0; + { + int major, minor; + if (XdbeQueryExtension(dsp, &major, &minor)) { + Scr[screen].kbdmonswp.swap_window = Scr[screen].kbdmonw; + Scr[screen].kbdmonswp.swap_action = 0; + Scr[screen].kbdmonbb = XdbeAllocateBackBufferName(dsp, + Scr[screen].kbdmonswp.swap_window, + Scr[screen].kbdmonswp.swap_action); + } + } +#endif + } +#endif /* USE_KBD_MON */ } XMapWindow(dsp, Scr[screen].window); XRaiseWindow(dsp, Scr[screen].window);