summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPhil Jones <philj56@gmail.com>2021-11-07 18:12:52 +0000
committerPhil Jones <philj56@gmail.com>2021-11-07 18:12:52 +0000
commit9a0ee7624c19acf7fabb311e6c01c45cc72a1da3 (patch)
treedbbeb78b90d1722678878cd27c5dd0d2b984babe /src
parentae23e86114f559ce6d01a3e2499fc5417dc90d37 (diff)
Initial working build.
Diffstat (limited to 'src')
-rw-r--r--src/egl.c1
-rw-r--r--src/entry.c295
-rw-r--r--src/entry.h24
-rw-r--r--src/greetd.c110
-rw-r--r--src/greetd.h43
-rw-r--r--src/log.c4
-rw-r--r--src/main.c321
-rw-r--r--src/string_vec.c30
-rw-r--r--src/string_vec.h8
9 files changed, 266 insertions, 570 deletions
diff --git a/src/egl.c b/src/egl.c
index 5af2b64..8ae70f2 100644
--- a/src/egl.c
+++ b/src/egl.c
@@ -41,6 +41,7 @@ void egl_create_context(struct egl *egl, struct wl_display *wl_display)
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
EGL_NONE
};
diff --git a/src/entry.c b/src/entry.c
index 95ab308..b08623c 100644
--- a/src/entry.c
+++ b/src/entry.c
@@ -13,14 +13,32 @@
#define TWO_PI 6.283185307179586f
#endif
-static void calculate_font_extents(struct entry *entry, uint32_t scale);
-static void draw_circles(struct entry *entry);
+void entry_preload(void)
+{
+ cairo_surface_t *surface = cairo_image_surface_create(
+ CAIRO_FORMAT_ARGB32,
+ 10,
+ 10
+ );
+ cairo_t *cr = cairo_create(surface);
+
+ PangoContext *context = pango_cairo_create_context(cr);
+ PangoLayout *layout = pango_layout_new(context);
+ pango_layout_set_text(layout, "test", -1);
+ pango_cairo_update_layout(cr, layout);
+ pango_cairo_show_layout(cr, layout);
+ g_object_unref(layout);
+ g_object_unref(context);
+ cairo_destroy(cr);
+ cairo_surface_destroy(surface);
+}
void entry_init(struct entry *entry, uint32_t scale)
{
- entry->dot_radius = entry->font_size >> 3;
/* Calculate the size of the entry from our font and various widths. */
- calculate_font_extents(entry, scale);
+ //calculate_font_extents(entry, scale);
+ entry->text_bounds.width = 500;
+ entry->text_bounds.height = 800;
entry->surface.width = entry->text_bounds.width;
entry->surface.height = entry->text_bounds.height;
@@ -62,82 +80,87 @@ void entry_init(struct entry *entry, uint32_t scale)
int32_t height = entry->surface.height / scale;
/* Draw the outer outline */
- struct color color = entry->border.outline_color;
- cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a);
- cairo_paint(cr);
-
- /* Move and clip following draws to be within this outline */
- cairo_translate(
- cr,
- entry->border.outline_width,
- entry->border.outline_width);
- width -= 2 * entry->border.outline_width;
- height -= 2 * entry->border.outline_width;
- cairo_rectangle(cr, 0, 0, width, height);
- cairo_clip(cr);
-
- /* Draw the border */
- color = entry->border.color;
- cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a);
- cairo_paint(cr);
-
- /* Move and clip following draws to be within the border */
- cairo_translate(cr, entry->border.width, entry->border.width);
- width -= 2 * entry->border.width;
- height -= 2 * entry->border.width;
- cairo_rectangle(cr, 0, 0, width, height);
- cairo_clip(cr);
-
- /* Draw the inner outline */
- color = entry->border.outline_color;
- cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a);
- cairo_paint(cr);
-
- /* Move and clip following draws to be within this outline */
- cairo_translate(
- cr,
- entry->border.outline_width,
- entry->border.outline_width);
- width -= 2 * entry->border.outline_width;
- height -= 2 * entry->border.outline_width;
- cairo_rectangle(cr, 0, 0, width, height);
- cairo_clip(cr);
-
- /* Draw the entry background */
- color = entry->background_color;
- cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a);
- cairo_paint(cr);
-
- /* Move and clip following draws to be within the specified padding */
- cairo_translate(cr, entry->padding, entry->padding);
- width -= 2 * entry->padding;
- height -= 2 * entry->padding;
- cairo_rectangle(cr, 0, 0, width, height);
- cairo_clip(cr);
+ //struct color color = entry->border.outline_color;
+ //cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a);
+ //cairo_paint(cr);
+
+ ///* Move and clip following draws to be within this outline */
+ //cairo_translate(
+ // cr,
+ // entry->border.outline_width,
+ // entry->border.outline_width);
+ //width -= 2 * entry->border.outline_width;
+ //height -= 2 * entry->border.outline_width;
+ //cairo_rectangle(cr, 0, 0, width, height);
+ //cairo_clip(cr);
+
+ ///* Draw the border */
+ //color = entry->border.color;
+ //cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a);
+ //cairo_paint(cr);
+
+ ///* Move and clip following draws to be within the border */
+ //cairo_translate(cr, entry->border.width, entry->border.width);
+ //width -= 2 * entry->border.width;
+ //height -= 2 * entry->border.width;
+ //cairo_rectangle(cr, 0, 0, width, height);
+ //cairo_clip(cr);
+
+ ///* Draw the inner outline */
+ //color = entry->border.outline_color;
+ //cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a);
+ //cairo_paint(cr);
+
+ ///* Move and clip following draws to be within this outline */
+ //cairo_translate(
+ // cr,
+ // entry->border.outline_width,
+ // entry->border.outline_width);
+ //width -= 2 * entry->border.outline_width;
+ //height -= 2 * entry->border.outline_width;
+ //cairo_rectangle(cr, 0, 0, width, height);
+ //cairo_clip(cr);
+
+ ///* Draw the entry background */
+ //color = entry->background_color;
+ //cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a);
+ //cairo_paint(cr);
+
+ ///* Move and clip following draws to be within the specified padding */
+ //cairo_translate(cr, entry->padding, entry->padding);
+ //width -= 2 * entry->padding;
+ //height -= 2 * entry->padding;
+ //cairo_rectangle(cr, 0, 0, width, height);
+ //cairo_clip(cr);
/*
* Move the cursor back up, so that Pango draws in the correct place if
* we're doing a tight layout.
*/
- cairo_translate(cr, -entry->text_bounds.x, -entry->text_bounds.y);
+ //cairo_translate(cr, -entry->text_bounds.x, -entry->text_bounds.y);
/* Setup Pango. */
- if (entry->use_pango) {
- PangoContext *context = pango_cairo_create_context(cr);
- PangoLayout *layout = pango_layout_new(context);
- pango_layout_set_text(layout, "", -1);
+ PangoContext *context = pango_cairo_create_context(cr);
- PangoFontDescription *font_description =
- pango_font_description_from_string(entry->font_name);
- pango_font_description_set_size(
- font_description,
- entry->font_size * PANGO_SCALE);
- pango_layout_set_font_description(layout, font_description);
- pango_font_description_free(font_description);
+ PangoFontDescription *font_description =
+ pango_font_description_from_string(entry->font_name);
+ pango_font_description_set_size(
+ font_description,
+ entry->font_size * PANGO_SCALE);
+ pango_context_set_font_description(context, font_description);
+ pango_font_description_free(font_description);
+
+ entry->pango.entry_layout = pango_layout_new(context);
+ pango_layout_set_text(entry->pango.entry_layout, "", -1);
- entry->pango.context = context;
- entry->pango.layout = layout;
+ for (size_t i = 0; i < 5; i++) {
+ PangoLayout *layout = pango_layout_new(context);
+ pango_layout_set_text(layout, "", -1);
+ entry->pango.result_layouts[i] = layout;
}
+
+ entry->pango.context = context;
+
entry->cairo.surface = surface;
entry->cairo.cr = cr;
@@ -148,10 +171,11 @@ void entry_init(struct entry *entry, uint32_t scale)
void entry_destroy(struct entry *entry)
{
- if (entry->use_pango) {
- g_object_unref(entry->pango.layout);
- g_object_unref(entry->pango.context);
+ for (size_t i = 0; i < 5; i++) {
+ g_object_unref(entry->pango.result_layouts[i]);
}
+ g_object_unref(entry->pango.entry_layout);
+ g_object_unref(entry->pango.context);
cairo_destroy(entry->cairo.cr);
cairo_surface_destroy(entry->cairo.surface);
}
@@ -159,120 +183,41 @@ void entry_destroy(struct entry *entry)
void entry_update(struct entry *entry)
{
cairo_t *cr = entry->cairo.cr;
- PangoLayout *layout = entry->pango.layout;
+ cairo_save(cr);
entry->image.redraw = true;
- /* Redraw the background. */
- struct color color = entry->background_color;
- cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a);
+ /* Clear the image. */
+ cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_paint(cr);
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
/* Draw our text. */
- color = entry->foreground_color;
+ struct color color = entry->foreground_color;
cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a);
- if (!entry->use_pango) {
- draw_circles(entry);
- return;
- }
- size_t len = 0;
- for (unsigned int i = 0; i < entry->password_length; i++) {
- len += wcrtomb(entry->password_mb_print + len, entry->password_character, NULL);
+ pango_layout_set_text(entry->pango.entry_layout, entry->input_mb, -1);
+ pango_cairo_update_layout(cr, entry->pango.entry_layout);
+ pango_cairo_show_layout(cr, entry->pango.entry_layout);
+
+ log_debug("%zu\n", entry->results.count);
+ for (size_t i = 0; i < 5; i++) {
+ cairo_translate(cr, 0, 50);
+ PangoLayout *layout = entry->pango.result_layouts[i];
+ const char *str;
+ if (i < entry->results.count) {
+ str = entry->results.buf[i];
+ } else {
+ str = "";
+ }
+ pango_layout_set_text(layout, str, -1);
+ pango_cairo_update_layout(cr, layout);
+ pango_cairo_show_layout(cr, layout);
}
- entry->password_mb_print[len] = '\0';
- pango_layout_set_text(layout, entry->password_mb_print, -1);
- pango_cairo_update_layout(cr, layout);
- pango_cairo_show_layout(cr, layout);
+ cairo_restore(cr);
}
void entry_set_scale(struct entry *entry, uint32_t scale)
{
cairo_surface_set_device_scale(entry->cairo.surface, scale, scale);
}
-
-void calculate_font_extents(struct entry *entry, uint32_t scale)
-{
- if (!entry->use_pango) {
- /* If we're not using pango, just do a simple calculation. */
- entry->text_bounds.height = 2 * entry->dot_radius;
- entry->text_bounds.width = 3 * entry->num_characters * entry->dot_radius;
- return;
- }
- /*
- * To calculate the size of the password box, we do the following:
- * 1. Load the font we're going to use.
- * 2. Create a string of the desired length using the specified
- * password character, e.g. ".......".
- * 3. Render the string with Pango in some abstract layout.
- * 4. Measure the bounding box of the layout.
- * 5. Add on the size of the border / outline.
- */
- PangoFontMap *font_map = pango_cairo_font_map_get_default();
- PangoContext *context = pango_font_map_create_context(font_map);
-
- PangoFontDescription *font_description =
- pango_font_description_from_string(entry->font_name);
- pango_font_description_set_size(
- font_description,
- entry->font_size * PANGO_SCALE);
- pango_context_set_font_description(context, font_description);
-
-#ifdef DEBUG
- {
- PangoFont *font =
- pango_context_load_font(context, font_description);
- PangoFontDescription *desc = pango_font_describe(font);
- char *string = pango_font_description_to_string(desc);
- log_debug("Using font: %s\n", string);
-
- g_free(string);
- pango_font_description_free(desc);
- g_object_unref(font);
- }
-#endif
- pango_font_description_free(font_description);
-
- PangoLayout *layout = pango_layout_new(context);
- char *buf = calloc(MAX_PASSWORD_LENGTH, 4);
- size_t len = 0;
- for (unsigned int i = 0; i < entry->num_characters; i++) {
- len += wcrtomb(buf + len, entry->password_character, NULL);
- }
- buf[len] = '\0';
- pango_layout_set_text(layout, buf, -1);
- free(buf);
-
- PangoRectangle rect;
- if (entry->tight_layout) {
- pango_layout_get_pixel_extents(layout, &rect, NULL);
- } else {
- pango_layout_get_pixel_extents(layout, NULL, &rect);
- }
- /*
- * TODO: This extra 1px padding is needed for certain fonts, why?
- */
- rect.width += 2;
- rect.height += 2;
- rect.x -= 1;
- rect.y -= 1;
-
- entry->text_bounds = rect;
-
- g_object_unref(layout);
- g_object_unref(context);
-}
-
-void draw_circles(struct entry *entry)
-{
- cairo_t *cr = entry->cairo.cr;
- uint32_t radius = entry->dot_radius;
- cairo_save(cr);
- cairo_translate(cr, radius, radius);
- for (uint32_t i = 0; i < entry->password_length && i < entry->num_characters; i++) {
- /* Draw circles with a one-radius gap between them. */
- cairo_arc(cr, 3 * i * radius, 0, radius, 0, TWO_PI);
- }
- cairo_fill(cr);
- cairo_restore(cr);
-}
diff --git a/src/entry.h b/src/entry.h
index b0e9542..6da7222 100644
--- a/src/entry.h
+++ b/src/entry.h
@@ -5,8 +5,9 @@
#include "color.h"
#include "image.h"
#include "surface.h"
+#include "string_vec.h"
-#define MAX_PASSWORD_LENGTH 64
+#define MAX_INPUT_LENGTH 64
struct entry {
struct surface surface;
@@ -14,7 +15,8 @@ struct entry {
struct image image;
struct {
PangoContext *context;
- PangoLayout *layout;
+ PangoLayout *entry_layout;
+ PangoLayout *result_layouts[5];
} pango;
struct {
cairo_surface_t *surface;
@@ -22,22 +24,21 @@ struct entry {
} cairo;
PangoRectangle text_bounds;
- wchar_t password[MAX_PASSWORD_LENGTH];
+ wchar_t input[MAX_INPUT_LENGTH];
/* Assume maximum of 4 bytes per wchar_t (for UTF-8) */
- char password_mb[4*MAX_PASSWORD_LENGTH];
- char password_mb_print[4*MAX_PASSWORD_LENGTH];
- uint32_t password_length;
- bool password_visible;
+ char input_mb[4*MAX_INPUT_LENGTH];
+ uint32_t input_length;
+ uint32_t input_mb_length;
+
+ struct string_vec results;
+ struct string_vec commands;
/* Options */
- bool use_pango;
- uint32_t dot_radius;
uint32_t font_size;
const char *font_name;
uint32_t padding;
- bool tight_layout;
- wchar_t password_character;
uint32_t num_characters;
+ uint32_t num_lines;
struct color foreground_color;
struct color background_color;
struct {
@@ -48,6 +49,7 @@ struct entry {
} border;
};
+void entry_preload(void);
void entry_init(struct entry *entry, uint32_t scale);
void entry_destroy(struct entry *entry);
void entry_update(struct entry *entry);
diff --git a/src/greetd.c b/src/greetd.c
deleted file mode 100644
index eb356af..0000000
--- a/src/greetd.c
+++ /dev/null
@@ -1,110 +0,0 @@
-#include "greetd.h"
-#include "ipc.h"
-#include <json-c/json_object.h>
-#include <string.h>
-
-struct json_object *greetd_create_session(const char *username)
-{
- struct json_object *request = json_object_new_object();
-
- struct json_object *type = json_object_new_string("create_session");
- json_object_object_add(request, "type", type);
-
- struct json_object *name = json_object_new_string(username);
- json_object_object_add(request, "username", name);
-
- struct json_object *resp = ipc_submit(request);
- json_object_put(request);
- return resp;
-}
-
-struct json_object *greetd_post_auth_message_response(const char *response)
-{
- struct json_object *request = json_object_new_object();
-
- struct json_object *type = json_object_new_string("post_auth_message_response");
- json_object_object_add(request, "type", type);
-
- if (response != NULL) {
- struct json_object *resp = json_object_new_string(response);
- json_object_object_add(request, "response", resp);
- }
-
- struct json_object *resp = ipc_submit(request);
- json_object_put(request);
- return resp;
-}
-
-struct json_object *greetd_start_session(const char *command)
-{
- struct json_object *request = json_object_new_object();
-
- struct json_object *type = json_object_new_string("start_session");
- json_object_object_add(request, "type", type);
-
- struct json_object *arr = json_object_new_array_ext(1);
- struct json_object *cmd = json_object_new_string(command);
- json_object_array_add(arr, cmd);
- json_object_object_add(request, "cmd", arr);
-
- struct json_object *resp = ipc_submit(request);
- json_object_put(request);
- return resp;
-}
-
-struct json_object *greetd_cancel_session(void)
-{
- struct json_object *request = json_object_new_object();
-
- struct json_object *type = json_object_new_string("cancel_session");
- json_object_object_add(request, "type", type);
-
- struct json_object *resp = ipc_submit(request);
- json_object_put(request);
- return resp;
-}
-
-enum greetd_response_type greetd_parse_response_type(struct json_object *response)
-{
- const char *str = json_object_get_string(json_object_object_get(response, "type"));
- if (!strcmp(str, "success")) {
- return GREETD_RESPONSE_SUCCESS;
- }
- if (!strcmp(str, "error")) {
- return GREETD_RESPONSE_ERROR;
- }
- if (!strcmp(str, "auth_message")) {
- return GREETD_RESPONSE_AUTH_MESSAGE;
- }
- return GREETD_RESPONSE_INVALID;
-}
-
-enum greetd_auth_message_type greetd_parse_auth_message_type(struct json_object *response)
-{
- const char *str = json_object_get_string(json_object_object_get(response, "auth_message_type"));
- if (!strcmp(str, "visible")) {
- return GREETD_AUTH_MESSAGE_VISIBLE;
- }
- if (!strcmp(str, "secret")) {
- return GREETD_AUTH_MESSAGE_SECRET;
- }
- if (!strcmp(str, "info")) {
- return GREETD_AUTH_MESSAGE_INFO;
- }
- if (!strcmp(str, "error")) {
- return GREETD_AUTH_MESSAGE_ERROR;
- }
- return GREETD_AUTH_MESSAGE_INVALID;
-}
-
-enum greetd_error_type greetd_parse_error_type(struct json_object *response)
-{
- const char *str = json_object_get_string(json_object_object_get(response, "error_type"));
- if (!strcmp(str, "auth_error")) {
- return GREETD_ERROR_AUTH_ERROR;
- }
- if (!strcmp(str, "error")) {
- return GREETD_ERROR_ERROR;
- }
- return GREETD_ERROR_INVALID;
-}
diff --git a/src/greetd.h b/src/greetd.h
deleted file mode 100644
index 3901d85..0000000
--- a/src/greetd.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef GREETD_H
-#define GREETD_H
-
-#include <json-c/json_object.h>
-
-enum greetd_request_type {
- GREETD_REQUEST_CREATE_SESSION,
- GREETD_REQUEST_POST_AUTH_MESSAGE_RESPONSE,
- GREETD_REQUEST_START_SESSION,
- GREETD_REQUEST_CANCEL_SESSION
-};
-
-enum greetd_response_type {
- GREETD_RESPONSE_INVALID,
- GREETD_RESPONSE_SUCCESS,
- GREETD_RESPONSE_ERROR,
- GREETD_RESPONSE_AUTH_MESSAGE
-};
-
-enum greetd_auth_message_type {
- GREETD_AUTH_MESSAGE_INVALID,
- GREETD_AUTH_MESSAGE_VISIBLE,
- GREETD_AUTH_MESSAGE_SECRET,
- GREETD_AUTH_MESSAGE_INFO,
- GREETD_AUTH_MESSAGE_ERROR
-};
-
-enum greetd_error_type {
- GREETD_ERROR_INVALID,
- GREETD_ERROR_AUTH_ERROR,
- GREETD_ERROR_ERROR
-};
-
-[[nodiscard]] struct json_object *greetd_create_session(const char *username);
-[[nodiscard]] struct json_object *greetd_post_auth_message_response(const char *response);
-[[nodiscard]] struct json_object *greetd_start_session(const char *command);
-[[nodiscard]] struct json_object *greetd_cancel_session(void);
-
-enum greetd_response_type greetd_parse_response_type(struct json_object *response);
-enum greetd_auth_message_type greetd_parse_auth_message_type(struct json_object *response);
-enum greetd_error_type greetd_parse_error_type(struct json_object *response);
-
-#endif /* GREETD_H */
diff --git a/src/log.c b/src/log.c
index f7138c5..a6c9a75 100644
--- a/src/log.c
+++ b/src/log.c
@@ -59,8 +59,8 @@ void log_info(const char *const fmt, ...)
{
va_list args;
va_start(args, fmt);
- printf("[INFO]: ");
- vprintf(fmt, args);
+ fprintf(stderr, "[INFO]: ");
+ vfprintf(stderr, fmt, args);
va_end(args);
}
diff --git a/src/main.c b/src/main.c
index a1c873c..89abe47 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3,25 +3,25 @@
#include <epoxy/gl.h>
#include <errno.h>
#include <getopt.h>
+#include <locale.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
+#include <threads.h>
#include <unistd.h>
#include <wayland-client.h>
-#include <wctype.h>
#include <wchar.h>
-#include <xkbcommon/xkbcommon.h>
+#include <wctype.h>
#include <xdg-shell.h>
-#include <locale.h>
+#include <xkbcommon/xkbcommon.h>
#include "client.h"
#include "compgen.h"
#include "egl.h"
#include "entry.h"
#include "image.h"
#include "gl.h"
-#include "greetd.h"
#include "log.h"
#include "nelem.h"
#include "string_vec.h"
@@ -30,16 +30,6 @@
#define MAX(a, b) ((a) > (b) ? (a) : (b))
-static void handle_response(
- struct client_state *state,
- struct json_object *response,
- enum greetd_request_type request);
-static void create_session(struct client_state *state);
-static void start_session(struct client_state *state);
-static void post_auth_message_response(struct client_state *state);
-static void cancel_session(struct client_state *state);
-static void restart_session(struct client_state *state);
-
static void resize(struct client_state *state)
{
struct surface *surface = &state->window.surface;
@@ -66,7 +56,7 @@ static void resize(struct client_state *state)
state->window.surface.redraw = true;
/*
- * Center the password entry.
+ * Center the entry.
* Wayland wants "surface-local" width / height, so we have to divide
* the entry's pixel size by the scale factor.
*/
@@ -185,57 +175,66 @@ static void wl_keyboard_key(
uint32_t state)
{
struct client_state *client_state = data;
- char buf[128];
uint32_t keycode = key + 8;
xkb_keysym_t sym = xkb_state_key_get_one_sym(
client_state->xkb_state,
keycode);
- xkb_keysym_get_name(sym, buf, sizeof(buf));
- if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
- struct entry *entry = &client_state->window.entry;
- int len = xkb_state_key_get_utf8(
- client_state->xkb_state,
- keycode,
- buf,
- sizeof(buf));
- wchar_t ch;
- mbtowc(&ch, buf, sizeof(buf));
- if (len > 0 && iswprint(ch)) {
- if (entry->password_length < N_ELEM(entry->password) - 1) {
- entry->password[entry->password_length] = ch;
- entry->password_length++;
- entry->password[entry->password_length] = L'\0';
- }
- } else if (entry->password_length > 0 && sym == XKB_KEY_BackSpace) {
- entry->password[entry->password_length - 1] = '\0';
- entry->password_length--;
- } else if (sym == XKB_KEY_Escape
- || (sym == XKB_KEY_c
- && xkb_state_mod_name_is_active(
- client_state->xkb_state,
- XKB_MOD_NAME_CTRL,
- XKB_STATE_MODS_EFFECTIVE)
- )
- )
- {
- entry->password[0] = '\0';
- entry->password_length = 0;
- } else if (entry->password_length > 0
- && (sym == XKB_KEY_Return
- || sym == XKB_KEY_KP_Enter)) {
- const wchar_t *src = entry->password;
- wcsrtombs(
- entry->password_mb,
- &src,
- N_ELEM(entry->password_mb),
- NULL);
- entry->password[0] = '\0';
- entry->password_length = 0;
- client_state->submit = true;
+ if (state != WL_KEYBOARD_KEY_STATE_PRESSED) {
+ return;
+ }
+
+ struct entry *entry = &client_state->window.entry;
+ char buf[5]; /* 4 UTF-8 bytes plus null terminator. */
+ int len = xkb_state_key_get_utf8(
+ client_state->xkb_state,
+ keycode,
+ buf,
+ sizeof(buf));
+ wchar_t ch;
+ mbtowc(&ch, buf, sizeof(buf));
+ if (len > 0 && iswprint(ch)) {
+ if (entry->input_length < N_ELEM(entry->input) - 1) {
+ entry->input[entry->input_length] = ch;
+ entry->input_length++;
+ entry->input[entry->input_length] = L'\0';
+ memcpy(&entry->input_mb[entry->input_mb_length],
+ buf,
+ N_ELEM(buf));
+ entry->input_mb_length += len;
+ struct string_vec tmp = entry->results;
+ entry->results = string_vec_filter(&entry->results, entry->input_mb);
+ string_vec_destroy(&tmp);
}
- entry_update(&client_state->window.entry);
- client_state->window.entry.surface.redraw = true;
+ } else if (entry->input_length > 0 && sym == XKB_KEY_BackSpace) {
+ entry->input_length--;
+ entry->input[entry->input_length] = L'\0';
+ const wchar_t *src = entry->input;
+ size_t siz = wcsrtombs(
+ entry->input_mb,
+ &src,
+ N_ELEM(entry->input_mb),
+ NULL);
+ entry->input_mb_length = siz;
+ string_vec_destroy(&entry->results);
+ entry->results = string_vec_filter(&entry->commands, entry->input_mb);
+ } else if (sym == XKB_KEY_Escape
+ || (sym == XKB_KEY_c
+ && xkb_state_mod_name_is_active(
+ client_state->xkb_state,
+ XKB_MOD_NAME_CTRL,
+ XKB_STATE_MODS_EFFECTIVE)
+ )
+ )
+ {
+ client_state->closed = true;
+ } else if (entry->input_length > 0
+ && (sym == XKB_KEY_Return || sym == XKB_KEY_KP_Enter)) {
+ client_state->submit = true;
+ return;
}
+ entry_update(&client_state->window.entry);
+ client_state->window.entry.surface.redraw = true;
+
}
static void wl_keyboard_modifiers(
@@ -577,10 +576,16 @@ static const struct wl_surface_listener wl_surface_listener = {
.leave = surface_leave
};
+static int initialise_entry(void *data)
+{
+ entry_preload();
+ return 0;
+}
+
static void usage()
{
fprintf(stderr,
-"Usage: greetd-mini-wl-greeter -u username -c command [options]\n"
+"Usage: tofi [options]\n"
" -u, --user=NAME The user to login as.\n"
" -c, --command=COMMAND The command to run on login.\n"
" -b, --background-image=PATH An image to use as the background.\n"
@@ -589,14 +594,12 @@ static void usage()
" -O, --outline-color=COLOR Color of the border outlines.\n"
" -r, --border-width=VALUE Width of the border in pixels.\n"
" -R, --border-color=COLOR Color of the border.\n"
-" -e, --entry-padding=VALUE Padding around the password text in pixels.\n"
-" -E, --entry-color=COLOR Color of the password entry box.\n"
-" -f, --font-name=NAME Font to use for the password entry.\n"
-" -F, --font-size=VALUE Point size of the password text.\n"
-" -T, --text-color=COLOR Color of the password text.\n"
-" -C, --password-character=CHAR Character to use to hide the password.\n"
-" -n, --width-characters=VALUE Width of the password entry box in characters.\n"
-" -w, --wide-layout Make the password entry box full height.\n"
+" -e, --entry-padding=VALUE Padding around the entry box in pixels.\n"
+" -E, --entry-color=COLOR Color of the entry box.\n"
+" -f, --font-name=NAME Font to use.\n"
+" -F, --font-size=VALUE Point size of text.\n"
+" -T, --text-color=COLOR Color of text.\n"
+" -n, --width-characters=VALUE Width of the entry box in characters.\n"
" -H, --hide-cursor Hide the cursor.\n"
" -h, --help Print this message and exit.\n"
);
@@ -604,6 +607,9 @@ static void usage()
int main(int argc, char *argv[])
{
+ thrd_t entry_thread;
+ thrd_create(&entry_thread, initialise_entry, NULL);
+
/*
* Set the locale to the user's default, so we can deal with non-ASCII
* characters.
@@ -630,8 +636,6 @@ int main(int argc, char *argv[])
.font_name = "Sans Bold",
.font_size = 24,
.padding = 8,
- .tight_layout = true,
- .password_character = '.',
.num_characters = 12,
.background_color = {0.106, 0.114, 0.118, 1.0},
.foreground_color = {1.0, 1.0, 1.0, 1.0}
@@ -639,6 +643,9 @@ int main(int argc, char *argv[])
}
};
+ state.window.entry.commands = compgen();
+ state.window.entry.results = string_vec_copy(&state.window.entry.commands);
+
/* Option parsing with getopt. */
struct option long_options[] = {
@@ -653,16 +660,14 @@ int main(int argc, char *argv[])
{"text-color", required_argument, NULL, 'T'},
{"font-name", required_argument, NULL, 'f'},
{"font-size", required_argument, NULL, 'F'},
- {"password-character", required_argument, NULL, 'C'},
{"command", required_argument, NULL, 'c'},
{"user", required_argument, NULL, 'u'},
{"width-characters", required_argument, NULL, 'n'},
- {"wide-layout", no_argument, NULL, 'w'},
{"hide-cursor", no_argument, NULL, 'H'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
- const char *short_options = ":b:B:c:C:e:E:f:F:hHr:R:n:o:O:T:u:w";
+ const char *short_options = ":b:B:c:e:E:f:F:hHr:R:n:o:O:T:u:";
int opt = getopt_long(argc, argv, short_options, long_options, NULL);
while (opt != -1) {
@@ -706,20 +711,11 @@ int main(int argc, char *argv[])
break;
case 'f':
state.window.entry.font_name = optarg;
- state.window.entry.use_pango = true;
break;
case 'F':
state.window.entry.font_size =
strtol(optarg, NULL, 0);
break;
- case 'C':
- mbrtowc(
- &state.window.entry.password_character,
- optarg,
- 4,
- NULL);
- state.window.entry.use_pango = true;
- break;
case 'c':
state.command = optarg;
break;
@@ -730,10 +726,6 @@ int main(int argc, char *argv[])
state.window.entry.num_characters =
strtol(optarg, NULL, 0);
break;
- case 'w':
- state.window.entry.tight_layout = false;
- state.window.entry.use_pango = true;
- break;
case 'H':
state.hide_cursor = true;
break;
@@ -809,7 +801,7 @@ int main(int argc, char *argv[])
/*
* Next, we create the Wayland surfaces that we need - one for
- * the whole window, and another for the password entry box.
+ * the whole window, and another for the entry box.
*/
/*
* The main window surface takes on the xdg_surface and xdg_toplevel
@@ -847,11 +839,11 @@ int main(int argc, char *argv[])
wl_surface_commit(state.window.surface.wl_surface);
/*
- * The password entry surface takes on a subsurface role and is set to
- * be desynchronised, so that we can update it independently from the
- * main window.
+ * The entry surface takes on a subsurface role and is set to be
+ * desynchronised, so that we can update it independently from the main
+ * window.
*/
- log_debug("Creating password entry surface.\n");
+ log_debug("Creating entry surface.\n");
state.window.entry.surface.wl_surface =
wl_compositor_create_surface(state.wl_compositor);
wl_surface_set_buffer_scale(
@@ -867,22 +859,19 @@ int main(int argc, char *argv[])
wl_surface_commit(state.window.entry.surface.wl_surface);
/*
- * Initialise the Pango & Cairo structures for rendering the password
- * entry. Cairo needs to know the size of the surface it's creating,
- * and there's no way to resize it aside from tearing everything down
- * and starting again, so we make sure to do this after we've
- * determined our output's scale factor. This stops us being able to
- * change the scale factor after startup, but this is just a greeter,
- * which shouldn't be moving between outputs while running.
+ * Initialise the Pango & Cairo structures for rendering the entry.
+ * Cairo needs to know the size of the surface it's creating, and
+ * there's no way to resize it aside from tearing everything down and
+ * starting again, so we make sure to do this after we've determined
+ * our output's scale factor. This stops us being able to change the
+ * scale factor after startup, but this is just a launcher, which
+ * shouldn't be moving between outputs while running.
*/
log_debug("Initialising Pango / Cairo.\n");
entry_init(&state.window.entry, state.window.scale);
log_debug("Pango / Cairo initialised.\n");
- /*
- * Tell the compositor not to make our window smaller than the password
- * entry.
- */
+ /* Tell the compositor not to make our window smaller than the entry. */
xdg_toplevel_set_min_size(
state.window.xdg_toplevel,
state.window.entry.surface.width / state.window.scale,
@@ -916,12 +905,17 @@ int main(int argc, char *argv[])
&state.window.entry.surface,
state.wl_display,
&state.window.entry.image);
+
+ log_debug("Rejoining thread\n");
+ thrd_join(entry_thread, NULL);
+ log_debug("Initial draw\n");
+ entry_update(&state.window.entry);
surface_draw(
&state.window.entry.surface,
&state.window.background_color,
&state.window.entry.image);
- /* Call resize() just to center the password entry properly. */
+ /* Call resize() just to center the entry properly. */
resize(&state);
/*
@@ -932,9 +926,6 @@ int main(int argc, char *argv[])
state.window.surface.redraw = false;
state.window.entry.surface.redraw = false;
- /* Create the greetd session. */
- create_session(&state);
-
while (wl_display_dispatch(state.wl_display) != -1) {
if (state.closed) {
break;
@@ -958,8 +949,10 @@ int main(int argc, char *argv[])
state.window.entry.surface.redraw = false;
}
if (state.submit) {
- post_auth_message_response(&state);
- state.submit = false;
+ if (state.window.entry.results.count > 0) {
+ printf("%s\n", state.window.entry.results.buf[0]);
+ }
+ break;
}
}
@@ -1007,113 +1000,3 @@ int main(int argc, char *argv[])
log_debug("Finished, exiting.\n");
return EXIT_SUCCESS;
}
-
-void handle_response(
- struct client_state *state,
- struct json_object *response,
- enum greetd_request_type request)
-{
- if (response == NULL) {
- return;
- }
- enum greetd_response_type type = greetd_parse_response_type(response);
-
- switch (type) {
- case GREETD_RESPONSE_SUCCESS:
- switch (request) {
- case GREETD_REQUEST_CREATE_SESSION:
- case GREETD_REQUEST_POST_AUTH_MESSAGE_RESPONSE:
- start_session(state);
- break;
- case GREETD_REQUEST_START_SESSION:
- state->closed = true;
- break;
- case GREETD_REQUEST_CANCEL_SESSION:
- break;
- }
- break;
- case GREETD_RESPONSE_ERROR:
- switch (request) {
- case GREETD_REQUEST_POST_AUTH_MESSAGE_RESPONSE:
- case GREETD_REQUEST_START_SESSION:
- log_error(
- "Failed to create greetd session: %s\n",
- json_object_get_string(
- json_object_object_get(
- response,
- "description")
- )
- );
- restart_session(state);
- break;
- case GREETD_REQUEST_CREATE_SESSION:
- log_error("Failed to connect to greetd session.\n");
- break;
- case GREETD_REQUEST_CANCEL_SESSION:
- break;
- }
- break;
- case GREETD_RESPONSE_AUTH_MESSAGE:
- switch (greetd_parse_auth_message_type(response)) {
- case GREETD_AUTH_MESSAGE_VISIBLE:
- state->window.entry.password_visible = true;
- break;
- case GREETD_AUTH_MESSAGE_SECRET:
- state->window.entry.password_visible = false;
- break;
- case GREETD_AUTH_MESSAGE_INFO:
- case GREETD_AUTH_MESSAGE_ERROR:
- /* TODO */
- restart_session(state);
- break;
- case GREETD_AUTH_MESSAGE_INVALID:
- break;
- }
- break;
- case GREETD_RESPONSE_INVALID:
- break;
- }
- json_object_put(response);
-}
-
-void create_session(struct client_state *state)
-{
- log_debug("Creating greetd session for user '%s'.\n", state->username);
- handle_response(
- state,
- greetd_create_session(state->username),
- GREETD_REQUEST_CREATE_SESSION);
-}
-
-void start_session(struct client_state *state)
-{
- log_debug("Starting session with command '%s'.\n", state->command);
- handle_response(
- state,
- greetd_start_session(state->command),
- GREETD_REQUEST_START_SESSION);
-}
-
-void post_auth_message_response(struct client_state *state)
-{
- log_debug("Posting auth message response.\n");
- handle_response(
- state,
- greetd_post_auth_message_response(state->window.entry.password_mb),
- GREETD_REQUEST_POST_AUTH_MESSAGE_RESPONSE);
-}
-
-void cancel_session(struct client_state *state)
-{
- log_debug("Cancelling session.\n");
- handle_response(
- state,
- greetd_cancel_session(),
- GREETD_REQUEST_CANCEL_SESSION);
-}
-
-void restart_session(struct client_state *state)
-{
- cancel_session(state);
- create_session(state);
-}
diff --git a/src/string_vec.c b/src/string_vec.c
index 94f41fa..f747339 100644
--- a/src/string_vec.c
+++ b/src/string_vec.c
@@ -1,15 +1,16 @@
+#define _GNU_SOURCE
#include <stdlib.h>
#include <string.h>
#include "string_vec.h"
-static int cmpstringp(const void *a, const void *b)
+static int cmpstringp(const void *restrict a, const void *restrict b)
{
/*
* We receive pointers to the array elements (which are pointers to
* char), so convert and dereference them for comparison.
*/
- const char *str1 = *(const char **)a;
- const char *str2 = *(const char **)b;
+ const char *restrict str1 = *(const char **)a;
+ const char *restrict str2 = *(const char **)b;
/*
* Ensure any NULL strings are shoved to the end.
@@ -20,10 +21,10 @@ static int cmpstringp(const void *a, const void *b)
if (str2 == NULL) {
return -1;
}
- return strcmp(str1, str2);
+ return strcasecmp(str1, str2);
}
-struct string_vec string_vec_create()
+struct string_vec string_vec_create(void)
{
struct string_vec vec = {
.count = 0,
@@ -41,6 +42,21 @@ void string_vec_destroy(struct string_vec *restrict vec)
free(vec->buf);
}
+struct string_vec string_vec_copy(struct string_vec *restrict vec)
+{
+ struct string_vec copy = {
+ .count = vec->count,
+ .size = vec->size,
+ .buf = calloc(vec->size, sizeof(char *))
+ };
+
+ for (size_t i = 0; i < vec->count; i++) {
+ copy.buf[i] = strdup(vec->buf[i]);
+ }
+
+ return copy;
+}
+
void string_vec_add(struct string_vec *restrict vec, const char *restrict str)
{
if (vec->count == vec->size) {
@@ -71,12 +87,12 @@ void string_vec_uniq(struct string_vec *restrict vec)
}
struct string_vec string_vec_filter(
- struct string_vec *restrict vec,
+ const struct string_vec *restrict vec,
const char *restrict substr)
{
struct string_vec filt = string_vec_create();
for (size_t i = 0; i < vec->count; i++) {
- if (strstr(vec->buf[i], substr) != NULL) {
+ if (strcasestr(vec->buf[i], substr) != NULL) {
string_vec_add(&filt, vec->buf[i]);
}
}
diff --git a/src/string_vec.h b/src/string_vec.h
index 0054c09..b3395ad 100644
--- a/src/string_vec.h
+++ b/src/string_vec.h
@@ -10,19 +10,21 @@ struct string_vec {
};
[[nodiscard]]
-struct string_vec string_vec_create();
+struct string_vec string_vec_create(void);
void string_vec_destroy(struct string_vec *restrict vec);
+struct string_vec string_vec_copy(struct string_vec *restrict vec);
+
void string_vec_add(struct string_vec *restrict vec, const char *restrict str);
void string_vec_sort(struct string_vec *restrict vec);
void string_vec_uniq(struct string_vec *restrict vec);
-[[nodiscard]] [[gnu::nonnull]]
+[[nodiscard]]
struct string_vec string_vec_filter(
- struct string_vec *restrict vec,
+ const struct string_vec *restrict vec,
const char *restrict substr);
#endif /* STRING_VEC_H */