add lock mode

Introducing `lock` mode. This turns the screen locker into a mode which
adds some more modularity to the code.

Visible views on sheet 0 are also displayed on the lock screen allowing
for a customizable setup without the needs for extra plugins.

An indicator adds feedback for typing and verification.
This commit is contained in:
raichoo 2020-06-09 15:37:41 +00:00
parent 18e775a7f8
commit 515499e8da
15 changed files with 913 additions and 336 deletions

View File

@ -29,6 +29,8 @@ OBJS = \
layout.o \
layout_config.o \
layout_select_mode.o \
lock_indicator.o \
lock_mode.o \
main.o \
mark.o \
mark_assign_mode.o \
@ -48,7 +50,6 @@ OBJS = \
sheet_assign_mode.o \
split.o \
tile.o \
unlocker.o \
view.o \
view_autoconf.o \
workspace.o \

View File

@ -0,0 +1,50 @@
#if !defined(HIKARI_LOCK_INDICATOR_H)
#define HIKARI_LOCK_INDICATOR_H
#include <wayland-util.h>
#include <wlr/render/wlr_texture.h>
struct hikari_output;
struct hikari_render_data;
struct hikari_lock_indicator {
struct wlr_texture *wait;
struct wlr_texture *type;
struct wlr_texture *verify;
struct wlr_texture *deny;
struct wlr_texture *current;
struct wl_event_source *reset_state;
};
void
hikari_lock_indicator_init(struct hikari_lock_indicator *lock_indicator);
void
hikari_lock_indicator_fini(struct hikari_lock_indicator *lock_indicator);
void
hikari_lock_indicator_set_wait(struct hikari_lock_indicator *lock_indicator);
void
hikari_lock_indicator_set_type(struct hikari_lock_indicator *lock_indicator);
void
hikari_lock_indicator_set_verify(struct hikari_lock_indicator *lock_indicator);
void
hikari_lock_indicator_set_deny(struct hikari_lock_indicator *lock_indicator);
void
hikari_lock_indicator_clear(struct hikari_lock_indicator *lock_indicator);
void
hikari_lock_indicator_damage(struct hikari_lock_indicator *lock_indicator);
void
hikari_lock_indicator_render(struct hikari_lock_indicator *lock_indicator,
struct hikari_render_data *render_data);
#endif

View File

@ -0,0 +1,34 @@
#if !defined(HIKARI_LOCK_MODE_H)
#define HIKARI_LOCK_MODE_H
#include <stdbool.h>
#include <wayland-util.h>
#include <hikari/lock_indicator.h>
#include <hikari/mode.h>
struct hikari_lock_mode {
struct hikari_mode mode;
struct wl_event_source *disable_outputs;
struct hikari_lock_indicator *lock_indicator;
bool outputs_disabled;
};
void
hikari_lock_mode_init(struct hikari_lock_mode *lock_mode);
void
hikari_lock_mode_fini(struct hikari_lock_mode *lock_mode);
void
hikari_lock_mode_enter(void);
static inline bool
hikari_lock_mode_are_outputs_disabled(struct hikari_lock_mode *lock_mode)
{
return lock_mode->outputs_disabled;
}
#endif

View File

