Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: clock #7

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions i3lock.1
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@ i3lock \- improved screen locker
.IR image.png \|]
.RB [\|\-c
.IR color \|]
.RB [\|\-F
.IR fgcolor \|]
.RB [\|\-t\|]
.RB [\|\-p
.IR pointer\|]
.RB [\|\-u\|]
.RB [\|\-e\|]
.RB [\|\-I\|]
.RB [\|\-T\|]
.RB [\|\-f\|]

.SH DESCRIPTION
Expand Down Expand Up @@ -93,6 +96,10 @@ Display the given PNG image instead of a blank screen.
Turn the screen into the given color instead of white. Color must be given in 3-byte
format: rrggbb (i.e. ff0000 is red).

.TP
.BI \-F\ rrggbb \fR,\ \fB\-\-fgcolor= rrggbb
Sets the color used for text.

.TP
.B \-t, \-\-tiling
If an image is specified (via \-i) it will display the image tiled all over the screen
Expand All @@ -116,6 +123,12 @@ another try. This can be useful if the XF86ScreenSaver key is used to
put a laptop to sleep and bounce on resume or if you happen to wake up
your computer with the enter key.

.TP
.B \-T, \-\-time
Makes
.B i3lock
draw the current time in the middle of the screen.

.TP
.B \-f, \-\-show-failed-attempts
Show the number of failed attempts, if any.
Expand Down
59 changes: 48 additions & 11 deletions i3lock.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ typedef void (*ev_callback_t)(EV_P_ ev_timer *w, int revents);

/* We need this for libxkbfile */
char color[7] = "ffffff";
uint8_t bgcolor[3] = {255, 255, 255};
uint8_t fgcolor[3] = {0, 0, 0};
int inactivity_timeout = 30;
uint32_t last_resolution[2];
xcb_window_t win;
Expand All @@ -65,6 +67,7 @@ static struct ev_timer *clear_pam_wrong_timeout;
static struct ev_timer *clear_indicator_timeout;
static struct ev_timer *dpms_timeout;
static struct ev_timer *discard_passwd_timeout;
static struct ev_timer clock_timer;
extern unlock_state_t unlock_state;
extern pam_state_t pam_state;
int failed_attempts = 0;
Expand All @@ -80,6 +83,7 @@ static uint8_t xkb_base_error;

cairo_surface_t *img = NULL;
bool tile = false;
bool showtime = false;
bool ignore_empty_password = false;
bool skip_repeated_empty_password = false;

Expand All @@ -94,6 +98,26 @@ void u8_dec(char *s, int *i) {
(void)(isutf(s[--(*i)]) || isutf(s[--(*i)]) || isutf(s[--(*i)]) || --(*i));
}

static int parse_color(const char *str, uint8_t color[]) {
char buf[6];
/* Skip # if present */
if (str[0] == '#')
str++;

if (strlen(str) != 6 || sscanf(str, "%06[0-9a-fA-F]", buf) != 1)
return -1;

char strgroups[3][3] = {{buf[0], buf[1], '\0'},
{buf[2], buf[3], '\0'},
{buf[4], buf[5], '\0'}};

color[0] = strtol(strgroups[0], NULL, 16);
color[1] = strtol(strgroups[1], NULL, 16);
color[2] = strtol(strgroups[2], NULL, 16);

return 0;
}

