From c78f8de38f77a65555e3241ede496da603017afd Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 18 Jan 2019 11:14:20 -0800 Subject: Move to meson build system. very cool --- asterisk.svg | 39 ------ build.sh | 5 - buzzsaver.c | 331 ------------------------------------------------- logo.svg | 41 ------ meson.build | 31 +++++ resources/asterisk.svg | 39 ++++++ resources/logo.svg | 41 ++++++ src/main.c | 331 +++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 442 insertions(+), 416 deletions(-) delete mode 100644 asterisk.svg delete mode 100755 build.sh delete mode 100644 buzzsaver.c delete mode 100644 logo.svg create mode 100644 meson.build create mode 100644 resources/asterisk.svg create mode 100644 resources/logo.svg create mode 100644 src/main.c diff --git a/asterisk.svg b/asterisk.svg deleted file mode 100644 index f9ff19a..0000000 --- a/asterisk.svg +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - diff --git a/build.sh b/build.sh deleted file mode 100755 index 33bdbcf..0000000 --- a/build.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -# TODO: Makefile? This will end up in the xsecurelock project anyway... -clang $(pkg-config --libs --cflags x11 cairo librsvg-2.0 pangocairo) -o buzzsaver buzzsaver.c - diff --git a/buzzsaver.c b/buzzsaver.c deleted file mode 100644 index 8f35feb..0000000 --- a/buzzsaver.c +++ /dev/null @@ -1,331 +0,0 @@ -/* - * buzzsaver.c - * - * Created 2019-01-16 by James Magahern - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int __width, __height; -static Window __window = { 0 }; -static Display *__display = NULL; - -static const size_t kMaxPasswordLength = 128; -static const double kLogoBackgroundWidth = 500.0; - -typedef struct { - cairo_t *ctx; - cairo_surface_t *surface; - - PangoLayout *pango_layout; - PangoFontDescription *status_font; - - 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) -{ - __width = event->width; - __height = event->height; - - 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); - - 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; - XEvent e; - - for (;;) { - if (block_for_next_event || XPending(__display)) { - // XNextEvent blocks the caller until an event arrives - XNextEvent(__display, &e); - } else { - return 0; - } - - // TODO: listen for window resize events and resize cairo surface - switch (e.type) { - case ConfigureNotify: - window_changed_size(state, (XConfigureEvent *)&e); - return 1; - case ButtonPress: - return -e.xbutton.button; - case KeyPress: - handle_key_event(state, (XKeyEvent *)&e); - return 1; - default: - fprintf(stderr, "Dropping unhandled XEevent.type = %d.\n", e.type); - } - } - - return 0; -} - -/* - * Scene specific stuff - */ - -void draw_logo(saver_state_t *state) -{ - if (state->logo_svg_handle == NULL) { - GError *error = NULL; - state->logo_svg_handle = rsvg_handle_new_from_file("logo.svg", &error); - if (error != NULL) { - fprintf(stderr, "Error loading logo SVG\n"); - return; - } - } - - cairo_t *cr = state->ctx; - - cairo_save(cr); - cairo_set_source_rgb(cr, (208.0 / 255.0), (69.0 / 255.0), (255.0 / 255.0)); - cairo_rectangle(cr, 0, 0, kLogoBackgroundWidth, __height); - cairo_fill(cr); - - cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); - - // Scale and draw logo - RsvgDimensionData dimensions; - rsvg_handle_get_dimensions(state->logo_svg_handle, &dimensions); - - const double padding = 100.0; - double scale_factor = ((kLogoBackgroundWidth - (padding * 2.0)) / dimensions.width); - 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); -} - -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; - - // 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); -} - -/* - * Main drawing/update routines - */ - -void update(saver_state_t *state) -{ - const double cursor_fade_speed = 0.007; - if (state->cursor_fade_direction > 0) { - state->cursor_opacity += cursor_fade_speed; - if (state->cursor_opacity > 1.0) { - state->cursor_fade_direction *= -1; - } - } else { - state->cursor_opacity -= cursor_fade_speed; - if (state->cursor_opacity <= 0.0) { - state->cursor_fade_direction *= -1; - } - } - - - poll_events(state); -} - -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_logo(state); - draw_password_field(state); -} - -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 }; - for (;;) { - update(&state); - - cairo_push_group(cr); - - draw(&state); - - cairo_pop_group_to_source(cr); - - cairo_paint(cr); - cairo_surface_flush(surface); - - nanosleep(&sleep_time, NULL); - } - - // Cleanup - cairo_destroy(cr); - - return EXIT_SUCCESS; -} - -int main(int argc, char **argv) -{ - __width = 800; - __height = 600; - - __display = XOpenDisplay(NULL); - if (__display == NULL) { - fprintf(stderr, "Error opening display\n"); - exit(1); - } - - Window root_window = DefaultRootWindow(__display); - __window = XCreateSimpleWindow( - __display, // display - root_window, // parent window - 0, 0, // x, y - __width, // width - __height, // height - 0, // border_width - 0, // border - 0 // background - ); - - // Enable key events - XSelectInput(__display, __window, ButtonPressMask | KeyPressMask | StructureNotifyMask); - - // Map window to display - XMapWindow(__display, __window); - - // Create cairo surface - int screen = DefaultScreen(__display); - Visual *visual = DefaultVisual(__display, screen); - cairo_surface_t *surface = cairo_xlib_surface_create( - __display, - __window, - visual, - __width, - __height - ); - - if (surface == NULL) { - fprintf(stderr, "Error creating cairo surface\n"); - exit(1); - } - - // Docs say this must be called whenever the size of the window changes - cairo_xlib_surface_set_size(surface, __width, __height); - - int result = runloop(surface); - - cairo_surface_destroy(surface); - XCloseDisplay(__display); - - return result; -} - diff --git a/logo.svg b/logo.svg deleted file mode 100644 index 27ef712..0000000 --- a/logo.svg +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..0f79608 --- /dev/null +++ b/meson.build @@ -0,0 +1,31 @@ +project('buzzlocker', 'c') + +sources = [ + 'src/main.c' +] + +dependencies = [ + dependency('x11'), + dependency('cairo'), + dependency('librsvg-2.0'), + dependency('pangocairo') +] + +executable('buzzlocker', + sources: sources, + dependencies: dependencies +) + +# Resources +configure_file( + input: 'resources/logo.svg', + output: 'logo.svg', + copy: true +) + +configure_file( + input: 'resources/asterisk.svg', + output: 'asterisk.svg', + copy: true +) + diff --git a/resources/asterisk.svg b/resources/asterisk.svg new file mode 100644 index 0000000..f9ff19a --- /dev/null +++ b/resources/asterisk.svg @@ -0,0 +1,39 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/resources/logo.svg b/resources/logo.svg new file mode 100644 index 0000000..27ef712 --- /dev/null +++ b/resources/logo.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..8f35feb --- /dev/null +++ b/src/main.c @@ -0,0 +1,331 @@ +/* + * buzzsaver.c + * + * Created 2019-01-16 by James Magahern + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int __width, __height; +static Window __window = { 0 }; +static Display *__display = NULL; + +static const size_t kMaxPasswordLength = 128; +static const double kLogoBackgroundWidth = 500.0; + +typedef struct { + cairo_t *ctx; + cairo_surface_t *surface; + + PangoLayout *pango_layout; + PangoFontDescription *status_font; + + 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) +{ + __width = event->width; + __height = event->height; + + 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); + + 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; + XEvent e; + + for (;;) { + if (block_for_next_event || XPending(__display)) { + // XNextEvent blocks the caller until an event arrives + XNextEvent(__display, &e); + } else { + return 0; + } + + // TODO: listen for window resize events and resize cairo surface + switch (e.type) { + case ConfigureNotify: + window_changed_size(state, (XConfigureEvent *)&e); + return 1; + case ButtonPress: + return -e.xbutton.button; + case KeyPress: + handle_key_event(state, (XKeyEvent *)&e); + return 1; + default: + fprintf(stderr, "Dropping unhandled XEevent.type = %d.\n", e.type); + } + } + + return 0; +} + +/* + * Scene specific stuff + */ + +void draw_logo(saver_state_t *state) +{ + if (state->logo_svg_handle == NULL) { + GError *error = NULL; + state->logo_svg_handle = rsvg_handle_new_from_file("logo.svg", &error); + if (error != NULL) { + fprintf(stderr, "Error loading logo SVG\n"); + return; + } + } + + cairo_t *cr = state->ctx; + + cairo_save(cr); + cairo_set_source_rgb(cr, (208.0 / 255.0), (69.0 / 255.0), (255.0 / 255.0)); + cairo_rectangle(cr, 0, 0, kLogoBackgroundWidth, __height); + cairo_fill(cr); + + cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); + + // Scale and draw logo + RsvgDimensionData dimensions; + rsvg_handle_get_dimensions(state->logo_svg_handle, &dimensions); + + const double padding = 100.0; + double scale_factor = ((kLogoBackgroundWidth - (padding * 2.0)) / dimensions.width); + 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); +} + +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; + + // 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); +} + +/* + * Main drawing/update routines + */ + +void update(saver_state_t *state) +{ + const double cursor_fade_speed = 0.007; + if (state->cursor_fade_direction > 0) { + state->cursor_opacity += cursor_fade_speed; + if (state->cursor_opacity > 1.0) { + state->cursor_fade_direction *= -1; + } + } else { + state->cursor_opacity -= cursor_fade_speed; + if (state->cursor_opacity <= 0.0) { + state->cursor_fade_direction *= -1; + } + } + + + poll_events(state); +} + +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_logo(state); + draw_password_field(state); +} + +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 }; + for (;;) { + update(&state); + + cairo_push_group(cr); + + draw(&state); + + cairo_pop_group_to_source(cr); + + cairo_paint(cr); + cairo_surface_flush(surface); + + nanosleep(&sleep_time, NULL); + } + + // Cleanup + cairo_destroy(cr); + + return EXIT_SUCCESS; +} + +int main(int argc, char **argv) +{ + __width = 800; + __height = 600; + + __display = XOpenDisplay(NULL); + if (__display == NULL) { + fprintf(stderr, "Error opening display\n"); + exit(1); + } + + Window root_window = DefaultRootWindow(__display); + __window = XCreateSimpleWindow( + __display, // display + root_window, // parent window + 0, 0, // x, y + __width, // width + __height, // height + 0, // border_width + 0, // border + 0 // background + ); + + // Enable key events + XSelectInput(__display, __window, ButtonPressMask | KeyPressMask | StructureNotifyMask); + + // Map window to display + XMapWindow(__display, __window); + + // Create cairo surface + int screen = DefaultScreen(__display); + Visual *visual = DefaultVisual(__display, screen); + cairo_surface_t *surface = cairo_xlib_surface_create( + __display, + __window, + visual, + __width, + __height + ); + + if (surface == NULL) { + fprintf(stderr, "Error creating cairo surface\n"); + exit(1); + } + + // Docs say this must be called whenever the size of the window changes + cairo_xlib_surface_set_size(surface, __width, __height); + + int result = runloop(surface); + + cairo_surface_destroy(surface); + XCloseDisplay(__display); + + return result; +} + -- cgit v1.2.3