@ -11,6 +11,8 @@
#include <hikari/output_config.h>
struct hikari_render_data;
struct hikari_output {
struct wlr_output *wlr_output;
struct wlr_output_damage *damage;
@ -59,11 +61,26 @@ hikari_output_disable(struct hikari_output *output);
void
hikari_output_enable(struct hikari_output *output);
void
hikari_output_enable_content(struct hikari_output *output);
void
hikari_output_disable_content(struct hikari_output *output);
void
hikari_output_load_background(struct hikari_output *output,
const char *path,
enum hikari_background_fit background_fit);
void
hikari_output_render_background(struct hikari_output *output,
struct hikari_render_data *render_data,
float alpha);
void
hikari_output_render_sticky(
struct hikari_output *output, struct hikari_render_data *render_data);
void
hikari_output_move(struct hikari_output *output, double lx, double ly);

View File

@ -12,6 +12,7 @@
#include <hikari/input_grab_mode.h>
#include <hikari/layer_shell.h>
#include <hikari/layout_select_mode.h>
#include <hikari/lock_mode.h>
#include <hikari/mark_assign_mode.h>
#include <hikari/mark_select_mode.h>
#include <hikari/move_mode.h>
@ -27,7 +28,6 @@ struct hikari_output;
struct hikari_group;
struct hikari_server {
bool locked;
bool cycling;
#ifndef NDEBUG
bool track_damage;
@ -95,6 +95,7 @@ struct hikari_server {
struct hikari_group_assign_mode group_assign_mode;
struct hikari_input_grab_mode input_grab_mode;
struct hikari_layout_select_mode layout_select_mode;
struct hikari_lock_mode lock_mode;
struct hikari_mark_assign_mode mark_assign_mode;
struct hikari_mark_select_mode mark_select_mode;
struct hikari_move_mode move_mode;
@ -173,9 +174,6 @@ hikari_server_reload(void *arg);
void
hikari_server_execute_command(void *arg);
void
hikari_server_unlock(void);
struct hikari_group *
hikari_server_find_group(const char *group_name);
@ -354,6 +352,7 @@ hikari_server_clear_workspace(void *arg)
MODE(group_assign)
MODE(input_grab)
MODE(layout_select)
MODE(lock)
MODE(mark_assign)
MODE(mark_select)
MODE(move)

View File

@ -1,18 +0,0 @@
#if !defined(HIKARI_UNLOCKER_H)
#define HIKARI_UNLOCKER_H
#include <wayland-server-core.h>
void
hikari_unlocker_init(void);
void
hikari_unlocker_fini(void);
void
hikari_unlocker_start(void);
void
hikari_unlocker_key_handler(struct wl_listener *listener, void *data);
#endif

View File

@ -164,6 +164,8 @@ General actions
needs pam.conf(5) to be aware of its existence, therefore there must be a
_hikari-unlocker_ service file in _pam.d_.
The lock screen displays all visible sheets that are a member of sheet 0.
* **quit**
Quit **hikari**.

View File

@ -79,9 +79,8 @@ hikari_cursor_deactivate(struct hikari_cursor *cursor)
wl_list_remove(&cursor->button.link);
wl_list_remove(&cursor->axis.link);
wl_list_remove(&cursor->request_set_cursor.link);
wl_list_remove(&cursor->surface_destroy.link);
wl_list_init(&cursor->surface_destroy.link);
hikari_cursor_set_image(cursor, NULL);
}
void
@ -90,8 +89,12 @@ hikari_cursor_set_image(struct hikari_cursor *cursor, const char *path)
wl_list_remove(&cursor->surface_destroy.link);
wl_list_init(&cursor->surface_destroy.link);
wlr_xcursor_manager_set_cursor_image(
hikari_server.cursor_mgr, path, cursor->wlr_cursor);
if (path != NULL) {
wlr_xcursor_manager_set_cursor_image(
hikari_server.cursor_mgr, path, cursor->wlr_cursor);
} else {
wlr_cursor_set_image(cursor->wlr_cursor, NULL, 0, 0, 0, 0, 0, 0);
}
}
void
@ -111,7 +114,7 @@ motion_absolute_handler(struct wl_listener *listener, void *data)
struct hikari_cursor *cursor =
wl_container_of(listener, cursor, motion_absolute);
assert(!hikari_server.locked);
assert(!hikari_server_in_lock_mode());
struct wlr_event_pointer_motion_absolute *event = data;
@ -124,7 +127,7 @@ motion_absolute_handler(struct wl_listener *listener, void *data)
static void
frame_handler(struct wl_listener *listener, void *data)
{
assert(!hikari_server.locked);
assert(!hikari_server_in_lock_mode());
wlr_seat_pointer_notify_frame(hikari_server.seat);
}
@ -134,7 +137,7 @@ motion_handler(struct wl_listener *listener, void *data)
{
struct hikari_cursor *cursor = wl_container_of(listener, cursor, motion);
assert(!hikari_server.locked);
assert(!hikari_server_in_lock_mode());
struct wlr_event_pointer_motion *event = data;
@ -147,7 +150,7 @@ motion_handler(struct wl_listener *listener, void *data)
static void
button_handler(struct wl_listener *listener, void *data)
{
assert(!hikari_server.locked);
assert(!hikari_server_in_lock_mode());
hikari_server.mode->button_handler(listener, data);
}
@ -155,7 +158,7 @@ button_handler(struct wl_listener *listener, void *data)
static void
axis_handler(struct wl_listener *listener, void *data)
{
assert(!hikari_server.locked);
assert(!hikari_server_in_lock_mode());
struct wlr_event_pointer_axis *event = data;

View File

@ -8,7 +8,6 @@
#include <hikari/memory.h>
#include <hikari/mode.h>
#include <hikari/server.h>
#include <hikari/unlocker.h>
static void
update_mod_state(struct hikari_keyboard *keyboard)
@ -30,11 +29,6 @@ key_handler(struct wl_listener *listener, void *data)
{
struct hikari_keyboard *keyboard = wl_container_of(listener, keyboard, key);
if (hikari_server.locked) {
hikari_unlocker_key_handler(listener, data);
return;
}
hikari_server.mode->key_handler(listener, data);
}
@ -46,10 +40,6 @@ modifiers_handler(struct wl_listener *listener, void *data)
update_mod_state(keyboard);
if (hikari_server.locked) {
return;
}
hikari_server.mode->modifier_handler(listener, data);
}

199
src/lock_indicator.c Normal file
View File

@ -0,0 +1,199 @@
#include <hikari/lock_indicator.h>
#include <wlr/backend.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_matrix.h>
#include <hikari/configuration.h>
#include <hikari/geometry.h>
#include <hikari/output.h>
#include <hikari/render_data.h>
#include <hikari/server.h>
static struct wlr_texture *
init_indicator_circle(float color[static 4])
{
const int size = 100;
struct wlr_texture *texture;
struct wlr_renderer *renderer =
wlr_backend_get_renderer(hikari_server.backend);
cairo_surface_t *surface =
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, size, size);
cairo_t *cairo = cairo_create(surface);
PangoLayout *layout = pango_cairo_create_layout(cairo);
float *border_inactive = hikari_configuration->border_active;
cairo_set_source_rgba(cairo,
border_inactive[0],
border_inactive[1],
border_inactive[2],
border_inactive[3]);
cairo_set_line_width(cairo, 5);
cairo_translate(cairo, size / 2, size / 2);
cairo_arc(cairo, 0, 0, (size - 5) / 2, 0, 2 * M_PI);
cairo_stroke_preserve(cairo);
cairo_set_source_rgba(cairo, color[0], color[1], color[2], color[3]);
cairo_fill(cairo);
cairo_surface_flush(surface);
unsigned char *data = cairo_image_surface_get_data(surface);
int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, size);
texture = wlr_texture_from_pixels(
renderer, WL_SHM_FORMAT_ARGB8888, stride, size, size, data);
cairo_surface_destroy(surface);
g_object_unref(layout);
cairo_destroy(cairo);
return texture;
}
static int
reset_state_handler(void *data)
{
struct hikari_lock_indicator *lock_indicator = data;
if (lock_indicator->current == lock_indicator->deny) {
hikari_lock_indicator_clear(lock_indicator);
} else {
hikari_lock_indicator_set_wait(lock_indicator);
}
return 0;
}
void
hikari_lock_indicator_init(struct hikari_lock_indicator *lock_indicator)
{
assert(lock_indicator != NULL);
lock_indicator->wait = init_indicator_circle(hikari_configuration->clear);
lock_indicator->type =
init_indicator_circle(hikari_configuration->indicator_insert);
lock_indicator->verify =
init_indicator_circle(hikari_configuration->indicator_selected);
lock_indicator->deny =
init_indicator_circle(hikari_configuration->indicator_conflict);
lock_indicator->current = NULL;
lock_indicator->reset_state = wl_event_loop_add_timer(
hikari_server.event_loop, reset_state_handler, lock_indicator);
}
void
hikari_lock_indicator_fini(struct hikari_lock_indicator *lock_indicator)
{
assert(lock_indicator != NULL);
wlr_texture_destroy(lock_indicator->wait);
wlr_texture_destroy(lock_indicator->type);
wlr_texture_destroy(lock_indicator->verify);
wlr_texture_destroy(lock_indicator->deny);
wl_event_source_remove(lock_indicator->reset_state);
}
void
hikari_lock_indicator_set_type(struct hikari_lock_indicator *lock_indicator)
{
assert(lock_indicator != NULL);
lock_indicator->current = lock_indicator->type;
hikari_lock_indicator_damage(lock_indicator);
wl_event_source_timer_update(lock_indicator->reset_state, 100);
}
void
hikari_lock_indicator_set_verify(struct hikari_lock_indicator *lock_indicator)
{
assert(lock_indicator != NULL);
lock_indicator->current = lock_indicator->verify;
hikari_lock_indicator_damage(lock_indicator);
wl_event_source_timer_update(lock_indicator->reset_state, 0);
}
void
hikari_lock_indicator_set_deny(struct hikari_lock_indicator *lock_indicator)
{
assert(lock_indicator != NULL);
lock_indicator->current = lock_indicator->deny;
hikari_lock_indicator_damage(lock_indicator);
wl_event_source_timer_update(lock_indicator->reset_state, 1000);
}
void
hikari_lock_indicator_set_wait(struct hikari_lock_indicator *lock_indicator)
{
assert(lock_indicator != NULL);
lock_indicator->current = lock_indicator->wait;
hikari_lock_indicator_damage(lock_indicator);
}
void
hikari_lock_indicator_clear(struct hikari_lock_indicator *lock_indicator)
{
assert(lock_indicator != NULL);
lock_indicator->current = NULL;
hikari_lock_indicator_damage(lock_indicator);
wl_event_source_timer_update(lock_indicator->reset_state, 0);
}
static inline void
get_geometry(struct hikari_output *output, struct wlr_box *geometry)
{
const int size = 100;
geometry->width = size;
geometry->height = size;
hikari_geometry_position_center(
geometry, &output->geometry, &geometry->x, &geometry->y);
}
void
hikari_lock_indicator_render(struct hikari_lock_indicator *lock_indicator,
struct hikari_render_data *render_data)
{
assert(lock_indicator != NULL);
struct wlr_texture *texture = lock_indicator->current;
if (texture == NULL) {
return;
}
float matrix[9];
struct wlr_renderer *renderer = render_data->renderer;
struct wlr_output *output = render_data->output;
struct wlr_box geometry;
get_geometry(output->data, &geometry);
wlr_renderer_scissor(renderer, &geometry);
wlr_matrix_project_box(matrix, &geometry, 0, 0, output->transform_matrix);
wlr_render_texture_with_matrix(renderer, texture, matrix, 1);
}
void
hikari_lock_indicator_damage(struct hikari_lock_indicator *lock_indicator)
{
assert(lock_indicator != NULL);
struct wlr_box geometry;
struct hikari_output *output;
wl_list_for_each (output, &hikari_server.outputs, server_outputs) {
get_geometry(output, &geometry);
hikari_output_add_damage(output, &geometry);
}
}

