aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Magahern <james@magahern.com>2019-01-16 21:56:24 -0800
committerJames Magahern <james@magahern.com>2019-01-16 21:56:24 -0800
commita3c00eb06c9b0e4fa0c37fe1e2ebc7c7ee6d0cc0 (patch)
treecb3a6eb927807647b758982a71d9f4ea3a76d07d
parentRespond to window size events (diff)
Password visualization
TODO: control keys (like ctrl-a and ctrl-u)
-rw-r--r--asterisk.svg39
-rwxr-xr-xbuild.sh2
-rw-r--r--buzzsaver.c116
3 files changed, 139 insertions, 18 deletions
diff --git a/asterisk.svg b/asterisk.svg
new file mode 100644
index 0000000..f9ff19a
--- /dev/null
+++ b/asterisk.svg
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ width="32.275391"
+ height="30.46875"
+ id="svg3033">
+ <metadata
+ id="metadata3041">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3039" />
+ <g
+ id="g3065">
+ <g
+ id="text3035"
+ style="font-size:100px;font-family:arial;fill:white">
+ <path
+ d="M 0,14.355469 2.2460938,7.421875 C 7.4218645,9.2448552 11.181626,10.82363 13.525391,12.158203 12.906885,6.2663426 12.581365,2.2136123 12.548828,0 l 7.080078,0 c -0.09768,3.2227258 -0.472027,7.2591801 -1.123047,12.109375 3.35284,-1.692646 7.193982,-3.2551444 11.523438,-4.6875 l 2.246094,6.933594 c -4.134146,1.367244 -8.186877,2.278702 -12.158204,2.734375 1.985652,1.725314 4.785129,4.801483 8.398438,9.228515 L 22.65625,30.46875 C 20.768205,27.89718 18.53839,24.397835 15.966797,19.970703 13.557926,24.560595 11.442043,28.059941 9.6191406,30.46875 L 3.8574219,26.318359 C 7.6334528,21.663463 10.335273,18.587294 11.962891,17.089844 7.763661,16.276098 3.7760348,15.364641 0,14.355469"
+ id="path3063"
+ style="font-size:100px;font-family:arial" />
+ </g>
+ </g>
+</svg>
diff --git a/build.sh b/build.sh
index 691ac2a..33bdbcf 100755
--- a/build.sh
+++ b/build.sh
@@ -1,5 +1,5 @@
#!/bin/bash
# TODO: Makefile? This will end up in the xsecurelock project anyway...
-clang $(pkg-config --libs --cflags x11 cairo librsvg-2.0) -o buzzsaver buzzsaver.c
+clang $(pkg-config --libs --cflags x11 cairo librsvg-2.0 pangocairo) -o buzzsaver buzzsaver.c
diff --git a/buzzsaver.c b/buzzsaver.c
index 811f734..d547aef 100644
--- a/buzzsaver.c
+++ b/buzzsaver.c
@@ -7,6 +7,7 @@
#include <cairo/cairo.h>
#include <cairo-xlib.h>
#include <librsvg/rsvg.h>
+#include <pango/pangocairo.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@@ -19,16 +20,24 @@ int __width, __height;
static Window __window = { 0 };
static Display *__display = NULL;
+static const size_t kMaxPasswordLength = 128;
static const double kLogoBackgroundWidth = 300.0;
typedef struct {
- cairo_t *ctx;
- cairo_surface_t *surface;
+ cairo_t *ctx;
+ cairo_surface_t *surface;
- RsvgHandle *logo_svg_handle;
+ PangoLayout *pango_layout;
+ PangoFontDescription *status_font;
- double cursor_opacity;
- double cursor_fade_direction;
+ RsvgHandle *logo_svg_handle;
+ RsvgHandle *asterisk_svg_handle;
+
+ double cursor_opacity;
+ double cursor_fade_direction;
+
+ char *password_buffer;
+ size_t password_buffer_len;
} saver_state_t;
void window_changed_size(saver_state_t *state, XConfigureEvent *event)
@@ -39,11 +48,31 @@ void window_changed_size(saver_state_t *state, XConfigureEvent *event)
cairo_xlib_surface_set_size(state->surface, __width, __height);
}
+void handle_key_event(saver_state_t *state, XKeyEvent *event)
+{
+ KeySym key;
+ char keybuf[8];
+ XLookupString(event, keybuf, sizeof(keybuf), &key, NULL);
+ printf("str: %d\n", key);
+
+ char *password_buf = state->password_buffer;
+ size_t length = strlen(password_buf);
+ if (XK_BackSpace == key) {
+ // delete char
+ if (length > 0) {
+ password_buf[length - 1] = '\0';
+ }
+ } else if (strlen(keybuf) > 0) {
+ size_t add_len = strlen(keybuf);
+ if ( (length + add_len) < state->password_buffer_len - 1 ) {
+ strncpy(password_buf + length, keybuf, add_len);
+ }
+ }
+}
+
int poll_events(saver_state_t *state)
{
const bool block_for_next_event = false;
- char keybuf[8];
- KeySym key;
XEvent e;
for (;;) {
@@ -58,12 +87,12 @@ int poll_events(saver_state_t *state)
switch (e.type) {
case ConfigureNotify:
window_changed_size(state, (XConfigureEvent *)&e);
- return 0;
+ return 1;
case ButtonPress:
return -e.xbutton.button;
case KeyPress:
- XLookupString(&e.xkey, keybuf, sizeof(keybuf), &key, NULL);
- return key;
+ handle_key_event(state, (XKeyEvent *)&e);
+ return 1;
default:
fprintf(stderr, "Dropping unhandled XEevent.type = %d.\n", e.type);
}
@@ -102,12 +131,10 @@ void draw_logo(saver_state_t *state)
const double padding = 10.0;
double scale_factor = ((kLogoBackgroundWidth - (padding * 2.0)) / dimensions.width);
- cairo_scale(cr, scale_factor, scale_factor);
-
double scaled_height = (dimensions.height * scale_factor);
double y_position = (__height - scaled_height) / 2.0;
-
cairo_translate(cr, padding, y_position);
+ cairo_scale(cr, scale_factor, scale_factor);
rsvg_handle_render_cairo(state->logo_svg_handle, cr);
cairo_restore(cr);
@@ -115,13 +142,60 @@ void draw_logo(saver_state_t *state)
void draw_password_field(saver_state_t *state)
{
+ const double cursor_height = 40.0;
+ const double cursor_width = 30.0;
+ const double field_x = kLogoBackgroundWidth + 50.0;
+ const double field_y = (__height - cursor_height) / 2.0;
+ const double field_padding = 10.0;
+
cairo_t *cr = state->ctx;
- cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, state->cursor_opacity);
- const double cursor_height = 50.0;
- const double cursor_width = 30.0;
- cairo_rectangle(cr, kLogoBackgroundWidth + 50.0, (__height - cursor_height) / 2.0, cursor_width, cursor_height);
+ // Draw status text
+ cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
+ pango_layout_set_font_description(state->pango_layout, state->status_font);
+ pango_layout_set_text(state->pango_layout, "Password: ", -1);
+
+ int t_width, t_height;
+ pango_layout_get_size(state->pango_layout, &t_width, &t_height);
+ double line_height = t_height / PANGO_SCALE;
+
+ cairo_move_to(cr, field_x, field_y - line_height - field_padding);
+ pango_cairo_show_layout(cr, state->pango_layout);
+
+ // Draw password asterisks
+ if (state->asterisk_svg_handle == NULL) {
+ GError *error = NULL;
+ state->asterisk_svg_handle = rsvg_handle_new_from_file("asterisk.svg", &error);
+ if (error != NULL) {
+ fprintf(stderr, "Error loading asterisk SVG\n");
+ return;
+ }
+ }
+
+ const double cursor_padding_x = 10.0;
+ double cursor_offset_x = 0.0;
+ RsvgDimensionData dimensions;
+ rsvg_handle_get_dimensions(state->asterisk_svg_handle, &dimensions);
+
+ double asterisk_height = cursor_height - 20.0;
+ double scale_factor = (asterisk_height / dimensions.height);
+ double scaled_width = (dimensions.width * scale_factor);
+
+ for (unsigned i = 0; i < strlen(state->password_buffer); i++) {
+ cairo_save(cr);
+ cairo_translate(cr, field_x + cursor_offset_x, field_y + ((cursor_height - asterisk_height) / 2.0));
+ cairo_scale(cr, scale_factor, scale_factor);
+ rsvg_handle_render_cairo(state->asterisk_svg_handle, cr);
+ cairo_restore(cr);
+
+ cursor_offset_x += scaled_width + cursor_padding_x;
+ }
+
+
+ // Draw cursor
+ cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, state->cursor_opacity);
+ cairo_rectangle(cr, field_x + cursor_offset_x, field_y, cursor_width, cursor_height);
cairo_fill(cr);
}
@@ -163,11 +237,19 @@ int runloop(cairo_surface_t *surface)
{
cairo_t *cr = cairo_create(surface);
+ // Initialize pango context
+ PangoLayout *pango_layout = pango_cairo_create_layout(cr);
+ PangoFontDescription *status_font = pango_font_description_from_string("Input Mono 22");
+
saver_state_t state = { 0 };
state.ctx = cr;
state.surface = surface;
state.cursor_opacity = 1.0;
state.cursor_fade_direction = -1.0;
+ state.pango_layout = pango_layout;
+ state.status_font = status_font;
+ state.password_buffer = calloc(1, kMaxPasswordLength);
+ state.password_buffer_len = kMaxPasswordLength;
// Main run loop
struct timespec sleep_time = { 0, 5000000 };