xsuperlock.c 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190
  1. /*
  2. * xsuperlock
  3. *
  4. * Copyright (C) 2015 Alexander Andrejevic <theflash AT sdf DOT lonestar DOT org>
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as
  8. * published by the Free Software Foundation, either version 3 of the
  9. * License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <stdlib.h>
  20. #include <stdio.h>
  21. #include <getopt.h>
  22. #include <signal.h>
  23. #include <time.h>
  24. #include <poll.h>
  25. #include <pwd.h>
  26. #include <crypt.h>
  27. #include <shadow.h>
  28. #include <X11/Xlib.h>
  29. #include <X11/Xft/Xft.h>
  30. #include <X11/extensions/xf86vmode.h>
  31. #include "config.h"
  32. #define POLL_TIMEOUT 200
  33. #define BUFFER_SIZE 256
  34. typedef struct screen_descriptor
  35. {
  36. Window wnd;
  37. pid_t saver_pid;
  38. int number;
  39. Visual *visual;
  40. Colormap colormap;
  41. GC gc;
  42. unsigned int width;
  43. unsigned int height;
  44. XftDraw *xft_draw;
  45. Cursor blank_cursor;
  46. int ramp_size;
  47. unsigned short *red_ramp;
  48. unsigned short *green_ramp;
  49. unsigned short *blue_ramp;
  50. } screen_descriptor_t;
  51. Display *dpy;
  52. screen_descriptor_t *screen_descriptors = NULL;
  53. int default_screen, screen_count;
  54. char password[BUFFER_SIZE];
  55. Bool dialog_displayed = False;
  56. unsigned int idle_counter = 0, incorrect_counter = 0;
  57. char *screensaver_dir = DEFAULT_SCREENSAVER_DIR;
  58. char *screensaver_name = NULL;
  59. char *screensaver_opts = NULL;
  60. char *correct_pwd_hash = NULL;
  61. unsigned int incorrect_timeout = 3;
  62. unsigned int idle_timeout = 30;
  63. Bool fade_enabled = False;
  64. unsigned int fade_timeout = 2000;
  65. unsigned int dialog_width = 400;
  66. unsigned int dialog_height = 300;
  67. XColor dialog_bg_color = { .red = 0xEEEE, .green = 0xEEEE, .blue = 0xEEEE };
  68. char *time_format = "%I:%M:%S %p";
  69. char *time_label_font = "sans-18:bold";
  70. int time_label_x = 0;
  71. int time_label_y = 20;
  72. XColor time_label_color = { .red = 0x0000, .green = 0x0000, .blue = 0x0000 };
  73. char *date_format = "%Y/%m/%d";
  74. char *date_label_font = "sans-12";
  75. int date_label_x = 0;
  76. int date_label_y = 45;
  77. XColor date_label_color = { .red = 0x0000, .green = 0x0000, .blue = 0x0000 };
  78. char *fullname_label = "%F";
  79. char *fullname_label_font = "sans-18";
  80. int fullname_label_x = 0;
  81. int fullname_label_y = 100;
  82. XColor fullname_label_color = { .red = 0x0000, .green = 0x0000, .blue = 0x0000 };
  83. char *username_label = "%n on %H";
  84. char *username_label_font = "sans-10";
  85. int username_label_x = 0;
  86. int username_label_y = 130;
  87. XColor username_label_color = { .red = 0x0000, .green = 0x0000, .blue = 0x0000 };
  88. char *password_label = "Password:";
  89. char *password_label_font = "sans-10";
  90. int password_label_x = 30;
  91. int password_label_y = 200;
  92. XColor password_label_color = { .red = 0x0000, .green = 0x0000, .blue = 0x0000 };
  93. unsigned int pwd_dot_size = 12;
  94. unsigned int pwd_field_width = 250;
  95. unsigned int pwd_field_height = 20;
  96. unsigned int pwd_field_border_width = 2;
  97. int pwd_field_x = -30;
  98. int pwd_field_y = 195;
  99. XColor pwd_field_border_color = { .red = 0x0000, .green = 0x0000, .blue = 0x0000 };
  100. XColor pwd_field_bg_color = { .red = 0xFFFF, .green = 0xFFFF, .blue = 0xFFFF };
  101. XColor pwd_field_dot_color = { .red = 0x0000, .green = 0x0000, .blue = 0x0000 };
  102. char *incorrect_label = "Incorrect password!";
  103. char *incorrect_label_font = "sans-10:bold";
  104. int incorrect_label_x = 0;
  105. int incorrect_label_y = 225;
  106. XColor incorrect_label_color = { .red = 0xFFFF, .green = 0x0000, .blue = 0x0000 };
  107. unsigned int button_width = 95;
  108. unsigned int button_height = 25;
  109. unsigned int button_border_width = 2;
  110. char *button_label_font = "sans-10";
  111. char *unlock_button_label = "Unlock";
  112. int unlock_button_x = 100;
  113. int unlock_button_y = 260;
  114. XColor unlock_button_bg_color = { .red = 0xFFFF, .green = 0xFFFF, .blue = 0xFFFF };
  115. XColor unlock_button_border_color = { .red = 0x0000, .green = 0x0000, .blue = 0x0000 };
  116. XColor unlock_button_label_color = { .red = 0x0000, .green = 0x0000, .blue = 0x0000 };
  117. char *cancel_button_label = "Cancel";
  118. int cancel_button_x = 205;
  119. int cancel_button_y = 260;
  120. XColor cancel_button_bg_color = { .red = 0xFFFF, .green = 0xFFFF, .blue = 0xFFFF };
  121. XColor cancel_button_border_color = { .red = 0x0000, .green = 0x0000, .blue = 0x0000 };
  122. XColor cancel_button_label_color = { .red = 0x0000, .green = 0x0000, .blue = 0x0000 };
  123. size_t strfpasswd(char *buffer, size_t size, const char *format, const struct passwd *pw)
  124. {
  125. size_t written = 0;
  126. char uid[BUFFER_SIZE];
  127. char gid[BUFFER_SIZE];
  128. char fullname[BUFFER_SIZE];
  129. char hostname[BUFFER_SIZE];
  130. if (size == 0) return 0;
  131. snprintf(uid, BUFFER_SIZE, "%lu", (unsigned long)pw->pw_uid);
  132. snprintf(gid, BUFFER_SIZE, "%lu", (unsigned long)pw->pw_gid);
  133. size_t name_length = strlen(pw->pw_gecos);
  134. char *last_comma = strchr(pw->pw_gecos, ',');
  135. if (last_comma) name_length = (size_t)(last_comma - pw->pw_gecos);
  136. if (name_length > BUFFER_SIZE - 1) name_length = BUFFER_SIZE - 1;
  137. memset(fullname, 0, sizeof(fullname));
  138. strncpy(fullname, pw->pw_gecos, name_length);
  139. memset(hostname, 0, sizeof(hostname));
  140. gethostname(hostname, BUFFER_SIZE - 1);
  141. while (*format && written < (size - 1))
  142. {
  143. if (*format == '%')
  144. {
  145. const char *to_append = NULL;
  146. switch (*++format)
  147. {
  148. case '%':
  149. to_append = "%";
  150. break;
  151. case 'n':
  152. to_append = pw->pw_name;
  153. break;
  154. case 'u':
  155. to_append = uid;
  156. break;
  157. case 'g':
  158. to_append = gid;
  159. break;
  160. case 'h':
  161. to_append = pw->pw_dir;
  162. break;
  163. case 'H':
  164. to_append = hostname;
  165. break;
  166. case 's':
  167. to_append = pw->pw_shell;
  168. break;
  169. case 'F':
  170. to_append = fullname;
  171. break;
  172. default:
  173. goto skip;
  174. }
  175. size_t amount = strlen(to_append);
  176. if (amount > (size - written - 1)) amount = size - written - 1;
  177. memcpy(buffer, to_append, amount);
  178. buffer += amount;
  179. written += amount;
  180. skip:
  181. if (*format) format++;
  182. }
  183. else
  184. {
  185. *buffer++ = *format++;
  186. written++;
  187. }
  188. }
  189. *buffer = 0;
  190. return written;
  191. }
  192. void start_screensaver(screen_descriptor_t *screen)
  193. {
  194. pid_t pid = fork();
  195. if (pid > 0)
  196. {
  197. screen->saver_pid = pid;
  198. }
  199. else if (pid == 0)
  200. {
  201. int i;
  202. char *token = NULL;
  203. char *cmdline = NULL;
  204. char hex_buffer[11];
  205. snprintf(hex_buffer, 11, "0x%08X", screen->wnd);
  206. char *path = (char*)alloca((strlen(screensaver_dir) + strlen(screensaver_name) + 2) * sizeof(char));
  207. strcpy(path, screensaver_dir);
  208. strcat(path, "/");
  209. strcat(path, screensaver_name);
  210. int argc = 3;
  211. if (screensaver_opts)
  212. {
  213. cmdline = (char*)alloca((strlen(screensaver_opts) + 1) * sizeof(char));
  214. strcpy(cmdline, screensaver_opts);
  215. for (token = strtok(cmdline, " "); token; token = strtok(NULL, " "))
  216. {
  217. if (strlen(token) > 0) argc++;
  218. }
  219. }
  220. char **argv = (char**)alloca((argc + 1) * sizeof(char*));
  221. argv[0] = screensaver_name;
  222. argv[1] = "-window-id";
  223. argv[2] = hex_buffer;
  224. argv[argc] = NULL;
  225. if (cmdline)
  226. {
  227. int i = 3;
  228. strcpy(cmdline, screensaver_opts);
  229. for (token = strtok(cmdline, " "); token && (i < argc); token = strtok(NULL, " "))
  230. {
  231. if (strlen(token) > 0) argv[i++] = token;
  232. }
  233. }
  234. execv(path, argv);
  235. perror("Couldn't exec screensaver process");
  236. exit(EXIT_FAILURE);
  237. }
  238. else
  239. {
  240. perror("Couldn't fork screensaver process");
  241. }
  242. }
  243. XRectangle get_absolute_rect(screen_descriptor_t *screen,
  244. int x,
  245. int y,
  246. unsigned int width,
  247. unsigned height)
  248. {
  249. if (x < 0) x += dialog_width - width;
  250. else if (x == 0) x = (dialog_width - width) / 2;
  251. x += (screen->width - dialog_width) / 2;
  252. y += (screen->height - dialog_height) / 2;
  253. XRectangle result = { x, y, width, height };
  254. return result;
  255. }
  256. void paint_label(screen_descriptor_t *screen,
  257. int x,
  258. int y,
  259. XColor *color,
  260. const char *font_name,
  261. const char *text)
  262. {
  263. XGlyphInfo extents;
  264. XftFont *font = XftFontOpenName(dpy, screen->number, font_name);
  265. XftColor xft_color;
  266. XftTextExtents8(dpy, font, text, strlen(text), &extents);
  267. XRectangle rect = get_absolute_rect(screen, x, y, extents.width, extents.height);
  268. color->flags = DoRed | DoGreen | DoBlue;
  269. dialog_bg_color.flags = DoRed | DoGreen | DoBlue;
  270. XAllocColor(dpy, screen->colormap, color);
  271. XAllocColor(dpy, screen->colormap, &dialog_bg_color);
  272. xft_color.pixel = color->pixel;
  273. xft_color.color.red = color->red;
  274. xft_color.color.green = color->green;
  275. xft_color.color.blue = color->blue;
  276. xft_color.color.alpha = 0xFFFF;
  277. XSetForeground(dpy, screen->gc, dialog_bg_color.pixel);
  278. XFillRectangle(dpy, screen->wnd, screen->gc, rect.x - 1, rect.y - 1, rect.width + 2, rect.height + 2);
  279. XftDrawString8(screen->xft_draw, &xft_color, font, rect.x, rect.y + rect.height, text, strlen(text));
  280. unsigned long pixels[2] = { color->pixel, dialog_bg_color.pixel };
  281. XFreeColors(dpy, screen->colormap, pixels, 2, 0);
  282. XftFontClose(dpy, font);
  283. }
  284. void paint_button(screen_descriptor_t *screen,
  285. int x,
  286. int y,
  287. XColor *border_color,
  288. XColor *background_color,
  289. XColor *text_color,
  290. const char *text)
  291. {
  292. XGlyphInfo extents;
  293. XftFont *font = XftFontOpenName(dpy, screen->number, button_label_font);
  294. XftColor xft_color;
  295. XRectangle rect = get_absolute_rect(screen, x, y, button_width, button_height);
  296. background_color->flags = DoRed | DoGreen | DoBlue;
  297. border_color->flags = DoRed | DoGreen | DoBlue;
  298. text_color->flags = DoRed | DoGreen | DoBlue;
  299. XAllocColor(dpy, screen->colormap, background_color);
  300. XAllocColor(dpy, screen->colormap, border_color);
  301. XAllocColor(dpy, screen->colormap, text_color);
  302. xft_color.pixel = text_color->pixel;
  303. xft_color.color.red = text_color->red;
  304. xft_color.color.green = text_color->green;
  305. xft_color.color.blue = text_color->blue;
  306. xft_color.color.alpha = 0xFFFF;
  307. XSetForeground(dpy, screen->gc, background_color->pixel);
  308. XFillRectangle(dpy, screen->wnd, screen->gc, rect.x, rect.y, rect.width, rect.height);
  309. XSetForeground(dpy, screen->gc, border_color->pixel);
  310. XSetLineAttributes(dpy, screen->gc, button_border_width, LineSolid, CapButt, JoinMiter);
  311. XDrawRectangle(dpy, screen->wnd, screen->gc, rect.x, rect.y, rect.width, rect.height);
  312. XftTextExtents8(dpy, font, text, strlen(text), &extents);
  313. XftDrawString8(screen->xft_draw,
  314. &xft_color,
  315. font,
  316. rect.x + (rect.width - extents.width) / 2,
  317. rect.y + (rect.height - extents.height) / 2 + extents.height,
  318. text,
  319. strlen(text));
  320. XftFontClose(dpy, font);
  321. unsigned long pixels[3] = { background_color->pixel, border_color->pixel, text_color->pixel };
  322. XFreeColors(dpy, screen->colormap, pixels, 3, 0);
  323. }
  324. void paint_password_field(screen_descriptor_t *screen, unsigned int num_dots)
  325. {
  326. unsigned int i;
  327. XRectangle rect = get_absolute_rect(screen, pwd_field_x, pwd_field_y, pwd_field_width, pwd_field_height);
  328. pwd_field_bg_color.flags = DoRed | DoGreen | DoBlue;
  329. pwd_field_border_color.flags = DoRed | DoGreen | DoBlue;
  330. pwd_field_dot_color.flags = DoRed | DoGreen | DoBlue;
  331. XAllocColor(dpy, screen->colormap, &pwd_field_bg_color);
  332. XAllocColor(dpy, screen->colormap, &pwd_field_border_color);
  333. XAllocColor(dpy, screen->colormap, &pwd_field_dot_color);
  334. XSetForeground(dpy, screen->gc, pwd_field_bg_color.pixel);
  335. XFillRectangle(dpy, screen->wnd, screen->gc, rect.x, rect.y, rect.width, rect.height);
  336. XSetClipRectangles(dpy, screen->gc, 0, 0, &rect, 1, Unsorted);
  337. XSetForeground(dpy, screen->gc, pwd_field_dot_color.pixel);
  338. for (i = 0; i < num_dots; i++)
  339. {
  340. int dot_x = rect.x + (pwd_dot_size + 1) * i + pwd_field_border_width + 1;
  341. int dot_y = rect.y + (rect.height - pwd_dot_size) / 2;
  342. XFillArc(dpy, screen->wnd, screen->gc, dot_x, dot_y, pwd_dot_size, pwd_dot_size, 0, 360 * 64);
  343. }
  344. XSetClipMask(dpy, screen->gc, None);
  345. XSetForeground(dpy, screen->gc, pwd_field_border_color.pixel);
  346. XSetLineAttributes(dpy, screen->gc, pwd_field_border_width, LineSolid, CapButt, JoinMiter);
  347. XDrawRectangle(dpy, screen->wnd, screen->gc, rect.x, rect.y, rect.width, rect.height);
  348. unsigned long pixels[3] =
  349. {
  350. pwd_field_bg_color.pixel,
  351. pwd_field_border_color.pixel,
  352. pwd_field_dot_color.pixel
  353. };
  354. XFreeColors(dpy, screen->colormap, pixels, 3, 0);
  355. }
  356. void paint_clock(screen_descriptor_t *screen, time_t timestamp)
  357. {
  358. char buffer[BUFFER_SIZE];
  359. struct tm *time_data = localtime(&timestamp);
  360. strftime(buffer, BUFFER_SIZE, time_format, time_data);
  361. paint_label(screen, time_label_x, time_label_y, &time_label_color, time_label_font, buffer);
  362. strftime(buffer, BUFFER_SIZE, date_format, time_data);
  363. paint_label(screen, date_label_x, date_label_y, &date_label_color, date_label_font, buffer);
  364. }
  365. void paint_dialog(screen_descriptor_t *screen)
  366. {
  367. char buffer[BUFFER_SIZE];
  368. unsigned int dialog_x = (screen->width - dialog_width) / 2;
  369. unsigned int dialog_y = (screen->height - dialog_height) / 2;
  370. time_t timestamp;
  371. struct passwd *user_info = getpwuid(getuid());
  372. dialog_bg_color.flags = DoRed | DoGreen | DoBlue;
  373. XAllocColor(dpy, screen->colormap, &dialog_bg_color);
  374. XSetForeground(dpy, screen->gc, dialog_bg_color.pixel);
  375. XFillRectangle(dpy, screen->wnd, screen->gc, dialog_x, dialog_y, dialog_width, dialog_height);
  376. XFreeColors(dpy, screen->colormap, &dialog_bg_color.pixel, 1, 0);
  377. time(&timestamp);
  378. paint_clock(screen, timestamp);
  379. strfpasswd(buffer, BUFFER_SIZE, fullname_label, user_info);
  380. paint_label(screen,
  381. fullname_label_x,
  382. fullname_label_y,
  383. &fullname_label_color,
  384. fullname_label_font,
  385. buffer);
  386. strfpasswd(buffer, BUFFER_SIZE, username_label, user_info);
  387. paint_label(screen,
  388. username_label_x,
  389. username_label_y,
  390. &username_label_color,
  391. username_label_font,
  392. buffer);
  393. paint_label(screen,
  394. password_label_x,
  395. password_label_y,
  396. &password_label_color,
  397. password_label_font,
  398. password_label);
  399. paint_password_field(screen, strlen(password));
  400. paint_button(screen,
  401. unlock_button_x,
  402. unlock_button_y,
  403. &unlock_button_border_color,
  404. &unlock_button_bg_color,
  405. &unlock_button_label_color,
  406. unlock_button_label);
  407. paint_button(screen,
  408. cancel_button_x,
  409. cancel_button_y,
  410. &cancel_button_border_color,
  411. &cancel_button_bg_color,
  412. &cancel_button_label_color,
  413. cancel_button_label);
  414. if (incorrect_counter > 0)
  415. {
  416. paint_label(screen,
  417. incorrect_label_x,
  418. incorrect_label_y,
  419. &incorrect_label_color,
  420. incorrect_label_font,
  421. incorrect_label);
  422. }
  423. }
  424. void set_brightness(screen_descriptor_t *screen, unsigned int percentage)
  425. {
  426. int i;
  427. unsigned short *red_ramp = alloca(screen->ramp_size * sizeof(unsigned short));
  428. unsigned short *green_ramp = alloca(screen->ramp_size * sizeof(unsigned short));
  429. unsigned short *blue_ramp = alloca(screen->ramp_size * sizeof(unsigned short));
  430. for (i = 0; i < screen->ramp_size; i++)
  431. {
  432. red_ramp[i] = (unsigned short)(((unsigned int)screen->red_ramp[i] * percentage) / 100);
  433. green_ramp[i] = (unsigned short)(((unsigned int)screen->green_ramp[i] * percentage) / 100);
  434. blue_ramp[i] = (unsigned short)(((unsigned int)screen->blue_ramp[i] * percentage) / 100);
  435. }
  436. XF86VidModeSetGammaRamp(dpy, screen->number, screen->ramp_size, red_ramp, green_ramp, blue_ramp);
  437. }
  438. Bool create_windows(void)
  439. {
  440. int i;
  441. for (i = 0; i < screen_count; i++)
  442. {
  443. Window root_wnd = RootWindow(dpy, i);
  444. screen_descriptor_t *screen = &screen_descriptors[i];
  445. memset(screen, 0, sizeof(screen_descriptor_t));
  446. if (XGrabKeyboard(dpy, root_wnd, False, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess)
  447. {
  448. fprintf(stderr, "Could not grab the keyboard on screen %d\n", i);
  449. return False;
  450. }
  451. if (XGrabPointer(dpy,
  452. root_wnd,
  453. False,
  454. PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
  455. GrabModeAsync,
  456. GrabModeAsync,
  457. None,
  458. None,
  459. CurrentTime)
  460. != GrabSuccess)
  461. {
  462. fprintf(stderr, "Could not grab the pointer on screen %d\n", i);
  463. return False;
  464. }
  465. XSetWindowAttributes wa =
  466. {
  467. .override_redirect = 1,
  468. .background_pixel = BlackPixel(dpy, i),
  469. .event_mask = ExposureMask
  470. };
  471. XGCValues gcv =
  472. {
  473. .foreground = WhitePixel(dpy, i),
  474. .background = BlackPixel(dpy, i),
  475. .line_width = 1
  476. };
  477. screen->number = i;
  478. screen->saver_pid = 0;
  479. screen->width = DisplayWidth(dpy, i);
  480. screen->height = DisplayHeight(dpy, i);
  481. screen->visual = DefaultVisual(dpy, i);
  482. screen->colormap = DefaultColormap(dpy, i);
  483. screen->wnd = XCreateWindow(dpy,
  484. root_wnd,
  485. 0,
  486. 0,
  487. screen->width,
  488. screen->height,
  489. 0,
  490. DefaultDepth(dpy, i),
  491. InputOutput,
  492. screen->visual,
  493. CWOverrideRedirect | CWBackPixel | CWEventMask,
  494. &wa);
  495. screen->gc = XCreateGC(dpy, screen->wnd, GCForeground | GCBackground | GCLineWidth, &gcv);
  496. screen->xft_draw = XftDrawCreate(dpy, screen->wnd, screen->visual, screen->colormap);
  497. Pixmap cursor_pixmap = XCreatePixmap(dpy, root_wnd, 1, 1, 1);
  498. XColor cursor_color = { .red = 0x0000, .green = 0x0000, .blue = 0x0000 };
  499. screen->blank_cursor = XCreatePixmapCursor(dpy,
  500. cursor_pixmap,
  501. cursor_pixmap,
  502. &cursor_color,
  503. &cursor_color,
  504. 0,
  505. 0);
  506. XDefineCursor(dpy, screen->wnd, screen->blank_cursor);
  507. XFreePixmap(dpy, cursor_pixmap);
  508. if (fade_enabled)
  509. {
  510. if (!XF86VidModeGetGammaRampSize(dpy, i, &screen->ramp_size))
  511. {
  512. fprintf(stderr, "Could not find the gamma ramp size. Fading will not work.");
  513. fade_enabled = False;
  514. }
  515. }
  516. if (fade_enabled)
  517. {
  518. screen->red_ramp = (unsigned short*)malloc(screen->ramp_size * sizeof(unsigned short));
  519. screen->green_ramp = (unsigned short*)malloc(screen->ramp_size * sizeof(unsigned short));
  520. screen->blue_ramp = (unsigned short*)malloc(screen->ramp_size * sizeof(unsigned short));
  521. if (!screen->red_ramp || !screen->green_ramp || !screen->blue_ramp)
  522. {
  523. fprintf(stderr, "Could not allocate memory for the gamma ramp. Fading will not work.");
  524. if (screen->red_ramp) free(screen->red_ramp);
  525. if (screen->green_ramp) free(screen->green_ramp);
  526. if (screen->blue_ramp) free(screen->blue_ramp);
  527. screen->red_ramp = screen->green_ramp = screen->blue_ramp = NULL;
  528. fade_enabled = False;
  529. }
  530. }
  531. if (fade_enabled)
  532. {
  533. if (!XF86VidModeGetGammaRamp(dpy,
  534. i,
  535. screen->ramp_size,
  536. screen->red_ramp,
  537. screen->green_ramp,
  538. screen->blue_ramp))
  539. {
  540. fprintf(stderr, "Could not extract the gamma ramp. Fading will not work.");
  541. if (screen->red_ramp) free(screen->red_ramp);
  542. if (screen->green_ramp) free(screen->green_ramp);
  543. if (screen->blue_ramp) free(screen->blue_ramp);
  544. screen->red_ramp = screen->green_ramp = screen->blue_ramp = NULL;
  545. fade_enabled = False;
  546. }
  547. }
  548. }
  549. return True;
  550. }
  551. void destroy_windows(void)
  552. {
  553. int i;
  554. for (i = 0; i < screen_count; i++)
  555. {
  556. screen_descriptor_t *screen = &screen_descriptors[i];
  557. if (screen->saver_pid)
  558. {
  559. kill(screen->saver_pid, SIGCONT);
  560. kill(screen->saver_pid, SIGTERM);
  561. screen->saver_pid = 0;
  562. }
  563. if (fade_enabled) set_brightness(screen, 100);
  564. if (screen->red_ramp) free(screen->red_ramp);
  565. if (screen->green_ramp) free(screen->green_ramp);
  566. if (screen->blue_ramp) free(screen->blue_ramp);
  567. if (screen->blank_cursor) XFreeCursor(dpy, screen->blank_cursor);
  568. if (screen->xft_draw) XftDrawDestroy(screen->xft_draw);
  569. if (screen->gc) XFreeGC(dpy, screen->gc);
  570. if (screen->wnd)
  571. {
  572. XUnmapWindow(dpy, screen->wnd);
  573. XDestroyWindow(dpy, screen->wnd);
  574. }
  575. }
  576. }
  577. Bool show_dialog(screen_descriptor_t *screen)
  578. {
  579. if (dialog_displayed) return True;
  580. if (screen->saver_pid)
  581. {
  582. kill(screen->saver_pid, SIGSTOP);
  583. Bool equal = False;
  584. XImage *prev_image = XGetImage(dpy, screen->wnd, 0, 0, screen->width, screen->height, AllPlanes, XYPixmap);
  585. while (!equal)
  586. {
  587. sched_yield();
  588. XImage *image = XGetImage(dpy, screen->wnd, 0, 0, screen->width, screen->height, AllPlanes, XYPixmap);
  589. if (!image) break;
  590. if (memcmp(image->data, prev_image->data, image->height * image->bytes_per_line) == 0)
  591. {
  592. equal = True;
  593. }
  594. XFree(prev_image);
  595. prev_image = image;
  596. }
  597. if (prev_image) XFree(prev_image);
  598. }
  599. dialog_displayed = True;
  600. idle_counter = 0;
  601. XUndefineCursor(dpy, screen->wnd);
  602. paint_dialog(screen);
  603. return False;
  604. }
  605. void hide_dialog(screen_descriptor_t *screen)
  606. {
  607. if (dialog_displayed)
  608. {
  609. XDefineCursor(dpy, screen->wnd, screen->blank_cursor);
  610. dialog_displayed = False;
  611. memset(password, 0, sizeof(password));
  612. XClearWindow(dpy, screen->wnd);
  613. if (screen->saver_pid) kill(screen->saver_pid, SIGCONT);
  614. }
  615. }
  616. Bool check_password(void)
  617. {
  618. if (strcmp(crypt(password, correct_pwd_hash), correct_pwd_hash) == 0) return True;
  619. incorrect_counter = incorrect_timeout;
  620. paint_label(&screen_descriptors[default_screen],
  621. incorrect_label_x,
  622. incorrect_label_y,
  623. &incorrect_label_color,
  624. incorrect_label_font,
  625. incorrect_label);
  626. return False;
  627. }
  628. void process_events(void)
  629. {
  630. int i;
  631. XEvent ev;
  632. struct pollfd poll_descriptor;
  633. screen_descriptor_t *screen = &screen_descriptors[default_screen];
  634. KeySym keysym;
  635. char buffer[BUFFER_SIZE];
  636. XComposeStatus compose_status;
  637. time_t current_time, last_update;
  638. time(&last_update);
  639. poll_descriptor.fd = ConnectionNumber(dpy);
  640. poll_descriptor.events = POLLIN;
  641. while (True)
  642. {
  643. while (XPending(dpy))
  644. {
  645. XNextEvent(dpy, &ev);
  646. switch (ev.type)
  647. {
  648. case Expose:
  649. if (dialog_displayed) paint_dialog(screen);
  650. break;
  651. case MotionNotify:
  652. show_dialog(screen);
  653. break;
  654. case ButtonPress:
  655. if (incorrect_counter) break;
  656. if (!show_dialog(screen)) break;
  657. XRectangle u = get_absolute_rect(screen, unlock_button_x, unlock_button_y, button_width, button_height);
  658. XRectangle c = get_absolute_rect(screen, cancel_button_x, cancel_button_y, button_width, button_height);
  659. if ((ev.xbutton.x_root >= u.x) && (ev.xbutton.x_root <= (u.x + u.width))
  660. && (ev.xbutton.y_root >= u.y) && (ev.xbutton.y_root <= (u.y + u.height)))
  661. {
  662. if (check_password()) return;
  663. }
  664. else if ((ev.xbutton.x_root >= c.x) && (ev.xbutton.x_root <= (c.x + c.width))
  665. && (ev.xbutton.y_root >= c.y) && (ev.xbutton.y_root <= (c.y + c.height)))
  666. {
  667. hide_dialog(screen);
  668. }
  669. break;
  670. case KeyPress:
  671. if (incorrect_counter) break;
  672. Bool was_displayed = show_dialog(screen);
  673. idle_counter = 0;
  674. memset(buffer, 0, sizeof(buffer));
  675. XLookupString(&ev.xkey, buffer, sizeof(buffer) - 1, &keysym, &compose_status);
  676. if (keysym == XK_Escape)
  677. {
  678. if (was_displayed) hide_dialog(screen);
  679. }
  680. else if (keysym == XK_Return || keysym == XK_KP_Enter || keysym == XK_Linefeed)
  681. {
  682. if (was_displayed && check_password()) return;
  683. }
  684. else if (keysym == XK_BackSpace)
  685. {
  686. size_t length = strlen(password);
  687. if (length > 0) password[length - 1] = 0;
  688. paint_password_field(screen, strlen(password));
  689. }
  690. else if (keysym < XK_Shift_L || keysym > XK_Hyper_R)
  691. {
  692. strncat(password, buffer, BUFFER_SIZE - strlen(password) - 1);
  693. paint_password_field(screen, strlen(password));
  694. }
  695. break;
  696. }
  697. }
  698. if (dialog_displayed)
  699. {
  700. time(&current_time);
  701. if (current_time != last_update)
  702. {
  703. paint_clock(screen, current_time);
  704. last_update = current_time;
  705. if (incorrect_counter)
  706. {
  707. incorrect_counter--;
  708. if (incorrect_counter == 0)
  709. {
  710. memset(password, 0, sizeof(password));
  711. paint_dialog(screen);
  712. }
  713. }
  714. idle_counter++;
  715. if (idle_counter == idle_timeout) hide_dialog(screen);
  716. }
  717. }
  718. poll(&poll_descriptor, 1, POLL_TIMEOUT);
  719. }
  720. }
  721. Bool fade(void)
  722. {
  723. int i;
  724. XEvent ev;
  725. struct pollfd poll_descriptor;
  726. long fade_counter = (long)fade_timeout;
  727. struct timespec current_time, last_update, delta;
  728. if (!fade_enabled) return True;
  729. clock_gettime(CLOCK_MONOTONIC, &last_update);
  730. poll_descriptor.fd = ConnectionNumber(dpy);
  731. poll_descriptor.events = POLLIN;
  732. while (fade_counter)
  733. {
  734. while (XPending(dpy))
  735. {
  736. XNextEvent(dpy, &ev);
  737. switch (ev.type)
  738. {
  739. case MotionNotify:
  740. case ButtonPress:
  741. case KeyPress:
  742. return False;
  743. }
  744. }
  745. clock_gettime(CLOCK_MONOTONIC, &current_time);
  746. delta.tv_sec = current_time.tv_sec - last_update.tv_sec;
  747. delta.tv_nsec = current_time.tv_nsec - last_update.tv_nsec;
  748. if (current_time.tv_nsec < last_update.tv_nsec)
  749. {
  750. delta.tv_sec--;
  751. delta.tv_nsec += 1000000000L;
  752. }
  753. last_update = current_time;
  754. fade_counter -= (long)delta.tv_sec * 1000L + (delta.tv_nsec / 1000000L);
  755. if (fade_counter < 0) fade_counter = 0;
  756. for (i = 0; i < screen_count; i++)
  757. {
  758. set_brightness(&screen_descriptors[i], (fade_counter * 100) / fade_timeout);
  759. }
  760. poll(&poll_descriptor, 1, 1);
  761. }
  762. return True;
  763. }
  764. void load_string_setting(char *string, char **value)
  765. {
  766. if (string) *value = string;
  767. }
  768. void load_integer_setting(char *string, int *value)
  769. {
  770. int num;
  771. if (string && scanf(string, "%d", &num) == 1) *value = num;
  772. }
  773. void load_color_setting(char *string, XColor *color)
  774. {
  775. unsigned short red, green, blue;
  776. if (string && sscanf(string, "%04hX/%04hX/%04hX", &red, &green, &blue) == 3)
  777. {
  778. color->red = red;
  779. color->green = green;
  780. color->blue = blue;
  781. }
  782. }
  783. void load_settings(void)
  784. {
  785. load_string_setting(XGetDefault(dpy, PACKAGE_NAME, "screensaverName"), &screensaver_name);
  786. load_string_setting(XGetDefault(dpy, PACKAGE_NAME, "screensaverDir"), &screensaver_dir);
  787. load_string_setting(XGetDefault(dpy, PACKAGE_NAME, "screensaverOpts"), &screensaver_opts);
  788. load_string_setting(XGetDefault(dpy, PACKAGE_NAME, "password"), &correct_pwd_hash);
  789. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "errorTimeout"), &incorrect_timeout);
  790. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "idleTimeout"), &idle_timeout);
  791. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "fadeTimeout"), &fade_timeout);
  792. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "dialogWidth"), &dialog_width);
  793. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "dialogHeight"), &dialog_height);
  794. load_color_setting(XGetDefault(dpy, PACKAGE_NAME, "dialogBgColor"), &dialog_bg_color);
  795. load_string_setting(XGetDefault(dpy, PACKAGE_NAME, "timeFormat"), &time_format);
  796. load_string_setting(XGetDefault(dpy, PACKAGE_NAME, "timeLabelFont"), &time_label_font);
  797. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "timeLabelX"), &time_label_x);
  798. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "timeLabelY"), &time_label_y);
  799. load_color_setting(XGetDefault(dpy, PACKAGE_NAME, "timeLabelColor"), &time_label_color);
  800. load_string_setting(XGetDefault(dpy, PACKAGE_NAME, "dateFormat"), &date_format);
  801. load_string_setting(XGetDefault(dpy, PACKAGE_NAME, "dateLabelFont"), &date_label_font);
  802. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "dateLabelX"), &date_label_x);
  803. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "dateLabelY"), &date_label_y);
  804. load_color_setting(XGetDefault(dpy, PACKAGE_NAME, "dateLabelColor"), &date_label_color);
  805. load_string_setting(XGetDefault(dpy, PACKAGE_NAME, "fullnameLabel"), &fullname_label);
  806. load_string_setting(XGetDefault(dpy, PACKAGE_NAME, "fullnameLabelFont"), &fullname_label_font);
  807. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "fullnameLabelX"), &fullname_label_x);
  808. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "fullnameLabelY"), &fullname_label_y);
  809. load_color_setting(XGetDefault(dpy, PACKAGE_NAME, "fullnameLabelColor"), &fullname_label_color);
  810. load_string_setting(XGetDefault(dpy, PACKAGE_NAME, "usernameLabel"), &username_label);
  811. load_string_setting(XGetDefault(dpy, PACKAGE_NAME, "usernameLabelFont"), &username_label_font);
  812. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "usernameLabelX"), &username_label_x);
  813. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "usernameLabelY"), &username_label_y);
  814. load_color_setting(XGetDefault(dpy, PACKAGE_NAME, "usernameLabelColor"), &username_label_color);
  815. load_string_setting(XGetDefault(dpy, PACKAGE_NAME, "passwordLabel"), &password_label);
  816. load_string_setting(XGetDefault(dpy, PACKAGE_NAME, "passwordLabelFont"), &password_label_font);
  817. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "passwordLabelX"), &password_label_x);
  818. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "passwordLabelY"), &password_label_y);
  819. load_color_setting(XGetDefault(dpy, PACKAGE_NAME, "passwordLabelColor"), &password_label_color);
  820. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "passwordDotSize"), &pwd_dot_size);
  821. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "passwordFieldWidth"), &pwd_field_width);
  822. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "passwordFieldHeight"), &pwd_field_height);
  823. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "passwordFieldBorderWidth"), &pwd_field_border_width);
  824. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "passwordFieldX"), &pwd_field_x);
  825. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "passwordFieldY"), &pwd_field_y);
  826. load_color_setting(XGetDefault(dpy, PACKAGE_NAME, "passwordFieldBorderColor"), &pwd_field_border_color);
  827. load_color_setting(XGetDefault(dpy, PACKAGE_NAME, "passwordFieldBgColor"), &pwd_field_bg_color);
  828. load_color_setting(XGetDefault(dpy, PACKAGE_NAME, "passwordFieldDotColor"), &pwd_field_dot_color);
  829. load_string_setting(XGetDefault(dpy, PACKAGE_NAME, "incorrectLabel"), &incorrect_label);
  830. load_string_setting(XGetDefault(dpy, PACKAGE_NAME, "incorrectLabelFont"), &incorrect_label_font);
  831. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "incorrectLabelX"), &incorrect_label_x);
  832. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "incorrectLabelY"), &incorrect_label_y);
  833. load_color_setting(XGetDefault(dpy, PACKAGE_NAME, "incorrectLabelColor"), &incorrect_label_color);
  834. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "buttonWidth"), &button_width);
  835. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "buttonHeight"), &button_height);
  836. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "buttonBorderWidth"), &button_border_width);
  837. load_string_setting(XGetDefault(dpy, PACKAGE_NAME, "buttonLabelFont"), &button_label_font);
  838. load_string_setting(XGetDefault(dpy, PACKAGE_NAME, "unlockButtonLabel"), &button_label_font);
  839. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "unlockButtonX"), &unlock_button_x);
  840. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "unlockButtonY"), &unlock_button_y);
  841. load_color_setting(XGetDefault(dpy, PACKAGE_NAME, "unlockButtonBgColor"), &unlock_button_bg_color);
  842. load_color_setting(XGetDefault(dpy, PACKAGE_NAME, "unlockButtonBorderColor"), &unlock_button_border_color);
  843. load_color_setting(XGetDefault(dpy, PACKAGE_NAME, "unlockButtonLabelColor"), &unlock_button_label_color);
  844. load_string_setting(XGetDefault(dpy, PACKAGE_NAME, "cancelButtonLabel"), &button_label_font);
  845. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "cancelButtonX"), &cancel_button_x);
  846. load_integer_setting(XGetDefault(dpy, PACKAGE_NAME, "cancelButtonY"), &cancel_button_y);
  847. load_color_setting(XGetDefault(dpy, PACKAGE_NAME, "cancelButtonBgColor"), &cancel_button_bg_color);
  848. load_color_setting(XGetDefault(dpy, PACKAGE_NAME, "cancelButtonBorderColor"), &cancel_button_border_color);
  849. load_color_setting(XGetDefault(dpy, PACKAGE_NAME, "cancelButtonLabelColor"), &cancel_button_label_color);
  850. }
  851. void signal_handler(int signum)
  852. {
  853. if (signum != SIGCHLD || screen_descriptors == NULL) return;
  854. pid_t pid = waitpid(-1, NULL, WNOHANG);
  855. if (pid == 0) return;
  856. int i;
  857. for (i = 0; i < screen_count; i++)
  858. {
  859. screen_descriptor_t *screen = &screen_descriptors[i];
  860. if (screen->saver_pid == pid) screen->saver_pid = 0;
  861. }
  862. }
  863. struct option options[] =
  864. {
  865. { "display", required_argument, NULL, 'd' },
  866. { "screensaver", required_argument, NULL, 's' },
  867. { "screensaver-dir", required_argument, NULL, 0 },
  868. { "screensaver-opts", required_argument, NULL, 'o' },
  869. { "fade", no_argument, NULL, 'f' },
  870. { "help", no_argument, NULL, 'h' },
  871. { "version", no_argument, NULL, 'V' },
  872. { NULL, 0, NULL, 0 }
  873. };
  874. int main(int argc, char *argv[])
  875. {
  876. int opt, index;
  877. char *display_name = NULL;
  878. struct sigaction act;
  879. char *scrnsvr_dir = NULL;
  880. char *scrnsvr_name = NULL;
  881. char *scrnsvr_opts = NULL;
  882. act.sa_handler = signal_handler;
  883. sigemptyset(&act.sa_mask);
  884. act.sa_flags = SA_NOCLDSTOP;
  885. if (sigaction(SIGCHLD, &act, NULL))
  886. {
  887. perror("Couldn't set signal handler");
  888. return EXIT_FAILURE;
  889. }
  890. while ((opt = getopt_long(argc, argv, "d:s:o:fhV", options, &index)) != -1)
  891. {
  892. switch (opt)
  893. {
  894. case 0:
  895. if (strcmp(options[index].name, "screensaver-dir") == 0) scrnsvr_dir = optarg;
  896. break;
  897. case 'd':
  898. display_name = optarg;
  899. break;
  900. case 's':
  901. scrnsvr_name = optarg;
  902. break;
  903. case 'o':
  904. scrnsvr_opts = optarg;
  905. break;
  906. case 'f':
  907. fade_enabled = True;
  908. break;
  909. case 'h':
  910. case 'V':
  911. puts(PACKAGE_STRING " - A screen locker.\n"
  912. "Copyright (C) 2015 Alexander Andrejevic <theflash AT sdf DOT lonestar DOT org>\n"
  913. "License AGPLv3+: GNU AGPL version 3 or later <http://www.gnu.org/licenses/agpl.html>\n"
  914. "This is free software: you are free to change and redistribute it.\n"
  915. "There is NO WARRANTY, to the extent permitted by law.");
  916. if (opt == 'V') return EXIT_SUCCESS;
  917. puts("\nUsage: xsuperlock [options]\n\n"
  918. "Options:\n"
  919. "\t-d, --display\t\tThe X server display to use.\n"
  920. "\t-s, --screensaver\tThe name of the screensaver executable to run.\n"
  921. "\t--screensaver-dir\tThe directory that contains screensavers\n"
  922. "\t\t\t\t(" DEFAULT_SCREENSAVER_DIR " by default)\n"
  923. "\t-o, --screensaver-opts\tParameters to pass to the screensaver. Remember\n"
  924. "\t\t\t\tto enclose them in quotes.\n"
  925. "\t-f, --fade\t\tFade before locking.\n"
  926. "\t-h, --help\t\tPrint this usage screen.\n"
  927. "\t-V, --version\t\tPrint version information.\n");
  928. return EXIT_SUCCESS;
  929. default:
  930. break;
  931. }
  932. }
  933. dpy = XOpenDisplay(display_name);
  934. if (dpy == NULL)
  935. {
  936. fputs("Could not open display.\n", stderr);
  937. return EXIT_FAILURE;
  938. }
  939. load_settings();
  940. if (scrnsvr_name) screensaver_name = scrnsvr_name;
  941. if (scrnsvr_dir) screensaver_dir = scrnsvr_dir;
  942. if (scrnsvr_opts) screensaver_opts = scrnsvr_opts;
  943. if (correct_pwd_hash == NULL)
  944. {
  945. struct passwd *pw = getpwuid(getuid());
  946. struct spwd *shadow = getspnam(pw->pw_name);
  947. if (!shadow || !shadow->sp_pwdp)
  948. {
  949. fputs("Could not read the shadow file and no password specified.\n", stderr);
  950. XCloseDisplay(dpy);
  951. return EXIT_FAILURE;
  952. }
  953. correct_pwd_hash = shadow->sp_pwdp;
  954. }
  955. seteuid(getuid());
  956. setegid(getgid());
  957. memset(password, 0, sizeof(password));
  958. default_screen = DefaultScreen(dpy);
  959. screen_count = ScreenCount(dpy);
  960. screen_descriptors = (screen_descriptor_t*)malloc(sizeof(screen_descriptor_t) * screen_count);
  961. if (!create_windows()) goto done;
  962. if (!fade()) goto done;
  963. for (index = 0; index < screen_count; index++)
  964. {
  965. screen_descriptor_t *screen = &screen_descriptors[index];
  966. XMapRaised(dpy, screen->wnd);
  967. if (screensaver_name) start_screensaver(screen);
  968. if (fade_enabled) set_brightness(screen, 100);
  969. }
  970. process_events();
  971. done:
  972. destroy_windows();
  973. free(screen_descriptors);
  974. screen_descriptors = NULL;
  975. XCloseDisplay(dpy);
  976. return EXIT_SUCCESS;
  977. }