369
src/lock_mode.c Normal file
View File

@ -0,0 +1,369 @@
#include <hikari/lock_mode.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <wlr/types/wlr_seat.h>
#include <hikari/cursor.h>
#include <hikari/keyboard.h>
#include <hikari/lock_indicator.h>
#include <hikari/output.h>
#include <hikari/render_data.h>
#include <hikari/server.h>
#include <hikari/utf8.h>
#include <hikari/view.h>
#define BUFFER_SIZE 1024
static char input_buffer[BUFFER_SIZE];
static int cursor = 0;
static int locker_pipe[2][2] = { { -1, -1 }, { -1, -1 } };
static struct hikari_lock_mode *
get_mode(void)
{
struct hikari_lock_mode *mode = &hikari_server.lock_mode;
assert(mode == (struct hikari_lock_mode *)hikari_server.mode);
return mode;
}
static void
clear_buffer(void)
{
cursor = 0;
memset(input_buffer, 0, BUFFER_SIZE);
}
static void
clear_password(void)
{
struct hikari_lock_mode *mode = get_mode();
clear_buffer();
hikari_lock_indicator_clear(mode->lock_indicator);
}
static void
start_unlocker(void)
{
pipe(locker_pipe[0]);
pipe(locker_pipe[1]);
pid_t locker = fork();
if (locker == 0) {
close(locker_pipe[0][1]);
close(locker_pipe[1][0]);
close(0);
close(1);
dup2(locker_pipe[0][0], 0);
dup2(locker_pipe[1][1], 1);
execl("/bin/sh", "/bin/sh", "-c", "hikari-unlocker", NULL);
exit(0);
} else {
close(locker_pipe[0][0]);
close(locker_pipe[1][1]);
}
}
static void
put_char(uint32_t codepoint)
{
size_t length = utf8_chsize(codepoint);
if (cursor + length < BUFFER_SIZE) {
struct hikari_lock_mode *mode = get_mode();
hikari_lock_indicator_set_type(mode->lock_indicator);
utf8_encode(&input_buffer[cursor], length, codepoint);
cursor += length;
}
}
static void
delete_char(void)
{
struct hikari_lock_mode *mode = get_mode();
if (cursor == 0) {
return;
}
hikari_lock_indicator_set_type(mode->lock_indicator);
input_buffer[--cursor] = '\0';
if (cursor == 0) {
hikari_lock_indicator_clear(mode->lock_indicator);
}
}
static void
submit_password(void)
{
struct hikari_lock_mode *mode = get_mode();
size_t password_length = strnlen(input_buffer, 1023) + 1;
bool success = false;
hikari_lock_indicator_set_verify(mode->lock_indicator);
write(locker_pipe[0][1], input_buffer, password_length);
clear_buffer();
read(locker_pipe[1][0], &success, sizeof(bool));
if (success) {
int status;
close(locker_pipe[1][0]);
close(locker_pipe[0][1]);
wait(&status);
hikari_server_enter_normal_mode(NULL);
} else {
hikari_lock_indicator_set_deny(mode->lock_indicator);
}
}
static void
disable_outputs(void)
{
struct hikari_lock_mode *mode = get_mode();
wl_event_source_timer_update(mode->disable_outputs, 0);
struct hikari_output *output;
wl_list_for_each (output, &hikari_server.outputs, server_outputs) {
if (output->enabled) {
hikari_output_disable(output);
}
hikari_output_damage_whole(output);
}
mode->outputs_disabled = true;
clear_password();
}
static void
enable_outputs(void)
{
struct hikari_lock_mode *mode = get_mode();
if (!mode->outputs_disabled) {
return;
}
assert(cursor == 0);
struct hikari_output *output;
wl_list_for_each (output, &hikari_server.outputs, server_outputs) {
if (!output->enabled) {
hikari_output_disable_content(output);
hikari_output_enable(output);
}
}
mode->outputs_disabled = false;
}
static void
key_handler(struct wl_listener *listener, void *data)
{
struct hikari_keyboard *keyboard = wl_container_of(listener, keyboard, key);
struct wlr_event_keyboard_key *event = data;
struct hikari_lock_mode *mode = get_mode();
if (event->state == WLR_KEY_PRESSED) {
const xkb_keysym_t *syms;
uint32_t keycode = event->keycode + 8;
uint32_t codepoint;
int nsyms = xkb_state_key_get_syms(
keyboard->device->keyboard->xkb_state, keycode, &syms);
enable_outputs();
for (int i = 0; i < nsyms; i++) {
switch (syms[i]) {
case XKB_KEY_Caps_Lock:
case XKB_KEY_Shift_L:
case XKB_KEY_Shift_R:
case XKB_KEY_Control_L:
case XKB_KEY_Control_R:
case XKB_KEY_Meta_L:
case XKB_KEY_Meta_R:
case XKB_KEY_Alt_L:
case XKB_KEY_Alt_R:
case XKB_KEY_Super_L:
case XKB_KEY_Super_R:
break;
case XKB_KEY_Escape:
clear_password();
break;
case XKB_KEY_BackSpace:
delete_char();
break;
case XKB_KEY_Return:
submit_password();
break;
case XKB_KEY_c:
if (hikari_keyboard_check_modifier(keyboard, WLR_MODIFIER_CTRL)) {
disable_outputs();
return;
}
default:
codepoint = hikari_keyboard_get_codepoint(keyboard, keycode);
if (codepoint) {
put_char(codepoint);
}
break;
}
}
if (mode->disable_outputs != NULL) {
wl_event_source_timer_update(mode->disable_outputs, 10 * 1000);
}
}
}
static void
modifier_handler(struct wl_listener *listener, void *data)
{}
static void
button_handler(struct wl_listener *listener, void *data)
{}
static void
render(struct hikari_output *output, struct hikari_render_data *render_data)
{
struct hikari_lock_mode *mode = get_mode();
hikari_output_render_background(output, render_data, 0.1);
hikari_output_render_sticky(output, render_data);
hikari_lock_indicator_render(mode->lock_indicator, render_data);
}
static void
cancel(void)
{
struct hikari_lock_mode *mode = get_mode();
wl_event_source_remove(mode->disable_outputs);
mode->disable_outputs = NULL;
struct hikari_output *output;
wl_list_for_each (output, &hikari_server.outputs, server_outputs) {
hikari_output_enable_content(output);
if (!output->enabled) {
hikari_output_enable(output);
}
}
hikari_lock_indicator_fini(mode->lock_indicator);
hikari_free(mode->lock_indicator);
mode->lock_indicator = NULL;
hikari_cursor_activate(&hikari_server.cursor);
}
static void
cursor_move(uint32_t time_msec)
{}
static int
disable_outputs_handler(void *data)
{
assert(hikari_server_in_lock_mode());
disable_outputs();
return 0;
}
void
hikari_lock_mode_init(struct hikari_lock_mode *lock_mode)
{
lock_mode->mode.key_handler = key_handler;
lock_mode->mode.button_handler = button_handler;
lock_mode->mode.modifier_handler = modifier_handler;
lock_mode->mode.render = render;
lock_mode->mode.cancel = cancel;
lock_mode->mode.cursor_move = cursor_move;
lock_mode->lock_indicator = NULL;
mlock(input_buffer, BUFFER_SIZE);
clear_buffer();
}
void
hikari_lock_mode_fini(struct hikari_lock_mode *lock_mode)
{
munlock(input_buffer, BUFFER_SIZE);
}
void
hikari_lock_mode_enter(void)
{
struct hikari_workspace *workspace = hikari_server.workspace;
struct hikari_view *focus_view = workspace->focus_view;
#ifdef HAVE_LAYERSHELL
struct hikari_layer *focus_layer = workspace->focus_layer;
if (focus_layer != NULL) {
assert(focus_view == NULL);
workspace->focus_layer = NULL;
wlr_seat_pointer_clear_focus(hikari_server.seat);
} else if (focus_view != NULL) {
assert(focus_layer != NULL);
hikari_workspace_focus_view(workspace, NULL);
}
#else
if (focus_view != NULL) {
hikari_workspace_focus_view(workspace, NULL);
}
#endif
struct hikari_output *output;
wl_list_for_each (output, &hikari_server.outputs, server_outputs) {
hikari_output_disable_content(output);
}
hikari_cursor_deactivate(&hikari_server.cursor);
hikari_server.mode = (struct hikari_mode *)&hikari_server.lock_mode;
struct hikari_lock_mode *mode = get_mode();
assert(mode->lock_indicator == NULL);
mode->lock_indicator = hikari_malloc(sizeof(struct hikari_lock_indicator));
hikari_lock_indicator_init(mode->lock_indicator);
clear_buffer();
start_unlocker();
mode->disable_outputs = wl_event_loop_add_timer(
hikari_server.event_loop, disable_outputs_handler, NULL);
wl_event_source_timer_update(mode->disable_outputs, 1000);
}

