summaryrefslogtreecommitdiff
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c321
1 files changed, 102 insertions, 219 deletions
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);
-}