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