View File

@ -31,7 +31,7 @@
#include <hikari/xwayland_view.h>
#endif
static void
static inline void
render_image_to_surface(cairo_surface_t *output,
cairo_surface_t *image,
enum hikari_background_fit fit)
@ -123,13 +123,14 @@ done:
}
}
static void
static inline void
render_texture(struct wlr_output *output,
pixman_region32_t *damage,
struct wlr_texture *texture,
struct wlr_renderer *renderer,
const float matrix[static 9],
struct wlr_box *box)
struct wlr_box *box,
float alpha)
{
pixman_region32_t local_damage;
pixman_region32_init(&local_damage);
@ -147,7 +148,7 @@ render_texture(struct wlr_output *output,
pixman_box32_t *rects = pixman_region32_rectangles(&local_damage, &nrects);
for (int i = 0; i < nrects; ++i) {
hikari_output_scissor_render(output, renderer, &rects[i]);
wlr_render_texture_with_matrix(renderer, texture, matrix, 1);
wlr_render_texture_with_matrix(renderer, texture, matrix, alpha);
}
damage_finish:
@ -189,12 +190,14 @@ render_surface(struct wlr_surface *surface, int sx, int sy, void *data)
texture,
render_data->renderer,
matrix,
&box);
&box,
1);
}
static void
render_background(
struct hikari_output *output, struct hikari_render_data *render_data)
static inline void
render_background(struct hikari_output *output,
struct hikari_render_data *render_data,
float alpha)
{
if (output->background == NULL) {
return;
@ -214,11 +217,12 @@ render_background(
output->background,
render_data->renderer,
matrix,
&geometry);
&geometry,
alpha);
}
#ifdef HAVE_LAYERSHELL
static void
static inline void
layer_for_each(struct wl_list *layers,
void (*func)(struct wlr_surface *, int, int, void *),
void *data)
@ -229,7 +233,7 @@ layer_for_each(struct wl_list *layers,
}
}
static void
static inline void
render_layer(struct wl_list *layers, struct hikari_render_data *render_data)
{
struct hikari_layer *layer;
@ -241,22 +245,86 @@ render_layer(struct wl_list *layers, struct hikari_render_data *render_data)
}
#endif
static void
render_output(struct hikari_output *output,
pixman_region32_t *damage,
struct timespec *now)
void
hikari_output_render_sticky(
struct hikari_output *output, struct hikari_render_data *render_data)
{
struct wlr_output *wlr_output = output->wlr_output;
struct hikari_view *view;
wl_list_for_each_reverse (
view, &output->workspace->sheets[0].views, sheet_views) {
if (!hikari_view_is_hidden(view)) {
render_data->geometry = hikari_view_border_geometry(view);
struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend);
if (hikari_view_wants_border(view)) {
hikari_border_render(&view->border, render_data);
}
wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
render_data->geometry = hikari_view_geometry(view);
if (!pixman_region32_not_empty(damage)) {
goto render_end;
hikari_view_interface_for_each_surface(
(struct hikari_view_interface *)view, render_surface, render_data);
}
}
}
static inline void
render_workspace(
struct hikari_output *output, struct hikari_render_data *render_data)
{
#ifdef HAVE_LAYERSHELL
render_layer(
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], render_data);
render_layer(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], render_data);
#endif
struct hikari_view *view;
wl_list_for_each_reverse (view, &output->workspace->views, workspace_views) {
render_data->geometry = hikari_view_border_geometry(view);
if (hikari_view_wants_border(view)) {
hikari_border_render(&view->border, render_data);
}
render_data->geometry = hikari_view_geometry(view);
hikari_view_interface_for_each_surface(
(struct hikari_view_interface *)view, render_surface, render_data);
}
#ifdef HAVE_LAYERSHELL
render_layer(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], render_data);
#endif
#ifdef HAVE_XWAYLAND
struct hikari_xwayland_unmanaged_view *xwayland_unmanaged_view;
wl_list_for_each_reverse (xwayland_unmanaged_view,
&output->unmanaged_xwayland_views,
unmanaged_server_views) {
render_data->geometry = &xwayland_unmanaged_view->geometry;
wlr_surface_for_each_surface(
xwayland_unmanaged_view->surface->surface, render_surface, render_data);
}
#endif
}
#ifdef HAVE_LAYERSHELL
static inline void
render_overlay(
struct hikari_output *output, struct hikari_render_data *render_data)
{
render_layer(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], render_data);
}
#endif
static inline void
clear_output(struct hikari_render_data *render_data)
{
float *clear_color = hikari_configuration->clear;
struct wlr_renderer *renderer = render_data->renderer;
struct wlr_output *wlr_output = render_data->output;
pixman_region32_t *damage = render_data->damage;
#ifndef NDEBUG
if (hikari_server.track_damage) {
@ -272,59 +340,15 @@ render_output(struct hikari_output *output,
hikari_output_scissor_render(wlr_output, renderer, &rects[i]);
wlr_renderer_clear(renderer, clear_color);
}
}
struct hikari_render_data render_data = {
.output = wlr_output, .renderer = renderer, .when = now, .damage = damage
};
static inline void
renderer_end(
struct hikari_output *output, struct hikari_render_data *render_data)
{
struct wlr_renderer *renderer = render_data->renderer;
struct wlr_output *wlr_output = render_data->output;
render_background(output, &render_data);
#ifdef HAVE_LAYERSHELL
render_layer(
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &render_data);
render_layer(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &render_data);
#endif
struct hikari_view *view = NULL;
wl_list_for_each_reverse (view, &output->workspace->views, workspace_views) {
render_data.geometry = hikari_view_border_geometry(view);
if (hikari_view_wants_border(view)) {
hikari_border_render(&view->border, &render_data);
}
render_data.geometry = hikari_view_geometry(view);
hikari_view_interface_for_each_surface(
(struct hikari_view_interface *)view, render_surface, &render_data);
}
#ifdef HAVE_LAYERSHELL
render_layer(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &render_data);
#endif
#ifdef HAVE_XWAYLAND
struct hikari_xwayland_unmanaged_view *xwayland_unmanaged_view = NULL;
wl_list_for_each_reverse (xwayland_unmanaged_view,
&output->unmanaged_xwayland_views,
unmanaged_server_views) {
render_data.geometry = &xwayland_unmanaged_view->geometry;
wlr_surface_for_each_surface(xwayland_unmanaged_view->surface->surface,
render_surface,
&render_data);
}
#endif
hikari_server.mode->render(output, &render_data);
#ifdef HAVE_LAYERSHELL
render_layer(
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &render_data);
#endif
render_end:
wlr_renderer_scissor(renderer, NULL);
wlr_output_render_software_cursors(wlr_output, NULL);
wlr_renderer_end(renderer);
@ -346,6 +370,59 @@ render_end:
wlr_output_commit(wlr_output);
}
static inline void
render_output(struct hikari_output *output,
pixman_region32_t *damage,
struct timespec *now)
{
struct wlr_output *wlr_output = output->wlr_output;
struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend);
struct hikari_render_data render_data = {
.output = wlr_output, .renderer = renderer, .when = now, .damage = damage
};
wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
if (pixman_region32_not_empty(damage)) {
clear_output(&render_data);
render_background(output, &render_data, 1);
render_workspace(output, &render_data);
hikari_server.mode->render(output, &render_data);
#ifdef HAVE_LAYERSHELL
render_overlay(output, &render_data);
#endif
}
renderer_end(output, &render_data);
}
static inline void
render_empty_output(struct hikari_output *output,
pixman_region32_t *damage,
struct timespec *now)
{
struct wlr_output *wlr_output = output->wlr_output;
struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend);
struct hikari_render_data render_data = {
.output = wlr_output, .renderer = renderer, .when = now, .damage = damage
};
wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
if (pixman_region32_not_empty(damage)) {
clear_output(&render_data);
hikari_server.mode->render(output, &render_data);
}
renderer_end(output, &render_data);
}
static void
send_frame_done(struct wlr_surface *surface, int sx, int sy, void *data)
{
@ -355,55 +432,80 @@ send_frame_done(struct wlr_surface *surface, int sx, int sy, void *data)
wlr_surface_send_frame_done(surface, now);
}
static void
damage_frame_handler(struct wl_listener *listener, void *data)
static inline void
frame_done(struct hikari_output *output, struct timespec *now)
{
assert(!hikari_server.locked);
bool needs_frame;
struct timespec now;
struct hikari_output *output =
wl_container_of(listener, output, damage_frame);
pixman_region32_t buffer_damage;
pixman_region32_init(&buffer_damage);
if (!wlr_output_damage_attach_render(
output->damage, &needs_frame, &buffer_damage)) {
goto buffer_damage_end;
}
if (needs_frame) {
clock_gettime(CLOCK_MONOTONIC, &now);
render_output(output, &buffer_damage, &now);
}
buffer_damage_end:
pixman_region32_fini(&buffer_damage);
struct hikari_view *view = NULL;
struct hikari_view *view;
wl_list_for_each_reverse (view, &output->views, output_views) {
hikari_view_interface_for_each_surface(
(struct hikari_view_interface *)view, send_frame_done, &now);
(struct hikari_view_interface *)view, send_frame_done, now);
}
#ifdef HAVE_XWAYLAND
struct hikari_xwayland_unmanaged_view *xwayland_unmanaged_view = NULL;
struct hikari_xwayland_unmanaged_view *xwayland_unmanaged_view;
wl_list_for_each_reverse (xwayland_unmanaged_view,
&output->unmanaged_xwayland_views,
unmanaged_server_views) {
wlr_surface_for_each_surface(
xwayland_unmanaged_view->surface->surface, send_frame_done, &now);
xwayland_unmanaged_view->surface->surface, send_frame_done, now);
}
#endif
#ifdef HAVE_LAYERSHELL
for (int i = 0; i < 4; i++) {
layer_for_each(&output->layers[i], send_frame_done, &now);
layer_for_each(&output->layers[i], send_frame_done, now);
}
#endif
}
#define DAMAGE_HANDLER(name, render) \
static void name##_handler(struct wl_listener *listener, void *data) \
{ \
bool needs_frame; \
struct timespec now; \
struct hikari_output *output = \
wl_container_of(listener, output, damage_frame); \
\
pixman_region32_t buffer_damage; \
pixman_region32_init(&buffer_damage); \
\
clock_gettime(CLOCK_MONOTONIC, &now); \
\
if (wlr_output_damage_attach_render( \
output->damage, &needs_frame, &buffer_damage) && \
needs_frame) { \
render(output, &buffer_damage, &now); \
} \
\
pixman_region32_fini(&buffer_damage); \
\
frame_done(output, &now); \
}
DAMAGE_HANDLER(damage_frame, render_output)
DAMAGE_HANDLER(damage_empty_frame, render_empty_output)
#undef DAMAGE_HANDLER
void
hikari_output_disable_content(struct hikari_output *output)
{
wl_list_remove(&output->damage_frame.link);
output->damage_frame.notify = damage_empty_frame_handler;
wl_signal_add(&output->damage->events.frame, &output->damage_frame);
hikari_output_damage_whole(output);
}
void
hikari_output_enable_content(struct hikari_output *output)
{
wl_list_remove(&output->damage_frame.link);
output->damage_frame.notify = damage_frame_handler;
wl_signal_add(&output->damage->events.frame, &output->damage_frame);
hikari_output_damage_whole(output);
}
void
hikari_output_damage_whole(struct hikari_output *output)
{
@ -421,6 +523,7 @@ hikari_output_disable(struct hikari_output *output)
struct wlr_output *wlr_output = output->wlr_output;
wl_list_remove(&output->damage_frame.link);
wl_list_init(&output->damage_frame.link);
wlr_output_rollback(wlr_output);
wlr_output_enable(wlr_output, false);
@ -437,8 +540,6 @@ hikari_output_enable(struct hikari_output *output)
struct wlr_output *wlr_output = output->wlr_output;
output->damage_frame.notify = damage_frame_handler;
wl_signal_add(&output->damage->events.frame, &output->damage_frame);
wlr_output_enable(wlr_output, true);
wlr_output_commit(wlr_output);
@ -592,8 +693,16 @@ hikari_output_init(struct hikari_output *output, struct wlr_output *wlr_output)
wlr_output_set_mode(wlr_output, mode);
}
if (!hikari_server.locked) {
wl_list_init(&output->damage_frame.link);
if (!hikari_server_in_lock_mode()) {
hikari_output_enable_content(output);
hikari_output_enable(output);
} else {
hikari_output_disable_content(output);
if (hikari_lock_mode_are_outputs_disabled(&hikari_server.lock_mode)) {
hikari_output_disable(output);
}
}
struct hikari_output_config *output_config =
@ -655,3 +764,11 @@ hikari_output_move(struct hikari_output *output, double lx, double ly)
wlr_output_layout_move(
hikari_server.output_layout, output->wlr_output, lx, ly);
}
void
hikari_output_render_background(struct hikari_output *output,
struct hikari_render_data *render_data,
float alpha)
{
render_background(output, render_data, alpha);
}

