aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Magahern <james@magahern.com>2019-01-20 19:05:51 -0800
committerJames Magahern <james@magahern.com>2019-01-20 19:05:51 -0800
commita6cc194e6e8a6df417c890589c54d1e6b1966875 (patch)
treefd6280196756fe14c2ea0dd7abe91b5b6dcf00be
parentFade out password (diff)
Red flash animation on bad password
-rw-r--r--src/animation.h29
-rw-r--r--src/main.c36
-rw-r--r--src/render.c53
-rw-r--r--src/render.h5
4 files changed, 91 insertions, 32 deletions
diff --git a/src/animation.h b/src/animation.h
index 3064d1b..a74bb60 100644
--- a/src/animation.h
+++ b/src/animation.h
@@ -14,39 +14,46 @@ struct animation_t;
typedef void(*AnimationCompletion)(struct animation_t *anim, void *context);
typedef enum {
+ IN,
+ OUT
+} AnimationDirection;
+
+typedef enum {
_EmptyAnimationType,
ACursorAnimation,
ALogoAnimation,
+ ARedFlashAnimation,
} AnimationType;
typedef struct {
- AnimationType type;
-
bool cursor_animating;
double cursor_fade_direction;
} CursorAnimation;
typedef struct {
- AnimationType type;
-
- bool direction; // false: in, true: out
+ AnimationDirection direction;
} LogoAnimation;
-typedef union {
- AnimationType type;
+typedef struct {
+ AnimationDirection direction;
+ unsigned flash_count;
+} RedFlashAnimation;
- CursorAnimation cursor_anim;
- LogoAnimation logo_anim;
+typedef union {
+ CursorAnimation cursor_anim;
+ LogoAnimation logo_anim;
+ RedFlashAnimation redflash_anim;
} Animation;
typedef struct {
+ AnimationType type;
+ Animation anim;
+
bool completed;
anim_time_interval_t start_time;
AnimationCompletion completion_func;
void *completion_func_context;
-
- Animation anim;
} animation_t;
// Convenience: returns current time as anim_time_interval_t
diff --git a/src/main.c b/src/main.c
index c70ff9d..ddaea43 100644
--- a/src/main.c
+++ b/src/main.c
@@ -18,8 +18,8 @@
static const int kXSecureLockCharFD = 0;
static const size_t kMaxPasswordLength = 128;
-static const int kDefaultWidth = 800;
-static const int kDefaultHeight = 600;
+static const int kDefaultWidth = 1024;
+static const int kDefaultHeight = 768;
static inline saver_state_t* saver_state(void *c)
{
@@ -175,17 +175,29 @@ static void ending_animation_completed(struct animation_t *animation, void *cont
static void authentication_accepted(saver_state_t *state)
{
animation_t out_animation = {
- .completed = false,
+ .type = ALogoAnimation,
.completion_func = ending_animation_completed,
.completion_func_context = state,
.anim.logo_anim = {
- .type = ALogoAnimation,
.direction = true
}
};
schedule_animation(state, out_animation);
}
+static void authentication_rejected(saver_state_t *state)
+{
+ animation_t flash_animation = {
+ .type = ARedFlashAnimation,
+ .anim.redflash_anim = {
+ .direction = IN
+ }
+ };
+ schedule_animation(state, flash_animation);
+
+ clear_password(state);
+}
+
/*
* Auth callbacks
*/
@@ -219,7 +231,7 @@ void callback_authentication_result(int result, void *context)
authentication_accepted(state);
} else {
// Try again
- clear_password(state);
+ authentication_rejected(state);
}
}
@@ -235,11 +247,7 @@ static void update(saver_state_t *state)
static void draw(saver_state_t *state)
{
- // Draw background
- cairo_t *cr = state->ctx;
- cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
- cairo_paint(cr);
-
+ draw_background(state);
draw_logo(state);
draw_password_field(state);
}
@@ -268,9 +276,8 @@ static int runloop(cairo_surface_t *surface)
// Add initial animations
// Cursor animation -- repeats indefinitely
animation_t cursor_animation = {
- .completed = false,
+ .type = ACursorAnimation,
.anim.cursor_anim = {
- .type = ACursorAnimation,
.cursor_fade_direction = -1.0,
.cursor_animating = true
}
@@ -279,10 +286,9 @@ static int runloop(cairo_surface_t *surface)
// Logo incoming animation
animation_t logo_animation = {
- .completed = false,
+ .type = ALogoAnimation,
.anim.logo_anim = {
- .type = ALogoAnimation,
- .direction = false
+ .direction = IN
}
};
schedule_animation(&state, logo_animation);
diff --git a/src/render.c b/src/render.c
index 34f5550..9f2c1b1 100644
--- a/src/render.c
+++ b/src/render.c
@@ -9,6 +9,7 @@
#include <assert.h>
#include <gio/gio.h>
+#include <math.h>
static const double kLogoBackgroundWidth = 500.0;
@@ -35,7 +36,7 @@ GBytes* get_data_for_resource(const char *resource_path)
static void update_single_animation(saver_state_t *state, animation_t *anim)
{
// Cursor animation
- if (anim->anim.type == ACursorAnimation) {
+ if (anim->type == ACursorAnimation) {
CursorAnimation *ca = &anim->anim.cursor_anim;
if (ca->cursor_animating && !state->is_processing) {
@@ -57,7 +58,7 @@ static void update_single_animation(saver_state_t *state, animation_t *anim)
}
// Logo animation
- else if (anim->anim.type == ALogoAnimation) {
+ else if (anim->type == ALogoAnimation) {
const double logo_duration = 0.6;
anim_time_interval_t now = anim_now();
@@ -79,6 +80,39 @@ static void update_single_animation(saver_state_t *state, animation_t *anim)
anim->completed = completed;
}
+
+ // 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;
+ 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) {
+ 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;
+ }
+ }
+
+ anim->completed = completed;
+ state->background_redshift = progress;
+ }
}
static unsigned next_anim_index(saver_state_t *state, unsigned cur_idx)
@@ -86,7 +120,7 @@ static unsigned next_anim_index(saver_state_t *state, unsigned cur_idx)
unsigned idx = cur_idx + 1;
for (; idx < kMaxAnimations; idx++) {
animation_t anim = state->animations[idx];
- if (anim.anim.type != _EmptyAnimationType) break;
+ if (anim.type != _EmptyAnimationType) break;
}
return idx;
@@ -99,7 +133,7 @@ void schedule_animation(saver_state_t *state, animation_t anim)
// Find next empty element
for (unsigned idx = 0; idx < kMaxAnimations; idx++) {
animation_t check_anim = state->animations[idx];
- if (check_anim.anim.type == _EmptyAnimationType) {
+ if (check_anim.type == _EmptyAnimationType) {
state->animations[idx] = anim;
state->num_animations++;
break;
@@ -117,7 +151,7 @@ void update_animations(saver_state_t *state)
update_single_animation(state, anim);
if (anim->completed) {
- state->animations[idx].anim.type = _EmptyAnimationType;
+ state->animations[idx].type = _EmptyAnimationType;
if (anim->completion_func != NULL) {
anim->completion_func((struct animation_t *)anim, anim->completion_func_context);
}
@@ -133,6 +167,14 @@ void update_animations(saver_state_t *state)
state->num_animations -= completed_animations;
}
+void draw_background(saver_state_t *state)
+{
+ // Draw background
+ cairo_t *cr = state->ctx;
+ cairo_set_source_rgba(cr, (state->background_redshift / 1.5), 0.0, 0.0, 1.0);
+ cairo_paint(cr);
+}
+
void draw_logo(saver_state_t *state)
{
if (state->logo_svg_handle == NULL) {
@@ -252,6 +294,5 @@ void draw_password_field(saver_state_t *state)
cairo_rectangle(cr, field_x, field_y, cursor_offset_x, cursor_height);
}
cairo_fill(cr);
-
}
diff --git a/src/render.h b/src/render.h
index 4520b3e..137470d 100644
--- a/src/render.h
+++ b/src/render.h
@@ -24,6 +24,8 @@ typedef struct {
PangoLayout *pango_layout;
PangoFontDescription *status_font;
+ double background_redshift;
+
RsvgHandle *logo_svg_handle;
double logo_fill_progress;
@@ -55,6 +57,9 @@ void schedule_animation(saver_state_t *state, animation_t anim);
// Update all running animations
void update_animations(saver_state_t *state);
+// Background
+void draw_background(saver_state_t *state);
+
// The purple sidebar
void draw_logo(saver_state_t *state);