panel.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  1. /* SLiM - Simple Login Manager
  2. Copyright (C) 1997, 1998 Per Liden
  3. Copyright (C) 2004-06 Simone Rota <sip@varlock.com>
  4. Copyright (C) 2004-06 Johannes Winkelmann <jw@tks6.net>
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. */
  10. #include <sstream>
  11. #include <poll.h>
  12. #include <X11/extensions/Xrandr.h>
  13. #include "panel.h"
  14. using namespace std;
  15. Panel::Panel(Display* dpy, int scr, Window root, Cfg* config,
  16. const string& themedir, PanelType panel_mode) {
  17. /* Set display */
  18. Dpy = dpy;
  19. Scr = scr;
  20. Root = root;
  21. cfg = config;
  22. mode = panel_mode;
  23. session = "";
  24. if (mode == Mode_Lock) {
  25. Win = root;
  26. viewport = GetPrimaryViewport();
  27. }
  28. /* Init GC */
  29. XGCValues gcv;
  30. unsigned long gcm;
  31. gcm = GCForeground|GCBackground|GCGraphicsExposures;
  32. gcv.foreground = GetColor("black");
  33. gcv.background = GetColor("white");
  34. gcv.graphics_exposures = False;
  35. if (mode == Mode_Lock)
  36. TextGC = XCreateGC(Dpy, Win, gcm, &gcv);
  37. else
  38. TextGC = XCreateGC(Dpy, Root, gcm, &gcv);
  39. if (mode == Mode_Lock) {
  40. gcm = GCGraphicsExposures;
  41. gcv.graphics_exposures = False;
  42. WinGC = XCreateGC(Dpy, Win, gcm, &gcv);
  43. if (WinGC < 0) {
  44. cerr << APPNAME
  45. << ": failed to create pixmap\n.";
  46. exit(ERR_EXIT);
  47. }
  48. }
  49. font = XftFontOpenName(Dpy, Scr, cfg->getOption("input_font").c_str());
  50. welcomefont = XftFontOpenName(Dpy, Scr, cfg->getOption("welcome_font").c_str());
  51. introfont = XftFontOpenName(Dpy, Scr, cfg->getOption("intro_font").c_str());
  52. enterfont = XftFontOpenName(Dpy, Scr, cfg->getOption("username_font").c_str());
  53. msgfont = XftFontOpenName(Dpy, Scr, cfg->getOption("msg_font").c_str());
  54. Visual* visual = DefaultVisual(Dpy, Scr);
  55. Colormap colormap = DefaultColormap(Dpy, Scr);
  56. /* NOTE: using XftColorAllocValue() would be a better solution. Lazy me. */
  57. XftColorAllocName(Dpy, visual, colormap, cfg->getOption("input_color").c_str(), &inputcolor);
  58. XftColorAllocName(Dpy, visual, colormap, cfg->getOption("input_shadow_color").c_str(), &inputshadowcolor);
  59. XftColorAllocName(Dpy, visual, colormap, cfg->getOption("welcome_color").c_str(), &welcomecolor);
  60. XftColorAllocName(Dpy, visual, colormap, cfg->getOption("welcome_shadow_color").c_str(), &welcomeshadowcolor);
  61. XftColorAllocName(Dpy, visual, colormap, cfg->getOption("username_color").c_str(), &entercolor);
  62. XftColorAllocName(Dpy, visual, colormap, cfg->getOption("username_shadow_color").c_str(), &entershadowcolor);
  63. XftColorAllocName(Dpy, visual, colormap, cfg->getOption("msg_color").c_str(), &msgcolor);
  64. XftColorAllocName(Dpy, visual, colormap, cfg->getOption("msg_shadow_color").c_str(), &msgshadowcolor);
  65. XftColorAllocName(Dpy, visual, colormap, cfg->getOption("intro_color").c_str(), &introcolor);
  66. XftColorAllocName(Dpy, visual, colormap,
  67. cfg->getOption("session_color").c_str(), &sessioncolor);
  68. XftColorAllocName(Dpy, visual, colormap,
  69. cfg->getOption("session_shadow_color").c_str(), &sessionshadowcolor);
  70. /* Load properties from config / theme */
  71. input_name_x = cfg->getIntOption("input_name_x");
  72. input_name_y = cfg->getIntOption("input_name_y");
  73. input_pass_x = cfg->getIntOption("input_pass_x");
  74. input_pass_y = cfg->getIntOption("input_pass_y");
  75. inputShadowXOffset = cfg->getIntOption("input_shadow_xoffset");
  76. inputShadowYOffset = cfg->getIntOption("input_shadow_yoffset");
  77. if (input_pass_x < 0 || input_pass_y < 0){ /* single inputbox mode */
  78. input_pass_x = input_name_x;
  79. input_pass_y = input_name_y;
  80. }
  81. /* Load panel and background image */
  82. string panelpng = "";
  83. panelpng = panelpng + themedir +"/panel.png";
  84. image = new Image;
  85. bool loaded = image->Read(panelpng.c_str());
  86. if (!loaded) { /* try jpeg if png failed */
  87. panelpng = themedir + "/panel.jpg";
  88. loaded = image->Read(panelpng.c_str());
  89. if (!loaded) {
  90. logStream << APPNAME
  91. << ": could not load panel image for theme '"
  92. << basename((char*)themedir.c_str()) << "'"
  93. << endl;
  94. exit(ERR_EXIT);
  95. }
  96. }
  97. Image* bg = new Image();
  98. string bgstyle = cfg->getOption("background_style");
  99. if (bgstyle != "color") {
  100. panelpng = themedir +"/background.png";
  101. loaded = bg->Read(panelpng.c_str());
  102. if (!loaded) { /* try jpeg if png failed */
  103. panelpng = themedir + "/background.jpg";
  104. loaded = bg->Read(panelpng.c_str());
  105. if (!loaded){
  106. logStream << APPNAME
  107. << ": could not load background image for theme '"
  108. << basename((char*)themedir.c_str()) << "'"
  109. << endl;
  110. exit(ERR_EXIT);
  111. }
  112. }
  113. }
  114. if (mode == Mode_Lock) {
  115. if (bgstyle == "stretch")
  116. bg->Resize(viewport.width, viewport.height);
  117. //bg->Resize(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)),
  118. // XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)));
  119. else if (bgstyle == "tile")
  120. bg->Tile(viewport.width, viewport.height);
  121. else if (bgstyle == "center") {
  122. string hexvalue = cfg->getOption("background_color");
  123. hexvalue = hexvalue.substr(1,6);
  124. bg->Center(viewport.width,
  125. viewport.height,
  126. hexvalue.c_str());
  127. } else { // plain color or error
  128. string hexvalue = cfg->getOption("background_color");
  129. hexvalue = hexvalue.substr(1,6);
  130. bg->Center(viewport.width,
  131. viewport.height,
  132. hexvalue.c_str());
  133. }
  134. } else {
  135. if (bgstyle == "stretch") {
  136. bg->Resize(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)),
  137. XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)));
  138. } else if (bgstyle == "tile") {
  139. bg->Tile(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)),
  140. XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)));
  141. } else if (bgstyle == "center") {
  142. string hexvalue = cfg->getOption("background_color");
  143. hexvalue = hexvalue.substr(1,6);
  144. bg->Center(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)),
  145. XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)),
  146. hexvalue.c_str());
  147. } else { /* plain color or error */
  148. string hexvalue = cfg->getOption("background_color");
  149. hexvalue = hexvalue.substr(1,6);
  150. bg->Center(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)),
  151. XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)),
  152. hexvalue.c_str());
  153. }
  154. }
  155. string cfgX = cfg->getOption("input_panel_x");
  156. string cfgY = cfg->getOption("input_panel_y");
  157. if (mode == Mode_Lock) {
  158. X = Cfg::absolutepos(cfgX, viewport.width, image->Width());
  159. Y = Cfg::absolutepos(cfgY, viewport.height, image->Height());
  160. input_name_x += X;
  161. input_name_y += Y;
  162. input_pass_x += X;
  163. input_pass_y += Y;
  164. } else {
  165. X = Cfg::absolutepos(cfgX, XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), image->Width());
  166. Y = Cfg::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), image->Height());
  167. }
  168. if (mode == Mode_Lock) {
  169. /* Merge image into background without crop */
  170. image->Merge_non_crop(bg, X, Y);
  171. PanelPixmap = image->createPixmap(Dpy, Scr, Win);
  172. } else {
  173. /* Merge image into background */
  174. image->Merge(bg, X, Y);
  175. PanelPixmap = image->createPixmap(Dpy, Scr, Root);
  176. }
  177. delete bg;
  178. /* Read (and substitute vars in) the welcome message */
  179. welcome_message = cfg->getWelcomeMessage();
  180. intro_message = cfg->getOption("intro_msg");
  181. if (mode == Mode_Lock) {
  182. SetName(getenv("USER"));
  183. field = Get_Passwd;
  184. OnExpose();
  185. }
  186. }
  187. Panel::~Panel() {
  188. Visual* visual = DefaultVisual(Dpy, Scr);
  189. Colormap colormap = DefaultColormap(Dpy, Scr);
  190. XftColorFree(Dpy, visual, colormap, &inputcolor);
  191. XftColorFree(Dpy, visual, colormap, &inputshadowcolor);
  192. XftColorFree(Dpy, visual, colormap, &welcomecolor);
  193. XftColorFree(Dpy, visual, colormap, &welcomeshadowcolor);
  194. XftColorFree(Dpy, visual, colormap, &entercolor);
  195. XftColorFree(Dpy, visual, colormap, &entershadowcolor);
  196. XftColorFree(Dpy, visual, colormap, &msgcolor);
  197. XftColorFree(Dpy, visual, colormap, &msgshadowcolor);
  198. XftColorFree(Dpy, visual, colormap, &introcolor);
  199. XftColorFree(Dpy, visual, colormap, &sessioncolor);
  200. XftColorFree(Dpy, visual, colormap, &sessionshadowcolor);
  201. XFreeGC(Dpy, TextGC);
  202. XftFontClose(Dpy, font);
  203. XftFontClose(Dpy, msgfont);
  204. XftFontClose(Dpy, introfont);
  205. XftFontClose(Dpy, welcomefont);
  206. XftFontClose(Dpy, enterfont);
  207. if (mode == Mode_Lock)
  208. XFreeGC(Dpy, WinGC);
  209. delete image;
  210. }
  211. void Panel::OpenPanel() {
  212. /* Create window */
  213. Win = XCreateSimpleWindow(Dpy, Root, X, Y,
  214. image->Width(),
  215. image->Height(),
  216. 0, GetColor("white"), GetColor("white"));
  217. /* Events */
  218. XSelectInput(Dpy, Win, ExposureMask | KeyPressMask);
  219. /* Set background */
  220. XSetWindowBackgroundPixmap(Dpy, Win, PanelPixmap);
  221. /* Show window */
  222. XMapWindow(Dpy, Win);
  223. XMoveWindow(Dpy, Win, X, Y); /* override wm positioning (for tests) */
  224. /* Grab keyboard */
  225. XGrabKeyboard(Dpy, Win, False, GrabModeAsync, GrabModeAsync, CurrentTime);
  226. XFlush(Dpy);
  227. }
  228. void Panel::ClosePanel() {
  229. XUngrabKeyboard(Dpy, CurrentTime);
  230. XUnmapWindow(Dpy, Win);
  231. XDestroyWindow(Dpy, Win);
  232. XFlush(Dpy);
  233. }
  234. void Panel::ClearPanel() {
  235. session = "";
  236. Reset();
  237. XClearWindow(Dpy, Root);
  238. XClearWindow(Dpy, Win);
  239. Cursor(SHOW);
  240. ShowText();
  241. XFlush(Dpy);
  242. }
  243. void Panel::WrongPassword(int timeout) {
  244. string message;
  245. XGlyphInfo extents;
  246. #if 0
  247. if (CapsLockOn)
  248. message = cfg->getOption("passwd_feedback_capslock");
  249. else
  250. #endif
  251. message = cfg->getOption("passwd_feedback_msg");
  252. XftDraw *draw = XftDrawCreate(Dpy, Win,
  253. DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
  254. XftTextExtents8(Dpy, msgfont, reinterpret_cast<const XftChar8*>(message.c_str()),
  255. message.length(), &extents);
  256. string cfgX = cfg->getOption("passwd_feedback_x");
  257. string cfgY = cfg->getOption("passwd_feedback_y");
  258. int shadowXOffset = cfg->getIntOption("msg_shadow_xoffset");
  259. int shadowYOffset = cfg->getIntOption("msg_shadow_yoffset");
  260. int msg_x = Cfg::absolutepos(cfgX, XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.width);
  261. int msg_y = Cfg::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.height);
  262. OnExpose();
  263. SlimDrawString8(draw, &msgcolor, msgfont, msg_x, msg_y, message,
  264. &msgshadowcolor, shadowXOffset, shadowYOffset);
  265. if (cfg->getOption("bell") == "1")
  266. XBell(Dpy, 100);
  267. XFlush(Dpy);
  268. sleep(timeout);
  269. ResetPasswd();
  270. OnExpose();
  271. // The message should stay on the screen even after the password field is
  272. // cleared, methinks. I don't like this solution, but it works.
  273. SlimDrawString8(draw, &msgcolor, msgfont, msg_x, msg_y, message,
  274. &msgshadowcolor, shadowXOffset, shadowYOffset);
  275. XSync(Dpy, True);
  276. XftDrawDestroy(draw);
  277. }
  278. void Panel::Message(const string& text) {
  279. string cfgX, cfgY;
  280. XGlyphInfo extents;
  281. XftDraw *draw;
  282. if (mode == Mode_Lock)
  283. draw = XftDrawCreate(Dpy, Win,
  284. DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
  285. else
  286. draw = XftDrawCreate(Dpy, Root,
  287. DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
  288. XftTextExtents8(Dpy, msgfont,
  289. reinterpret_cast<const XftChar8*>(text.c_str()),
  290. text.length(), &extents);
  291. cfgX = cfg->getOption("msg_x");
  292. cfgY = cfg->getOption("msg_y");
  293. int shadowXOffset = cfg->getIntOption("msg_shadow_xoffset");
  294. int shadowYOffset = cfg->getIntOption("msg_shadow_yoffset");
  295. int msg_x, msg_y;
  296. if (mode == Mode_Lock) {
  297. msg_x = Cfg::absolutepos(cfgX, viewport.width, extents.width);
  298. msg_y = Cfg::absolutepos(cfgY, viewport.height, extents.height);
  299. } else {
  300. msg_x = Cfg::absolutepos(cfgX, XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.width);
  301. msg_y = Cfg::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.height);
  302. }
  303. SlimDrawString8 (draw, &msgcolor, msgfont, msg_x, msg_y,
  304. text,
  305. &msgshadowcolor,
  306. shadowXOffset, shadowYOffset);
  307. XFlush(Dpy);
  308. XftDrawDestroy(draw);
  309. }
  310. void Panel::Error(const string& text) {
  311. ClosePanel();
  312. Message(text);
  313. sleep(ERROR_DURATION);
  314. OpenPanel();
  315. ClearPanel();
  316. }
  317. unsigned long Panel::GetColor(const char* colorname) {
  318. XColor color;
  319. XWindowAttributes attributes;
  320. if (mode == Mode_Lock)
  321. XGetWindowAttributes(Dpy, Win, &attributes);
  322. else
  323. XGetWindowAttributes(Dpy, Root, &attributes);
  324. color.pixel = 0;
  325. if(!XParseColor(Dpy, attributes.colormap, colorname, &color))
  326. logStream << APPNAME << ": can't parse color " << colorname << endl;
  327. else if(!XAllocColor(Dpy, attributes.colormap, &color))
  328. logStream << APPNAME << ": can't allocate color " << colorname << endl;
  329. return color.pixel;
  330. }
  331. void Panel::Cursor(int visible) {
  332. const char* text = NULL;
  333. int xx = 0, yy = 0, y2 = 0, cheight = 0;
  334. const char* txth = "Wj"; /* used to get cursor height */
  335. if (mode == Mode_Lock) {
  336. text = HiddenPasswdBuffer.c_str();
  337. xx = input_pass_x;
  338. yy = input_pass_y;
  339. } else {
  340. switch(field) {
  341. case Get_Passwd:
  342. text = HiddenPasswdBuffer.c_str();
  343. xx = input_pass_x;
  344. yy = input_pass_y;
  345. break;
  346. case Get_Name:
  347. text = NameBuffer.c_str();
  348. xx = input_name_x;
  349. yy = input_name_y;
  350. break;
  351. }
  352. }
  353. XGlyphInfo extents;
  354. XftTextExtents8(Dpy, font, (XftChar8*)txth, strlen(txth), &extents);
  355. cheight = extents.height;
  356. y2 = yy - extents.y + extents.height;
  357. XftTextExtents8(Dpy, font, (XftChar8*)text, strlen(text), &extents);
  358. xx += extents.width;
  359. if(visible == SHOW) {
  360. if (mode == Mode_Lock) {
  361. xx += viewport.x;
  362. yy += viewport.y;
  363. y2 += viewport.y;
  364. }
  365. XSetForeground(Dpy, TextGC,
  366. GetColor(cfg->getOption("input_color").c_str()));
  367. XDrawLine(Dpy, Win, TextGC,
  368. xx+1, yy-cheight,
  369. xx+1, y2);
  370. } else {
  371. if (mode == Mode_Lock)
  372. ApplyBackground(Rectangle(xx+1, yy-cheight,
  373. 1, y2-(yy-cheight)+1));
  374. else
  375. XClearArea(Dpy, Win, xx+1, yy-cheight,
  376. 1, y2-(yy-cheight)+1, false);
  377. }
  378. }
  379. void Panel::EventHandler(const Panel::FieldType& curfield) {
  380. XEvent event;
  381. field = curfield;
  382. bool loop = true;
  383. if (mode == Mode_DM)
  384. OnExpose();
  385. struct pollfd x11_pfd = {0};
  386. x11_pfd.fd = ConnectionNumber(Dpy);
  387. x11_pfd.events = POLLIN;
  388. while (loop) {
  389. if (XPending(Dpy) || poll(&x11_pfd, 1, -1) > 0) {
  390. while(XPending(Dpy)) {
  391. XNextEvent(Dpy, &event);
  392. switch(event.type) {
  393. case Expose:
  394. OnExpose();
  395. break;
  396. case KeyPress:
  397. loop=OnKeyPress(event);
  398. break;
  399. }
  400. }
  401. }
  402. }
  403. return;
  404. }
  405. void Panel::OnExpose(void) {
  406. XftDraw *draw = XftDrawCreate(Dpy, Win,
  407. DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
  408. if (mode == Mode_Lock)
  409. ApplyBackground();
  410. else
  411. XClearWindow(Dpy, Win);
  412. if (input_pass_x != input_name_x || input_pass_y != input_name_y){
  413. SlimDrawString8 (draw, &inputcolor, font, input_name_x, input_name_y,
  414. NameBuffer,
  415. &inputshadowcolor,
  416. inputShadowXOffset, inputShadowYOffset);
  417. SlimDrawString8 (draw, &inputcolor, font, input_pass_x, input_pass_y,
  418. HiddenPasswdBuffer,
  419. &inputshadowcolor,
  420. inputShadowXOffset, inputShadowYOffset);
  421. } else { /*single input mode */
  422. switch(field) {
  423. case Get_Passwd:
  424. SlimDrawString8 (draw, &inputcolor, font,
  425. input_pass_x, input_pass_y,
  426. HiddenPasswdBuffer,
  427. &inputshadowcolor,
  428. inputShadowXOffset, inputShadowYOffset);
  429. break;
  430. case Get_Name:
  431. SlimDrawString8 (draw, &inputcolor, font,
  432. input_name_x, input_name_y,
  433. NameBuffer,
  434. &inputshadowcolor,
  435. inputShadowXOffset, inputShadowYOffset);
  436. break;
  437. }
  438. }
  439. XftDrawDestroy (draw);
  440. Cursor(SHOW);
  441. ShowText();
  442. }
  443. bool Panel::OnKeyPress(XEvent& event) {
  444. char ascii;
  445. KeySym keysym;
  446. XComposeStatus compstatus;
  447. int xx = 0;
  448. int yy = 0;
  449. string text;
  450. string formerString = "";
  451. XLookupString(&event.xkey, &ascii, 1, &keysym, &compstatus);
  452. switch(keysym){
  453. case XK_F1:
  454. SwitchSession();
  455. return true;
  456. case XK_F11:
  457. /* Take a screenshot */
  458. system(cfg->getOption("screenshot_cmd").c_str());
  459. return true;
  460. case XK_Return:
  461. case XK_KP_Enter:
  462. if (field==Get_Name){
  463. /* Don't allow an empty username */
  464. if (NameBuffer.empty()) return true;
  465. if (NameBuffer==CONSOLE_STR){
  466. action = Console;
  467. } else if (NameBuffer==HALT_STR){
  468. action = Halt;
  469. } else if (NameBuffer==REBOOT_STR){
  470. action = Reboot;
  471. } else if (NameBuffer==SUSPEND_STR){
  472. action = Suspend;
  473. } else if (NameBuffer==EXIT_STR){
  474. action = Exit;
  475. } else{
  476. if (mode == Mode_DM)
  477. action = Login;
  478. else
  479. action = Lock;
  480. }
  481. };
  482. return false;
  483. default:
  484. break;
  485. };
  486. Cursor(HIDE);
  487. switch(keysym){
  488. case XK_Delete:
  489. case XK_BackSpace:
  490. switch(field) {
  491. case GET_NAME:
  492. if (! NameBuffer.empty()){
  493. formerString=NameBuffer;
  494. NameBuffer.erase(--NameBuffer.end());
  495. };
  496. break;
  497. case GET_PASSWD:
  498. if (! PasswdBuffer.empty()){
  499. formerString=HiddenPasswdBuffer;
  500. PasswdBuffer.erase(--PasswdBuffer.end());
  501. HiddenPasswdBuffer.erase(--HiddenPasswdBuffer.end());
  502. };
  503. break;
  504. };
  505. break;
  506. case XK_w:
  507. case XK_u:
  508. if (reinterpret_cast<XKeyEvent&>(event).state & ControlMask) {
  509. switch(field) {
  510. case Get_Passwd:
  511. formerString = HiddenPasswdBuffer;
  512. HiddenPasswdBuffer.clear();
  513. PasswdBuffer.clear();
  514. break;
  515. case Get_Name:
  516. formerString = NameBuffer;
  517. NameBuffer.clear();
  518. break;
  519. };
  520. break;
  521. }
  522. /* Deliberate fall-through */
  523. default:
  524. if (isprint(ascii) && (keysym < XK_Shift_L || keysym > XK_Hyper_R)){
  525. switch(field) {
  526. case GET_NAME:
  527. formerString=NameBuffer;
  528. if (NameBuffer.length() < INPUT_MAXLENGTH_NAME-1){
  529. NameBuffer.append(&ascii,1);
  530. };
  531. break;
  532. case GET_PASSWD:
  533. formerString=HiddenPasswdBuffer;
  534. if (PasswdBuffer.length() < INPUT_MAXLENGTH_PASSWD-1){
  535. PasswdBuffer.append(&ascii,1);
  536. HiddenPasswdBuffer.append("*");
  537. };
  538. break;
  539. };
  540. };
  541. break;
  542. };
  543. XGlyphInfo extents;
  544. XftDraw *draw = XftDrawCreate(Dpy, Win,
  545. DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
  546. switch(field) {
  547. case Get_Name:
  548. text = NameBuffer;
  549. xx = input_name_x;
  550. yy = input_name_y;
  551. break;
  552. case Get_Passwd:
  553. text = HiddenPasswdBuffer;
  554. xx = input_pass_x;
  555. yy = input_pass_y;
  556. break;
  557. }
  558. if (!formerString.empty()){
  559. const char* txth = "Wj"; /* get proper maximum height ? */
  560. XftTextExtents8(Dpy, font,
  561. reinterpret_cast<const XftChar8*>(txth), strlen(txth), &extents);
  562. int maxHeight = extents.height;
  563. XftTextExtents8(Dpy, font,
  564. reinterpret_cast<const XftChar8*>(formerString.c_str()),
  565. formerString.length(), &extents);
  566. int maxLength = extents.width;
  567. if (mode == Mode_Lock)
  568. ApplyBackground(Rectangle(input_pass_x - 3,
  569. input_pass_y - maxHeight - 3,
  570. maxLength + 6, maxHeight + 6));
  571. else
  572. XClearArea(Dpy, Win, xx - 3, yy-maxHeight - 3,
  573. maxLength + 6, maxHeight + 6, false);
  574. }
  575. if (!text.empty()) {
  576. SlimDrawString8 (draw, &inputcolor, font, xx, yy,
  577. text,
  578. &inputshadowcolor,
  579. inputShadowXOffset, inputShadowYOffset);
  580. }
  581. XftDrawDestroy (draw);
  582. Cursor(SHOW);
  583. return true;
  584. }
  585. /* Draw welcome and "enter username" message */
  586. void Panel::ShowText(){
  587. string cfgX, cfgY;
  588. XGlyphInfo extents;
  589. bool singleInputMode =
  590. input_name_x == input_pass_x &&
  591. input_name_y == input_pass_y;
  592. XftDraw *draw = XftDrawCreate(Dpy, Win,
  593. DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
  594. /* welcome message */
  595. XftTextExtents8(Dpy, welcomefont, (XftChar8*)welcome_message.c_str(),
  596. strlen(welcome_message.c_str()), &extents);
  597. cfgX = cfg->getOption("welcome_x");
  598. cfgY = cfg->getOption("welcome_y");
  599. int shadowXOffset = cfg->getIntOption("welcome_shadow_xoffset");
  600. int shadowYOffset = cfg->getIntOption("welcome_shadow_yoffset");
  601. welcome_x = Cfg::absolutepos(cfgX, image->Width(), extents.width);
  602. welcome_y = Cfg::absolutepos(cfgY, image->Height(), extents.height);
  603. if (welcome_x >= 0 && welcome_y >= 0) {
  604. SlimDrawString8 (draw, &welcomecolor, welcomefont,
  605. welcome_x, welcome_y,
  606. welcome_message,
  607. &welcomeshadowcolor, shadowXOffset, shadowYOffset);
  608. }
  609. /* Enter username-password message */
  610. string msg;
  611. if ((!singleInputMode|| field == Get_Passwd) && mode == Mode_DM) {
  612. msg = cfg->getOption("password_msg");
  613. XftTextExtents8(Dpy, enterfont, (XftChar8*)msg.c_str(),
  614. strlen(msg.c_str()), &extents);
  615. cfgX = cfg->getOption("password_x");
  616. cfgY = cfg->getOption("password_y");
  617. int shadowXOffset = cfg->getIntOption("username_shadow_xoffset");
  618. int shadowYOffset = cfg->getIntOption("username_shadow_yoffset");
  619. password_x = Cfg::absolutepos(cfgX, image->Width(), extents.width);
  620. password_y = Cfg::absolutepos(cfgY, image->Height(), extents.height);
  621. if (password_x >= 0 && password_y >= 0){
  622. SlimDrawString8 (draw, &entercolor, enterfont, password_x, password_y,
  623. msg, &entershadowcolor, shadowXOffset, shadowYOffset);
  624. }
  625. }
  626. if (!singleInputMode|| field == Get_Name) {
  627. msg = cfg->getOption("username_msg");
  628. XftTextExtents8(Dpy, enterfont, (XftChar8*)msg.c_str(),
  629. strlen(msg.c_str()), &extents);
  630. cfgX = cfg->getOption("username_x");
  631. cfgY = cfg->getOption("username_y");
  632. int shadowXOffset = cfg->getIntOption("username_shadow_xoffset");
  633. int shadowYOffset = cfg->getIntOption("username_shadow_yoffset");
  634. username_x = Cfg::absolutepos(cfgX, image->Width(), extents.width);
  635. username_y = Cfg::absolutepos(cfgY, image->Height(), extents.height);
  636. if (username_x >= 0 && username_y >= 0){
  637. SlimDrawString8 (draw, &entercolor, enterfont, username_x, username_y,
  638. msg, &entershadowcolor, shadowXOffset, shadowYOffset);
  639. }
  640. }
  641. XftDrawDestroy(draw);
  642. if (mode == Mode_Lock) {
  643. // If only the password box is visible, draw the user name somewhere too
  644. string user_msg = "User: " + GetName();
  645. int show_username = cfg->getIntOption("show_username");
  646. if (singleInputMode && show_username) {
  647. Message(user_msg);
  648. }
  649. }
  650. }
  651. string Panel::getSession() {
  652. return session;
  653. }
  654. /* choose next available session type */
  655. void Panel::SwitchSession() {
  656. session = cfg->nextSession(session);
  657. if (session.size() > 0) {
  658. ShowSession();
  659. }
  660. }
  661. /* Display session type on the screen */
  662. void Panel::ShowSession() {
  663. string msg_x, msg_y;
  664. XClearWindow(Dpy, Root);
  665. string currsession = cfg->getOption("session_msg") + " " + session;
  666. XGlyphInfo extents;
  667. sessionfont = XftFontOpenName(Dpy, Scr, cfg->getOption("session_font").c_str());
  668. XftDraw *draw = XftDrawCreate(Dpy, Root,
  669. DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
  670. XftTextExtents8(Dpy, sessionfont, reinterpret_cast<const XftChar8*>(currsession.c_str()),
  671. currsession.length(), &extents);
  672. msg_x = cfg->getOption("session_x");
  673. msg_y = cfg->getOption("session_y");
  674. int x = Cfg::absolutepos(msg_x, XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.width);
  675. int y = Cfg::absolutepos(msg_y, XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.height);
  676. int shadowXOffset = cfg->getIntOption("session_shadow_xoffset");
  677. int shadowYOffset = cfg->getIntOption("session_shadow_yoffset");
  678. SlimDrawString8(draw, &sessioncolor, sessionfont, x, y,
  679. currsession,
  680. &sessionshadowcolor,
  681. shadowXOffset, shadowYOffset);
  682. XFlush(Dpy);
  683. XftDrawDestroy(draw);
  684. }
  685. void Panel::SlimDrawString8(XftDraw *d, XftColor *color, XftFont *font,
  686. int x, int y, const string& str,
  687. XftColor* shadowColor,
  688. int xOffset, int yOffset)
  689. {
  690. int calc_x = 0;
  691. int calc_y = 0;
  692. if (mode == Mode_Lock) {
  693. calc_x = viewport.x;
  694. calc_y = viewport.y;
  695. }
  696. if (xOffset && yOffset) {
  697. XftDrawStringUtf8(d, shadowColor, font,
  698. x + xOffset + calc_x,
  699. y + yOffset + calc_y,
  700. reinterpret_cast<const FcChar8*>(str.c_str()),
  701. str.length());
  702. }
  703. XftDrawStringUtf8(d, color, font,
  704. x + calc_x,
  705. y + calc_y,
  706. reinterpret_cast<const FcChar8*>(str.c_str()),
  707. str.length());
  708. }
  709. Panel::ActionType Panel::getAction(void) const{
  710. return action;
  711. };
  712. void Panel::Reset(void){
  713. ResetName();
  714. ResetPasswd();
  715. };
  716. void Panel::ResetName(void){
  717. NameBuffer.clear();
  718. };
  719. void Panel::ResetPasswd(void){
  720. PasswdBuffer.clear();
  721. HiddenPasswdBuffer.clear();
  722. };
  723. void Panel::SetName(const string& name){
  724. NameBuffer=name;
  725. if (mode == Mode_DM)
  726. action = Login;
  727. else
  728. action = Lock;
  729. };
  730. const string& Panel::GetName(void) const{
  731. return NameBuffer;
  732. };
  733. const string& Panel::GetPasswd(void) const{
  734. return PasswdBuffer;
  735. };
  736. Rectangle Panel::GetPrimaryViewport() {
  737. Rectangle fallback;
  738. Rectangle result;
  739. RROutput primary;
  740. XRROutputInfo *primary_info;
  741. XRRScreenResources *resources;
  742. XRRCrtcInfo *crtc_info;
  743. fallback.x = 0;
  744. fallback.y = 0;
  745. fallback.width = DisplayWidth(Dpy, Scr);
  746. fallback.height = DisplayHeight(Dpy, Scr);
  747. primary = XRRGetOutputPrimary(Dpy, Win);
  748. if (!primary) {
  749. return fallback;
  750. }
  751. resources = XRRGetScreenResources(Dpy, Win);
  752. if (!resources)
  753. return fallback;
  754. primary_info = XRRGetOutputInfo(Dpy, resources, primary);
  755. if (!primary_info) {
  756. XRRFreeScreenResources(resources);
  757. return fallback;
  758. }
  759. crtc_info = XRRGetCrtcInfo(Dpy, resources, primary_info->crtc);
  760. if (!crtc_info) {
  761. XRRFreeOutputInfo(primary_info);
  762. XRRFreeScreenResources(resources);
  763. return fallback;
  764. }
  765. result.x = crtc_info->x;
  766. result.y = crtc_info->y;
  767. result.width = crtc_info->width;
  768. result.height = crtc_info->height;
  769. XRRFreeCrtcInfo(crtc_info);
  770. XRRFreeOutputInfo(primary_info);
  771. XRRFreeScreenResources(resources);
  772. return result;
  773. }
  774. void Panel::ApplyBackground(Rectangle rect) {
  775. int ret = 0;
  776. if (rect.is_empty()) {
  777. rect.x = 0;
  778. rect.y = 0;
  779. rect.width = viewport.width;
  780. rect.height = viewport.height;
  781. }
  782. ret = XCopyArea(Dpy, PanelPixmap, Win, WinGC,
  783. rect.x, rect.y, rect.width, rect.height,
  784. viewport.x + rect.x, viewport.y + rect.y);
  785. if (!ret)
  786. cerr << APPNAME << ": failed to put pixmap on the screen\n.";
  787. }