View | Details | Raw Unified | Return to bug 192783 | Differences between
and this patch

Collapse All | Expand All

(-)./Makefile (-2 / +9 lines)
Lines 3-9 Link Here
3
3
4
PORTNAME=	slim
4
PORTNAME=	slim
5
PORTVERSION=	1.3.6
5
PORTVERSION=	1.3.6
6
PORTREVISION=	2
6
PORTREVISION=	3
7
CATEGORIES=	x11
7
CATEGORIES=	x11
8
MASTER_SITES=	ftp://ftp.berlios.de/pub/slim/ \
8
MASTER_SITES=	ftp://ftp.berlios.de/pub/slim/ \
9
		SF/slim.berlios
9
		SF/slim.berlios
Lines 31-39 Link Here
31
	-DBUILD_SLIMLOCK=no \
31
	-DBUILD_SLIMLOCK=no \
32
	-DBUILD_SHARED_LIBS=yes
32
	-DBUILD_SHARED_LIBS=yes
33
33
34
OPTIONS_DEFINE=		PAM
34
OPTIONS_DEFINE=		PAM UTF8
35
OPTIONS_DEFAULT=	PAM
35
OPTIONS_DEFAULT=	PAM
36
36
37
UTF8_DESC=	Support UTF-8 characters
38
37
PLIST_SUB+=	VERSION="${PORTVERSION}"
39
PLIST_SUB+=	VERSION="${PORTVERSION}"
38
40
39
.include <bsd.port.options.mk>
41
.include <bsd.port.options.mk>
Lines 46-51 Link Here
46
PLIST_SUB+=	PAM="@comment "
48
PLIST_SUB+=	PAM="@comment "
47
.endif
49
.endif
48
50
51
.if ${PORT_OPTIONS:MUTF8}
52
# patch taken from slim-unicode in Arch User Repository
53
EXTRA_PATCHES+=	${PATCHDIR}/extra-patch-utf8
54
.endif
55
49
post-patch:
56
post-patch:
50
	@${CP} ${WRKSRC}/slim.conf ${WRKSRC}/slim.conf.sample
57
	@${CP} ${WRKSRC}/slim.conf ${WRKSRC}/slim.conf.sample
51
	@${REINPLACE_CMD} -e 's|%%LOCALBASE%%|${LOCALBASE}|g' \
58
	@${REINPLACE_CMD} -e 's|%%LOCALBASE%%|${LOCALBASE}|g' \
(-)./files/extra-patch-utf8 (+938 lines)
Line 0 Link Here
1
--- const.h.orig	2014-08-12 18:08:28.000000000 +0200
2
+++ const.h	2014-08-12 18:09:20.000000000 +0200
3
@@ -24,9 +24,6 @@
4
 #define HIDE		0
5
 #define SHOW		1
6
 
7
-#define GET_NAME	0
8
-#define GET_PASSWD  1
9
-
10
 #define OK_EXIT	 0
11
 #define ERR_EXIT	1
12
 
13
--- main.cpp.orig	2014-08-12 18:08:28.000000000 +0200
14
+++ main.cpp	2014-08-12 18:09:20.000000000 +0200
15
@@ -16,6 +16,8 @@
16
 
17
 int main(int argc, char** argv)
18
 {
19
+    // We need to set the locale to get the input encoded in UTF-8
20
+    setlocale (LC_ALL, "");
21
 	LoginApp = new App(argc, argv);
22
 	LoginApp->Run();
23
 	return 0;
24
--- panel.cpp.orig	2014-08-12 18:08:28.000000000 +0200
25
+++ panel.cpp	2014-08-12 18:09:20.000000000 +0200
26
@@ -13,6 +13,7 @@
27
 #include <poll.h>
28
 #include <X11/extensions/Xrandr.h>
29
 #include "panel.h"
30
+#include "util.h"
31
 
32
 using namespace std;
33
 
34
@@ -78,6 +79,15 @@
35
 	XftColorAllocName(Dpy, visual, colormap,
36
 					  cfg->getOption("session_shadow_color").c_str(), &sessionshadowcolor);
37
 
38
+	/* Build XIC and XIM to be able to get unicode string from keyboard events */
39
+	char classname = 0;
40
+	displayIc = NULL;
41
+	displayIm = XOpenIM(Dpy, NULL, &classname, &classname);
42
+	if(displayIm) {
43
+		displayIc = XCreateIC(displayIm, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
44
+							  XNResourceName, &classname,
45
+							  XNResourceClass, &classname, NULL);
46
+	}
47
 	/* Load properties from config / theme */
48
 	input_name_x = cfg->getIntOption("input_name_x");
49
 	input_name_y = cfg->getIntOption("input_name_y");
50
@@ -91,6 +101,8 @@
51
 		input_pass_y = input_name_y;
52
 	}
53
 
54
+	Reset();
55
+
56
 	/* Load panel and background image */
57
 	string panelpng = "";
58
 	panelpng = panelpng + themedir +"/panel.png";
59
@@ -210,6 +222,12 @@
60
 	Visual* visual = DefaultVisual(Dpy, Scr);
61
 	Colormap colormap = DefaultColormap(Dpy, Scr);
62
 
63
+	if(displayIc) {
64
+		XDestroyIC(displayIc);
65
+	}
66
+	if(displayIm) {
67
+		XCloseIM(displayIm);
68
+	}
69
 	XftColorFree(Dpy, visual, colormap, &inputcolor);
70
 	XftColorFree(Dpy, visual, colormap, &inputshadowcolor);
71
 	XftColorFree(Dpy, visual, colormap, &welcomecolor);
72
@@ -289,7 +307,8 @@
73
 
