--- panel.cpp.orig 2014-08-12 18:08:28.000000000 +0200 +++ panel.cpp 2014-08-12 18:09:20.000000000 +0200 @@ -13,6 +13,7 @@ #include #include #include "panel.h" +#include "util.h" using namespace std; @@ -78,6 +79,15 @@ XftColorAllocName(Dpy, visual, colormap, cfg->getOption("session_shadow_color").c_str(), &sessionshadowcolor); + /* Build XIC and XIM to be able to get unicode string from keyboard events */ + char classname = 0; + displayIc = NULL; + displayIm = XOpenIM(Dpy, NULL, &classname, &classname); + if(displayIm) { + displayIc = XCreateIC(displayIm, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, + XNResourceName, &classname, + XNResourceClass, &classname, NULL); + } /* Load properties from config / theme */ input_name_x = cfg->getIntOption("input_name_x"); input_name_y = cfg->getIntOption("input_name_y"); @@ -91,6 +101,8 @@ input_pass_y = input_name_y; } + Reset(); + /* Load panel and background image */ string panelpng = ""; panelpng = panelpng + themedir +"/panel.png"; @@ -210,6 +222,12 @@ Visual* visual = DefaultVisual(Dpy, Scr); Colormap colormap = DefaultColormap(Dpy, Scr); + if(displayIc) { + XDestroyIC(displayIc); + } + if(displayIm) { + XCloseIM(displayIm); + } XftColorFree(Dpy, visual, colormap, &inputcolor); XftColorFree(Dpy, visual, colormap, &inputshadowcolor); XftColorFree(Dpy, visual, colormap, &welcomecolor); @@ -289,7 +307,8 @@ XftDraw *draw = XftDrawCreate(Dpy, Win, DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr)); - XftTextExtents8(Dpy, msgfont, reinterpret_cast(message.c_str()), + + XftTextExtentsUtf8(Dpy, msgfont, reinterpret_cast(message.c_str()), message.length(), &extents); string cfgX = cfg->getOption("passwd_feedback_x"); @@ -300,7 +319,7 @@ int msg_y = Cfg::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.height); OnExpose(); - SlimDrawString8(draw, &msgcolor, msgfont, msg_x, msg_y, message, + SlimDrawStringUtf8(draw, &msgcolor, msgfont, msg_x, msg_y, message, &msgshadowcolor, shadowXOffset, shadowYOffset); if (cfg->getOption("bell") == "1") @@ -312,7 +331,7 @@ OnExpose(); // The message should stay on the screen even after the password field is // cleared, methinks. I don't like this solution, but it works. - SlimDrawString8(draw, &msgcolor, msgfont, msg_x, msg_y, message, + SlimDrawStringUtf8(draw, &msgcolor, msgfont, msg_x, msg_y, message, &msgshadowcolor, shadowXOffset, shadowYOffset); XSync(Dpy, True); XftDrawDestroy(draw); @@ -330,9 +349,8 @@ draw = XftDrawCreate(Dpy, Root, DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr)); - XftTextExtents8(Dpy, msgfont, - reinterpret_cast(text.c_str()), - text.length(), &extents); + XftTextExtentsUtf8(Dpy, msgfont, + reinterpret_cast(text.c_str()), text.length(), &extents); cfgX = cfg->getOption("msg_x"); cfgY = cfg->getOption("msg_y"); int shadowXOffset = cfg->getIntOption("msg_shadow_xoffset"); @@ -347,9 +365,8 @@ msg_y = Cfg::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.height); } - SlimDrawString8 (draw, &msgcolor, msgfont, msg_x, msg_y, - text, - &msgshadowcolor, + SlimDrawStringUtf8(draw, &msgcolor, msgfont, msg_x, msg_y, + text, &msgshadowcolor, shadowXOffset, shadowYOffset); XFlush(Dpy); XftDrawDestroy(draw); @@ -383,24 +400,27 @@ } void Panel::Cursor(int visible) { - const char* text = NULL; - int xx = 0, yy = 0, y2 = 0, cheight = 0; + const uint16_t* text = NULL; + int xx = 0, yy = 0, y2 = 0, cheight = 0, textLen = 0; const char* txth = "Wj"; /* used to get cursor height */ if (mode == Mode_Lock) { - text = HiddenPasswdBuffer.c_str(); + text = hiddenPasswdBuffer; + textLen = passwdBufferLen; xx = input_pass_x; yy = input_pass_y; } else { switch(field) { case Get_Passwd: - text = HiddenPasswdBuffer.c_str(); + text = hiddenPasswdBuffer; + textLen = passwdBufferLen; xx = input_pass_x; yy = input_pass_y; break; case Get_Name: - text = NameBuffer.c_str(); + text = nameBuffer; + textLen = nameBufferLen; xx = input_name_x; yy = input_name_y; break; @@ -411,7 +431,7 @@ XftTextExtents8(Dpy, font, (XftChar8*)txth, strlen(txth), &extents); cheight = extents.height; y2 = yy - extents.y + extents.height; - XftTextExtents8(Dpy, font, (XftChar8*)text, strlen(text), &extents); + XftTextExtents16(Dpy, font, (XftChar16*)text, textLen, &extents); xx += extents.width; if(visible == SHOW) { @@ -478,27 +498,25 @@ XClearWindow(Dpy, Win); if (input_pass_x != input_name_x || input_pass_y != input_name_y){ - SlimDrawString8 (draw, &inputcolor, font, input_name_x, input_name_y, - NameBuffer, - &inputshadowcolor, + SlimDrawString16(draw, &inputcolor, font, input_name_x, input_name_y, + nameBuffer, nameBufferLen, &inputshadowcolor, inputShadowXOffset, inputShadowYOffset); - SlimDrawString8 (draw, &inputcolor, font, input_pass_x, input_pass_y, - HiddenPasswdBuffer, - &inputshadowcolor, + SlimDrawString16(draw, &inputcolor, font, input_pass_x, input_pass_y, + hiddenPasswdBuffer, passwdBufferLen, &inputshadowcolor, inputShadowXOffset, inputShadowYOffset); } else { /*single input mode */ switch(field) { case Get_Passwd: - SlimDrawString8 (draw, &inputcolor, font, + SlimDrawString16(draw, &inputcolor, font, input_pass_x, input_pass_y, - HiddenPasswdBuffer, + hiddenPasswdBuffer, passwdBufferLen, &inputshadowcolor, inputShadowXOffset, inputShadowYOffset); break; case Get_Name: - SlimDrawString8 (draw, &inputcolor, font, + SlimDrawString16(draw, &inputcolor, font, input_name_x, input_name_y, - NameBuffer, + nameBuffer, nameBufferLen, &inputshadowcolor, inputShadowXOffset, inputShadowYOffset); break; @@ -510,35 +528,105 @@ ShowText(); } -void Panel::EraseLastChar(string &formerString) { +int Panel::FieldEraseLastChar(const uint16_t **buf, int *len) { + + static const uint16_t emptyBuf = 0; + int formerTextBufferLen = 0; + switch(field) { - case GET_NAME: - if (! NameBuffer.empty()) { - formerString=NameBuffer; - NameBuffer.erase(--NameBuffer.end()); + case Get_Name: + formerTextBufferLen = nameBufferLen; + if (nameBufferLen > 0) { + nameBufferLen--; } + *buf = nameBuffer; + *len = nameBufferLen; break; - case GET_PASSWD: - if (!PasswdBuffer.empty()) { - formerString=HiddenPasswdBuffer; - PasswdBuffer.erase(--PasswdBuffer.end()); - HiddenPasswdBuffer.erase(--HiddenPasswdBuffer.end()); + case Get_Passwd: + formerTextBufferLen = passwdBufferLen; + if (passwdBufferLen > 0) { + passwdBufferLen--; + passwdBuffer[passwdBufferLen] = 0; } + *buf = hiddenPasswdBuffer; + *len = passwdBufferLen; + break; + + default: + *buf = &emptyBuf; + *len = 0; break; } + return formerTextBufferLen; } +int Panel::FieldClear(const uint16_t **buf, int *len) { + + static const uint16_t emptyBuf = 0; + int formerTextBufferLen = 0; + + switch(field) { + case Get_Name: + formerTextBufferLen = nameBufferLen; + nameBufferLen = 0; + *buf = nameBuffer; + *len = nameBufferLen; + break; + + case Get_Passwd: + formerTextBufferLen = passwdBufferLen; + memset(passwdBuffer, 0, sizeof(passwdBuffer)); + passwdBufferLen = 0; + *buf = hiddenPasswdBuffer; + *len = passwdBufferLen; + break; + + default: + *buf = &emptyBuf; + *len = 0; + break; + } + return formerTextBufferLen; +} + +/* Check if the input character is allowed */ +bool Panel::isUtf16CharAllowed(uint16_t c) { + return ((0x020 <= c && c <= 0x07E) || (0x0A0 <= c && c != 0x0AD)); +} + +#define SIZE_BUFFER_KEY_PRESS 64 + bool Panel::OnKeyPress(XEvent& event) { - char ascii; + int formerTextBufferLen = -1; + int textBufferLen = -1; + const uint16_t *textBuffer = NULL; KeySym keysym; + int nbReadBuf = -1; + uint16_t utf16buf[SIZE_BUFFER_KEY_PRESS]; + if(displayIc) + { + Status status; + char databuf[SIZE_BUFFER_KEY_PRESS]; + nbReadBuf = Xutf8LookupString(displayIc, &event.xkey, databuf, + SIZE_BUFFER_KEY_PRESS, &keysym, &status); + if(nbReadBuf > 0) { + nbReadBuf = Util::utf8ToUtf16(databuf, nbReadBuf, + utf16buf, SIZE_BUFFER_KEY_PRESS); + } + } + else + { XComposeStatus compstatus; - int xx = 0; - int yy = 0; - string text; - string formerString = ""; + char databuf[SIZE_BUFFER_KEY_PRESS]; + nbReadBuf = XLookupString(&event.xkey, databuf, + SIZE_BUFFER_KEY_PRESS, &keysym, &compstatus); + if(nbReadBuf > 0) { + nbReadBuf = Util::utf8ToUtf16(databuf, nbReadBuf, + utf16buf, SIZE_BUFFER_KEY_PRESS); + } + } - XLookupString(&event.xkey, &ascii, 1, &keysym, &compstatus); switch(keysym){ case XK_F1: SwitchSession(); @@ -553,17 +641,17 @@ case XK_KP_Enter: if (field==Get_Name){ /* Don't allow an empty username */ - if (NameBuffer.empty()) return true; + if (nameBufferLen <= 0) return true; - if (NameBuffer==CONSOLE_STR){ + if (Util::utf16EqualToAscii(CONSOLE_STR, nameBuffer, nameBufferLen)) { action = Console; - } else if (NameBuffer==HALT_STR){ + } else if (Util::utf16EqualToAscii(HALT_STR, nameBuffer, nameBufferLen)) { action = Halt; - } else if (NameBuffer==REBOOT_STR){ + } else if (Util::utf16EqualToAscii(REBOOT_STR, nameBuffer, nameBufferLen)) { action = Reboot; - } else if (NameBuffer==SUSPEND_STR){ + } else if (Util::utf16EqualToAscii(SUSPEND_STR, nameBuffer, nameBufferLen)) { action = Suspend; - } else if (NameBuffer==EXIT_STR){ + } else if (Util::utf16EqualToAscii(EXIT_STR, nameBuffer, nameBufferLen)) { action = Exit; } else{ if (mode == Mode_DM) @@ -581,80 +669,80 @@ switch(keysym){ case XK_Delete: case XK_BackSpace: - EraseLastChar(formerString); + formerTextBufferLen = FieldEraseLastChar(&textBuffer, &textBufferLen); break; case XK_w: case XK_u: if (reinterpret_cast(event).state & ControlMask) { - switch(field) { - case Get_Passwd: - formerString = HiddenPasswdBuffer; - HiddenPasswdBuffer.clear(); - PasswdBuffer.clear(); - break; - case Get_Name: - formerString = NameBuffer; - NameBuffer.clear(); - break; - } + formerTextBufferLen = FieldClear(&textBuffer, &textBufferLen); break; } case XK_h: if (reinterpret_cast(event).state & ControlMask) { - EraseLastChar(formerString); + formerTextBufferLen = FieldEraseLastChar(&textBuffer, &textBufferLen); break; } /* Deliberate fall-through */ default: - if (isprint(ascii) && (keysym < XK_Shift_L || keysym > XK_Hyper_R)){ + if(nbReadBuf > 0) { switch(field) { - case GET_NAME: - formerString=NameBuffer; - if (NameBuffer.length() < INPUT_MAXLENGTH_NAME-1){ - NameBuffer.append(&ascii,1); - }; + case Get_Name: + formerTextBufferLen = nameBufferLen; + for(int i = 0; i < nbReadBuf && + nameBufferLen < INPUT_MAXLENGTH_NAME; i++) { + + if(isUtf16CharAllowed(utf16buf[i])) { + nameBuffer[nameBufferLen++] = utf16buf[i]; + } + } + textBuffer = nameBuffer; + textBufferLen = nameBufferLen; break; - case GET_PASSWD: - formerString=HiddenPasswdBuffer; - if (PasswdBuffer.length() < INPUT_MAXLENGTH_PASSWD-1){ - PasswdBuffer.append(&ascii,1); - HiddenPasswdBuffer.append("*"); - }; + + case Get_Passwd: + formerTextBufferLen = passwdBufferLen; + for(int i = 0; i < nbReadBuf && + passwdBufferLen < INPUT_MAXLENGTH_PASSWD; i++) { + + if(isUtf16CharAllowed(utf16buf[i])) { + passwdBuffer[passwdBufferLen] = utf16buf[i]; + hiddenPasswdBuffer[passwdBufferLen++] = (uint16_t)'*'; + } + } + textBuffer = hiddenPasswdBuffer; + textBufferLen = passwdBufferLen; break; - }; - }; + } + } break; }; - XGlyphInfo extents; - XftDraw *draw = XftDrawCreate(Dpy, Win, - DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr)); + int xx = 0, yy = 0; + if (formerTextBufferLen > 0 || textBufferLen > 0) { switch(field) { case Get_Name: - text = NameBuffer; xx = input_name_x; yy = input_name_y; break; case Get_Passwd: - text = HiddenPasswdBuffer; xx = input_pass_x; yy = input_pass_y; break; } + } - if (!formerString.empty()){ + if (formerTextBufferLen > 0) { + XGlyphInfo extents; const char* txth = "Wj"; /* get proper maximum height ? */ XftTextExtents8(Dpy, font, reinterpret_cast(txth), strlen(txth), &extents); int maxHeight = extents.height; - XftTextExtents8(Dpy, font, - reinterpret_cast(formerString.c_str()), - formerString.length(), &extents); + XftTextExtents16(Dpy, font, (XftChar16*)textBuffer, formerTextBufferLen, &extents); int maxLength = extents.width; if (mode == Mode_Lock) @@ -666,14 +754,15 @@ maxLength + 6, maxHeight + 6, false); } - if (!text.empty()) { - SlimDrawString8 (draw, &inputcolor, font, xx, yy, - text, - &inputshadowcolor, - inputShadowXOffset, inputShadowYOffset); + if(textBufferLen > 0) { + XftDraw *draw = XftDrawCreate(Dpy, Win, DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr)); + if(draw != NULL) { + SlimDrawString16(draw, &inputcolor, font, xx, yy, textBuffer, textBufferLen, + &inputshadowcolor, inputShadowXOffset, inputShadowYOffset); + XftDrawDestroy(draw); + } } - XftDrawDestroy (draw); Cursor(SHOW); return true; } @@ -690,7 +779,7 @@ XftDraw *draw = XftDrawCreate(Dpy, Win, DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr)); /* welcome message */ - XftTextExtents8(Dpy, welcomefont, (XftChar8*)welcome_message.c_str(), + XftTextExtentsUtf8(Dpy, welcomefont, (XftChar8*)welcome_message.c_str(), strlen(welcome_message.c_str()), &extents); cfgX = cfg->getOption("welcome_x"); cfgY = cfg->getOption("welcome_y"); @@ -700,9 +789,8 @@ welcome_x = Cfg::absolutepos(cfgX, image->Width(), extents.width); welcome_y = Cfg::absolutepos(cfgY, image->Height(), extents.height); if (welcome_x >= 0 && welcome_y >= 0) { - SlimDrawString8 (draw, &welcomecolor, welcomefont, - welcome_x, welcome_y, - welcome_message, + SlimDrawStringUtf8(draw, &welcomecolor, welcomefont, + welcome_x, welcome_y, welcome_message, &welcomeshadowcolor, shadowXOffset, shadowYOffset); } @@ -710,7 +798,7 @@ string msg; if ((!singleInputMode|| field == Get_Passwd) && mode == Mode_DM) { msg = cfg->getOption("password_msg"); - XftTextExtents8(Dpy, enterfont, (XftChar8*)msg.c_str(), + XftTextExtentsUtf8(Dpy, enterfont, (XftChar8*)msg.c_str(), strlen(msg.c_str()), &extents); cfgX = cfg->getOption("password_x"); cfgY = cfg->getOption("password_y"); @@ -719,14 +807,14 @@ password_x = Cfg::absolutepos(cfgX, image->Width(), extents.width); password_y = Cfg::absolutepos(cfgY, image->Height(), extents.height); if (password_x >= 0 && password_y >= 0){ - SlimDrawString8 (draw, &entercolor, enterfont, password_x, password_y, + SlimDrawStringUtf8(draw, &entercolor, enterfont, password_x, password_y, msg, &entershadowcolor, shadowXOffset, shadowYOffset); } } if (!singleInputMode|| field == Get_Name) { msg = cfg->getOption("username_msg"); - XftTextExtents8(Dpy, enterfont, (XftChar8*)msg.c_str(), + XftTextExtentsUtf8(Dpy, enterfont, (XftChar8*)msg.c_str(), strlen(msg.c_str()), &extents); cfgX = cfg->getOption("username_x"); cfgY = cfg->getOption("username_y"); @@ -735,7 +823,7 @@ username_x = Cfg::absolutepos(cfgX, image->Width(), extents.width); username_y = Cfg::absolutepos(cfgY, image->Height(), extents.height); if (username_x >= 0 && username_y >= 0){ - SlimDrawString8 (draw, &entercolor, enterfont, username_x, username_y, + SlimDrawStringUtf8(draw, &entercolor, enterfont, username_x, username_y, msg, &entershadowcolor, shadowXOffset, shadowYOffset); } } @@ -776,7 +864,7 @@ XftDraw *draw = XftDrawCreate(Dpy, Root, DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr)); - XftTextExtents8(Dpy, sessionfont, reinterpret_cast(currsession.c_str()), + XftTextExtentsUtf8(Dpy, sessionfont, reinterpret_cast(currsession.c_str()), currsession.length(), &extents); msg_x = cfg->getOption("session_x"); msg_y = cfg->getOption("session_y"); @@ -785,16 +873,37 @@ int shadowXOffset = cfg->getIntOption("session_shadow_xoffset"); int shadowYOffset = cfg->getIntOption("session_shadow_yoffset"); - SlimDrawString8(draw, &sessioncolor, sessionfont, x, y, - currsession, - &sessionshadowcolor, - shadowXOffset, shadowYOffset); + SlimDrawStringUtf8(draw, &sessioncolor, sessionfont, x, y, + currsession, &sessionshadowcolor, shadowXOffset, shadowYOffset); XFlush(Dpy); XftDrawDestroy(draw); } +void Panel::SlimDrawString16(XftDraw *d, XftColor *color, XftFont *font, + int x, int y, const uint16_t *str, int strLen, + XftColor* shadowColor, int xOffset, int yOffset) +{ + int calc_x = 0; + int calc_y = 0; + if (mode == Mode_Lock) { + calc_x = viewport.x; + calc_y = viewport.y; + } + + if (xOffset && yOffset) { + XftDrawString16(d, shadowColor, font, + x + xOffset + calc_x, + y + yOffset + calc_y, + (XftChar16*)str, strLen); + } + + XftDrawString16(d, color, font, + x + calc_x, + y + calc_y, + (XftChar16*)str, strLen); +} -void Panel::SlimDrawString8(XftDraw *d, XftColor *color, XftFont *font, +void Panel::SlimDrawStringUtf8(XftDraw *d, XftColor *color, XftFont *font, int x, int y, const string& str, XftColor* shadowColor, int xOffset, int yOffset) @@ -831,28 +940,31 @@ } void Panel::ResetName(void){ - NameBuffer.clear(); + nameBufferLen = 0; + memset(nameBuffer, 0, sizeof(nameBuffer)); } void Panel::ResetPasswd(void){ - PasswdBuffer.clear(); - HiddenPasswdBuffer.clear(); + passwdBufferLen = 0; + memset(passwdBuffer, 0, sizeof(passwdBuffer)); + memset(hiddenPasswdBuffer, 0, sizeof(hiddenPasswdBuffer)); } void Panel::SetName(const string& name){ - NameBuffer=name; + nameBufferLen = Util::utf8ToUtf16(name.c_str(), name.length(), + nameBuffer, INPUT_MAXLENGTH_NAME); if (mode == Mode_DM) action = Login; else action = Lock; } -const string& Panel::GetName(void) const{ - return NameBuffer; +const string Panel::GetName(void) const{ + return Util::utf16BufToUtf8String(nameBuffer, nameBufferLen); } -const string& Panel::GetPasswd(void) const{ - return PasswdBuffer; +const string Panel::GetPasswd(void) const{ + return Util::utf16BufToUtf8String(passwdBuffer, passwdBufferLen); } Rectangle Panel::GetPrimaryViewport() {