Added date and password entry; still needs lots of work.
This commit is contained in:
1 parent
5bace1d0e8
commit
cb9d0ea7ac
62 files changed
+62517
-234
No files matched your search
@@ -15,6 +15,7 @@
|
||||
#include <unistd.h>
|
||||
#include <spawn.h>
|
||||
#include <time.h>
|
||||
#include <sys/timerfd.h> /* timerfd_create */
|
||||
#include <sys/types.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#include <X11/extensions/dpms.h>
|
||||
@@ -23,6 +24,12 @@
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
#include "main_font.h"
|
||||
#include "secondary_font.h"
|
||||
|
||||
#include "arg.h"
|
||||
#include "util.h"
|
||||
|
||||
@@ -34,28 +41,28 @@ static unsigned int numlockmask = 0;
|
||||
char *argv0;
|
||||
|
||||
enum {
|
||||
INIT,
|
||||
INPUT,
|
||||
FAILED,
|
||||
NUMCOLS
|
||||
INIT,
|
||||
INPUT,
|
||||
FAILED,
|
||||
NUMCOLS
|
||||
};
|
||||
|
||||
struct lock {
|
||||
int screen;
|
||||
Window root, win;
|
||||
Pixmap pmap;
|
||||
unsigned long colors[NUMCOLS];
|
||||
int screen;
|
||||
Window root, win;
|
||||
Pixmap pmap;
|
||||
unsigned long colors[NUMCOLS];
|
||||
};
|
||||
|
||||
struct xrandr {
|
||||
int active;
|
||||
int evbase;
|
||||
int errbase;
|
||||
int active;
|
||||
int evbase;
|
||||
int errbase;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
unsigned int mod;
|
||||
KeySym keysym;
|
||||
unsigned int mod;
|
||||
KeySym keysym;
|
||||
} Passthrough;
|
||||
|
||||
typedef union {
|
||||
@@ -85,14 +92,24 @@ spawn(const Arg *arg)
|
||||
static void
|
||||
die(const char *errstr, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, errstr);
|
||||
vfprintf(stderr, errstr, ap);
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
va_start(ap, errstr);
|
||||
vfprintf(stderr, errstr, ap);
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int str_len(const char *str)
|
||||
{
|
||||
int i = 0;
|
||||
while(*(str++) != '\0') {
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/* TODO: Move to top. */
|
||||
#ifdef __linux__
|
||||
#include <fcntl.h>
|
||||
#include <linux/oom.h>
|
||||
@@ -120,8 +137,7 @@ void update_crtc_infos(Display *dpy)
|
||||
root = DefaultRootWindow(dpy);
|
||||
crtcres = XRRGetScreenResources(dpy, root);
|
||||
|
||||
for(i = 0; i < crtcres->ncrtc; i++) { /* TODO: FIX: Choose minimum of ncrtc and my crtcinfos value.
|
||||
Could it be that the OS disables displays after inactivity? */
|
||||
for(i = 0; i < crtcres->ncrtc; i++) {
|
||||
RRCrtc crtc;
|
||||
XRRCrtcInfo *info;
|
||||
|
||||
@@ -132,7 +148,6 @@ void update_crtc_infos(Display *dpy)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Error-prone. See which of these can return errors.
|
||||
void set_screen_on(Display *dpy)
|
||||
{
|
||||
if(crtcres) {
|
||||
@@ -152,7 +167,6 @@ void set_screen_on(Display *dpy)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Error-prone. See which of these can return errors.
|
||||
void set_screen_off(Display *dpy)
|
||||
{
|
||||
if(crtcres) {
|
||||
@@ -170,104 +184,361 @@ void set_screen_off(Display *dpy)
|
||||
CurrentTime, 0, 0, None, RR_Rotate_0,
|
||||
NULL, 0);
|
||||
if(s != RRSetConfigSuccess) {
|
||||
/* TODO: Failed to disable... */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: When new CRTCs are connected when the screen is off. Turn on all
|
||||
* screens and then update the structure. We want the displays on when new
|
||||
* one connects. */
|
||||
|
||||
static void
|
||||
dontkillme(void)
|
||||
{
|
||||
FILE *f;
|
||||
const char oomfile[] = "/proc/self/oom_score_adj";
|
||||
FILE *f;
|
||||
const char oomfile[] = "/proc/self/oom_score_adj";
|
||||
|
||||
if (!(f = fopen(oomfile, "w"))) {
|
||||
if (errno == ENOENT)
|
||||
return;
|
||||
die("slock: fopen %s: %s\n", oomfile, strerror(errno));
|
||||
}
|
||||
fprintf(f, "%d", OOM_SCORE_ADJ_MIN);
|
||||
if (fclose(f)) {
|
||||
if (errno == EACCES)
|
||||
die("slock: unable to disable OOM killer. "
|
||||
"Make sure to suid or sgid slock.\n");
|
||||
else
|
||||
die("slock: fclose %s: %s\n", oomfile, strerror(errno));
|
||||
}
|
||||
if (!(f = fopen(oomfile, "w"))) {
|
||||
if (errno == ENOENT)
|
||||
return;
|
||||
die("slock: fopen %s: %s\n", oomfile, strerror(errno));
|
||||
}
|
||||
fprintf(f, "%d", OOM_SCORE_ADJ_MIN);
|
||||
if (fclose(f)) {
|
||||
if (errno == EACCES)
|
||||
die("slock: unable to disable OOM killer. "
|
||||
"Make sure to suid or sgid slock.\n");
|
||||
else
|
||||
die("slock: fclose %s: %s\n", oomfile, strerror(errno));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char *
|
||||
gethash(void)
|
||||
{
|
||||
const char *hash;
|
||||
struct passwd *pw;
|
||||
const char *hash;
|
||||
struct passwd *pw;
|
||||
|
||||
/* Check if the current user has a password entry */
|
||||
errno = 0;
|
||||
if (!(pw = getpwuid(getuid()))) {
|
||||
if (errno)
|
||||
die("slock: getpwuid: %s\n", strerror(errno));
|
||||
else
|
||||
die("slock: cannot retrieve password entry\n");
|
||||
}
|
||||
hash = pw->pw_passwd;
|
||||
/* Check if the current user has a password entry */
|
||||
errno = 0;
|
||||
if (!(pw = getpwuid(getuid()))) {
|
||||
if (errno)
|
||||
die("slock: getpwuid: %s\n", strerror(errno));
|
||||
else
|
||||
die("slock: cannot retrieve password entry\n");
|
||||
}
|
||||
hash = pw->pw_passwd;
|
||||
|
||||
#if HAVE_SHADOW_H
|
||||
if (!strcmp(hash, "x")) {
|
||||
struct spwd *sp;
|
||||
if (!(sp = getspnam(pw->pw_name)))
|
||||
die("slock: getspnam: cannot retrieve shadow entry. "
|
||||
"Make sure to suid or sgid slock.\n");
|
||||
hash = sp->sp_pwdp;
|
||||
}
|
||||
if (!strcmp(hash, "x")) {
|
||||
struct spwd *sp;
|
||||
if (!(sp = getspnam(pw->pw_name)))
|
||||
die("slock: getspnam: cannot retrieve shadow entry. "
|
||||
"Make sure to suid or sgid slock.\n");
|
||||
hash = sp->sp_pwdp;
|
||||
}
|
||||
#else
|
||||
if (!strcmp(hash, "*")) {
|
||||
if (!strcmp(hash, "*")) {
|
||||
#ifdef __OpenBSD__
|
||||
if (!(pw = getpwuid_shadow(getuid())))
|
||||
die("slock: getpwnam_shadow: cannot retrieve shadow entry. "
|
||||
"Make sure to suid or sgid slock.\n");
|
||||
hash = pw->pw_passwd;
|
||||
if (!(pw = getpwuid_shadow(getuid())))
|
||||
die("slock: getpwnam_shadow: cannot retrieve shadow entry. "
|
||||
"Make sure to suid or sgid slock.\n");
|
||||
hash = pw->pw_passwd;
|
||||
#else
|
||||
die("slock: getpwuid: cannot retrieve shadow entry. "
|
||||
"Make sure to suid or sgid slock.\n");
|
||||
die("slock: getpwuid: cannot retrieve shadow entry. "
|
||||
"Make sure to suid or sgid slock.\n");
|
||||
#endif /* __OpenBSD__ */
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_SHADOW_H */
|
||||
|
||||
return hash;
|
||||
return hash;
|
||||
}
|
||||
|
||||
struct game_offscreen_buffer { /* TODO: REMOVE! */
|
||||
/* Pixels are always 32-bit and have the bytes in BGRX (little-endian). */
|
||||
void *memory;
|
||||
int width;
|
||||
int height;
|
||||
int bytes_per_pixel;
|
||||
int pitch;
|
||||
};
|
||||
|
||||
#include <math.h>
|
||||
int round_float_to_int(float real32)
|
||||
{
|
||||
int result = (int)roundf(real32);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void clear_background(void *memory, int width, int height, int color)
|
||||
{
|
||||
int x;
|
||||
for(x = 0; x < width * height; x++) {
|
||||
unsigned int *pixel = &((unsigned int *)memory)[x];
|
||||
*pixel = color;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
draw_glyph(void *memory, int width, int height, int bytes_per_pixel,
|
||||
FT_Face face, int x, int y)
|
||||
{
|
||||
int pitch;
|
||||
int bitmap_pitch, bitmap_width, bitmap_rows;
|
||||
void *bitmap_pixels;
|
||||
|
||||
int row, column;
|
||||
int rows, columns;
|
||||
|
||||
unsigned char *tdest;
|
||||
int mx, my;
|
||||
|
||||
pitch = width * bytes_per_pixel;
|
||||
|
||||
bitmap_pitch = face->glyph->bitmap.pitch;
|
||||
bitmap_width = face->glyph->bitmap.width;
|
||||
bitmap_rows = face->glyph->bitmap.rows;
|
||||
bitmap_pixels = (void *)face->glyph->bitmap.buffer;
|
||||
y -= face->glyph->bitmap_top;
|
||||
|
||||
row = 0;
|
||||
column = 0;
|
||||
|
||||
rows = bitmap_rows;
|
||||
columns = bitmap_width;
|
||||
|
||||
if(x < 0)
|
||||
column = -x;
|
||||
if(y < 0)
|
||||
row = -y;
|
||||
|
||||
if(x + columns > width)
|
||||
columns = width - x;
|
||||
if(y + rows > height)
|
||||
rows = height - y;
|
||||
|
||||
tdest = (unsigned char *)(memory + y*pitch + x*bytes_per_pixel);
|
||||
|
||||
for(my = row; my < rows; my++) {
|
||||
unsigned char *source;
|
||||
unsigned int *dest;
|
||||
|
||||
source = (unsigned char *)(bitmap_pixels + my*bitmap_pitch);
|
||||
dest = (unsigned int *)(tdest + my*pitch);
|
||||
|
||||
for(mx = column; mx < columns; mx++) {
|
||||
unsigned char gray;
|
||||
unsigned int source_pixel;
|
||||
|
||||
float a, r, g, b, sa, sr, sg, sb, da, dr, dg, db, ar;
|
||||
|
||||
/* TODO: This should be replaced by premultiplied alpha. */
|
||||
a = (1.0f-ar)*da + ar*sa;
|
||||
r = (1.0f-ar)*dr + ar*sr;
|
||||
g = (1.0f-ar)*dg + ar*sg;
|
||||
b = (1.0f-ar)*db + ar*sb;
|
||||
|
||||
gray = source[mx];
|
||||
source_pixel = (gray << 24) | (gray << 16) | (gray << 8) | gray;
|
||||
|
||||
sa = (float)((source_pixel >> 24) & 0xFF);
|
||||
sr = (float)((source_pixel >> 16) & 0xFF);
|
||||
sg = (float)((source_pixel >> 8) & 0xFF);
|
||||
sb = (float)((source_pixel >> 0) & 0xFF);
|
||||
|
||||
da = (float)((dest[mx] >> 24) & 0xFF);
|
||||
dr = (float)((dest[mx] >> 16) & 0xFF);
|
||||
dg = (float)((dest[mx] >> 8) & 0xFF);
|
||||
db = (float)((dest[mx] >> 0) & 0xFF);
|
||||
|
||||
ar = sa / 255.0f;
|
||||
|
||||
/* TODO: This should be replaced by premultiplied alpha. */
|
||||
a = (1.0f-ar)*da + ar*sa;
|
||||
r = (1.0f-ar)*dr + ar*sr;
|
||||
g = (1.0f-ar)*dg + ar*sg;
|
||||
b = (1.0f-ar)*db + ar*sb;
|
||||
|
||||
dest[mx] = (((unsigned int)round_float_to_int(a) << 24) |
|
||||
((unsigned int)round_float_to_int(r) << 16) |
|
||||
((unsigned int)round_float_to_int(g) << 8) |
|
||||
((unsigned int)round_float_to_int(b) << 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Must not crash on error! */
|
||||
static void
|
||||
draw_string(void *buffer, int width, int height,
|
||||
const char *str, FT_Face face, int x, int y)
|
||||
{
|
||||
int str_length, start_x, start_y, i, error;
|
||||
|
||||
str_length = str_len(str);
|
||||
|
||||
start_x = x;
|
||||
start_y = y;
|
||||
|
||||
for(i = 0; i < str_length; i++) {
|
||||
char character = str[i];
|
||||
|
||||
if(character == ' ') {
|
||||
start_x += 20;
|
||||
} else {
|
||||
int glyph_index = FT_Get_Char_Index(face, character);
|
||||
|
||||
error = FT_Load_Glyph(face, glyph_index, 0);
|
||||
if(error)
|
||||
die("slock: FT_Set_Pixel_Sizes\n");
|
||||
|
||||
if(face->glyph->format != FT_GLYPH_FORMAT_BITMAP) {
|
||||
error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
|
||||
if(error)
|
||||
die("slock: FT_Set_Pixel_Sizes\n");
|
||||
}
|
||||
|
||||
draw_glyph(buffer, width, height, 4, face, start_x, start_y);
|
||||
|
||||
start_x += face->glyph->bitmap.width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Must not crash on error! */
|
||||
static void
|
||||
get_string_dimension(int *width, int *height, const char *str, FT_Face face)
|
||||
{
|
||||
int str_length, start_x, start_y, i, error;
|
||||
|
||||
str_length = str_len(str);
|
||||
|
||||
int result_width = 0;
|
||||
int result_height = 0;
|
||||
|
||||
for(i = 0; i < str_length; i++) {
|
||||
char character = str[i];
|
||||
|
||||
if(character == ' ') {
|
||||
result_width += 20;
|
||||
} else {
|
||||
int glyph_index = FT_Get_Char_Index(face, character);
|
||||
|
||||
error = FT_Load_Glyph(face, glyph_index, 0);
|
||||
if(error)
|
||||
die("slock: FT_Set_Pixel_Sizes\n");
|
||||
|
||||
if(face->glyph->format != FT_GLYPH_FORMAT_BITMAP) {
|
||||
error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
|
||||
if(error)
|
||||
die("slock: FT_Set_Pixel_Sizes\n");
|
||||
}
|
||||
|
||||
result_width += face->glyph->bitmap.width;
|
||||
if(face->glyph->bitmap.rows > (unsigned int)result_height)
|
||||
result_height = face->glyph->bitmap.rows;
|
||||
}
|
||||
}
|
||||
|
||||
*width = result_width;
|
||||
*height = result_height;
|
||||
}
|
||||
|
||||
static void
|
||||
render_screen(Display *dpy, struct lock **locks,
|
||||
FT_Face main_font_face, FT_Face secondary_font_face,
|
||||
unsigned int pass_len)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = 0;
|
||||
|
||||
/* TODO: Do not free the pixel buffer. */
|
||||
XWindowAttributes attrs;
|
||||
if(XGetWindowAttributes(dpy, locks[0]->win, &attrs)) {
|
||||
int width = attrs.width;
|
||||
int height = attrs.height;
|
||||
int depth = DefaultDepth(dpy, 0);
|
||||
|
||||
Visual *visual = DefaultVisual(dpy, 0);
|
||||
GC gc = XCreateGC(dpy, locks[0]->win, 0, NULL);
|
||||
|
||||
void *data = malloc(width * height * 4);
|
||||
XImage *img = XCreateImage(dpy, visual, depth, ZPixmap, 0,
|
||||
data, width, height, 32, 0);
|
||||
|
||||
clear_background(data, width, height, 0);
|
||||
|
||||
time_t now = time(NULL);
|
||||
struct tm *tm_info = localtime(&now);
|
||||
char time[64];
|
||||
strftime(time, sizeof(time), "%H:%M", tm_info);
|
||||
|
||||
FT_Set_Pixel_Sizes(main_font_face, 0, 200);
|
||||
if(!error) {
|
||||
int mwidth, mheight;
|
||||
get_string_dimension(&mwidth, &mheight, time, main_font_face);
|
||||
draw_string(data,
|
||||
width, height,
|
||||
time,
|
||||
main_font_face,
|
||||
width/2-mwidth/2, height/4+mheight/2);
|
||||
}
|
||||
|
||||
error = FT_Set_Pixel_Sizes(secondary_font_face, 0, 30);
|
||||
if(!error) {
|
||||
char message[16] = "";
|
||||
if(pass_len > 0) {
|
||||
message[0] = '\0';
|
||||
|
||||
unsigned int i;
|
||||
for(i = 0; i < 10 && i < pass_len; i++) {
|
||||
message[i] = '*';
|
||||
}
|
||||
message[i] = '\0';
|
||||
}
|
||||
|
||||
int mwidth, mheight;
|
||||
get_string_dimension(&mwidth, &mheight,
|
||||
message, secondary_font_face);
|
||||
draw_string(data,
|
||||
width, height,
|
||||
message,
|
||||
secondary_font_face,
|
||||
width/2-mwidth/2, height/2+mheight/2);
|
||||
}
|
||||
|
||||
XPutImage(dpy, locks[0]->win, gc, img, 0, 0, 0, 0, width, height);
|
||||
XFlush(dpy);
|
||||
|
||||
XDestroyImage(img);
|
||||
XFreeGC(dpy, gc);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens,
|
||||
const char *hash)
|
||||
{
|
||||
XRRScreenChangeNotifyEvent *rre;
|
||||
char buf[32], passwd[256], *inputhash;
|
||||
int num, screen, running, failure, oldc, i, passing, dson, xfd;
|
||||
unsigned int len, color;
|
||||
XRRScreenChangeNotifyEvent *rre;
|
||||
char buf[32], passwd[256], *inputhash;
|
||||
int num, screen, running, failure, oldc, i, passing, dson, tfd, xfd;
|
||||
unsigned int len, color;
|
||||
struct timeval tv;
|
||||
KeySym ksym;
|
||||
XEvent ev;
|
||||
KeySym ksym;
|
||||
XEvent ev;
|
||||
|
||||
Bool dpmsavailable;
|
||||
CARD16 dpmspowerlevel;
|
||||
BOOL dpmsstate;
|
||||
CARD16 dpmsstandby, dpmssuspend, dpmsoff;
|
||||
|
||||
len = 0;
|
||||
running = 1;
|
||||
failure = 0;
|
||||
oldc = INIT;
|
||||
len = 0;
|
||||
running = 1;
|
||||
failure = 0;
|
||||
oldc = INIT;
|
||||
dson = 1;
|
||||
|
||||
xfd = ConnectionNumber(dpy);
|
||||
tfd = timerfd_create(CLOCK_REALTIME, 0);
|
||||
|
||||
update_crtc_infos(dpy);
|
||||
|
||||
@@ -280,15 +551,53 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens,
|
||||
XSync(dpy, 0);
|
||||
}
|
||||
|
||||
/* TODO: Disable the DPMS timeout, save settings, and restore. */
|
||||
FT_Library main_font_library;
|
||||
FT_Face main_font_face;
|
||||
|
||||
FT_Library secondary_font_library;
|
||||
FT_Face secondary_font_face;
|
||||
|
||||
int error;
|
||||
|
||||
error = FT_Init_FreeType(&main_font_library);
|
||||
if(error)
|
||||
die("slock: FT_Init_FreeType\n");
|
||||
|
||||
error = FT_New_Memory_Face(main_font_library,
|
||||
main_ttf, main_ttf_len,
|
||||
0, &main_font_face);
|
||||
if(error)
|
||||
die("slock: FT_New_Memory_Face\n");
|
||||
|
||||
error = FT_Init_FreeType(&secondary_font_library);
|
||||
if(error)
|
||||
die("slock: FT_Init_FreeType\n");
|
||||
|
||||
error = FT_New_Memory_Face(secondary_font_library,
|
||||
secondary_ttf, secondary_ttf_len,
|
||||
0, &secondary_font_face);
|
||||
if(error)
|
||||
die("slock: FT_New_Memory_Face\n");
|
||||
|
||||
unsigned long long count = 0;
|
||||
while(running) {
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(xfd, &fds);
|
||||
FD_SET(tfd, &fds);
|
||||
|
||||
XFlush(dpy);
|
||||
|
||||
time_t now = time(NULL);
|
||||
struct tm tmv;
|
||||
localtime_r(&now, &tmv);
|
||||
|
||||
int secs_left = 60 - tmv.tm_sec;
|
||||
|
||||
struct itimerspec its = {0};
|
||||
its.it_value.tv_sec = secs_left;
|
||||
timerfd_settime(tfd, 0, &its, NULL);
|
||||
|
||||
while(XPending(dpy)) {
|
||||
XNextEvent(dpy, &ev);
|
||||
|
||||
@@ -344,12 +653,16 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens,
|
||||
continue;
|
||||
|
||||
if(len == 0 && ksym == XK_Escape) {
|
||||
#if DEBUG
|
||||
exit(1);
|
||||
#else
|
||||
dson = !dson;
|
||||
if(dson)
|
||||
set_screen_on(dpy);
|
||||
else
|
||||
set_screen_off(dpy);
|
||||
continue;
|
||||
#endif
|
||||
}
|
||||
|
||||
switch (ksym) {
|
||||
@@ -391,14 +704,14 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens,
|
||||
color = len ? INPUT : ((failure || failonclear) ? FAILED : INIT);
|
||||
if (running && oldc != (int)color) { /* WARNING: Unsafe cast. */
|
||||
for (screen = 0; screen < nscreens; screen++) {
|
||||
XSetWindowBackground(dpy,
|
||||
/*XSetWindowBackground(dpy,
|
||||
locks[screen]->win,
|
||||
locks[screen]->colors[color]);
|
||||
XClearWindow(dpy, locks[screen]->win);
|
||||
locks[screen]->colors[color]);*/
|
||||
/*XClearWindow(dpy, locks[screen]->win);*/
|
||||
}
|
||||
oldc = color;
|
||||
}
|
||||
} else if (rr->active && ev.type == rr->evbase + RRScreenChangeNotify) {
|
||||
} else if (rr->active && ev.type == rr->evbase + RRScreenChangeNotify) {
|
||||
rre = (XRRScreenChangeNotifyEvent*)&ev;
|
||||
for (screen = 0; screen < nscreens; screen++) {
|
||||
if (locks[screen]->win == rre->window) {
|
||||
@@ -411,33 +724,31 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens,
|
||||
XResizeWindow(dpy, locks[screen]->win,
|
||||
rre->width, rre->height);
|
||||
}
|
||||
XClearWindow(dpy, locks[screen]->win);
|
||||
/*XClearWindow(dpy, locks[screen]->win);*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if(rr->active && ev.type == rr->evbase + RRNotify) {
|
||||
/* TODO: Update crts variables and detect if new displays
|
||||
* are connected. XRRNotifyEvent->subtype,
|
||||
* XRRCrtcChangeNotifyEvent, XRROutputChangeNotifyEvent,
|
||||
* RRNotify_OutputProperty*/
|
||||
} else {
|
||||
for(screen = 0; screen < nscreens; screen++)
|
||||
XRaiseWindow(dpy, locks[screen]->win);
|
||||
}
|
||||
render_screen(dpy, locks, main_font_face, secondary_font_face, len);
|
||||
}
|
||||
|
||||
int ret;
|
||||
if(displaytimeout > 0 && dson) {
|
||||
tv.tv_sec = displaytimeout;
|
||||
tv.tv_usec = 0;
|
||||
ret = select(xfd + 1, &fds, 0, 0, &tv);
|
||||
ret = select(tfd + 1, &fds, 0, 0, &tv);
|
||||
} else {
|
||||
ret = select(xfd + 1, &fds, 0, 0, 0);
|
||||
ret = select(tfd + 1, &fds, 0, 0, 0);
|
||||
}
|
||||
if (ret == 0) {
|
||||
dson = 0;
|
||||
set_screen_off(dpy);
|
||||
} else if (ret > 0 && FD_ISSET(xfd, &fds)) {
|
||||
} else if (ret > 0 && FD_ISSET(tfd, &fds)) {
|
||||
render_screen(dpy, locks, main_font_face, secondary_font_face, len);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,114 +763,128 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens,
|
||||
static struct lock *
|
||||
lockscreen(Display *dpy, struct xrandr *rr, int screen)
|
||||
{
|
||||
char curs[] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
int i, ptgrab, kbgrab;
|
||||
struct lock *lock;
|
||||
XColor color, dummy;
|
||||
XSetWindowAttributes wa;
|
||||
Cursor invisible;
|
||||
char curs[] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
int i, ptgrab, kbgrab;
|
||||
struct lock *lock;
|
||||
XColor color, dummy;
|
||||
XSetWindowAttributes wa;
|
||||
Cursor invisible;
|
||||
|
||||
if (dpy == NULL || screen < 0 || !(lock = malloc(sizeof(struct lock))))
|
||||
return NULL;
|
||||
if (dpy == NULL || screen < 0 || !(lock = malloc(sizeof(struct lock))))
|
||||
return NULL;
|
||||
|
||||
lock->screen = screen;
|
||||
lock->root = RootWindow(dpy, lock->screen);
|
||||
lock->screen = screen;
|
||||
lock->root = RootWindow(dpy, lock->screen);
|
||||
|
||||
for (i = 0; i < NUMCOLS; i++) {
|
||||
XAllocNamedColor(dpy, DefaultColormap(dpy, lock->screen),
|
||||
colorname[i], &color, &dummy);
|
||||
lock->colors[i] = color.pixel;
|
||||
}
|
||||
for (i = 0; i < NUMCOLS; i++) {
|
||||
XAllocNamedColor(dpy, DefaultColormap(dpy, lock->screen),
|
||||
colorname[i], &color, &dummy);
|
||||
lock->colors[i] = color.pixel;
|
||||
}
|
||||
|
||||
/* init */
|
||||
wa.override_redirect = 1;
|
||||
wa.background_pixel = lock->colors[INIT];
|
||||
lock->win = XCreateWindow(dpy, lock->root, 0, 0,
|
||||
DisplayWidth(dpy, lock->screen),
|
||||
DisplayHeight(dpy, lock->screen),
|
||||
0, DefaultDepth(dpy, lock->screen),
|
||||
CopyFromParent,
|
||||
DefaultVisual(dpy, lock->screen),
|
||||
CWOverrideRedirect | CWBackPixel, &wa);
|
||||
lock->pmap = XCreateBitmapFromData(dpy, lock->win, curs, 8, 8);
|
||||
invisible = XCreatePixmapCursor(dpy, lock->pmap, lock->pmap,
|
||||
&color, &color, 0, 0);
|
||||
XDefineCursor(dpy, lock->win, invisible);
|
||||
/* init */
|
||||
wa.override_redirect = 1;
|
||||
wa.background_pixel = lock->colors[INIT];
|
||||
#if DEBUG
|
||||
lock->win = XCreateWindow(dpy, lock->root, 0, 0,
|
||||
800,
|
||||
400,
|
||||
0, DefaultDepth(dpy, lock->screen),
|
||||
CopyFromParent,
|
||||
DefaultVisual(dpy, lock->screen),
|
||||
CWBackPixel, &wa);
|
||||
#else
|
||||
lock->win = XCreateWindow(dpy, lock->root, 0, 0,
|
||||
DisplayWidth(dpy, lock->screen),
|
||||
DisplayHeight(dpy, lock->screen),
|
||||
0, DefaultDepth(dpy, lock->screen),
|
||||
CopyFromParent,
|
||||
DefaultVisual(dpy, lock->screen),
|
||||
CWOverrideRedirect | CWBackPixel, &wa);
|
||||
#endif
|
||||
lock->pmap = XCreateBitmapFromData(dpy, lock->win, curs, 8, 8);
|
||||
invisible = XCreatePixmapCursor(dpy, lock->pmap, lock->pmap,
|
||||
&color, &color, 0, 0);
|
||||
XDefineCursor(dpy, lock->win, invisible);
|
||||
|
||||
XRRSelectInput(dpy, lock->win, RRScreenChangeNotifyMask |
|
||||
RRCrtcChangeNotifyMask |
|
||||
RROutputChangeNotifyMask |
|
||||
RROutputPropertyNotifyMask);
|
||||
#if DEBUG
|
||||
XMapRaised(dpy, lock->win);
|
||||
XSelectInput(dpy, lock->win, KeyPressMask | KeyReleaseMask |
|
||||
ButtonPressMask | ButtonReleaseMask |
|
||||
PointerMotionMask);
|
||||
return lock;
|
||||
#else
|
||||
/* Try to grab mouse pointer *and* keyboard for 600ms, else fail the lock */
|
||||
for (i = 0, ptgrab = kbgrab = -1; i < 6; i++) {
|
||||
if (ptgrab != GrabSuccess) {
|
||||
ptgrab = XGrabPointer(dpy, lock->root, False,
|
||||
ButtonPressMask | ButtonReleaseMask |
|
||||
PointerMotionMask, GrabModeAsync,
|
||||
GrabModeAsync, None, invisible, CurrentTime);
|
||||
}
|
||||
if (kbgrab != GrabSuccess) {
|
||||
kbgrab = XGrabKeyboard(dpy, lock->root, True,
|
||||
GrabModeAsync, GrabModeAsync, CurrentTime);
|
||||
}
|
||||
|
||||
/* Try to grab mouse pointer *and* keyboard for 600ms, else fail the lock */
|
||||
for (i = 0, ptgrab = kbgrab = -1; i < 6; i++) {
|
||||
if (ptgrab != GrabSuccess) {
|
||||
ptgrab = XGrabPointer(dpy, lock->root, False,
|
||||
ButtonPressMask | ButtonReleaseMask |
|
||||
PointerMotionMask, GrabModeAsync,
|
||||
GrabModeAsync, None, invisible, CurrentTime);
|
||||
}
|
||||
if (kbgrab != GrabSuccess) {
|
||||
kbgrab = XGrabKeyboard(dpy, lock->root, True,
|
||||
GrabModeAsync, GrabModeAsync, CurrentTime);
|
||||
}
|
||||
/* input is grabbed: we can lock the screen */
|
||||
if (ptgrab == GrabSuccess && kbgrab == GrabSuccess) {
|
||||
XMapRaised(dpy, lock->win);
|
||||
if (rr->active)
|
||||
XRRSelectInput(dpy, lock->win, RRScreenChangeNotifyMask);
|
||||
|
||||
/* input is grabbed: we can lock the screen */
|
||||
if (ptgrab == GrabSuccess && kbgrab == GrabSuccess) {
|
||||
XMapRaised(dpy, lock->win);
|
||||
if (rr->active)
|
||||
XRRSelectInput(dpy, lock->win, RRScreenChangeNotifyMask);
|
||||
XSelectInput(dpy, lock->root, SubstructureNotifyMask);
|
||||
return lock;
|
||||
}
|
||||
|
||||
XSelectInput(dpy, lock->root, SubstructureNotifyMask);
|
||||
return lock;
|
||||
}
|
||||
/* retry on AlreadyGrabbed but fail on other errors */
|
||||
if ((ptgrab != AlreadyGrabbed && ptgrab != GrabSuccess) ||
|
||||
(kbgrab != AlreadyGrabbed && kbgrab != GrabSuccess))
|
||||
break;
|
||||
|
||||
/* retry on AlreadyGrabbed but fail on other errors */
|
||||
if ((ptgrab != AlreadyGrabbed && ptgrab != GrabSuccess) ||
|
||||
(kbgrab != AlreadyGrabbed && kbgrab != GrabSuccess))
|
||||
break;
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
usleep(100000);
|
||||
}
|
||||
/* we couldn't grab all input: fail out */
|
||||
if (ptgrab != GrabSuccess)
|
||||
fprintf(stderr, "slock: unable to grab mouse pointer for screen %d\n",
|
||||
screen);
|
||||
if (kbgrab != GrabSuccess)
|
||||
fprintf(stderr, "slock: unable to grab keyboard for screen %d\n",
|
||||
screen);
|
||||
#endif
|
||||
|
||||
/* we couldn't grab all input: fail out */
|
||||
if (ptgrab != GrabSuccess)
|
||||
fprintf(stderr, "slock: unable to grab mouse pointer for screen %d\n",
|
||||
screen);
|
||||
if (kbgrab != GrabSuccess)
|
||||
fprintf(stderr, "slock: unable to grab keyboard for screen %d\n",
|
||||
screen);
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
die("usage: slock [-v] [cmd [arg ...]]\n");
|
||||
die("usage: slock [-v] [cmd [arg ...]]\n");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv) {
|
||||
struct xrandr rr;
|
||||
struct lock **locks;
|
||||
struct passwd *pwd;
|
||||
struct group *grp;
|
||||
uid_t duid;
|
||||
gid_t dgid;
|
||||
const char *hash;
|
||||
Display *dpy;
|
||||
int s, nlocks, nscreens;
|
||||
struct xrandr rr;
|
||||
struct lock **locks;
|
||||
struct passwd *pwd;
|
||||
struct group *grp;
|
||||
uid_t duid;
|
||||
gid_t dgid;
|
||||
const char *hash;
|
||||
Display *dpy;
|
||||
int s, nlocks, nscreens;
|
||||
int event_base, error_base;
|
||||
|
||||
char *username, *groupname;
|
||||
|
||||
ARGBEGIN {
|
||||
case 'v':
|
||||
puts("slock-"VERSION);
|
||||
return 0;
|
||||
default:
|
||||
usage();
|
||||
} ARGEND
|
||||
ARGBEGIN {
|
||||
case 'v':
|
||||
puts("slock-"VERSION);
|
||||
return 0;
|
||||
default:
|
||||
usage();
|
||||
} ARGEND
|
||||
|
||||
if(strlen(user) && strlen(group)) {
|
||||
username = (char *)user;
|
||||
@@ -569,73 +894,73 @@ main(int argc, char **argv) {
|
||||
groupname = username;
|
||||
}
|
||||
|
||||
/* validate drop-user and -group */
|
||||
errno = 0;
|
||||
if (!(pwd = getpwnam(username)))
|
||||
die("slock: getpwnam %s: %s\n", username,
|
||||
errno ? strerror(errno) : "user entry not found");
|
||||
duid = pwd->pw_uid;
|
||||
errno = 0;
|
||||
if (!(grp = getgrnam(groupname)))
|
||||
die("slock: getgrnam %s: %s\n", groupname,
|
||||
errno ? strerror(errno) : "group entry not found");
|
||||
dgid = grp->gr_gid;
|
||||
/* validate drop-user and -group */
|
||||
errno = 0;
|
||||
if (!(pwd = getpwnam(username)))
|
||||
die("slock: getpwnam %s: %s\n", username,
|
||||
errno ? strerror(errno) : "user entry not found");
|
||||
duid = pwd->pw_uid;
|
||||
errno = 0;
|
||||
if (!(grp = getgrnam(groupname)))
|
||||
die("slock: getgrnam %s: %s\n", groupname,
|
||||
errno ? strerror(errno) : "group entry not found");
|
||||
dgid = grp->gr_gid;
|
||||
|
||||
#ifdef __linux__
|
||||
dontkillme();
|
||||
dontkillme();
|
||||
#endif
|
||||
|
||||
hash = gethash();
|
||||
errno = 0;
|
||||
if (!crypt("", hash))
|
||||
die("slock: crypt: %s\n", strerror(errno));
|
||||
hash = gethash();
|
||||
errno = 0;
|
||||
if (!crypt("", hash))
|
||||
die("slock: crypt: %s\n", strerror(errno));
|
||||
|
||||
if (!(dpy = XOpenDisplay(NULL)))
|
||||
die("slock: cannot open display\n");
|
||||
if (!(dpy = XOpenDisplay(NULL)))
|
||||
die("slock: cannot open display\n");
|
||||
|
||||
if (!DPMSQueryExtension(dpy, &event_base, &error_base))
|
||||
die("slock: dpms extension is not supported\n");
|
||||
die("slock: dpms extension is not supported\n");
|
||||
|
||||
/* drop privileges */
|
||||
if (setgroups(0, NULL) < 0)
|
||||
die("slock: setgroups: %s\n", strerror(errno));
|
||||
if (setgid(dgid) < 0)
|
||||
die("slock: setgid: %s\n", strerror(errno));
|
||||
if (setuid(duid) < 0)
|
||||
die("slock: setuid: %s\n", strerror(errno));
|
||||
/* drop privileges */
|
||||
if (setgroups(0, NULL) < 0)
|
||||
die("slock: setgroups: %s\n", strerror(errno));
|
||||
if (setgid(dgid) < 0)
|
||||
die("slock: setgid: %s\n", strerror(errno));
|
||||
if (setuid(duid) < 0)
|
||||
die("slock: setuid: %s\n", strerror(errno));
|
||||
|
||||
/* check for Xrandr support */
|
||||
rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase);
|
||||
/* check for Xrandr support */
|
||||
rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase);
|
||||
|
||||
/* get number of screens in display "dpy" and blank them */
|
||||
nscreens = ScreenCount(dpy);
|
||||
if (!(locks = calloc(nscreens, sizeof(struct lock *))))
|
||||
die("slock: out of memory\n");
|
||||
for (nlocks = 0, s = 0; s < nscreens; s++) {
|
||||
if ((locks[s] = lockscreen(dpy, &rr, s)) != NULL)
|
||||
nlocks++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
XSync(dpy, 0);
|
||||
/* get number of screens in display "dpy" and blank them */
|
||||
nscreens = ScreenCount(dpy);
|
||||
if (!(locks = calloc(nscreens, sizeof(struct lock *))))
|
||||
die("slock: out of memory\n");
|
||||
for (nlocks = 0, s = 0; s < nscreens; s++) {
|
||||
if ((locks[s] = lockscreen(dpy, &rr, s)) != NULL)
|
||||
nlocks++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
XSync(dpy, 0);
|
||||
|
||||
/* did we manage to lock everything? */
|
||||
if (nlocks != nscreens)
|
||||
return 1;
|
||||
/* did we manage to lock everything? */
|
||||
if (nlocks != nscreens)
|
||||
return 1;
|
||||
|
||||
/* run post-lock command */
|
||||
if (argc > 0) {
|
||||
pid_t pid;
|
||||
extern char **environ;
|
||||
int err = posix_spawnp(&pid, argv[0], NULL, NULL, argv, environ);
|
||||
if (err) {
|
||||
die("slock: failed to execute post-lock command: %s: %s\n",
|
||||
argv[0], strerror(err));
|
||||
}
|
||||
}
|
||||
/* run post-lock command */
|
||||
if (argc > 0) {
|
||||
pid_t pid;
|
||||
extern char **environ;
|
||||
int err = posix_spawnp(&pid, argv[0], NULL, NULL, argv, environ);
|
||||
if (err) {
|
||||
die("slock: failed to execute post-lock command: %s: %s\n",
|
||||
argv[0], strerror(err));
|
||||
}
|
||||
}
|
||||
|
||||
/* everything is now blank. Wait for the correct password */
|
||||
readpw(dpy, &rr, locks, nscreens, hash);
|
||||
/* everything is now blank. Wait for the correct password */
|
||||
readpw(dpy, &rr, locks, nscreens, hash);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user