74
 	XftDraw *draw = XftDrawCreate(Dpy, Win,
75
 		DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
76
-		XftTextExtents8(Dpy, msgfont, reinterpret_cast<const XftChar8*>(message.c_str()),
77
+
78
+	XftTextExtentsUtf8(Dpy, msgfont, reinterpret_cast<const XftChar8*>(message.c_str()),
79
 		message.length(), &extents);
80
 
81
 	string cfgX = cfg->getOption("passwd_feedback_x");
82
@@ -300,7 +319,7 @@
83
 	int msg_y = Cfg::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.height);
84
 
85
 	OnExpose();
86
-	SlimDrawString8(draw, &msgcolor, msgfont, msg_x, msg_y, message,
87
+	SlimDrawStringUtf8(draw, &msgcolor, msgfont, msg_x, msg_y, message,
88
 		&msgshadowcolor, shadowXOffset, shadowYOffset);
89
 
90
 	if (cfg->getOption("bell") == "1")
91
@@ -312,7 +331,7 @@
92
 	OnExpose();
93
 	// The message should stay on the screen even after the password field is
94
 	// cleared, methinks. I don't like this solution, but it works.
95
-	SlimDrawString8(draw, &msgcolor, msgfont, msg_x, msg_y, message,
96
+	SlimDrawStringUtf8(draw, &msgcolor, msgfont, msg_x, msg_y, message,
97
 		&msgshadowcolor, shadowXOffset, shadowYOffset);
98
 	XSync(Dpy, True);
99
 	XftDrawDestroy(draw);
100
@@ -330,9 +349,8 @@
101
 		draw = XftDrawCreate(Dpy, Root,
102
 			DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
103
 
104
-	XftTextExtents8(Dpy, msgfont,
105
-		reinterpret_cast<const XftChar8*>(text.c_str()),
106
-					text.length(), &extents);
107
+	XftTextExtentsUtf8(Dpy, msgfont,
108
+		reinterpret_cast<const XftChar8*>(text.c_str()), text.length(), &extents);
109
 	cfgX = cfg->getOption("msg_x");
110
 	cfgY = cfg->getOption("msg_y");
111
 	int shadowXOffset = cfg->getIntOption("msg_shadow_xoffset");
112
@@ -347,9 +365,8 @@
113
 		msg_y = Cfg::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.height);
114
 	}
115
 
116
-	SlimDrawString8 (draw, &msgcolor, msgfont, msg_x, msg_y,
117
-					 text,
118
-					 &msgshadowcolor,
119
+	SlimDrawStringUtf8(draw, &msgcolor, msgfont, msg_x, msg_y,
120
+					   text, &msgshadowcolor,
121
 					 shadowXOffset, shadowYOffset);
122
 	XFlush(Dpy);
123
 	XftDrawDestroy(draw);
124
@@ -383,24 +400,27 @@
125
 }
126
 
127
 void Panel::Cursor(int visible) {
128
-	const char* text = NULL;
129
-	int xx = 0, yy = 0, y2 = 0, cheight = 0;
130
+	const uint16_t* text = NULL;
131
+	int xx = 0, yy = 0, y2 = 0, cheight = 0, textLen = 0;
132
 	const char* txth = "Wj"; /* used to get cursor height */
133
 
134
 	if (mode == Mode_Lock) {
135
-			text = HiddenPasswdBuffer.c_str();
136
+			text = hiddenPasswdBuffer;
137
+			textLen = passwdBufferLen;
138
 			xx = input_pass_x;
139
 			yy = input_pass_y;
140
 	} else {
141
 		switch(field) {
142
 			case Get_Passwd:
143
-				text = HiddenPasswdBuffer.c_str();
144
+				text = hiddenPasswdBuffer;
145
+				textLen = passwdBufferLen;
146
 				xx = input_pass_x;
147
 				yy = input_pass_y;
148
 				break;
149
 
150
 			case Get_Name:
151
-				text = NameBuffer.c_str();
152
+				text = nameBuffer;
153
+				textLen = nameBufferLen;
154
 				xx = input_name_x;
155
 				yy = input_name_y;
156
 				break;
157
@@ -411,7 +431,7 @@
158
 	XftTextExtents8(Dpy, font, (XftChar8*)txth, strlen(txth), &extents);
159
 	cheight = extents.height;
160
 	y2 = yy - extents.y + extents.height;
161
-	XftTextExtents8(Dpy, font, (XftChar8*)text, strlen(text), &extents);
162
+	XftTextExtents16(Dpy, font, (XftChar16*)text, textLen, &extents);
163
 	xx += extents.width;
164
 
165
 	if(visible == SHOW) {
166
@@ -478,27 +498,25 @@
167
 		XClearWindow(Dpy, Win);
168
 
169
 	if (input_pass_x != input_name_x || input_pass_y != input_name_y){
170
-		SlimDrawString8 (draw, &inputcolor, font, input_name_x, input_name_y,
171
-						 NameBuffer,
172
-						 &inputshadowcolor,
173
+		SlimDrawString16(draw, &inputcolor, font, input_name_x, input_name_y,
174
+						 nameBuffer, nameBufferLen, &inputshadowcolor,
175
 						 inputShadowXOffset, inputShadowYOffset);
176
-		SlimDrawString8 (draw, &inputcolor, font, input_pass_x, input_pass_y,
177
-						 HiddenPasswdBuffer,
178
-						 &inputshadowcolor,
179
+		SlimDrawString16(draw, &inputcolor, font, input_pass_x, input_pass_y,
180
+						 hiddenPasswdBuffer, passwdBufferLen, &inputshadowcolor,
181
 						 inputShadowXOffset, inputShadowYOffset);
182
 	} else { /*single input mode */
183
 		switch(field) {
184
 			case Get_Passwd:
185
-				SlimDrawString8 (draw, &inputcolor, font,
186
+				SlimDrawString16(draw, &inputcolor, font,
187
 								 input_pass_x, input_pass_y,
188
-								 HiddenPasswdBuffer,
189
+								 hiddenPasswdBuffer, passwdBufferLen,
190
 								 &inputshadowcolor,
191
 								 inputShadowXOffset, inputShadowYOffset);
192
 				break;
193
 			case Get_Name:
194
-				SlimDrawString8 (draw, &inputcolor, font,
195
+				SlimDrawString16(draw, &inputcolor, font,
196
 								 input_name_x, input_name_y,
197
-								 NameBuffer,
198
+								 nameBuffer, nameBufferLen,
199
 								 &inputshadowcolor,
200
 								 inputShadowXOffset, inputShadowYOffset);
201
 				break;
202
@@ -510,35 +528,105 @@
203
 	ShowText();
204
 }
205
 
206
-void Panel::EraseLastChar(string &formerString) {
207
+int Panel::FieldEraseLastChar(const uint16_t **buf, int *len) {
208
+
209
+	static const uint16_t emptyBuf = 0;
210
+	int formerTextBufferLen = 0;
211
+
212
 	switch(field) {
213
-	case GET_NAME:
214
-		if (! NameBuffer.empty()) {
215
-			formerString=NameBuffer;
216
-			NameBuffer.erase(--NameBuffer.end());
217
+		case Get_Name:
218
+			formerTextBufferLen = nameBufferLen;
219
+			if (nameBufferLen > 0) {
220
+				nameBufferLen--;
221
 		}
222
+			*buf = nameBuffer;
223
+			*len = nameBufferLen;
224
 		break;
225
 
226
-	case GET_PASSWD:
227
-		if (!PasswdBuffer.empty()) {
228
-			formerString=HiddenPasswdBuffer;
229
-			PasswdBuffer.erase(--PasswdBuffer.end());
230
-			HiddenPasswdBuffer.erase(--HiddenPasswdBuffer.end());
231
+		case Get_Passwd:
232
+			formerTextBufferLen = passwdBufferLen;
233
+			if (passwdBufferLen > 0) {
234
+				passwdBufferLen--;
235
+				passwdBuffer[passwdBufferLen] = 0;
236
 		}
237
+			*buf = hiddenPasswdBuffer;
238
+			*len = passwdBufferLen;
239
+			break;
240
+
241
+		default:
242
+			*buf = &emptyBuf;
243
+			*len = 0;
244
 		break;
245
 	}
246
+	return formerTextBufferLen;
247
 }
248
 
249
+int Panel::FieldClear(const uint16_t **buf, int *len) {
250
+
251
+	static const uint16_t emptyBuf = 0;
252
+	int formerTextBufferLen = 0;
253
+
254
+	switch(field) {
255
+		case Get_Name:
256
+			formerTextBufferLen = nameBufferLen;
257
+			nameBufferLen = 0;
258
+			*buf = nameBuffer;
259
+			*len = nameBufferLen;
260
+			break;
261
+
262
+		case Get_Passwd:
263
+			formerTextBufferLen = passwdBufferLen;
264
+			memset(passwdBuffer, 0, sizeof(passwdBuffer));
265
+			passwdBufferLen = 0;
266
+			*buf = hiddenPasswdBuffer;
267
+			*len = passwdBufferLen;
268
+			break;
269
+
270
+		default:
271
+			*buf = &emptyBuf;
272
+			*len = 0;
273
+			break;
274
+	}
275
+	return formerTextBufferLen;
276
+}
277
+
278
+/* Check if the input character is allowed */
279
+bool Panel::isUtf16CharAllowed(uint16_t c) {
280
+	return ((0x020 <= c && c <= 0x07E) || (0x0A0 <= c && c != 0x0AD));
281
+}
282
+
283
+#define SIZE_BUFFER_KEY_PRESS 64
284
+
285
 bool Panel::OnKeyPress(XEvent& event) {
286
-	char ascii;
287
+	int formerTextBufferLen = -1;
288
+	int textBufferLen = -1;
289
+	const uint16_t *textBuffer = NULL;
290
 	KeySym keysym;
291
+	int nbReadBuf = -1;
292
+	uint16_t utf16buf[SIZE_BUFFER_KEY_PRESS];
293
+	if(displayIc)
294
+	{
295
+		Status status;
296
+		char databuf[SIZE_BUFFER_KEY_PRESS];
297
+		nbReadBuf = Xutf8LookupString(displayIc, &event.xkey, databuf,
298
+									  SIZE_BUFFER_KEY_PRESS, &keysym, &status);
299
+		if(nbReadBuf > 0) {
300
+			nbReadBuf = Util::utf8ToUtf16(databuf, nbReadBuf,
301
+										  utf16buf, SIZE_BUFFER_KEY_PRESS);
302
+		}
303
+	}
304
+	else
305
+	{
306
 	XComposeStatus compstatus;
307
-	int xx = 0;
308
-	int yy = 0;
309
-	string text;
310
-	string formerString = "";
311
+		char databuf[SIZE_BUFFER_KEY_PRESS];
312
+		nbReadBuf = XLookupString(&event.xkey, databuf,
313
+								  SIZE_BUFFER_KEY_PRESS, &keysym, &compstatus);
314
+		if(nbReadBuf > 0) {
315
+			nbReadBuf = Util::utf8ToUtf16(databuf, nbReadBuf,
316
+										  utf16buf, SIZE_BUFFER_KEY_PRESS);
317
+		}
318
+	}
319
 
320
-	XLookupString(&event.xkey, &ascii, 1, &keysym, &compstatus);
321
 	switch(keysym){
322
 		case XK_F1:
323
 			SwitchSession();
324
@@ -553,17 +641,17 @@
325
 		case XK_KP_Enter:
326
 			if (field==Get_Name){
327
 				/* Don't allow an empty username */
328
-				if (NameBuffer.empty()) return true;
329
+				if (nameBufferLen <= 0) return true;
330
 
331
-				if (NameBuffer==CONSOLE_STR){
332
+				if (Util::utf16EqualToAscii(CONSOLE_STR, nameBuffer, nameBufferLen)) {
333
 					action = Console;
334
-				} else if (NameBuffer==HALT_STR){
335
+				} else if (Util::utf16EqualToAscii(HALT_STR, nameBuffer, nameBufferLen)) {
336
 					action = Halt;
337
-				} else if (NameBuffer==REBOOT_STR){
338
+				} else if (Util::utf16EqualToAscii(REBOOT_STR, nameBuffer, nameBufferLen)) {
339
 					action = Reboot;
340
-				} else if (NameBuffer==SUSPEND_STR){
341
+				} else if (Util::utf16EqualToAscii(SUSPEND_STR, nameBuffer, nameBufferLen)) {
342
 					action = Suspend;
343
-				} else if (NameBuffer==EXIT_STR){
344
+				} else if (Util::utf16EqualToAscii(EXIT_STR, nameBuffer, nameBufferLen)) {
345
 					action = Exit;
346
 				} else{
347
 					if (mode == Mode_DM)
348
@@ -581,80 +669,80 @@
349
 	switch(keysym){
350
 		case XK_Delete:
351
 		case XK_BackSpace:
352
-			EraseLastChar(formerString);
353
+			formerTextBufferLen = FieldEraseLastChar(&textBuffer, &textBufferLen);
354
 			break;
355
 
356
 		case XK_w:
357
 		case XK_u:
358
 			if (reinterpret_cast<XKeyEvent&>(event).state & ControlMask) {
359
-				switch(field) {
360
-					case Get_Passwd:
361
-						formerString = HiddenPasswdBuffer;
362
-						HiddenPasswdBuffer.clear();
363
-						PasswdBuffer.clear();
364
-						break;
365
-					case Get_Name:
366
-						formerString = NameBuffer;
367
-						NameBuffer.clear();
368
-						break;
369
-				}
370
+				formerTextBufferLen = FieldClear(&textBuffer, &textBufferLen);
371
 				break;
372
 			}
373
 		case XK_h:
374
 			if (reinterpret_cast<XKeyEvent&>(event).state & ControlMask) {
375
-				EraseLastChar(formerString);
376
+				formerTextBufferLen = FieldEraseLastChar(&textBuffer, &textBufferLen);
377
 				break;
378
 			}
379
 			/* Deliberate fall-through */
380
 
381
 		default:
382
-			if (isprint(ascii) && (keysym < XK_Shift_L || keysym > XK_Hyper_R)){
383
+			if(nbReadBuf > 0) {
384
 				switch(field) {
385
-					case GET_NAME:
386
-						formerString=NameBuffer;
387
-						if (NameBuffer.length() < INPUT_MAXLENGTH_NAME-1){
388
-							NameBuffer.append(&ascii,1);
389
-						};
390
+					case Get_Name:
391
+						formerTextBufferLen = nameBufferLen;
392
+						for(int i = 0; i < nbReadBuf &&
393
+							nameBufferLen < INPUT_MAXLENGTH_NAME; i++) {
394
+
395
+							if(isUtf16CharAllowed(utf16buf[i])) {
396
+								nameBuffer[nameBufferLen++] = utf16buf[i];
397
+							}
398
+						}
399
+						textBuffer = nameBuffer;
400
+						textBufferLen = nameBufferLen;
401
 						break;
402
-					case GET_PASSWD:
403
-						formerString=HiddenPasswdBuffer;
404
-						if (PasswdBuffer.length() < INPUT_MAXLENGTH_PASSWD-1){
405
-							PasswdBuffer.append(&ascii,1);
406
-							HiddenPasswdBuffer.append("*");
407
-						};
408
+
409
+					case Get_Passwd:
410
+						formerTextBufferLen = passwdBufferLen;
411
+						for(int i = 0; i < nbReadBuf &&
412
+							passwdBufferLen < INPUT_MAXLENGTH_PASSWD; i++) {
413
+
414
+							if(isUtf16CharAllowed(utf16buf[i])) {
415
+								passwdBuffer[passwdBufferLen] = utf16buf[i];
416
+								hiddenPasswdBuffer[passwdBufferLen++] = (uint16_t)'*';
417
+							}
418
+						}
419
+						textBuffer = hiddenPasswdBuffer;
420
+						textBufferLen = passwdBufferLen;
421
 					break;
422
-				};
423
-			};
424
+				}
425
+			}
426
 			break;
427
 	};
428
 
429
-	XGlyphInfo extents;
430
-	XftDraw *draw = XftDrawCreate(Dpy, Win,
431
-			  DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
432
+	int xx = 0, yy = 0;
433
+	if (formerTextBufferLen > 0 || textBufferLen > 0) {
434
 
435
 	switch(field) {
436
 		case Get_Name:
437
-			text = NameBuffer;
438
 			xx = input_name_x;
439
 			yy = input_name_y;
440
 			break;
441
 
442
 		case Get_Passwd:
443
-			text = HiddenPasswdBuffer;
444
 			xx = input_pass_x;
445
 			yy = input_pass_y;
446
 			break;
447
 	}
448
+	}
449
 
450
-	if (!formerString.empty()){
451
+	if (formerTextBufferLen > 0) {
452
+		XGlyphInfo extents;
453
 		const char* txth = "Wj"; /* get proper maximum height ? */
454
 		XftTextExtents8(Dpy, font,
455
 				reinterpret_cast<const XftChar8*>(txth), strlen(txth), &extents);
456
 		int maxHeight = extents.height;
457
 
458
-		XftTextExtents8(Dpy, font,
459
-				reinterpret_cast<const XftChar8*>(formerString.c_str()),
460
-						formerString.length(), &extents);
461
+		XftTextExtents16(Dpy, font, (XftChar16*)textBuffer, formerTextBufferLen, &extents);
462
 		int maxLength = extents.width;
463
 
464
 		if (mode == Mode_Lock)
465
@@ -666,14 +754,15 @@
466
 				maxLength + 6, maxHeight + 6, false);
467
 	}
468
 
469
-	if (!text.empty()) {
470
-		SlimDrawString8 (draw, &inputcolor, font, xx, yy,
471
-				 text,
472
-				 &inputshadowcolor,
473
-				 inputShadowXOffset, inputShadowYOffset);
474
+	if(textBufferLen > 0) {
475
+		XftDraw *draw = XftDrawCreate(Dpy, Win, DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
476
+		if(draw != NULL) {
477
+			SlimDrawString16(draw, &inputcolor, font, xx, yy, textBuffer, textBufferLen,
478
+							&inputshadowcolor, inputShadowXOffset, inputShadowYOffset);
479
+			XftDrawDestroy(draw);
480
+		}
481
 	}
482
 
483
-	XftDrawDestroy (draw);
484
 	Cursor(SHOW);
485
 	return true;
486
 }
487
@@ -690,7 +779,7 @@
488
 	XftDraw *draw = XftDrawCreate(Dpy, Win,
489
 		  DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
490
 	/* welcome message */
491
-	XftTextExtents8(Dpy, welcomefont, (XftChar8*)welcome_message.c_str(),
492
+	XftTextExtentsUtf8(Dpy, welcomefont, (XftChar8*)welcome_message.c_str(),
493
 					strlen(welcome_message.c_str()), &extents);
494
 	cfgX = cfg->getOption("welcome_x");
495
 	cfgY = cfg->getOption("welcome_y");
496
@@ -700,9 +789,8 @@
497
 	welcome_x = Cfg::absolutepos(cfgX, image->Width(), extents.width);
498
 	welcome_y = Cfg::absolutepos(cfgY, image->Height(), extents.height);
499
 	if (welcome_x >= 0 && welcome_y >= 0) {
500
-		SlimDrawString8 (draw, &welcomecolor, welcomefont,
501
-						 welcome_x, welcome_y,
502
-						 welcome_message,
503
+		SlimDrawStringUtf8(draw, &welcomecolor, welcomefont,
504
+						   welcome_x, welcome_y, welcome_message,
505
 						 &welcomeshadowcolor, shadowXOffset, shadowYOffset);
506
 	}
507
 
508
@@ -710,7 +798,7 @@
509
 	string msg;
510
 	if ((!singleInputMode|| field == Get_Passwd) && mode == Mode_DM) {
511
 		msg = cfg->getOption("password_msg");
512
-		XftTextExtents8(Dpy, enterfont, (XftChar8*)msg.c_str(),
513
+		XftTextExtentsUtf8(Dpy, enterfont, (XftChar8*)msg.c_str(),
514
 						strlen(msg.c_str()), &extents);
515
 		cfgX = cfg->getOption("password_x");
516
 		cfgY = cfg->getOption("password_y");
517
@@ -719,14 +807,14 @@
518
 		password_x = Cfg::absolutepos(cfgX, image->Width(), extents.width);
519
 		password_y = Cfg::absolutepos(cfgY, image->Height(), extents.height);
520
 		if (password_x >= 0 && password_y >= 0){
521
-			SlimDrawString8 (draw, &entercolor, enterfont, password_x, password_y,
522
+			SlimDrawStringUtf8(draw, &entercolor, enterfont, password_x, password_y,
523
 							 msg, &entershadowcolor, shadowXOffset, shadowYOffset);
524
 		}
525
 	}
526
 
527
 	if (!singleInputMode|| field == Get_Name) {
528
 		msg = cfg->getOption("username_msg");
529
-		XftTextExtents8(Dpy, enterfont, (XftChar8*)msg.c_str(),
530
+		XftTextExtentsUtf8(Dpy, enterfont, (XftChar8*)msg.c_str(),
531
 						strlen(msg.c_str()), &extents);
532
 		cfgX = cfg->getOption("username_x");
533
 		cfgY = cfg->getOption("username_y");
534
@@ -735,7 +823,7 @@
535
 		username_x = Cfg::absolutepos(cfgX, image->Width(), extents.width);
536
 		username_y = Cfg::absolutepos(cfgY, image->Height(), extents.height);
537
 		if (username_x >= 0 && username_y >= 0){
538
-			SlimDrawString8 (draw, &entercolor, enterfont, username_x, username_y,
539
+			SlimDrawStringUtf8(draw, &entercolor, enterfont, username_x, username_y,
540
 							 msg, &entershadowcolor, shadowXOffset, shadowYOffset);
541
 		}
542
 	}
543
@@ -776,7 +864,7 @@
544
 
545
 	XftDraw *draw = XftDrawCreate(Dpy, Root,
546
 								  DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
547
-	XftTextExtents8(Dpy, sessionfont, reinterpret_cast<const XftChar8*>(currsession.c_str()),
548
+	XftTextExtentsUtf8(Dpy, sessionfont, reinterpret_cast<const XftChar8*>(currsession.c_str()),
549
 					currsession.length(), &extents);
550
 	msg_x = cfg->getOption("session_x");
551
 	msg_y = cfg->getOption("session_y");
552
@@ -785,16 +873,37 @@
553
 	int shadowXOffset = cfg->getIntOption("session_shadow_xoffset");
554
 	int shadowYOffset = cfg->getIntOption("session_shadow_yoffset");
555
 
556
-	SlimDrawString8(draw, &sessioncolor, sessionfont, x, y,
557
-					currsession,
558
-					&sessionshadowcolor,
559
-					shadowXOffset, shadowYOffset);
560
+	SlimDrawStringUtf8(draw, &sessioncolor, sessionfont, x, y,
561
+					   currsession, &sessionshadowcolor, shadowXOffset, shadowYOffset);
562
 	XFlush(Dpy);
563
 	XftDrawDestroy(draw);
564
 }
565
 
566
+void Panel::SlimDrawString16(XftDraw *d, XftColor *color, XftFont *font,
567
+							 int x, int y, const uint16_t *str, int strLen,
568
+							 XftColor* shadowColor, int xOffset, int yOffset)
569
+{
570
+	int calc_x = 0;
571
+	int calc_y = 0;
572
+	if (mode == Mode_Lock) {
573
+		calc_x = viewport.x;
574
+		calc_y = viewport.y;
575
+	}
576
+
577
+	if (xOffset && yOffset) {
578
+		XftDrawString16(d, shadowColor, font,
579
+			x + xOffset + calc_x,
580
+			y + yOffset + calc_y,
581
+			(XftChar16*)str, strLen);
582
+	}
583
+
584
+	XftDrawString16(d, color, font,
585
+		x + calc_x,
586
+		y + calc_y,
587
+		(XftChar16*)str, strLen);
588
+}
589
 
590
-void Panel::SlimDrawString8(XftDraw *d, XftColor *color, XftFont *font,
591
+void Panel::SlimDrawStringUtf8(XftDraw *d, XftColor *color, XftFont *font,
592
 							int x, int y, const string& str,
593
 							XftColor* shadowColor,
594
 							int xOffset, int yOffset)
595
@@ -831,28 +940,31 @@
596
 }
597
 
598
 void Panel::ResetName(void){
599
-	NameBuffer.clear();
600
+	nameBufferLen = 0;
601
+	memset(nameBuffer, 0, sizeof(nameBuffer));
602
 }
603
 
604
 void Panel::ResetPasswd(void){
605
-	PasswdBuffer.clear();
606
-	HiddenPasswdBuffer.clear();
607
+	passwdBufferLen = 0;
608
+	memset(passwdBuffer, 0, sizeof(passwdBuffer));
609
+	memset(hiddenPasswdBuffer, 0, sizeof(hiddenPasswdBuffer));
610
 }
611
 
612
 void Panel::SetName(const string& name){
613
-	NameBuffer=name;
614
+	nameBufferLen = Util::utf8ToUtf16(name.c_str(), name.length(),
615
+									  nameBuffer, INPUT_MAXLENGTH_NAME);
616
 	if (mode == Mode_DM)
617
 		action = Login;
618
 	else
619
 		action = Lock;
620
 }
621
 
622
-const string& Panel::GetName(void) const{
623
-	return NameBuffer;
624
+const string Panel::GetName(void) const{
625
+	return Util::utf16BufToUtf8String(nameBuffer, nameBufferLen);
626
 }
627
 
628
-const string& Panel::GetPasswd(void) const{
629
-	return PasswdBuffer;
630
+const string Panel::GetPasswd(void) const{
631
+	return Util::utf16BufToUtf8String(passwdBuffer, passwdBufferLen);
632
 }
633
 
634
 Rectangle Panel::GetPrimaryViewport() {
635
--- panel.h.orig	2014-08-12 18:08:28.000000000 +0200
636
+++ panel.h	2014-08-12 18:09:20.000000000 +0200
637
@@ -20,6 +20,7 @@
638
 #include <X11/Xmu/WinUtil.h>
639
 #include <sys/wait.h>
640
 #include <stdlib.h>
641
+#include <stdint.h>
642
 #include <signal.h>
643
 #include <iostream>
644
 #include <string>
645
@@ -86,20 +87,26 @@
646
 	void ResetName(void);
647
 	void ResetPasswd(void);
648
 	void SetName(const std::string &name);
649
-	const std::string& GetName(void) const;
650
-	const std::string& GetPasswd(void) const;
651
+	const std::string GetName(void) const;
652
+	const std::string GetPasswd(void) const;
653
 	void SwitchSession();
654
 private:
655
 	Panel();
656
 	void Cursor(int visible);
657
 	unsigned long GetColor(const char *colorname);
658
 	void OnExpose(void);
659
-	void EraseLastChar(string &formerString);
660
+	int FieldEraseLastChar(const uint16_t **buf, int *len);
661
+	int FieldClear(const uint16_t **buf, int *len);
662
 	bool OnKeyPress(XEvent& event);
663
 	void ShowText();
664
 	void ShowSession();
665
 
666
-	void SlimDrawString8(XftDraw *d, XftColor *color, XftFont *font,
667
+	static bool isUtf16CharAllowed(uint16_t c);
668
+	void SlimDrawString16(XftDraw *d, XftColor *color, XftFont *font,
669
+						  int x, int y, const uint16_t *str, int strLen,
670
+						  XftColor* shadowColor, int xOffset, int yOffset);
671
+
672
+	void SlimDrawStringUtf8(XftDraw *d, XftColor *color, XftFont *font,
673
 							int x, int y, const std::string &str,
674
 							XftColor *shadowColor,
675
 							int xOffset, int yOffset);
676
@@ -136,12 +143,16 @@
677
 	XftColor entershadowcolor;
678
 	ActionType action;
679
 	FieldType field;
680
+	XIM displayIm;
681
+	XIC displayIc;
682
 	//Pixmap   background;
683
 	
684
 	/* Username/Password */
685
-	std::string NameBuffer;
686
-	std::string PasswdBuffer;
687
-	std::string HiddenPasswdBuffer;
688
+	uint16_t nameBuffer[INPUT_MAXLENGTH_NAME + 1];
689
+	int nameBufferLen;
690
+	uint16_t passwdBuffer[INPUT_MAXLENGTH_PASSWD + 1];
691
+	int passwdBufferLen;
692
+	uint16_t hiddenPasswdBuffer[INPUT_MAXLENGTH_PASSWD + 1];
693
 
694
 	/* screen stuff */
695
 	Rectangle viewport;
696
--- slimlock.cpp.orig	2014-08-12 18:08:28.000000000 +0200
697
+++ slimlock.cpp	2014-08-12 18:09:24.000000000 +0200
698
@@ -48,19 +48,19 @@
699
 void *RaiseWindow(void *data);
700
 
701
 // I really didn't wanna put these globals here, but it's the only way...
702
-Display* dpy;
703
-int scr;
704
-Window win;
705
-Cfg* cfg;
706
-Panel* loginPanel;
707
-string themeName = "";
708
-
709
-pam_handle_t *pam_handle;
710
-struct pam_conv conv = {ConvCallback, NULL};
711
-
712
-CARD16 dpms_standby, dpms_suspend, dpms_off, dpms_level;
713
-BOOL dpms_state, using_dpms;
714
-int term;
715
+static Display* dpy;
716
+static int scr;
717
+static Window win;
718
+static Cfg* cfg;
719
+static Panel* loginPanel;
720
+static string themeName = "";
721
+
722
+static pam_handle_t *pam_handle;
723
+static struct pam_conv conv = {ConvCallback, NULL};
724
+
725
+static CARD16 dpms_standby, dpms_suspend, dpms_off, dpms_level;
726
+static BOOL dpms_state, using_dpms;
727
+static int term;
728
 
729
 static void
730
 die(const char *errstr, ...) {
731
@@ -73,6 +73,10 @@
732
 }
733
 
734
 int main(int argc, char **argv) {
735
+
736
+	// We need to set the locale to get the input encoded in UTF-8
737
+	setlocale (LC_ALL, "");
738
+
739
 	if((argc == 2) && !strcmp("-v", argv[1]))
740
 		die(APPNAME"-"VERSION", © 2010-2012 Joel Burget\n");
741
 	else if(argc != 1)
742
--- switchuser.h.orig	2014-08-12 18:08:28.000000000 +0200
743
+++ switchuser.h	2014-08-12 18:09:20.000000000 +0200
744
@@ -32,8 +32,6 @@
745
 	void Login(const char* cmd, const char* mcookie);
746
 
747
 private:
748
-	SwitchUser();
749
-	void SetEnvironment();
750
 	void SetUserId();
751
 	void Execute(const char* cmd);
752
 	void SetClientAuth(const char* mcookie);
753
--- util.cpp.orig	2014-08-12 18:08:28.000000000 +0200
754
+++ util.cpp	2014-08-12 18:09:20.000000000 +0200
755
@@ -67,3 +67,162 @@
756
 
757
 	return pid + tm + (ts.tv_sec ^ ts.tv_nsec);
758
 }
759
+
760
+/* Given a UTF-8 encoded string pointed to by utf8 of length length in
761
+bytes, returns the corresponding UTF-16 encoded string in the
762
+buffer pointed to by utf16.  The maximum number of UTF-16 encoding
763
+units (i.e., Unit16s) allowed in the buffer is specified in
764
+utf16_max_length.  The return value is the number of UTF-16
765
+encoding units placed in the output buffer pointed to by utf16.
766
+
767
+In case of an error, -1 is returned, leaving some unusable partial
768
+results in the output buffer.
769
+
770
+The caller must estimate the size of utf16 buffer by itself before
771
+calling this function.  Insufficient output buffer is considered as
772
+an error, and once an error occured, this function doesn't give any
773
+clue how large the result will be.
774
+
775
+The error cases include following:
776
+
777
+- Invalid byte sequences were in the input UTF-8 bytes.  The caller
778
+	has no way to know what point in the input buffer was the
779
+	errornous byte.
780
+
781
+- The input contained a character (a valid UTF-8 byte sequence)
782
+	whose scalar value exceeded the range that UTF-16 can represent
783
+	(i.e., characters whose Unicode scalar value above 0x110000).
784
+
785
+- The output buffer has no enough space to hold entire utf16 data.
786
+
787
+Please note:
788
+
789
+- '\0'-termination is not assumed both on the input UTF-8 string
790
+	and on the output UTF-16 string; any legal zero byte in the input
791
+	UTF-8 string will be converted to a 16-bit zero in output.  As a
792
+	side effect, the last UTF-16 encoding unit stored in the output
793
+	buffer will have a non-zero value if the input UTF-8 was not
794
+	'\0'-terminated.
795
+
796
+- UTF-8 aliases are *not* considered as an error.  They are
797
+	converted to UTF-16.  For example, 0xC0 0xA0, 0xE0 0x80 0xA0,
798
+	and 0xF0 0x80 0x80 0xA0 are all mapped to a single UTF-16
799
+	encoding unit 0x0020.
800
+
801
+- Three byte UTF-8 sequences whose value corresponds to a surrogate
802
+	code or other reserved scalar value are not considered as an
803
+	error either.  They may cause an invalid UTF-16 data (e.g., those
804
+	containing unpaired surrogates).
805
+
806
+*/
807
+int Util::utf8ToUtf16(const char *buf, const int utf8_length, uint16_t *utf16, const int utf16_max_length) {
808
+
809
+	/* p moves over the output buffer.  max_ptr points to the next to the last slot of the buffer.  */
810
+	uint16_t *p = utf16;
811
+	const uint16_t *max_ptr = utf16 + utf16_max_length;
812
+	const unsigned char *utf8 = (const unsigned char *)buf;
813
+
814
+	/* end_of_input points to the last byte of input as opposed to the next to the last byte.  */
815
+	unsigned char const *const end_of_input = utf8 + utf8_length - 1;
816
+
817
+	while (utf8 <= end_of_input) {
818
+		const unsigned char c = *utf8;
819
+		if (p >= max_ptr) {
820
+			/* No more output space.  */
821
+			return -1;
822
+		}
823
+		if (c < 0x80) {
824
+			/* One byte ASCII.  */
825
+			*p++ = c;
826
+			utf8 += 1;
827
+		} else if (c < 0xC0) {
828
+			/* Follower byte without preceeding leader bytes.  */
829
+			return -1;
830
+		} else if (c < 0xE0) {
831
+			/* Two byte sequence.  We need one follower byte.  */
832
+			if (end_of_input - utf8 < 1 || (((utf8[1] ^ 0x80)) & 0xC0)) {
833
+				return -1;
834
+			}
835
+			*p++ = (uint16_t)(0xCF80 + (c << 6) + utf8[1]);
836
+			utf8 += 2;
837
+		} else if (c < 0xF0) {
838
+			/* Three byte sequence.  We need two follower byte.  */
839
+			if (end_of_input - utf8 < 2 || (((utf8[1] ^ 0x80) | (utf8[2] ^ 0x80)) & 0xC0)) {
840
+				return -1;
841
+			}
842
+			*p++ = (uint16_t)(0xDF80 + (c << 12) + (utf8[1] << 6) + utf8[2]);
843
+			utf8 += 3;
844
+		} else if (c < 0xF8) {
845
+			int plane;
846
+			/* Four byte sequence.  We need three follower bytes.  */
847
+			if (end_of_input - utf8 < 3 || (((utf8[1] ^ 0x80) | (utf8[2] ^0x80) | (utf8[3] ^ 0x80)) & 0xC0)) {
848
+				return -1;
849
+			}
850
+			plane = (-0xC8 + (c << 2) + (utf8[1] >> 4));
851
+			if (plane == 0) {
852
+				/* This four byte sequence is an alias that
853
+						corresponds to a Unicode scalar value in BMP.
854
+				It fits in an UTF-16 encoding unit.  */
855
+				*p++ = (uint16_t)(0xDF80 + (utf8[1] << 12) + (utf8[2] << 6) + utf8[3]);
856
+			} else if (plane <= 16) {
857
+				/* This is a legal four byte sequence that corresponds to a surrogate pair.  */
858
+				if (p + 1 >= max_ptr) {
859
+					/* No enough space on the output buffer for the pair.  */
860
+					return -1;
861
+				}
862
+				*p++ = (uint16_t)(0xE5B8 + (c << 8) + (utf8[1] << 2) + (utf8[2] >> 4));
863
+				*p++ = (uint16_t)(0xDB80 + ((utf8[2] & 0x0F) << 6) + utf8[3]);
864
+			} else {
865
+				/* This four byte sequence is out of UTF-16 code space.  */
866
+				return -1;
867
+			}
868
+			utf8 += 4;
869
+		} else {
870
+			/* Longer sequence or unused byte.  */
871
+			return -1;
872
+		}
873
+	}
874
+	return p - utf16;
875
+}
876
+
877
+/* Compare an ASCII string with an UTF-16 string */
878
+bool Util::utf16EqualToAscii(const char *ascii, uint16_t *utf16, int utf16Len) {
879
+
880
+	while(*ascii != 0 && utf16Len > 0) {
881
+		if(*utf16++ != (uint16_t)*ascii++) {
882
+			return false;
883
+		}
884
+		utf16Len--;
885
+	}
886
+	return *ascii == 0 && utf16Len == 0;
887
+}
888
+
889
+std::string Util::utf16BufToUtf8String(const uint16_t *utf16Buf, int utf16Len) {
890
+
891
+	std::string outStr;
892
+	outStr.reserve(utf16Len * 2);
893
+
894
+	while(*utf16Buf != 0 && utf16Len > 0) {
895
+
896
+		const uint16_t c16 = *utf16Buf++;
897
+		if (c16 <= 0x007F) {
898
+			outStr.push_back((char)c16);
899
+		}
900
+		else if (c16 <= 0x07FF) {
901
+			unsigned char c = 0xC0 | ((unsigned char)(c16 >> 6));
902
+			outStr.push_back(c);
903
+			c = 0x80 | ((unsigned char)(c16 & 0x003F));
904
+			outStr.push_back(c);
905
+		}
906
+		else {
907
+			unsigned char c = 0xE0 | ((unsigned char)(c16 >> 12));
908
+			outStr.push_back(c);
909
+			c = 0x80 | ((unsigned char)((c16 >> 6) & 0x003F));
910
+			outStr.push_back(c);
911
+			c = 0x80 | ((unsigned char)(c16 & 0x003F));
912
+			outStr.push_back(c);
913
+		}
914
+		utf16Len--;
915
+	}
916
+	return outStr;
917
+}
918
--- util.h.orig	2014-08-12 18:08:28.000000000 +0200
919
+++ util.h	2014-08-12 18:09:20.000000000 +0200
920
@@ -10,6 +10,7 @@
921
 #define _UTIL_H__
922
 
923
 #include <string>
924
+#include <stdint.h>
925
 
926
 namespace Util {
927
 	bool add_mcookie(const std::string &mcookie, const char *display,
928
@@ -19,6 +20,10 @@
929
 	long random(void);
930
 
931
 	long makeseed(void);
932
+	int utf8ToUtf16(const char *utf8, const int utf8_length,
933
+					uint16_t *utf16, const int utf16_max_length);
934
+	bool utf16EqualToAscii(const char *ascii, uint16_t *utf16, int utf16Len);
935
+	std::string utf16BufToUtf8String(const uint16_t *utf16Buf, int utf16Len);
936
 }
937
 
938
 #endif /* _UTIL_H__ */
(-)./files/patch-slim.conf (-7 / +30 lines)
Lines 1-12 Link Here
1
--- ./slim.conf.orig	2012-12-31 07:03:42.000000000 -0600
1
--- slim.conf.orig	2013-10-01 18:38:05.000000000 -0400
2
+++ ./slim.conf	2013-03-23 14:10:35.000000000 -0500
2
+++ slim.conf	2014-08-28 21:35:07.000000000 -0400
3
@@ -1,17 +1,19 @@
3
@@ -1,17 +1,20 @@
4
 # Path, X server and arguments (if needed)
4
 # Path, X server and arguments (if needed)
5
 # Note: -xauth $authfile is automatically appended
5
 # Note: -xauth $authfile is automatically appended
6
-default_path        /bin:/usr/bin:/usr/local/bin
6
-default_path        /bin:/usr/bin:/usr/local/bin
7
-default_xserver     /usr/bin/X
7
-default_xserver     /usr/bin/X
8
-#xserver_arguments   -dpi 75
8
-#xserver_arguments   -dpi 75
9
+default_path        /bin:/usr/bin:%%LOCALBASE%%/bin
9
+# Use default path from /etc/login.conf
10
+default_path        /sbin:/bin:/usr/sbin:/usr/bin:/usr/games:%%LOCALBASE%%/sbin:%%LOCALBASE%%/bin:$HOME/bin
10
+default_xserver     %%LOCALBASE%%/bin/X
11
+default_xserver     %%LOCALBASE%%/bin/X
11
+# The X server needs to be started on an unused virtual terminal,
12
+# The X server needs to be started on an unused virtual terminal,
12
+# for FreeBSD in a default configuration, the first one of those is #09
13
+# for FreeBSD in a default configuration, the first one of those is #09
Lines 27-33 Link Here
27
 
28
 
28
 # Xauth file for server
29
 # Xauth file for server
29
 authfile           /var/run/slim.auth
30
 authfile           /var/run/slim.auth
30
@@ -32,8 +34,8 @@
31
@@ -32,8 +35,8 @@
31
 # NOTE: if your system does not have bash you need
32
 # NOTE: if your system does not have bash you need
32
 # to adjust the command according to your preferred shell,
33
 # to adjust the command according to your preferred shell,
33
 # i.e. for freebsd use:
34
 # i.e. for freebsd use:
Lines 38-44 Link Here
38
 
39
 
39
 # Commands executed when starting and exiting a session.
40
 # Commands executed when starting and exiting a session.
40
 # They can be used for registering a X11 session with
41
 # They can be used for registering a X11 session with
41
@@ -63,7 +65,7 @@
42
@@ -47,11 +50,16 @@
43
 # options "-d" and "-nodaemon"
44
 # daemon	yes
45
 
46
-# Available sessions (first one is the default).
47
-# The current chosen session name is replaced in the login_cmd
48
-# above, so your login command can handle different sessions.
49
-# see the xinitrc.sample file shipped with slim sources
50
-sessions            xfce4,icewm-session,wmaker,blackbox
51
+# Option "sessions" is no longer supported.
52
+# Now you need to put session files in the directory specified
53
+# by option "sessiondir".
54
+# sessions            xfce4,icewm-session,wmaker,blackbox
55
+
56
+# Directory of session files.
57
+# They should be xdg-style .desktop files.
58
+# The "Name" entry in the session file would be used as session name.
59
+# The "Exec" entry would replace %session in login_cmd.
60
+sessiondir		%%LOCALBASE%%/share/xsessions
61
 
62
 # Executed when pressing F11 (requires imagemagick)
63
 screenshot_cmd      import -window root /slim.png
64
@@ -63,7 +71,7 @@
42
 # session_msg         Session: 
65
 # session_msg         Session: 
43
 
66
 
44
 # shutdown / reboot messages
67
 # shutdown / reboot messages
Lines 47-53 Link Here
47
 reboot_msg         The system is rebooting...
70
 reboot_msg         The system is rebooting...
48
 
71
 
49
 # default user, leave blank or remove this line
72
 # default user, leave blank or remove this line
50
@@ -84,7 +86,7 @@
73
@@ -84,7 +92,7 @@
51
 current_theme       default
74
 current_theme       default
52
 
75
 
53
 # Lock file
76
 # Lock file
(-)./files/pkg-message.in (+7 lines)
Lines 9-12 Link Here
9
9
10
into /etc/rc.conf
10
into /etc/rc.conf
11
11
12
*** Option "sessions" is no longer supported. ***
13
14
Now you need to put session files in the directory specified by option
15
"sessiondir". They should be xdg-style .desktop files.
16
The "Name" entry in the session file would be used as session name.
17
The "Exec" entry would replace %session in login_cmd.
18
12
*************************************************************************
19
*************************************************************************

Return to bug 192783