View File

@ -51,7 +51,6 @@
#include <hikari/pointer.h>
#include <hikari/pointer_config.h>
#include <hikari/sheet.h>
#include <hikari/unlocker.h>
#include <hikari/workspace.h>
#include <hikari/xdg_view.h>
@ -342,10 +341,6 @@ hikari_server_view_interface_at(double x,
void
hikari_server_cursor_focus(void)
{
if (!hikari_server_in_normal_mode()) {
return;
}
struct timespec now;
uint32_t time_msec = (uint32_t)clock_gettime(CLOCK_MONOTONIC, &now);
hikari_server.mode->cursor_move(time_msec);
@ -744,7 +739,6 @@ server_init(struct hikari_server *server, char *config_path)
server->keyboard_state.mod_changed = false;
server->keyboard_state.mod_pressed = false;
server->locked = false;
server->cycling = false;
server->workspace = NULL;
@ -753,8 +747,6 @@ server_init(struct hikari_server *server, char *config_path)
wl_list_init(&server->outputs);
hikari_unlocker_init();
signal(SIGPIPE, SIG_IGN);
server->renderer = wlr_backend_get_renderer(server->backend);
@ -823,6 +815,7 @@ server_init(struct hikari_server *server, char *config_path)
hikari_group_assign_mode_init(&server->group_assign_mode);
hikari_input_grab_mode_init(&server->input_grab_mode);
hikari_layout_select_mode_init(&server->layout_select_mode);
hikari_lock_mode_init(&server->lock_mode);
hikari_mark_assign_mode_init(&server->mark_assign_mode);
hikari_mark_select_mode_init(&server->mark_select_mode);
hikari_move_mode_init(&server->move_mode);
@ -885,6 +878,7 @@ hikari_server_stop(void)
hikari_cursor_fini(&hikari_server.cursor);
hikari_indicator_fini(&hikari_server.indicator);
hikari_lock_mode_fini(&hikari_server.lock_mode);
hikari_mark_assign_mode_fini(&hikari_server.mark_assign_mode);
wlr_seat_destroy(hikari_server.seat);
@ -928,22 +922,7 @@ hikari_server_find_or_create_group(const char *group_name)
void
hikari_server_lock(void *arg)
{
hikari_unlocker_start();
hikari_server.locked = true;
hikari_cursor_deactivate(&hikari_server.cursor);
if (hikari_server.workspace->focus_view != NULL) {
hikari_workspace_focus_view(hikari_server.workspace, NULL);
}
wlr_seat_pointer_clear_focus(hikari_server.seat);
struct hikari_output *output = NULL;
wl_list_for_each (output, &hikari_server.outputs, server_outputs) {
hikari_output_disable(output);
}
hikari_lock_mode_enter();
}
void
@ -952,20 +931,6 @@ hikari_server_reload(void *arg)
hikari_configuration_reload(hikari_server.config_path);
}
void
hikari_server_unlock(void)
{
hikari_server.locked = false;
struct hikari_output *output = NULL;
wl_list_for_each (output, &hikari_server.outputs, server_outputs) {
hikari_output_enable(output);
}
hikari_cursor_activate(&hikari_server.cursor);
hikari_server_cursor_focus();
}
#define CYCLE_VIEW(name, link) \
static struct hikari_view *cycle_##name##_view(void) \
{ \

View File

@ -1,152 +0,0 @@
#include <hikari/unlocker.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <wlr/types/wlr_input_device.h>
#include <hikari/keyboard.h>
#include <hikari/server.h>
#include <hikari/utf8.h>
#define BUFFER_SIZE 1024
static char input_buffer[BUFFER_SIZE];
static int cursor = 0;
static int locker_pipe[2][2] = { { -1, -1 }, { -1, -1 } };
void
hikari_unlocker_init(void)
{
mlock(input_buffer, BUFFER_SIZE);
memset(input_buffer, 0, BUFFER_SIZE);
}
void
hikari_unlocker_start(void)
{
cursor = 0;
memset(input_buffer, 0, BUFFER_SIZE);
pipe(locker_pipe[0]);
pipe(locker_pipe[1]);
pid_t locker = fork();
if (locker == 0) {
close(locker_pipe[0][1]);
close(locker_pipe[1][0]);
close(0);
close(1);
dup2(locker_pipe[0][0], 0);
dup2(locker_pipe[1][1], 1);
execl("/bin/sh", "/bin/sh", "-c", "hikari-unlocker", NULL);
exit(0);
} else {
close(locker_pipe[0][0]);
close(locker_pipe[1][1]);
}
}
static void
put_char(uint32_t codepoint)
{
size_t length = utf8_chsize(codepoint);
if (cursor + length < BUFFER_SIZE) {
utf8_encode(&input_buffer[cursor], length, codepoint);
cursor += length;
}
}
static void
delete_char(void)
{
if (cursor == 0) {
return;
}
input_buffer[--cursor] = '\0';
}
static void
submit_password(void)
{
size_t password_length = strnlen(input_buffer, 1023) + 1;
bool success = false;
write(locker_pipe[0][1], input_buffer, password_length);
memset(input_buffer, 0, BUFFER_SIZE);
cursor = 0;
read(locker_pipe[1][0], &success, sizeof(bool));
if (success) {
int status;
hikari_server_unlock();
close(locker_pipe[1][0]);
close(locker_pipe[0][1]);
wait(&status);
}
}
void
hikari_unlocker_key_handler(struct wl_listener *listener, void *data)
{
struct hikari_keyboard *keyboard = wl_container_of(listener, keyboard, key);
struct wlr_event_keyboard_key *event = data;
if (event->state == WLR_KEY_PRESSED) {
const xkb_keysym_t *syms;
uint32_t keycode = event->keycode + 8;
uint32_t codepoint;
int nsyms = xkb_state_key_get_syms(
keyboard->device->keyboard->xkb_state, keycode, &syms);
for (int i = 0; i < nsyms; i++) {
switch (syms[i]) {
case XKB_KEY_Caps_Lock:
case XKB_KEY_Shift_L:
case XKB_KEY_Shift_R:
case XKB_KEY_Control_L:
case XKB_KEY_Control_R:
case XKB_KEY_Meta_L:
case XKB_KEY_Meta_R:
case XKB_KEY_Alt_L:
case XKB_KEY_Alt_R:
case XKB_KEY_Super_L:
case XKB_KEY_Super_R:
break;
case XKB_KEY_BackSpace:
delete_char();
break;
case XKB_KEY_Return:
submit_password();
break;
default:
codepoint = hikari_keyboard_get_codepoint(keyboard, keycode);
if (codepoint) {
put_char(codepoint);
}
break;
}
}
}
}
void
hikari_unlocker_fini(void)
{
munlock(input_buffer, BUFFER_SIZE);
}

View File

@ -50,6 +50,7 @@ static void
move_to_top(struct hikari_view *view)
{
assert(view != NULL);
assert(hikari_view_is_mapped(view));
wl_list_remove(&view->sheet_views);
wl_list_insert(&view->sheet->views, &view->sheet_views);