aboutsummaryrefslogtreecommitdiff
path: root/x11/slim
diff options
context:
space:
mode:
authorJohn Marino <marino@FreeBSD.org>2014-09-20 19:07:37 +0000
committerJohn Marino <marino@FreeBSD.org>2014-09-20 19:07:37 +0000
commitd0e576b5d7ed6eb4d7348ce47b82207f1626999b (patch)
tree06dbf07cb79e5c543c80a9596e13182b59602ba1 /x11/slim
parent0a08b1e3a7defaa253d3f6f4a04a554190a9b516 (diff)
downloadports-d0e576b5d7ed6eb4d7348ce47b82207f1626999b.tar.gz
ports-d0e576b5d7ed6eb4d7348ce47b82207f1626999b.zip
Notes
Diffstat (limited to 'x11/slim')
-rw-r--r--x11/slim/Makefile11
-rw-r--r--x11/slim/files/extra-patch-utf8938
-rw-r--r--x11/slim/files/patch-slim.conf37
-rw-r--r--x11/slim/files/pkg-message.in7
4 files changed, 984 insertions, 9 deletions
diff --git a/x11/slim/Makefile b/x11/slim/Makefile
index 7985d6d0eaa6..58c6ef8141b4 100644
--- a/x11/slim/Makefile
+++ b/x11/slim/Makefile
@@ -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 <bsd.port.options.mk>
@@ -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' \
diff --git a/x11/slim/files/extra-patch-utf8 b/x11/slim/files/extra-patch-utf8
new file mode 100644
index 000000000000..c998270f14c4
--- /dev/null
+++ b/x11/slim/files/extra-patch-utf8
@@ -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 <poll.h>
+ #include <X11/extensions/Xrandr.h>
+ #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<const XftChar8*>(message.c_str()),
++
++ XftTextExtentsUtf8(Dpy, msgfont, reinterpret_cast<const XftChar8*>(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<const XftChar8*>(text.c_str()),
+- text.length(), &extents);
++ XftTextExtentsUtf8(Dpy, msgfont,
++ reinterpret_cast<const XftChar8*>(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<XKeyEvent&>(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<XKeyEvent&>(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<const XftChar8*>(txth), strlen(txth), &extents);
+ int maxHeight = extents.height;
+
+- XftTextExtents8(Dpy, font,
+- reinterpret_cast<const XftChar8*>(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<const XftChar8*>(currsession.c_str()),
++ XftTextExtentsUtf8(Dpy, sessionfont, reinterpret_cast<const XftChar8*>(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 <X11/Xmu/WinUtil.h>
+ #include <sys/wait.h>
+ #include <stdlib.h>
++#include <stdint.h>
+ #include <signal.h>
+ #include <iostream>
+ #include <string>
+@@ -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 <string>
++#include <stdint.h>
+
+ 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__ */
diff --git a/x11/slim/files/patch-slim.conf b/x11/slim/files/patch-slim.conf
index 86e2e22833a0..8c8b5d538b5b 100644
--- a/x11/slim/files/patch-slim.conf
+++ b/x11/slim/files/patch-slim.conf
@@ -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
authfile /var/run/slim.auth
-@@ -32,8 +34,8 @@
+@@ -32,8 +35,8 @@
# NOTE: if your system does not have bash you need
# to adjust the command according to your preferred shell,
# i.e. for freebsd use:
@@ -38,7 +39,29 @@
# Commands executed when starting and exiting a session.
# They can be used for registering a X11 session with
-@@ -63,7 +65,7 @@
+@@ -47,11 +50,16 @@
+ # options "-d" and "-nodaemon"
+ # daemon yes
+
+-# Available sessions (first one is the default).
+-# The current chosen session name is replaced in the login_cmd
+-# above, so your login command can handle different sessions.
+-# see the xinitrc.sample file shipped with slim sources
+-sessions xfce4,icewm-session,wmaker,blackbox
++# Option "sessions" is no longer supported.
++# Now you need to put session files in the directory specified
++# by option "sessiondir".
++# sessions xfce4,icewm-session,wmaker,blackbox
++
++# Directory of session files.
++# They should be xdg-style .desktop files.
++# The "Name" entry in the session file would be used as session name.
++# The "Exec" entry would replace %session in login_cmd.
++sessiondir %%LOCALBASE%%/share/xsessions
+
+ # Executed when pressing F11 (requires imagemagick)
+ screenshot_cmd import -window root /slim.png
+@@ -63,7 +71,7 @@
# session_msg Session:
# shutdown / reboot messages
@@ -47,7 +70,7 @@
reboot_msg The system is rebooting...
# default user, leave blank or remove this line
-@@ -84,7 +86,7 @@
+@@ -84,7 +92,7 @@
current_theme default
# Lock file
diff --git a/x11/slim/files/pkg-message.in b/x11/slim/files/pkg-message.in
index ebdd7bbfde26..4b3099605586 100644
--- a/x11/slim/files/pkg-message.in
+++ b/x11/slim/files/pkg-message.in
@@ -9,4 +9,11 @@ slim_enable=yes
into /etc/rc.conf
+*** Option "sessions" is no longer supported. ***
+
+Now you need to put session files in the directory specified by option
+"sessiondir". They should be xdg-style .desktop files.
+The "Name" entry in the session file would be used as session name.
+The "Exec" entry would replace %session in login_cmd.
+
*************************************************************************