static void turn_monitors_on(void) {
if (dpms)
dpms_set_mode(conn, XCB_DPMS_DPMS_MODE_ON);
Expand Down Expand Up @@ -252,6 +276,10 @@ static void discard_passwd_cb(EV_P_ ev_timer *w, int revents) {
STOP_TIMER(discard_passwd_timeout);
}

static void clock_tick_cb(EV_P_ ev_timer *w, int revents) {
redraw_screen();
}

static void input_done(void) {
STOP_TIMER(clear_pam_wrong_timeout);
pam_state = STATE_PAM_VERIFY;
Expand Down Expand Up @@ -725,12 +753,14 @@ int main(int argc, char *argv[]) {
{"beep", no_argument, NULL, 'b'},
{"dpms", no_argument, NULL, 'd'},
{"color", required_argument, NULL, 'c'},
{"fgcolor", required_argument, NULL, 'F'},
{"pointer", required_argument, NULL , 'p'},
{"debug", no_argument, NULL, 0},
{"help", no_argument, NULL, 'h'},
{"no-unlock-indicator", no_argument, NULL, 'u'},
{"image", required_argument, NULL, 'i'},
{"tiling", no_argument, NULL, 't'},
{"time", no_argument, NULL, 'T'},
{"ignore-empty-password", no_argument, NULL, 'e'},
{"inactivity-timeout", required_argument, NULL, 'I'},
{"show-failed-attempts", no_argument, NULL, 'f'},
Expand All @@ -742,7 +772,7 @@ int main(int argc, char *argv[]) {
if ((username = pw->pw_name) == NULL)
errx(EXIT_FAILURE, "pw->pw_name is NULL.\n");

char *optstring = "hvnbdc:p:ui:teI:f";
char *optstring = "hvnbdc:F:p:ui:teI:Tf";
while ((o = getopt_long(argc, argv, optstring, longopts, &optind)) != -1) {
switch (o) {
case 'v':
Expand All @@ -764,15 +794,14 @@ int main(int argc, char *argv[]) {
break;
}
case 'c': {
char *arg = optarg;

/* Skip # if present */
if (arg[0] == '#')
arg++;

if (strlen(arg) != 6 || sscanf(arg, "%06[0-9a-fA-F]", color) != 1)
if (parse_color(optarg, bgcolor) != 0)
errx(EXIT_FAILURE, "color is invalid, it must be given in 3-byte hexadecimal format: rrggbb\n");
strncpy(color, optarg, 7);
break;
}
case 'F': {
if (parse_color(optarg, fgcolor) != 0)
errx(EXIT_FAILURE, "color is invalid, it must be given in 3-byte hexadecimal format: rrggbb\n");

break;
}
case 'u':
Expand All @@ -784,6 +813,9 @@ int main(int argc, char *argv[]) {
case 't':
tile = true;
break;
case 'T':
showtime = true;
break;
case 'p':
if (!strcmp(optarg, "win")) {
curs_choice = CURS_WIN;
Expand All @@ -804,8 +836,8 @@ int main(int argc, char *argv[]) {
show_failed_attempts = true;
break;
default:
errx(EXIT_FAILURE, "Syntax: i3lock [-v] [-n] [-b] [-d] [-c color] [-u] [-p win|default]"
" [-i image.png] [-t] [-e] [-I] [-f]"
errx(EXIT_FAILURE, "Syntax: i3lock [-v] [-n] [-b] [-d] [-c bgcolor] [-F fgcolor] [-u] [-p win|default]"
" [-i image.png] [-t] [-e] [-I] [-T] [-f]"
);
}
}
Expand Down Expand Up @@ -957,6 +989,11 @@ int main(int argc, char *argv[]) {
if (main_loop == NULL)
errx(EXIT_FAILURE, "Could not initialize libev. Bad LIBEV_FLAGS?\n");

if (showtime) {
ev_timer_init(&clock_timer, clock_tick_cb, 1.0, 1.0);
ev_timer_start(main_loop, &clock_timer);
}

struct ev_io *xcb_watcher = calloc(sizeof(struct ev_io), 1);
struct ev_check *xcb_check = calloc(sizeof(struct ev_check), 1);
struct ev_prepare *xcb_prepare = calloc(sizeof(struct ev_prepare), 1);
Expand Down
61 changes: 53 additions & 8 deletions unlock_indicator.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <xcb/xcb.h>
#include <ev.h>
#include <cairo.h>
Expand Down Expand Up @@ -49,8 +50,11 @@ extern cairo_surface_t *img;

/* Whether the image should be tiled. */
extern bool tile;
/* The background color to use (in hex). */
/* Whether we need to draw clock */
extern bool showtime;
/* The background and foreground color to use. */
extern char color[7];
extern uint8_t bgcolor[3], fgcolor[3];

/* Whether the failed attempts should be displayed. */
extern bool show_failed_attempts;
Expand Down Expand Up @@ -125,17 +129,58 @@ xcb_pixmap_t draw_image(uint32_t *resolution) {
cairo_pattern_destroy(pattern);
}
} else {
char strgroups[3][3] = {{color[0], color[1], '\0'},
{color[2], color[3], '\0'},
{color[4], color[5], '\0'}};
uint32_t rgb16[3] = {(strtol(strgroups[0], NULL, 16)),
(strtol(strgroups[1], NULL, 16)),
(strtol(strgroups[2], NULL, 16))};
cairo_set_source_rgb(xcb_ctx, rgb16[0] / 255.0, rgb16[1] / 255.0, rgb16[2] / 255.0);
cairo_set_source_rgb(xcb_ctx, bgcolor[0] / 255.0, bgcolor[1] / 255.0, bgcolor[2] / 255.0);
cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]);
cairo_fill(xcb_ctx);
}

if (showtime) {
/* Drawing the current time */
char text[20];
time_t t;
struct tm *tm;

t = time(NULL);
tm = localtime(&t);
if (strftime(text, sizeof(text), "%T", tm)) {
const int fontsz = resolution[0] / 10;
cairo_text_extents_t extents;
static bool fresh = true;
static double x, y;

/* frame spec */
static double rx, ry, rw, rh;
const double lw = 4, spc = 15;

cairo_set_font_size(xcb_ctx, fontsz);
cairo_text_extents(xcb_ctx, text, &extents);
/* avoid wobbling */
if (fresh) {
x = resolution[0] / 2 - ((extents.width / 2) + extents.x_bearing);
y = resolution[1] / 2 - ((extents.height / 2) + extents.y_bearing);

rx = x + extents.x_bearing - lw - spc;
ry = y + extents.y_bearing - lw - spc;
rw = extents.width + 2 * (lw + spc);
rh = extents.height + 2 * (lw + spc);
fresh = false;
}

/* draw a frame */
cairo_set_line_join(xcb_ctx, CAIRO_LINE_JOIN_ROUND);
cairo_set_source_rgb(xcb_ctx, bgcolor[0] / 255.0, bgcolor[1] / 255.0, bgcolor[2] / 255.0);
cairo_rectangle(xcb_ctx, rx, ry, rw, rh);
cairo_fill(xcb_ctx);
cairo_set_source_rgb(xcb_ctx, fgcolor[0] / 255.0, fgcolor[1] / 255.0, fgcolor[2] / 255.0);
cairo_set_line_width(xcb_ctx, lw);
cairo_rectangle(xcb_ctx, rx, ry, rw, rh);
cairo_stroke(xcb_ctx);

/* draw the time */
cairo_move_to(xcb_ctx, x, y);
cairo_show_text(xcb_ctx, text);
}
}
if (unlock_state >= STATE_KEY_PRESSED && unlock_indicator) {
cairo_scale(ctx, scaling_factor(), scaling_factor());
/* Draw a (centered) circle with transparent background. */
Expand Down