aboutsummaryrefslogtreecommitdiff
path: root/src/render.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/render.c')
-rw-r--r--src/render.c146
1 files changed, 106 insertions, 40 deletions
diff --git a/src/render.c b/src/render.c
index 9f2c1b1..908238e 100644
--- a/src/render.c
+++ b/src/render.c
@@ -33,27 +33,34 @@ GBytes* get_data_for_resource(const char *resource_path)
return result;
}
+void set_password_prompt(saver_state_t *state, const char *prompt)
+{
+ strncpy(state->password_prompt, prompt, kMaxPromptLength - 1);
+}
+
static void update_single_animation(saver_state_t *state, animation_t *anim)
{
// Cursor animation
if (anim->type == ACursorAnimation) {
CursorAnimation *ca = &anim->anim.cursor_anim;
- if (ca->cursor_animating && !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;
+ 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;
+ }
}
} else {
- state->cursor_opacity -= cursor_fade_speed;
- if (state->cursor_opacity <= 0.0) {
- ca->cursor_fade_direction *= -1;
- }
+ state->cursor_opacity = 1.0;
}
- } else {
- state->cursor_opacity = 1.0;
}
}
@@ -113,6 +120,11 @@ static void update_single_animation(saver_state_t *state, animation_t *anim)
anim->completed = completed;
state->background_redshift = progress;
}
+
+ // Spinner animation
+ else if (anim->type == ASpinnerAnimation) {
+ anim->anim.spinner_anim.rotation += 0.07;
+ }
}
static unsigned next_anim_index(saver_state_t *state, unsigned cur_idx)
@@ -126,19 +138,38 @@ static unsigned next_anim_index(saver_state_t *state, unsigned cur_idx)
return idx;
}
-void schedule_animation(saver_state_t *state, animation_t anim)
+animation_key_t schedule_animation(saver_state_t *state, animation_t anim)
{
anim.start_time = anim_now();
// Find next empty element
+ animation_key_t key = 0;
for (unsigned idx = 0; idx < kMaxAnimations; idx++) {
animation_t check_anim = state->animations[idx];
if (check_anim.type == _EmptyAnimationType) {
+ key = idx;
state->animations[idx] = anim;
state->num_animations++;
break;
}
}
+
+ return key;
+}
+
+void remove_animation(saver_state_t *state, animation_key_t key)
+{
+ state->animations[key].type = _EmptyAnimationType;
+}
+
+animation_t* get_animation_for_key(saver_state_t *state, animation_key_t anim_key)
+{
+ animation_t *animation = NULL;
+ if (state->animations[anim_key].type != _EmptyAnimationType) {
+ animation = &state->animations[anim_key];
+ }
+
+ return animation;
}
void update_animations(saver_state_t *state)
@@ -151,7 +182,7 @@ void update_animations(saver_state_t *state)
update_single_animation(state, anim);
if (anim->completed) {
- state->animations[idx].type = _EmptyAnimationType;
+ remove_animation(state, idx);
if (anim->completion_func != NULL) {
anim->completion_func((struct animation_t *)anim, anim->completion_func_context);
}
@@ -167,6 +198,23 @@ void update_animations(saver_state_t *state)
state->num_animations -= completed_animations;
}
+RsvgHandle* load_svg_for_resource_path(const char *resource_path)
+{
+ GError *error = NULL;
+ GBytes *bytes = get_data_for_resource(resource_path);
+ RsvgHandle *handle = NULL;
+
+ gsize size = 0;
+ gconstpointer data = g_bytes_get_data(bytes, &size);
+ handle = rsvg_handle_new_from_data(data, size, &error);
+ g_bytes_unref(bytes);
+ if (error != NULL) {
+ fprintf(stderr, "Error loading SVG at resource path: %s\n", resource_path);
+ }
+
+ return handle;
+}
+
void draw_background(saver_state_t *state)
{
// Draw background
@@ -178,20 +226,9 @@ void draw_background(saver_state_t *state)
void draw_logo(saver_state_t *state)
{
if (state->logo_svg_handle == NULL) {
- GError *error = NULL;
- GBytes *bytes = get_data_for_resource("/resources/logo.svg");
-
- gsize size = 0;
- gconstpointer data = g_bytes_get_data(bytes, &size);
- state->logo_svg_handle = rsvg_handle_new_from_data(data, size, &error);
- g_bytes_unref(bytes);
- if (error != NULL) {
- fprintf(stderr, "Error loading logo SVG\n");
- return;
- }
+ state->logo_svg_handle = load_svg_for_resource_path("/resources/logo.svg");
}
-
cairo_t *cr = state->ctx;
cairo_save(cr);
@@ -230,8 +267,8 @@ void draw_password_field(saver_state_t *state)
// Common color for status and password field
cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, state->password_opacity);
- // Draw status text
- const char *prompt = (state->password_prompt ?: "???");
+ // Measure status text
+ const char *prompt = state->password_prompt;
pango_layout_set_font_description(state->pango_layout, state->status_font);
pango_layout_set_text(state->pango_layout, prompt, -1);
@@ -239,22 +276,50 @@ void draw_password_field(saver_state_t *state)
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);
+ // Measure processing indicator
+ double spinner_width = 0.0;
+ double spinner_scale_factor = 0.0;
+ RsvgDimensionData spinner_dimensions;
+ if (state->is_processing) {
+ if (state->spinner_svg_handle == NULL) {
+ state->spinner_svg_handle = load_svg_for_resource_path("/resources/spinner.svg");
+ }
+
+ rsvg_handle_get_dimensions(state->spinner_svg_handle, &spinner_dimensions);
+ spinner_scale_factor = ((line_height - 5.0) / spinner_dimensions.height);
+ spinner_width = spinner_dimensions.width * spinner_scale_factor;
+
+ // padding
+ spinner_width += 10.0;
+ }
+
+ // Draw status text
+ cairo_move_to(cr, spinner_width + field_x, field_y - line_height - field_padding);
pango_cairo_show_layout(cr, state->pango_layout);
+ // Draw processing indicator
+ if (state->is_processing) {
+ SpinnerAnimation spinner_anim = get_animation_for_key(state, state->spinner_anim_key)->anim.spinner_anim;
+
+ cairo_save(cr);
+
+ cairo_translate(cr, field_x, field_y - line_height - 8.0);
+
+ double tr_amount = (spinner_dimensions.width * spinner_scale_factor) / 2.0;
+ cairo_translate(cr, tr_amount, tr_amount);
+ cairo_rotate(cr, spinner_anim.rotation);
+ cairo_translate(cr, -tr_amount, -tr_amount);
+
+ cairo_scale(cr, spinner_scale_factor, spinner_scale_factor);
+
+ rsvg_handle_render_cairo(state->spinner_svg_handle, cr);
+
+ cairo_restore(cr);
+ }
+
// Draw password asterisks
if (state->asterisk_svg_handle == NULL) {
- GError *error = NULL;
- GBytes *bytes = get_data_for_resource("/resources/asterisk.svg");
-
- gsize size = 0;
- gconstpointer data = g_bytes_get_data(bytes, &size);
- state->asterisk_svg_handle = rsvg_handle_new_from_data(data, size, &error);
- g_bytes_unref(bytes);
- if (error != NULL) {
- fprintf(stderr, "Error loading asterisk SVG\n");
- return;
- }
+ state->asterisk_svg_handle = load_svg_for_resource_path("/resources/asterisk.svg");
}
const double cursor_padding_x = 10.0;
@@ -284,6 +349,7 @@ void draw_password_field(saver_state_t *state)
cairo_set_source(cr, asterisk_pattern);
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));