Skip to content

Commit

Permalink
Show backend messages similarly to the keyboard layout
Browse files Browse the repository at this point in the history
  • Loading branch information
mgunyho committed Jan 6, 2025
1 parent 7b8ef41 commit eead45d
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 6 deletions.
4 changes: 4 additions & 0 deletions cairo.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
#include <gdk-pixbuf/gdk-pixbuf.h>
#endif

uint32_t color_with_alpha(uint32_t color, uint8_t alpha) {
return (color & 0xFFFFFF00) | alpha;
}

void cairo_set_source_u32(cairo_t *cairo, uint32_t color) {
cairo_set_source_rgba(cairo,
(color >> (3*8) & 0xFF) / 255.0,
Expand Down
1 change: 1 addition & 0 deletions include/cairo.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <gdk-pixbuf/gdk-pixbuf.h>
#endif

uint32_t color_with_alpha(uint32_t color, uint8_t alpha);
void cairo_set_source_u32(cairo_t *cairo, uint32_t color);
cairo_subpixel_order_t to_cairo_subpixel_order(enum wl_output_subpixel subpixel);

Expand Down
11 changes: 11 additions & 0 deletions include/swaylock.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ struct swaylock_password {
char *buffer;
};

struct swaylock_backend_message_list {
size_t num_messages;
size_t max_num_messages;
char **messages;
};

struct swaylock_state {
struct loop *eventloop;
struct loop_timer *input_idle_timer; // timer to reset input state to IDLE
Expand All @@ -90,6 +96,7 @@ struct swaylock_state {
struct wl_list images;
struct swaylock_args args;
struct swaylock_password password;
struct swaylock_backend_message_list backend_message_list; // backend messages displayed in the UI
struct swaylock_xkb xkb;
cairo_surface_t *test_surface;
cairo_t *test_cairo; // used to estimate font/text sizes
Expand Down Expand Up @@ -144,4 +151,8 @@ void initialize_pw_backend(int argc, char **argv);
void run_pw_backend_child(void);
void clear_buffer(char *buf, size_t size);

// Add a message to the list of displayed backend messages. Creates a copy of
// the string, it can be freed after calling this function.
void add_backend_message(struct swaylock_state *state, char *msg);

#endif
31 changes: 28 additions & 3 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1034,9 +1034,24 @@ static void display_in(int fd, short mask, void *data) {
}
}

void add_backend_message(struct swaylock_state *state, char *msg) {
size_t n_max = state->backend_message_list.max_num_messages;
char **messages = state->backend_message_list.messages;
if (state->backend_message_list.num_messages == n_max) {
free(messages[n_max - 1]);
} else {
state->backend_message_list.num_messages += 1;
}
for (int i = n_max - 1; i > 0; i--) {
messages[i] = messages[i - 1];
}
messages[0] = strdup(msg);
}

static void handle_backend_text_message(char *msg) {
//TODO: show message in UI
swaylock_log(LOG_DEBUG, "Received text message from backend: %s", msg);
//TODO: schedule old messages to be hidden after a timeout?
add_backend_message(&state, msg);
damage_state(&state);
}

static void handle_auth_result(bool success) {
Expand Down Expand Up @@ -1067,7 +1082,7 @@ static void comm_in(int fd, short mask, void *data) {
switch(msg_type){
case BACKEND_MESSAGE_TYPE_TEXT:
handle_backend_text_message((char *) comm_data);
//TODO: memory leak; where to free comm_data?
free(comm_data);
break;
case BACKEND_MESSAGE_TYPE_AUTH_RESULT:
handle_auth_result(*(bool *) comm_data);
Expand Down Expand Up @@ -1178,6 +1193,16 @@ int main(int argc, char **argv) {
return EXIT_FAILURE;
}

state.backend_message_list = (struct swaylock_backend_message_list){
.num_messages = 0,
//TODO: make configurable?
.max_num_messages = 4,
};
state.backend_message_list.messages = malloc(state.backend_message_list.max_num_messages * sizeof(char *));
for (size_t i = 0; i < state.backend_message_list.max_num_messages; i++) {
state.backend_message_list.messages[i] = NULL;
}

if (pipe(sigusr_fds) != 0) {
swaylock_log(LOG_ERROR, "Failed to pipe");
return EXIT_FAILURE;
Expand Down
82 changes: 79 additions & 3 deletions render.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ static bool render_frame(struct swaylock_surface *surface) {
int buffer_diameter = (arc_radius + arc_thickness) * 2;
int buffer_width = buffer_diameter;
int buffer_height = buffer_diameter;
double box_padding = 4.0 * surface->scale;

if (text || layout_text) {
cairo_set_antialias(state->test_cairo, CAIRO_ANTIALIAS_BEST);
Expand All @@ -204,7 +205,6 @@ static bool render_frame(struct swaylock_surface *surface) {
if (layout_text) {
cairo_text_extents_t extents;
cairo_font_extents_t fe;
double box_padding = 4.0 * surface->scale;
cairo_text_extents(state->test_cairo, layout_text, &extents);
cairo_font_extents(state->test_cairo, &fe);
buffer_height += fe.height + 2 * box_padding;
Expand All @@ -213,6 +213,25 @@ static bool render_frame(struct swaylock_surface *surface) {
}
}
}
if (state->backend_message_list.num_messages > 0) {
cairo_set_antialias(state->test_cairo, CAIRO_ANTIALIAS_BEST);
configure_font_drawing(state->test_cairo, state, surface->subpixel, arc_radius);

buffer_height += 2 * box_padding;
for (size_t i = 0; i < state->backend_message_list.num_messages; i++) {
cairo_text_extents_t extents;
cairo_font_extents_t fe;
cairo_text_extents(state->test_cairo, state->backend_message_list.messages[i], &extents);
cairo_font_extents(state->test_cairo, &fe);
// NOTE: if the indicator is not shown, this results in
// unnecessarily large buffer_height, that could be checked here
buffer_height += fe.height + 2 * box_padding;
if (buffer_width < extents.width + 2 * box_padding) {
buffer_width = extents.width + 2 * box_padding;
}
}
}

// Ensure buffer size is multiple of buffer scale - required by protocol
buffer_height += surface->scale - (buffer_height % surface->scale);
buffer_width += surface->scale - (buffer_width % surface->scale);
Expand Down Expand Up @@ -260,6 +279,8 @@ static bool render_frame(struct swaylock_surface *surface) {
float type_indicator_border_thickness =
TYPE_INDICATOR_BORDER_THICKNESS * surface->scale;

float layout_text_box_height = 0;

if (draw_indicator) {
// Fill inner circle
cairo_set_line_width(cairo, 0);
Expand Down Expand Up @@ -348,17 +369,17 @@ static bool render_frame(struct swaylock_surface *surface) {
cairo_text_extents_t extents;
cairo_font_extents_t fe;
double x, y;
double box_padding = 4.0 * surface->scale;
cairo_text_extents(cairo, layout_text, &extents);
cairo_font_extents(cairo, &fe);
// upper left coordinates for box
x = (buffer_width / 2) - (extents.width / 2) - box_padding;
y = buffer_diameter;

// background box
layout_text_box_height = fe.height + 2.0 * box_padding;
cairo_rectangle(cairo, x, y,
extents.width + 2.0 * box_padding,
fe.height + 2.0 * box_padding);
layout_text_box_height);
cairo_set_source_u32(cairo, state->args.colors.layout_background);
cairo_fill_preserve(cairo);
// border
Expand All @@ -375,6 +396,61 @@ static bool render_frame(struct swaylock_surface *surface) {
}
}

// display messages from backend
if (state->backend_message_list.num_messages > 0) {
configure_font_drawing(cairo, state, surface->subpixel, arc_radius);
for (size_t i = 0; i < state->backend_message_list.num_messages; i++) {
char *str = state->backend_message_list.messages[i];

cairo_text_extents_t extents;
cairo_font_extents_t fe;
double x, y;

cairo_text_extents(cairo, str, &extents);
cairo_font_extents(cairo, &fe);

// upper left coordinates for box
x = (buffer_width / 2) - (extents.width / 2) - box_padding;
if (draw_indicator) {
y = buffer_diameter + 2 * box_padding;
if (layout_text) {
y += layout_text_box_height;
}
} else {
y = (buffer_diameter / 2) - (fe.height / 2) - box_padding;
}
y += (fe.height + 2 * box_padding) * i;

// background box
cairo_rectangle(cairo, x, y,
extents.width + 2.0 * box_padding,
fe.height + 2.0 * box_padding);
//TODO: make colors customizable
cairo_set_source_u32(cairo,
color_with_alpha(
state->args.colors.layout_background,
(uint8_t) (state->args.colors.layout_background & 0xFF) / (i == 0 ? 1 : 2)));
cairo_fill_preserve(cairo);

// border
cairo_set_source_u32(cairo,
color_with_alpha(
state->args.colors.layout_border,
(uint8_t) (state->args.colors.layout_border & 0xFF) / (i == 0 ? 1 : 2)));
cairo_stroke(cairo);

cairo_move_to(cairo,
x - extents.x_bearing + box_padding,
y + (fe.height - fe.descent) + box_padding);
cairo_set_source_u32(cairo,
color_with_alpha(
state->args.colors.layout_text,
(uint8_t) (state->args.colors.layout_text & 0xFF) / (i == 0 ? 1 : 2)));
cairo_show_text(cairo, str);
cairo_new_sub_path(cairo);
}
}

// Send Wayland requests
wl_subsurface_set_position(surface->subsurface, subsurf_xpos, subsurf_ypos);

Expand Down

0 comments on commit eead45d

Please sign in to comment.