Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 20 Sep 2014 19:07:37 +0000 (UTC)
From:      John Marino <marino@FreeBSD.org>
To:        ports-committers@freebsd.org, svn-ports-all@freebsd.org, svn-ports-head@freebsd.org
Subject:   svn commit: r368677 - in head/x11/slim: . files
Message-ID:  <201409201907.s8KJ7bmq062860@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 <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' \

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 <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__ */

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 ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201409201907.s8KJ7bmq062860>