From owner-svn-ports-head@FreeBSD.ORG Sat Sep 20 19:07:38 2014 Return-Path: Delivered-To: svn-ports-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 609D1A5E; Sat, 20 Sep 2014 19:07:38 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 4A265DAF; Sat, 20 Sep 2014 19:07:38 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s8KJ7cuQ062867; Sat, 20 Sep 2014 19:07:38 GMT (envelope-from marino@FreeBSD.org) Received: (from marino@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id s8KJ7bmq062860; Sat, 20 Sep 2014 19:07:37 GMT (envelope-from marino@FreeBSD.org) Message-Id: <201409201907.s8KJ7bmq062860@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: marino set sender to marino@FreeBSD.org using -f From: John Marino Date: Sat, 20 Sep 2014 19:07:37 +0000 (UTC) To: ports-committers@freebsd.org, svn-ports-all@freebsd.org, svn-ports-head@freebsd.org Subject: svn commit: r368677 - in head/x11/slim: . files X-SVN-Group: ports-head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-ports-head@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for the ports tree for head List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 20 Sep 2014 19:07:38 -0000 Author: marino Date: Sat Sep 20 19:07:37 2014 New Revision: 368677 URL: http://svnweb.freebsd.org/changeset/ports/368677 QAT: https://qat.redports.org/buildarchive/r368677/ Log: x11/slim: Add non-default UTF-8 character input support PR: 192783 Submitted by: DaLynX Refined by: maintainer (Henry Hu) Added: head/x11/slim/files/extra-patch-utf8 (contents, props changed) Modified: head/x11/slim/Makefile head/x11/slim/files/patch-slim.conf head/x11/slim/files/pkg-message.in Modified: head/x11/slim/Makefile ============================================================================== --- head/x11/slim/Makefile Sat Sep 20 19:02:30 2014 (r368676) +++ head/x11/slim/Makefile Sat Sep 20 19:07:37 2014 (r368677) @@ -3,7 +3,7 @@ PORTNAME= slim PORTVERSION= 1.3.6 -PORTREVISION= 3 +PORTREVISION= 4 CATEGORIES= x11 MASTER_SITES= ftp://ftp.berlios.de/pub/slim/ \ SF/slim.berlios @@ -31,9 +31,11 @@ CMAKE_ARGS= -DUSE_CONSOLEKIT=yes \ -DBUILD_SLIMLOCK=no \ -DBUILD_SHARED_LIBS=yes -OPTIONS_DEFINE= PAM +OPTIONS_DEFINE= PAM UTF8 OPTIONS_DEFAULT= PAM +UTF8_DESC= Support UTF-8 characters + PLIST_SUB+= VERSION="${PORTVERSION}" .include @@ -46,6 +48,11 @@ CMAKE_ARGS+= -DUSE_PAM=no PLIST_SUB+= PAM="@comment " .endif +.if ${PORT_OPTIONS:MUTF8} +# patch taken from slim-unicode in Arch User Repository +EXTRA_PATCHES+= ${PATCHDIR}/extra-patch-utf8 +.endif + post-patch: @${CP} ${WRKSRC}/slim.conf ${WRKSRC}/slim.conf.sample @${REINPLACE_CMD} -e 's|%%LOCALBASE%%|${LOCALBASE}|g' \ Added: head/x11/slim/files/extra-patch-utf8 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/x11/slim/files/extra-patch-utf8 Sat Sep 20 19:07:37 2014 (r368677) @@ -0,0 +1,938 @@ +--- const.h.orig 2014-08-12 18:08:28.000000000 +0200 ++++ const.h 2014-08-12 18:09:20.000000000 +0200 +@@ -24,9 +24,6 @@ + #define HIDE 0 + #define SHOW 1 + +-#define GET_NAME 0 +-#define GET_PASSWD 1 +- + #define OK_EXIT 0 + #define ERR_EXIT 1 + +--- main.cpp.orig 2014-08-12 18:08:28.000000000 +0200 ++++ main.cpp 2014-08-12 18:09:20.000000000 +0200 +@@ -16,6 +16,8 @@ + + int main(int argc, char** argv) + { ++ // We need to set the locale to get the input encoded in UTF-8 ++ setlocale (LC_ALL, ""); + LoginApp = new App(argc, argv); + LoginApp->Run(); + return 0; +--- 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() { +--- panel.h.orig 2014-08-12 18:08:28.000000000 +0200 ++++ panel.h 2014-08-12 18:09:20.000000000 +0200 +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -86,20 +87,26 @@ + void ResetName(void); + void ResetPasswd(void); + void SetName(const std::string &name); +- const std::string& GetName(void) const; +- const std::string& GetPasswd(void) const; ++ const std::string GetName(void) const; ++ const std::string GetPasswd(void) const; + void SwitchSession(); + private: + Panel(); + void Cursor(int visible); + unsigned long GetColor(const char *colorname); + void OnExpose(void); +- void EraseLastChar(string &formerString); ++ int FieldEraseLastChar(const uint16_t **buf, int *len); ++ int FieldClear(const uint16_t **buf, int *len); + bool OnKeyPress(XEvent& event); + void ShowText(); + void ShowSession(); + +- void SlimDrawString8(XftDraw *d, XftColor *color, XftFont *font, ++ static bool isUtf16CharAllowed(uint16_t c); ++ void SlimDrawString16(XftDraw *d, XftColor *color, XftFont *font, ++ int x, int y, const uint16_t *str, int strLen, ++ XftColor* shadowColor, int xOffset, int yOffset); ++ ++ void SlimDrawStringUtf8(XftDraw *d, XftColor *color, XftFont *font, + int x, int y, const std::string &str, + XftColor *shadowColor, + int xOffset, int yOffset); +@@ -136,12 +143,16 @@ + XftColor entershadowcolor; + ActionType action; + FieldType field; ++ XIM displayIm; ++ XIC displayIc; + //Pixmap background; + + /* Username/Password */ +- std::string NameBuffer; +- std::string PasswdBuffer; +- std::string HiddenPasswdBuffer; ++ uint16_t nameBuffer[INPUT_MAXLENGTH_NAME + 1]; ++ int nameBufferLen; ++ uint16_t passwdBuffer[INPUT_MAXLENGTH_PASSWD + 1]; ++ int passwdBufferLen; ++ uint16_t hiddenPasswdBuffer[INPUT_MAXLENGTH_PASSWD + 1]; + + /* screen stuff */ + Rectangle viewport; +--- slimlock.cpp.orig 2014-08-12 18:08:28.000000000 +0200 ++++ slimlock.cpp 2014-08-12 18:09:24.000000000 +0200 +@@ -48,19 +48,19 @@ + void *RaiseWindow(void *data); + + // I really didn't wanna put these globals here, but it's the only way... +-Display* dpy; +-int scr; +-Window win; +-Cfg* cfg; +-Panel* loginPanel; +-string themeName = ""; +- +-pam_handle_t *pam_handle; +-struct pam_conv conv = {ConvCallback, NULL}; +- +-CARD16 dpms_standby, dpms_suspend, dpms_off, dpms_level; +-BOOL dpms_state, using_dpms; +-int term; ++static Display* dpy; ++static int scr; ++static Window win; ++static Cfg* cfg; ++static Panel* loginPanel; ++static string themeName = ""; ++ ++static pam_handle_t *pam_handle; ++static struct pam_conv conv = {ConvCallback, NULL}; ++ ++static CARD16 dpms_standby, dpms_suspend, dpms_off, dpms_level; ++static BOOL dpms_state, using_dpms; ++static int term; + + static void + die(const char *errstr, ...) { +@@ -73,6 +73,10 @@ + } + + int main(int argc, char **argv) { ++ ++ // We need to set the locale to get the input encoded in UTF-8 ++ setlocale (LC_ALL, ""); ++ + if((argc == 2) && !strcmp("-v", argv[1])) + die(APPNAME"-"VERSION", © 2010-2012 Joel Burget\n"); + else if(argc != 1) +--- switchuser.h.orig 2014-08-12 18:08:28.000000000 +0200 ++++ switchuser.h 2014-08-12 18:09:20.000000000 +0200 +@@ -32,8 +32,6 @@ + void Login(const char* cmd, const char* mcookie); + + private: +- SwitchUser(); +- void SetEnvironment(); + void SetUserId(); + void Execute(const char* cmd); + void SetClientAuth(const char* mcookie); +--- util.cpp.orig 2014-08-12 18:08:28.000000000 +0200 ++++ util.cpp 2014-08-12 18:09:20.000000000 +0200 +@@ -67,3 +67,162 @@ + + return pid + tm + (ts.tv_sec ^ ts.tv_nsec); + } ++ ++/* Given a UTF-8 encoded string pointed to by utf8 of length length in ++bytes, returns the corresponding UTF-16 encoded string in the ++buffer pointed to by utf16. The maximum number of UTF-16 encoding ++units (i.e., Unit16s) allowed in the buffer is specified in ++utf16_max_length. The return value is the number of UTF-16 ++encoding units placed in the output buffer pointed to by utf16. ++ ++In case of an error, -1 is returned, leaving some unusable partial ++results in the output buffer. ++ ++The caller must estimate the size of utf16 buffer by itself before ++calling this function. Insufficient output buffer is considered as ++an error, and once an error occured, this function doesn't give any ++clue how large the result will be. ++ ++The error cases include following: ++ ++- Invalid byte sequences were in the input UTF-8 bytes. The caller ++ has no way to know what point in the input buffer was the ++ errornous byte. ++ ++- The input contained a character (a valid UTF-8 byte sequence) ++ whose scalar value exceeded the range that UTF-16 can represent ++ (i.e., characters whose Unicode scalar value above 0x110000). ++ ++- The output buffer has no enough space to hold entire utf16 data. ++ ++Please note: ++ ++- '\0'-termination is not assumed both on the input UTF-8 string ++ and on the output UTF-16 string; any legal zero byte in the input ++ UTF-8 string will be converted to a 16-bit zero in output. As a ++ side effect, the last UTF-16 encoding unit stored in the output ++ buffer will have a non-zero value if the input UTF-8 was not ++ '\0'-terminated. ++ ++- UTF-8 aliases are *not* considered as an error. They are ++ converted to UTF-16. For example, 0xC0 0xA0, 0xE0 0x80 0xA0, ++ and 0xF0 0x80 0x80 0xA0 are all mapped to a single UTF-16 ++ encoding unit 0x0020. ++ ++- Three byte UTF-8 sequences whose value corresponds to a surrogate ++ code or other reserved scalar value are not considered as an ++ error either. They may cause an invalid UTF-16 data (e.g., those ++ containing unpaired surrogates). ++ ++*/ ++int Util::utf8ToUtf16(const char *buf, const int utf8_length, uint16_t *utf16, const int utf16_max_length) { ++ ++ /* p moves over the output buffer. max_ptr points to the next to the last slot of the buffer. */ ++ uint16_t *p = utf16; ++ const uint16_t *max_ptr = utf16 + utf16_max_length; ++ const unsigned char *utf8 = (const unsigned char *)buf; ++ ++ /* end_of_input points to the last byte of input as opposed to the next to the last byte. */ ++ unsigned char const *const end_of_input = utf8 + utf8_length - 1; ++ ++ while (utf8 <= end_of_input) { ++ const unsigned char c = *utf8; ++ if (p >= max_ptr) { ++ /* No more output space. */ ++ return -1; ++ } ++ if (c < 0x80) { ++ /* One byte ASCII. */ ++ *p++ = c; ++ utf8 += 1; ++ } else if (c < 0xC0) { ++ /* Follower byte without preceeding leader bytes. */ ++ return -1; ++ } else if (c < 0xE0) { ++ /* Two byte sequence. We need one follower byte. */ ++ if (end_of_input - utf8 < 1 || (((utf8[1] ^ 0x80)) & 0xC0)) { ++ return -1; ++ } ++ *p++ = (uint16_t)(0xCF80 + (c << 6) + utf8[1]); ++ utf8 += 2; ++ } else if (c < 0xF0) { ++ /* Three byte sequence. We need two follower byte. */ ++ if (end_of_input - utf8 < 2 || (((utf8[1] ^ 0x80) | (utf8[2] ^ 0x80)) & 0xC0)) { ++ return -1; ++ } ++ *p++ = (uint16_t)(0xDF80 + (c << 12) + (utf8[1] << 6) + utf8[2]); ++ utf8 += 3; ++ } else if (c < 0xF8) { ++ int plane; ++ /* Four byte sequence. We need three follower bytes. */ ++ if (end_of_input - utf8 < 3 || (((utf8[1] ^ 0x80) | (utf8[2] ^0x80) | (utf8[3] ^ 0x80)) & 0xC0)) { ++ return -1; ++ } ++ plane = (-0xC8 + (c << 2) + (utf8[1] >> 4)); ++ if (plane == 0) { ++ /* This four byte sequence is an alias that ++ corresponds to a Unicode scalar value in BMP. ++ It fits in an UTF-16 encoding unit. */ ++ *p++ = (uint16_t)(0xDF80 + (utf8[1] << 12) + (utf8[2] << 6) + utf8[3]); ++ } else if (plane <= 16) { ++ /* This is a legal four byte sequence that corresponds to a surrogate pair. */ ++ if (p + 1 >= max_ptr) { ++ /* No enough space on the output buffer for the pair. */ ++ return -1; ++ } ++ *p++ = (uint16_t)(0xE5B8 + (c << 8) + (utf8[1] << 2) + (utf8[2] >> 4)); ++ *p++ = (uint16_t)(0xDB80 + ((utf8[2] & 0x0F) << 6) + utf8[3]); ++ } else { ++ /* This four byte sequence is out of UTF-16 code space. */ ++ return -1; ++ } ++ utf8 += 4; ++ } else { ++ /* Longer sequence or unused byte. */ ++ return -1; ++ } ++ } ++ return p - utf16; ++} ++ ++/* Compare an ASCII string with an UTF-16 string */ ++bool Util::utf16EqualToAscii(const char *ascii, uint16_t *utf16, int utf16Len) { ++ ++ while(*ascii != 0 && utf16Len > 0) { ++ if(*utf16++ != (uint16_t)*ascii++) { ++ return false; ++ } ++ utf16Len--; ++ } ++ return *ascii == 0 && utf16Len == 0; ++} ++ ++std::string Util::utf16BufToUtf8String(const uint16_t *utf16Buf, int utf16Len) { ++ ++ std::string outStr; ++ outStr.reserve(utf16Len * 2); ++ ++ while(*utf16Buf != 0 && utf16Len > 0) { ++ ++ const uint16_t c16 = *utf16Buf++; ++ if (c16 <= 0x007F) { ++ outStr.push_back((char)c16); ++ } ++ else if (c16 <= 0x07FF) { ++ unsigned char c = 0xC0 | ((unsigned char)(c16 >> 6)); ++ outStr.push_back(c); ++ c = 0x80 | ((unsigned char)(c16 & 0x003F)); ++ outStr.push_back(c); ++ } ++ else { ++ unsigned char c = 0xE0 | ((unsigned char)(c16 >> 12)); ++ outStr.push_back(c); ++ c = 0x80 | ((unsigned char)((c16 >> 6) & 0x003F)); ++ outStr.push_back(c); ++ c = 0x80 | ((unsigned char)(c16 & 0x003F)); ++ outStr.push_back(c); ++ } ++ utf16Len--; ++ } ++ return outStr; ++} +--- util.h.orig 2014-08-12 18:08:28.000000000 +0200 ++++ util.h 2014-08-12 18:09:20.000000000 +0200 +@@ -10,6 +10,7 @@ + #define _UTIL_H__ + + #include ++#include + + namespace Util { + bool add_mcookie(const std::string &mcookie, const char *display, +@@ -19,6 +20,10 @@ + long random(void); + + long makeseed(void); ++ int utf8ToUtf16(const char *utf8, const int utf8_length, ++ uint16_t *utf16, const int utf16_max_length); ++ bool utf16EqualToAscii(const char *ascii, uint16_t *utf16, int utf16Len); ++ std::string utf16BufToUtf8String(const uint16_t *utf16Buf, int utf16Len); + } + + #endif /* _UTIL_H__ */ Modified: head/x11/slim/files/patch-slim.conf ============================================================================== --- head/x11/slim/files/patch-slim.conf Sat Sep 20 19:02:30 2014 (r368676) +++ head/x11/slim/files/patch-slim.conf Sat Sep 20 19:07:37 2014 (r368677) @@ -1,12 +1,13 @@ ---- ./slim.conf.orig 2012-12-31 07:03:42.000000000 -0600 -+++ ./slim.conf 2013-03-23 14:10:35.000000000 -0500 -@@ -1,17 +1,19 @@ +--- slim.conf.orig 2013-10-01 18:38:05.000000000 -0400 ++++ slim.conf 2014-08-28 21:35:07.000000000 -0400 +@@ -1,17 +1,20 @@ # Path, X server and arguments (if needed) # Note: -xauth $authfile is automatically appended -default_path /bin:/usr/bin:/usr/local/bin -default_xserver /usr/bin/X -#xserver_arguments -dpi 75 -+default_path /bin:/usr/bin:%%LOCALBASE%%/bin ++# Use default path from /etc/login.conf ++default_path /sbin:/bin:/usr/sbin:/usr/bin:/usr/games:%%LOCALBASE%%/sbin:%%LOCALBASE%%/bin:$HOME/bin +default_xserver %%LOCALBASE%%/bin/X +# The X server needs to be started on an unused virtual terminal, +# for FreeBSD in a default configuration, the first one of those is #09 @@ -27,7 +28,7 @@ # Xauth file for server *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***