aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Magahern <james@magahern.com>2019-01-27 22:39:30 -0800
committerJames Magahern <james@magahern.com>2019-01-27 22:39:30 -0800
commit90e2b03662847fda9843d2ed73369653a3bcbea6 (patch)
tree159d16e27b6417d1282aac83a6637442f9908229
parentSpinner animation and tweaks to memory management (diff)
Some code cleanup
-rw-r--r--src/animation.c34
-rw-r--r--src/animation.h21
-rw-r--r--src/main.c44
-rw-r--r--src/render.c59
4 files changed, 93 insertions, 65 deletions
diff --git a/src/animation.c b/src/animation.c
index 15093d3..ecefb97 100644
--- a/src/animation.c
+++ b/src/animation.c
@@ -7,15 +7,6 @@
#include "animation.h"
#include <stdlib.h>
-anim_time_interval_t anim_now()
-{
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
-
- long ms = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
- return (ms / 1000.0);
-}
-
/*
* Easing functions
*/
@@ -31,4 +22,29 @@ double anim_quad_ease_out(double p)
return -(p * (p - 2.0));
}
+/*
+ * Convenience calculation functions
+ */
+
+anim_time_interval_t anim_now()
+{
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+
+ long ms = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
+ return (ms / 1000.0);
+}
+
+double anim_progress(animation_t *anim, const double duration)
+{
+ const anim_time_interval_t now = anim_now();
+ double progress = (now - anim->start_time) / duration;
+ return (anim->direction == IN) ? progress : (1.0 - progress);
+}
+
+bool anim_complete(animation_t *anim, const double progress)
+{
+ return (anim->direction == IN) ? progress >= 1.0 : progress <= 0.0;
+}
+
diff --git a/src/animation.h b/src/animation.h
index 108fbe2..54adb70 100644
--- a/src/animation.h
+++ b/src/animation.h
@@ -26,20 +26,21 @@ typedef enum {
ASpinnerAnimation,
} AnimationType;
+// Cursor flash animation
typedef struct {
- bool cursor_animating;
- double cursor_fade_direction;
+ bool cursor_animating;
} CursorAnimation;
+// Logo transition in/out animation
typedef struct {
- AnimationDirection direction;
} LogoAnimation;
+// Red flash for incorrect password
typedef struct {
- AnimationDirection direction;
unsigned flash_count;
} RedFlashAnimation;
+// Spinner shown when checking password
typedef struct {
double rotation;
} SpinnerAnimation;
@@ -58,13 +59,23 @@ typedef struct {
bool completed;
anim_time_interval_t start_time;
+ AnimationDirection direction;
+
AnimationCompletion completion_func;
void *completion_func_context;
} animation_t;
-// Convenience: returns current time as anim_time_interval_t
+// Convenience functions
+
+// returns current time as anim_time_interval_t
anim_time_interval_t anim_now();
+// Returns normalized progress based on start time of `anim` and `duration`
+double anim_progress(animation_t *anim, const double duration);
+
+// Returns true if `anim` is complete depending on direction
+bool anim_complete(animation_t *anim, const double progress);
+
// Easing functions
double anim_qubic_ease_out(double p);
double anim_quad_ease_out(double p);
diff --git a/src/main.c b/src/main.c
index f7b75d3..3eebc55 100644
--- a/src/main.c
+++ b/src/main.c
@@ -20,6 +20,8 @@ static const int kXSecureLockCharFD = 0;
static const int kDefaultWidth = 1024;
static const int kDefaultHeight = 768;
+static const char *kDefaultFont = "Input Mono 22";
+
static inline saver_state_t* saver_state(void *c)
{
return (saver_state_t *)c;
@@ -28,6 +30,25 @@ static inline saver_state_t* saver_state(void *c)
static void clear_password(saver_state_t *state);
static void accept_password(saver_state_t *state);
+static int poll_events(saver_state_t *state);
+
+static void handle_key_event(saver_state_t *state, XKeyEvent *event);
+static void handle_xsl_key_input(saver_state_t *state, const char c);
+static void window_changed_size(saver_state_t *state, XConfigureEvent *event);
+
+static void ending_animation_completed(struct animation_t *animation, void *context);
+static void authentication_accepted(saver_state_t *state);
+static void authentication_rejected(saver_state_t *state);
+
+static void update(saver_state_t *state);
+static void draw(saver_state_t *state);
+static int runloop(cairo_surface_t *surface);
+
+void callback_show_info(const char *info_msg, void *context);
+void callback_show_error(const char *error_msg, void *context);
+void callback_prompt_user(const char *prompt, void *context);
+void callback_authentication_result(int result, void *context);
+
/*
* Event handling
*/
@@ -40,6 +61,11 @@ static void window_changed_size(saver_state_t *state, XConfigureEvent *event)
cairo_xlib_surface_set_size(state->surface, event->width, event->height);
}
+// The following two methods are separate methods for processing input:
+// The first one `handle_xsl_key_input` is for handling input via the XSecureLock
+// file descriptor, which basically gives us TTY keycodes. The second handles
+// input via X11, which is really only used for testing (when the locker is being
+// run inside a window during development).
static void handle_xsl_key_input(saver_state_t *state, const char c)
{
if (!state->input_allowed) return;
@@ -76,6 +102,8 @@ static void handle_xsl_key_input(saver_state_t *state, const char c)
}
}
+// This input handler is only when the locker is being run in "X11 mode" for development
+// (See comment above for why this is separate)
static void handle_key_event(saver_state_t *state, XKeyEvent *event)
{
if (!state->input_allowed) return;
@@ -195,9 +223,7 @@ static void authentication_accepted(saver_state_t *state)
.type = ALogoAnimation,
.completion_func = ending_animation_completed,
.completion_func_context = state,
- .anim.logo_anim = {
- .direction = true
- }
+ .direction = OUT,
};
schedule_animation(state, out_animation);
}
@@ -206,9 +232,7 @@ static void authentication_rejected(saver_state_t *state)
{
animation_t flash_animation = {
.type = ARedFlashAnimation,
- .anim.redflash_anim = {
- .direction = IN
- }
+ .direction = IN,
};
schedule_animation(state, flash_animation);
@@ -271,7 +295,7 @@ static int runloop(cairo_surface_t *surface)
// Initialize pango context
PangoLayout *pango_layout = pango_cairo_create_layout(cr);
- PangoFontDescription *status_font = pango_font_description_from_string("Input Mono 22");
+ PangoFontDescription *status_font = pango_font_description_from_string(kDefaultFont);
saver_state_t state = { 0 };
state.ctx = cr;
@@ -288,8 +312,8 @@ static int runloop(cairo_surface_t *surface)
// Cursor animation -- repeats indefinitely
animation_t cursor_animation = {
.type = ACursorAnimation,
+ .direction = OUT,
.anim.cursor_anim = {
- .cursor_fade_direction = -1.0,
.cursor_animating = true
}
};
@@ -298,9 +322,7 @@ static int runloop(cairo_surface_t *surface)
// Logo incoming animation
animation_t logo_animation = {
.type = ALogoAnimation,
- .anim.logo_anim = {
- .direction = IN
- }
+ .direction = IN,
};
schedule_animation(&state, logo_animation);
diff --git a/src/render.c b/src/render.c
index 908238e..b6a70d4 100644
--- a/src/render.c
+++ b/src/render.c
@@ -46,17 +46,14 @@ static void update_single_animation(saver_state_t *state, animation_t *anim)
if (ca->cursor_animating) {
if (!state->is_processing) {
- const double cursor_fade_speed = 0.05;
- if (ca->cursor_fade_direction > 0) {
- state->cursor_opacity += cursor_fade_speed;
- if (state->cursor_opacity > 1.0) {
- ca->cursor_fade_direction *= -1;
- }
- } else {
- state->cursor_opacity -= cursor_fade_speed;
- if (state->cursor_opacity <= 0.0) {
- ca->cursor_fade_direction *= -1;
- }
+ const double fade_duration = 0.5;
+ double progress = anim_progress(anim, fade_duration);
+
+ state->cursor_opacity = progress;
+
+ if (anim_complete(anim, progress)) {
+ anim->direction = !anim->direction;
+ anim->start_time = anim_now();
}
} else {
state->cursor_opacity = 1.0;
@@ -68,49 +65,27 @@ static void update_single_animation(saver_state_t *state, animation_t *anim)
else if (anim->type == ALogoAnimation) {
const double logo_duration = 0.6;
- anim_time_interval_t now = anim_now();
- double progress = (now - anim->start_time) / logo_duration;
+ double progress = anim_progress(anim, logo_duration);
progress = anim_qubic_ease_out(progress);
- // Check for reverse direction
- if (anim->anim.logo_anim.direction) {
- progress = 1.0 - progress;
- }
-
state->logo_fill_progress = progress;
state->password_opacity = progress;
- bool completed = (progress >= 1.0);
- if (anim->anim.logo_anim.direction) {
- completed = (progress <= 0.0);
- }
-
- anim->completed = completed;
+ anim->completed = anim_complete(anim, progress);
}
// Background red flash animation
else if (anim->type == ARedFlashAnimation) {
const double duration = 0.1;
- anim_time_interval_t now = anim_now();
- double progress = (now - anim->start_time) / duration;
+ double progress = anim_progress(anim, duration);
progress = anim_qubic_ease_out(progress);
- // Check for reverse direction
- if (anim->anim.redflash_anim.direction == OUT) {
- progress = 1.0 - progress;
- }
-
- AnimationDirection direction = anim->anim.redflash_anim.direction;
- bool finished = (progress >= 1.0);
- if (anim->anim.redflash_anim.direction) {
- finished = (progress <= 0.0);
- }
-
bool completed = false;
- if (finished) {
+ if (anim_complete(anim, progress)) {
+ AnimationDirection direction = anim->direction;
+ anim->direction = !direction;
anim->anim.redflash_anim.flash_count++;
- anim->anim.redflash_anim.direction = !direction;
anim->start_time = anim_now();
if (anim->anim.redflash_anim.flash_count > 3) {
completed = true;
@@ -231,12 +206,14 @@ void draw_logo(saver_state_t *state)
cairo_t *cr = state->ctx;
+ // Draw bar background
cairo_save(cr);
cairo_set_source_rgb(cr, (208.0 / 255.0), (69.0 / 255.0), (255.0 / 255.0));
double fill_height = (state->canvas_height * state->logo_fill_progress);
cairo_rectangle(cr, 0, 0, kLogoBackgroundWidth, fill_height);
cairo_fill(cr);
+ // Common color -- transparent for logo
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
// Scale and draw logo
@@ -305,6 +282,7 @@ void draw_password_field(saver_state_t *state)
cairo_translate(cr, field_x, field_y - line_height - 8.0);
+ // Translate, rotate, translate; so rotation is happening about the center.
double tr_amount = (spinner_dimensions.width * spinner_scale_factor) / 2.0;
cairo_translate(cr, tr_amount, tr_amount);
cairo_rotate(cr, spinner_anim.rotation);
@@ -332,6 +310,7 @@ void draw_password_field(saver_state_t *state)
double scale_factor = (asterisk_height / dimensions.height);
double scaled_width = (dimensions.width * scale_factor);
+ // Asterisks are all rendered in a single group so their opacity can change (password_opacity)
cairo_push_group(cr);
for (unsigned i = 0; i < strlen(state->password_buffer); i++) {
cairo_save(cr);
@@ -350,7 +329,7 @@ void draw_password_field(saver_state_t *state)
cairo_paint_with_alpha(cr, state->password_opacity);
cairo_restore(cr);
cairo_pattern_destroy(asterisk_pattern);
-
+
// Draw cursor
cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, MIN(state->password_opacity, state->cursor_opacity));
if (!state->is_processing) {