summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--meson.build6
-rw-r--r--src/client.h33
-rw-r--r--src/entry.c126
-rw-r--r--src/entry.h33
-rw-r--r--src/gl.c43
-rw-r--r--src/gl.h9
-rw-r--r--src/main.c85
-rw-r--r--src/nelem.h13
-rw-r--r--src/surface.c34
-rw-r--r--src/surface.h21
-rw-r--r--src/util.h22
11 files changed, 320 insertions, 105 deletions
diff --git a/meson.build b/meson.build
index 7f1439e..a8f7cfb 100644
--- a/meson.build
+++ b/meson.build
@@ -47,13 +47,17 @@ sources = files(
'src/main.c',
'src/background.c',
'src/egl.c',
+ 'src/entry.c',
'src/gl.c',
'src/log.c',
+ 'src/surface.c',
'src/xdg-shell-protocol.c',
)
cc = meson.get_compiler('c')
epoxy = dependency('epoxy')
+glib = dependency('glib-2.0')
+pangocairo = dependency('pangocairo')
png = dependency('libpng')
wayland_client = dependency('wayland-client')
wayland_egl = dependency('wayland-egl')
@@ -62,7 +66,7 @@ xkbcommon = dependency('xkbcommon')
executable(
'greetd-mini-wl-greeter',
sources,
- dependencies: [epoxy, png, wayland_client, wayland_egl, xkbcommon],
+ dependencies: [epoxy, glib, pangocairo, png, wayland_client, wayland_egl, xkbcommon],
install: true
)
diff --git a/src/client.h b/src/client.h
index 4814fdb..934d4d3 100644
--- a/src/client.h
+++ b/src/client.h
@@ -3,30 +3,9 @@
#include <stdbool.h>
#include <stdint.h>
-#include "egl.h"
-#include "gl.h"
-
-struct surface {
- struct egl egl;
- struct gl gl;
- struct wl_surface *wl_surface;
- int32_t width;
- int32_t height;
- bool redraw;
-};
-
-struct image {
- uint8_t *buffer;
- uint32_t width;
- uint32_t height;
-};
-
-struct color {
- float r;
- float g;
- float b;
- float a;
-};
+#include "entry.h"
+#include "surface.h"
+#include "util.h"
struct client_state {
/* Globals */
@@ -57,11 +36,7 @@ struct client_state {
struct xdg_toplevel *xdg_toplevel;
struct image background_image;
struct color background_color;
- struct {
- struct surface surface;
- struct wl_subsurface *wl_subsurface;
- struct image image;
- } entry;
+ struct entry entry;
uint32_t scale;
} window;
diff --git a/src/entry.c b/src/entry.c
new file mode 100644
index 0000000..61b0211
--- /dev/null
+++ b/src/entry.c
@@ -0,0 +1,126 @@
+#include <arpa/inet.h>
+#include <cairo/cairo.h>
+#include <glib.h>
+#include <pango/pangocairo.h>
+#include <pango/pango.h>
+#include <wchar.h>
+#include "client.h"
+#include "entry.h"
+#include "log.h"
+#include "nelem.h"
+
+static void calculate_font_extents(struct entry *entry);
+
+void entry_init(struct entry *entry)
+{
+ calculate_font_extents(entry);
+
+ /*
+ * Cairo uses native 32 bit integers for pixels, so if this computer is
+ * little endian we have to tell OpenGL to swizzle the texture.
+ */
+ if (htonl(0xFFu) != 0xFFu) {
+ entry->image.swizzle = true;
+ }
+
+ cairo_surface_t *surface = cairo_image_surface_create(
+ CAIRO_FORMAT_ARGB32,
+ entry->surface.width,
+ entry->surface.height
+ );
+ cairo_t *cr = cairo_create(surface);
+ cairo_set_source_rgb(cr, 0.031, 0.031, 0);
+ cairo_paint(cr);
+
+ cairo_translate(cr, entry->border.outline_width, entry->border.outline_width);
+ cairo_rectangle(cr,
+ 0,
+ 0,
+ entry->surface.width - 2*entry->border.outline_width,
+ entry->surface.height - 2*entry->border.outline_width
+ );
+ cairo_clip(cr);
+ cairo_set_source_rgb(cr, 0.976, 0.149, 0.447);
+ cairo_paint(cr);
+
+ cairo_translate(cr, entry->border.width, entry->border.width);
+ cairo_rectangle(cr,
+ 0,
+ 0,
+ entry->surface.width - 2*(entry->border.outline_width + entry->border.width),
+ entry->surface.height - 2*(entry->border.outline_width + entry->border.width)
+ );
+ cairo_clip(cr);
+ cairo_set_source_rgb(cr, 0.106, 0.114, 0.118);
+ cairo_paint(cr);
+
+ PangoLayout *layout = pango_cairo_create_layout(cr);
+ pango_layout_set_text(layout, "", -1);
+
+ PangoFontDescription *font_description = pango_font_description_from_string("Rubik Bold 48");
+ pango_layout_set_font_description(layout, font_description);
+ pango_font_description_free(font_description);
+
+ cairo_set_source_rgb(cr, 0.973, 0.973, 0.941);
+ pango_cairo_update_layout(cr, layout);
+ pango_cairo_show_layout(cr, layout);
+
+ entry->pangocairo.surface = surface;
+ entry->pangocairo.cr = cr;
+ entry->pangocairo.layout = layout;
+ entry->image.width = entry->surface.width;
+ entry->image.height = entry->surface.height;
+ entry->image.buffer = cairo_image_surface_get_data(surface);
+}
+
+void entry_update(struct entry *entry)
+{
+ cairo_t *cr = entry->pangocairo.cr;
+ PangoLayout *layout = entry->pangocairo.layout;
+ cairo_set_source_rgb(cr, 0.106, 0.114, 0.118);
+ cairo_paint(cr);
+ cairo_set_source_rgb(cr, 0.973, 0.973, 0.941);
+ //const wchar_t *src = entry->password;
+ //wcsrtombs(entry->password_mb, &src, N_ELEM(entry->password_mb), NULL);
+ for (unsigned int i = 0; i < entry->password_length; i++) {
+ entry->password_mb[2 * i] = '\xC2';
+ entry->password_mb[2 * i + 1] = '\xB7';
+ }
+ entry->password_mb[2 * entry->password_length] = '\0';
+ fprintf(stderr, "%s\n", entry->password_mb);
+ pango_layout_set_text(layout, entry->password_mb, -1);
+ pango_cairo_update_layout(cr, layout);
+ pango_cairo_show_layout(cr, layout);
+ entry->image.redraw = true;
+}
+
+void calculate_font_extents(struct entry *entry)
+{
+ PangoFontMap *font_map = pango_cairo_font_map_get_default();
+ PangoContext *context = pango_font_map_create_context(font_map);
+ PangoLayout *layout = pango_layout_new(context);
+ {
+ PangoFontDescription *font_description = pango_font_description_from_string("Rubik Bold 48");
+ pango_layout_set_font_description(layout, font_description);
+ PangoFont *font = pango_font_map_load_font(font_map, context, font_description);
+ g_object_unref(font);
+ pango_font_description_free(font_description);
+
+ font_description = pango_context_get_font_description(context);
+ log_info("Using family: %s\n", pango_font_description_get_family(font_description));
+ }
+ pango_layout_set_text(layout, "············", -1);
+
+ int width;
+ int height;
+ pango_layout_get_pixel_size(layout, &width, &height);
+ fprintf(stderr, "%d x %d\n", width, height);
+ fprintf(stderr, "%d, %d\n", entry->border.width, entry->border.outline_width);
+ width += 2 * (entry->border.width + entry->border.outline_width);
+ height += 2 * (entry->border.width + entry->border.outline_width);
+ entry->surface.width = width;
+ entry->surface.height = height;
+
+ g_object_unref(layout);
+ g_object_unref(context);
+}
diff --git a/src/entry.h b/src/entry.h
new file mode 100644
index 0000000..18276a1
--- /dev/null
+++ b/src/entry.h
@@ -0,0 +1,33 @@
+#ifndef ENTRY_H
+#define ENTRY_H
+
+#include <pango/pangocairo.h>
+#include "util.h"
+#include "surface.h"
+
+#define MAX_PASSWORD_LENGTH 256
+
+struct entry {
+ struct surface surface;
+ struct wl_subsurface *wl_subsurface;
+ struct image image;
+ struct {
+ PangoLayout *layout;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ } pangocairo;
+ struct {
+ struct color color;
+ struct color outline_color;
+ int32_t width;
+ int32_t outline_width;
+ } border;
+ wchar_t password[MAX_PASSWORD_LENGTH];
+ char password_mb[4*MAX_PASSWORD_LENGTH];
+ uint32_t password_length;
+};
+
+void entry_init(struct entry *entry);
+void entry_update(struct entry *entry);
+
+#endif /* ENTRY_H */
diff --git a/src/gl.c b/src/gl.c
index f9ff059..94262b4 100644
--- a/src/gl.c
+++ b/src/gl.c
@@ -12,14 +12,12 @@
static void load_shader(GLuint shader, const char *filename);
static GLuint create_shader_program(const char *vert, const char *frag);
-void gl_initialise(struct client_state *state)
+void gl_initialise(struct gl *gl, struct image *texture)
{
- if (state->window.background_image.buffer == NULL) {
+ if (texture == NULL) {
return;
}
- struct gl *gl = &state->window.surface.gl;
-
/* Compile and link the shader programs */
gl->shader = create_shader_program(
SHADER_PATH "vert.vert",
@@ -71,40 +69,39 @@ void gl_initialise(struct client_state *state)
/* Create the texture we'll draw to */
glGenTextures(1, &gl->texture);
glBindTexture(GL_TEXTURE_2D, gl->texture);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, state->window.background_image.width, state->window.background_image.height, 0, GL_RGBA,
- GL_UNSIGNED_BYTE, (GLvoid *)state->window.background_image.buffer);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->width, texture->height, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, (GLvoid *)texture->buffer);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ if (texture->swizzle) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ALPHA);
+ }
+
/* Bind the actual bits we'll be using to render */
glBindVertexArray(gl->vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gl->ebo);
}
-void gl_draw(struct client_state *state)
+void gl_clear(struct gl *gl, struct color *color)
{
- glClearColor(
- state->window.background_color.r,
- state->window.background_color.g,
- state->window.background_color.b,
- state->window.background_color.a
- );
+ glClearColor(color->r, color->g, color->b, color->a);
glClear(GL_COLOR_BUFFER_BIT);
+}
- if (state->window.background_image.buffer == NULL) {
- return;
+void gl_draw_texture(struct gl *gl, struct image *texture, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+ if (texture->redraw) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->width, texture->height, GL_RGBA,
+ GL_UNSIGNED_BYTE, (GLvoid *)texture->buffer);
+ texture->redraw = false;
}
- double scale = max(
- (double)state->window.surface.width / state->window.background_image.width,
- (double)state->window.surface.height / state->window.background_image.height
- );
- uint32_t width = (uint32_t)(scale * state->window.background_image.width);
- uint32_t height = (uint32_t)(scale * state->window.background_image.height);
- int32_t x = -((int32_t)width - (int32_t)state->window.surface.width) / 2;
- int32_t y = -((int32_t)height - (int32_t)state->window.surface.height) / 2;
glViewport(x, y, width, height);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
diff --git a/src/gl.h b/src/gl.h
index d963f0f..8a4ff73 100644
--- a/src/gl.h
+++ b/src/gl.h
@@ -3,7 +3,9 @@
#include <epoxy/gl.h>
-struct client_state;
+struct color;
+struct image;
+
struct gl {
GLuint vbo;
GLuint vao;
@@ -12,7 +14,8 @@ struct gl {
GLuint shader;
};
-void gl_initialise(struct client_state *state);
-void gl_draw(struct client_state *state);
+void gl_initialise(struct gl *gl, struct image *texture);
+void gl_clear(struct gl *gl, struct color *color);
+void gl_draw_texture(struct gl *gl, struct image *texture, int32_t x, int32_t y, int32_t width, int32_t height);
#endif /* GL_H */
diff --git a/src/main.c b/src/main.c
index cacc82e..5b59b68 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,6 +1,5 @@
#include <assert.h>
#include <wayland-egl.h>
-#include <epoxy/egl.h>
#include <epoxy/gl.h>
#include <errno.h>
#include <stdbool.h>
@@ -13,22 +12,19 @@
#include <wctype.h>
#include <xkbcommon/xkbcommon.h>
#include <locale.h>
+#include "background.h"
#include "client.h"
#include "egl.h"
+#include "entry.h"
#include "gl.h"
-#include "background.h"
+#include "nelem.h"
#include "xdg-shell-client-protocol.h"
+#undef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
-static void wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time);
-static const struct wl_callback_listener wl_surface_frame_listener = {
- .done = wl_surface_frame_done,
-};
-
void draw_frame(struct surface *surface)
{
- printf("DRAW\n");
surface->redraw = true;
}
@@ -51,10 +47,6 @@ xdg_toplevel_configure(void *data,
state->window.surface.height = scaled_height;
wl_egl_window_resize(state->window.surface.egl.window, scaled_width, scaled_height, 0, 0);
- printf("%d, %d\n",
- (width - state->window.entry.surface.width / state->window.scale) / 2,
- (height - state->window.entry.surface.height / state->window.scale) / 2
- );
wl_subsurface_set_position(state->window.entry.wl_subsurface,
(width - state->window.entry.surface.width / state->window.scale) / 2,
(height - state->window.entry.surface.height / state->window.scale) / 2
@@ -127,11 +119,23 @@ wl_keyboard_key(void *data, struct wl_keyboard *wl_keyboard,
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)) {
- fprintf(stderr, "%s\n", buf);
+ if (entry->password_length < N_ELEM(entry->password) - 1) {
+ entry->password[entry->password_length] = ch;
+ entry->password_length++;
+ }
+ fprintf(stderr, "%ls\n", entry->password);
+ entry_update(&client_state->window.entry);
+ draw_frame(&client_state->window.entry.surface);
+ } else if (entry->password_length > 0 && sym == XKB_KEY_BackSpace) {
+ entry->password[entry->password_length - 1] = '\0';
+ entry->password_length--;
+ entry_update(&client_state->window.entry);
+ draw_frame(&client_state->window.entry.surface);
}
}
}
@@ -188,7 +192,7 @@ wl_seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities)
static void
wl_seat_name(void *data, struct wl_seat *wl_seat, const char *name)
{
- fprintf(stderr, "seat name: %s\n", name);
+ /* Deliberately left blank */
}
static const struct wl_seat_listener wl_seat_listener = {
@@ -206,22 +210,6 @@ static const struct xdg_wm_base_listener xdg_wm_base_listener = {
.ping = xdg_wm_base_ping,
};
-static void
-wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time)
-{
- /* Destroy this callback */
- wl_callback_destroy(cb);
- fprintf(stderr, "callback\n");
-
- /* Request another frame */
- struct client_state *state = data;
- cb = wl_surface_frame(state->window.surface.wl_surface);
- wl_callback_add_listener(cb, &wl_surface_frame_listener, state);
-
- /* Submit a frame for this event */
- wl_surface_commit(state->window.surface.wl_surface);
-}
-
static void output_geometry(void *data, struct wl_output *wl_output,
int32_t x, int32_t y, int32_t physical_width, int32_t physical_height,
int32_t subpixel, const char *make, const char *model, int32_t transform)
@@ -297,12 +285,14 @@ static const struct wl_registry_listener wl_registry_listener = {
static void surface_enter(void *data, struct wl_surface *wl_surface, struct wl_output *wl_output)
{
- fprintf(stderr, "enter\n");
+ /* TODO */
+ fprintf(stderr, "TODO: enter\n");
}
static void surface_leave(void *data, struct wl_surface *wl_surface, struct wl_output *wl_output)
{
- fprintf(stderr, "leave\n");
+ /* TODO */
+ fprintf(stderr, "TODO: leave\n");
}
static const struct wl_surface_listener wl_surface_listener = {
@@ -320,6 +310,8 @@ int main(int argc, char *argv[])
state.window.surface.height = 480;
state.window.entry.surface.width = 80;
state.window.entry.surface.height = 40;
+ state.window.entry.border.width = 12;
+ state.window.entry.border.outline_width = 3;
state.wl_display = wl_display_connect(NULL);
state.wl_registry = wl_display_get_registry(state.wl_display);
state.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
@@ -337,41 +329,36 @@ int main(int argc, char *argv[])
xdg_toplevel_set_title(state.window.xdg_toplevel, "Greetd mini wayland greeter");
wl_surface_commit(state.window.surface.wl_surface);
+ entry_init(&state.window.entry);
+ xdg_toplevel_set_min_size(state.window.xdg_toplevel,
+ state.window.entry.surface.width,
+ state.window.entry.surface.height);
+
state.window.entry.surface.wl_surface = wl_compositor_create_surface(state.wl_compositor);
state.window.entry.wl_subsurface = wl_subcompositor_get_subsurface(state.wl_subcompositor, state.window.entry.surface.wl_surface, state.window.surface.wl_surface);
wl_subsurface_set_desync(state.window.entry.wl_subsurface);
wl_surface_commit(state.window.entry.surface.wl_surface);
-
- struct surface *surface = &state.window.surface;
- egl_create_window(&surface->egl, surface->wl_surface, surface->width, surface->height);
- egl_create_context(&surface->egl, state.wl_display);
- gl_initialise(&state);
-
- surface = &state.window.entry.surface;
- egl_create_window(&surface->egl, surface->wl_surface, surface->width, surface->height);
- egl_create_context(&surface->egl, state.wl_display);
-
+ surface_initialise(&state.window.surface, state.wl_display, &state.window.background_image);
+ surface_initialise(&state.window.entry.surface, state.wl_display, &state.window.entry.image);
wl_display_roundtrip(state.wl_display);
egl_make_current(&state.window.surface.egl);
- eglSwapBuffers(state.window.surface.egl.display, state.window.surface.egl.surface);
+ egl_swap_buffers(&state.window.surface.egl);
egl_make_current(&state.window.entry.surface.egl);
- eglSwapBuffers(state.window.entry.surface.egl.display, state.window.entry.surface.egl.surface);
+ egl_swap_buffers(&state.window.entry.surface.egl);
draw_frame(&state.window.surface);
+ draw_frame(&state.window.entry.surface);
while (wl_display_dispatch(state.wl_display) != -1) {
if (state.closed) {
break;
}
if (state.window.surface.redraw) {
- egl_make_current(&state.window.surface.egl);
- gl_draw(&state);
- egl_swap_buffers(&state.window.surface.egl);
+ surface_draw(&state.window.surface, &state.window.background_color, &state.window.background_image);
state.window.surface.redraw = false;
}
if (state.window.entry.surface.redraw) {
- egl_make_current(&state.window.entry.surface.egl);
- egl_swap_buffers(&state.window.entry.surface.egl);
+ surface_draw(&state.window.entry.surface, &state.window.background_color, &state.window.entry.image);
state.window.entry.surface.redraw = false;
}
}
diff --git a/src/nelem.h b/src/nelem.h
new file mode 100644
index 0000000..61bf6ce
--- /dev/null
+++ b/src/nelem.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2021 Philip Jones
+ *
+ * Licensed under the MIT License.
+ * See either the LICENSE file, or:
+ *
+ * https://opensource.org/licenses/MIT
+ *
+ */
+
+#ifndef N_ELEM
+#define N_ELEM(x) (sizeof(x) / sizeof(*(x)))
+#endif
diff --git a/src/surface.c b/src/surface.c
new file mode 100644
index 0000000..6253801
--- /dev/null
+++ b/src/surface.c
@@ -0,0 +1,34 @@
+#include "client.h"
+#include "gl.h"
+#include "surface.h"
+
+#undef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+void surface_initialise(struct surface *surface, struct wl_display *wl_display, struct image *texture)
+{
+ egl_create_window(&surface->egl, surface->wl_surface, surface->width, surface->height);
+ egl_create_context(&surface->egl, wl_display);
+ gl_initialise(&surface->gl, texture);
+}
+
+void surface_draw(struct surface *surface, struct color *color, struct image *texture)
+{
+ egl_make_current(&surface->egl);
+ gl_clear(&surface->gl, color);
+
+ if (texture != NULL && texture->buffer != NULL) {
+ double scale = MAX(
+ (double)surface->width / texture->width,
+ (double)surface->height / texture->height
+ );
+ uint32_t width = (uint32_t)(scale * texture->width);
+ uint32_t height = (uint32_t)(scale * texture->height);
+ int32_t x = -((int32_t)width - (int32_t)surface->width) / 2;
+ int32_t y = -((int32_t)height - (int32_t)surface->height) / 2;
+
+ gl_draw_texture(&surface->gl, texture, x, y, width, height);
+ }
+
+ egl_swap_buffers(&surface->egl);
+}
diff --git a/src/surface.h b/src/surface.h
new file mode 100644
index 0000000..2b2910a
--- /dev/null
+++ b/src/surface.h
@@ -0,0 +1,21 @@
+#ifndef SURFACE_H
+#define SURFACE_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "egl.h"
+#include "gl.h"
+
+struct surface {
+ struct egl egl;
+ struct gl gl;
+ struct wl_surface *wl_surface;
+ int32_t width;
+ int32_t height;
+ bool redraw;
+};
+
+void surface_initialise(struct surface *surface, struct wl_display *wl_display, struct image *texture);
+void surface_draw(struct surface *surface, struct color *color, struct image *texture);
+
+#endif /* SURFACE_H */
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..02e2c6a
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,22 @@
+#ifndef UTIL_H
+#define UTIL_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct image {
+ uint8_t *buffer;
+ uint32_t width;
+ uint32_t height;
+ bool swizzle;
+ bool redraw;
+};
+
+struct color {
+ float r;
+ float g;
+ float b;
+ float a;
+};
+
+#endif /* UTIL_H */