forked from virt-mirrors/wayneko
make neko have somewhat of a sleep schedule
This commit is contained in:
parent
c1919dc3a7
commit
0917c3f9aa
3 changed files with 148 additions and 111 deletions
17
README
17
README
|
@ -1,5 +1,20 @@
|
||||||
wayneko - Neko on Wayland
|
wayneko - Neko on Wayland but with phases
|
||||||
|
|
||||||
Display an animated neko cat on the bottom of an output. Requires the Wayland
|
Display an animated neko cat on the bottom of an output. Requires the Wayland
|
||||||
server to implement zwlr-layer-shell-unstable-v1. All code is licensed under
|
server to implement zwlr-layer-shell-unstable-v1. All code is licensed under
|
||||||
the GPLv3. The neko bitmaps were taken from public domain.
|
the GPLv3. The neko bitmaps were taken from public domain.
|
||||||
|
|
||||||
|
This fork changes the behaviour of neko to be more calm and less random. Neko
|
||||||
|
will now sleep and be awake in phases, whose duration is randomized but has
|
||||||
|
a minimum and maximum duration which can be changed. This means it can no
|
||||||
|
longer happen that Neko wakes up just to go to sleep immediately again and
|
||||||
|
makes Neko being awake something you can look forward to.
|
||||||
|
|
||||||
|
Refer to the man page or `--help` command to see how to use this fork and which
|
||||||
|
options are new or no longer available.
|
||||||
|
|
||||||
|
The following features are missing from this fork for now:
|
||||||
|
- Neko does not yet behave differently at night.
|
||||||
|
- Idle detection is working but implemented sloppily.
|
||||||
|
- Pointer following is currently removed.
|
||||||
|
- Waking up Neko with a signal is something that should be possible.
|
||||||
|
|
35
wayneko.1
35
wayneko.1
|
@ -2,7 +2,7 @@
|
||||||
.
|
.
|
||||||
.SH NAME
|
.SH NAME
|
||||||
.P
|
.P
|
||||||
wayneko \- Neko on Wayland
|
wayneko \- Neko on Wayland but with phases
|
||||||
.
|
.
|
||||||
.
|
.
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
|
@ -17,10 +17,9 @@ wayneko \- Neko on Wayland
|
||||||
.OP \-\-outline\-colour 0xRRGGBB[AA]
|
.OP \-\-outline\-colour 0xRRGGBB[AA]
|
||||||
.OP \-\-type neko|inu|random
|
.OP \-\-type neko|inu|random
|
||||||
.OP \-\-idle-sleep seconds
|
.OP \-\-idle-sleep seconds
|
||||||
.OP \-\-sleepiness num
|
.OP \-\-phase-sleep seconds-seconds
|
||||||
.OP \-\-sleepiness-night num
|
.OP \-\-phase-awake seconds-seconds
|
||||||
.OP \-\-layer background|bottom|top|overlay
|
.OP \-\-layer background|bottom|top|overlay
|
||||||
.OP \-\-follow\-pointer true|false
|
|
||||||
.OP \-\-survive\-close
|
.OP \-\-survive\-close
|
||||||
.YS
|
.YS
|
||||||
.
|
.
|
||||||
|
@ -70,18 +69,19 @@ idle.
|
||||||
.RE
|
.RE
|
||||||
.
|
.
|
||||||
.P
|
.P
|
||||||
\fB\-\-sleepiness\fR \fInum\fR
|
\fB\-\-phase-awake\fR \fIseconds-seconds\fR
|
||||||
.RS
|
.RS
|
||||||
Set neko's sleepiness as an integer (greater than 0). Higher values make neko
|
Set the duration of how long neko will be awake at a time. Takes a minimum
|
||||||
more sleepy. Defaults to 4.
|
and a maximum amount of seconds, separated by a dash. Actual duration will
|
||||||
|
be drawn uniformly at random between the two values. Defaults to 120-600.
|
||||||
.RE
|
.RE
|
||||||
.
|
.
|
||||||
.P
|
.P
|
||||||
\fB\-\-sleepiness-night\fR \fInum\fR
|
\fB\-\-phase-sleep\fR \fIseconds-seconds\fR
|
||||||
.RS
|
.RS
|
||||||
Set neko's sleepiness at night as an integer (greater than 0). Higher values
|
Set the duration of how long neko will sleep at a time. Takes a minimum
|
||||||
make neko more sleepy. This setting acts as an additional sleepiness on top of
|
and a maximum amount of seconds, separated by a dash. Actual duration will
|
||||||
the normal sleepiness. Defaults to 5.
|
be drawn uniformly at random between the two values. Defaults to 450-1800.
|
||||||
.RE
|
.RE
|
||||||
.
|
.
|
||||||
.P
|
.P
|
||||||
|
@ -95,12 +95,6 @@ Background may conflict with wallpaper clients.
|
||||||
.RE
|
.RE
|
||||||
.
|
.
|
||||||
.P
|
.P
|
||||||
\fB\-\-follow\-pointer\fR \fBtrue\fR|\fBfalse\fR
|
|
||||||
.RS
|
|
||||||
Set whether neko follows the pointer when it approaches the bottom of the output
|
|
||||||
.RE
|
|
||||||
.
|
|
||||||
.P
|
|
||||||
\fB\-\-survive\-close\fR
|
\fB\-\-survive\-close\fR
|
||||||
.RS
|
.RS
|
||||||
If this flag is used, wayneko will recreate the surface after it has been closed.
|
If this flag is used, wayneko will recreate the surface after it has been closed.
|
||||||
|
@ -112,10 +106,15 @@ close the surface for a different reason.
|
||||||
.
|
.
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
.P
|
.P
|
||||||
Code by
|
Original code by
|
||||||
.MT leonhenrik.plickat@stud.uni-goettingen.de
|
.MT leonhenrik.plickat@stud.uni-goettingen.de
|
||||||
Leon Henrik Plickat
|
Leon Henrik Plickat
|
||||||
.ME .
|
.ME .
|
||||||
|
.P
|
||||||
|
Fork with phases made by
|
||||||
|
.MT virtinstance@gmail.com
|
||||||
|
Virt
|
||||||
|
.ME .
|
||||||
.
|
.
|
||||||
.P
|
.P
|
||||||
Neko bitmaps taken from public domain.
|
Neko bitmaps taken from public domain.
|
||||||
|
|
207
wayneko.c
207
wayneko.c
|
@ -32,11 +32,10 @@ const char usage[] =
|
||||||
" --background-colour 0xRRGGBB[AA]\n"
|
" --background-colour 0xRRGGBB[AA]\n"
|
||||||
" --outline-colour 0xRRGGBB[AA]\n"
|
" --outline-colour 0xRRGGBB[AA]\n"
|
||||||
" --type neko|inu|random\n"
|
" --type neko|inu|random\n"
|
||||||
" --idle-sleep num\n"
|
" --idle-sleep num\n"
|
||||||
" --sleepiness num\n"
|
" --phase-sleep num-num\n"
|
||||||
" --sleepiness-night num\n"
|
" --phase-awake num-num\n"
|
||||||
" --layer background|bottom|top|overlay\n"
|
" --layer background|bottom|top|overlay\n"
|
||||||
" --follow-pointer true|false\n"
|
|
||||||
" --survive-close\n"
|
" --survive-close\n"
|
||||||
"\n";
|
"\n";
|
||||||
|
|
||||||
|
@ -73,19 +72,31 @@ enum Neko
|
||||||
NEKO_RUN_LEFT_2,
|
NEKO_RUN_LEFT_2,
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint16_t animation_timeout = 200;
|
const uint16_t animation_timeout = 200; /* milliseconds */
|
||||||
size_t animation_ticks_until_next_frame = 10;
|
size_t animation_ticks_until_next_frame = 10;
|
||||||
enum Neko current_neko = NEKO_STARE;
|
enum Neko current_neko = NEKO_STARE;
|
||||||
enum Type type = NEKO;
|
enum Type type = NEKO;
|
||||||
bool follow_pointer = true;
|
bool follow_pointer = false; // TODO: implement this again
|
||||||
bool recreate_surface_on_close = false;
|
bool recreate_surface_on_close = false;
|
||||||
enum zwlr_layer_shell_v1_layer layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
|
enum zwlr_layer_shell_v1_layer layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
|
||||||
|
|
||||||
struct ext_idle_notifier_v1 *idle_notifier = NULL;
|
struct ext_idle_notifier_v1 *idle_notifier = NULL;
|
||||||
uint32_t neko_idle_timeout_ms = 180000; /* 3 minutes. */
|
uint32_t neko_idle_timeout_ms = 180000; /* 3 minutes. */
|
||||||
|
|
||||||
int sleepiness = 4;
|
enum Phase {
|
||||||
int sleepiness_night = 5;
|
PHASE_AWAKE,
|
||||||
|
PHASE_SLEEP
|
||||||
|
};
|
||||||
|
typedef enum Phase Phase;
|
||||||
|
|
||||||
|
/* wayneko will wake up at startup */
|
||||||
|
Phase current_phase = PHASE_SLEEP;
|
||||||
|
size_t ticks_until_phase_change = 0;
|
||||||
|
|
||||||
|
uint32_t phase_sleep_min = 450;
|
||||||
|
uint32_t phase_sleep_max = 1800;
|
||||||
|
uint32_t phase_awake_min = 120;
|
||||||
|
uint32_t phase_awake_max = 600;
|
||||||
|
|
||||||
struct Seat
|
struct Seat
|
||||||
{
|
{
|
||||||
|
@ -167,15 +178,15 @@ static void handle_error (int signum)
|
||||||
{
|
{
|
||||||
const char *msg =
|
const char *msg =
|
||||||
"\n"
|
"\n"
|
||||||
"🐈 🐈 🐈\n"
|
|
||||||
"┌──────────────────────────────────────────┐\n"
|
"┌──────────────────────────────────────────┐\n"
|
||||||
"│ │\n"
|
"│ │\n"
|
||||||
"│ wayneko has crashed. │\n"
|
"│ wayneko has crashed :( │\n"
|
||||||
"│ │\n"
|
"│ │\n"
|
||||||
"│ This is likely a bug, so please │\n"
|
"│ This is likely a bug in the fork │\n"
|
||||||
"│ report this to the mailing list. │\n"
|
"│ you are running, so feel free to │\n"
|
||||||
|
"│ report your stuff there. │\n"
|
||||||
"│ │\n"
|
"│ │\n"
|
||||||
"│ ~leon_plickat/public-inbox@lists.sr.ht │\n"
|
"│ https://copeberg.org/virt/wayneko │\n"
|
||||||
"│ │\n"
|
"│ │\n"
|
||||||
"└──────────────────────────────────────────┘\n"
|
"└──────────────────────────────────────────┘\n"
|
||||||
"\n";
|
"\n";
|
||||||
|
@ -823,11 +834,8 @@ static bool animtation_neko_wants_sleep (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns true if new frame is needed. */
|
/** Returns true if new frame is needed. */
|
||||||
static bool animation_next_state_with_idle (void)
|
static bool animation_next_state_sleep(void) {
|
||||||
{
|
switch (current_neko) {
|
||||||
/* If no one is there (system is idle), neko gets bored and will sleep. */
|
|
||||||
switch (current_neko)
|
|
||||||
{
|
|
||||||
case NEKO_SLEEP_1:
|
case NEKO_SLEEP_1:
|
||||||
case NEKO_SLEEP_2:
|
case NEKO_SLEEP_2:
|
||||||
case NEKO_YAWN:
|
case NEKO_YAWN:
|
||||||
|
@ -919,39 +927,9 @@ static bool animation_next_state_with_hotspot (uint32_t x)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns true if new frame is needed. */
|
/** Returns true if new frame is needed. */
|
||||||
static bool animation_next_state_normal (void)
|
static bool animation_next_state_awake (void)
|
||||||
{
|
{
|
||||||
/* Sleep at night, but with a small chance to wake up and do something.
|
switch (current_neko) {
|
||||||
* If the neko is already awake, slightly higher chance to stay awake.
|
|
||||||
*/
|
|
||||||
const bool neko_is_sleeping = current_neko == NEKO_SLEEP_1 || current_neko == NEKO_SLEEP_2;
|
|
||||||
if ( animtation_neko_wants_sleep() && (( neko_is_sleeping && rand() % sleepiness_night != 0 ) || ( !neko_is_sleeping && rand() % 2 != 0 )) )
|
|
||||||
{
|
|
||||||
switch (current_neko)
|
|
||||||
{
|
|
||||||
case NEKO_RUN_RIGHT_1:
|
|
||||||
case NEKO_RUN_RIGHT_2:
|
|
||||||
case NEKO_RUN_LEFT_1:
|
|
||||||
case NEKO_RUN_LEFT_2:
|
|
||||||
animation_neko_do_stare(true);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case NEKO_SLEEP_1:
|
|
||||||
case NEKO_SLEEP_2:
|
|
||||||
animation_neko_do_sleep();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (rand() % 3 == 0)
|
|
||||||
animation_neko_do_yawn();
|
|
||||||
else
|
|
||||||
animation_neko_do_stare(false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (current_neko)
|
|
||||||
{
|
|
||||||
case NEKO_STARE:
|
case NEKO_STARE:
|
||||||
switch (rand() % 24)
|
switch (rand() % 24)
|
||||||
{
|
{
|
||||||
|
@ -960,9 +938,6 @@ static bool animation_next_state_normal (void)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
animation_neko_do_sleep();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
animation_neko_do_yawn();
|
animation_neko_do_yawn();
|
||||||
break;
|
break;
|
||||||
|
@ -1014,15 +989,10 @@ static bool animation_next_state_normal (void)
|
||||||
|
|
||||||
case NEKO_SLEEP_1:
|
case NEKO_SLEEP_1:
|
||||||
case NEKO_SLEEP_2:
|
case NEKO_SLEEP_2:
|
||||||
if ( rand() % sleepiness == 0 )
|
if ( rand() % 2 == 0 )
|
||||||
{
|
animation_neko_do_shock();
|
||||||
if ( rand() % 2 == 0 )
|
|
||||||
animation_neko_do_shock();
|
|
||||||
else
|
|
||||||
animation_neko_do_stare(false);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
animation_neko_do_sleep();
|
animation_neko_do_yawn();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case NEKO_SCRATCH_1:
|
case NEKO_SCRATCH_1:
|
||||||
|
@ -1041,12 +1011,6 @@ static bool animation_next_state_normal (void)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case NEKO_YAWN:
|
case NEKO_YAWN:
|
||||||
if ( rand() % 2 == 0 )
|
|
||||||
animation_neko_do_stare(false);
|
|
||||||
else
|
|
||||||
animation_neko_do_sleep();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case NEKO_SHOCK:
|
case NEKO_SHOCK:
|
||||||
animation_neko_do_stare(true);
|
animation_neko_do_stare(true);
|
||||||
return true;
|
return true;
|
||||||
|
@ -1056,27 +1020,61 @@ static bool animation_next_state_normal (void)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** called once per tick, checks for a phase change, and changes the phase if required */
|
||||||
|
static void check_phase(void) {
|
||||||
|
if (ticks_until_phase_change > 0)
|
||||||
|
ticks_until_phase_change--;
|
||||||
|
else {
|
||||||
|
// change phase
|
||||||
|
uint32_t min = 0, max = 0;
|
||||||
|
|
||||||
|
if (current_phase == PHASE_AWAKE) {
|
||||||
|
current_phase = PHASE_SLEEP;
|
||||||
|
min = phase_sleep_min;
|
||||||
|
max = phase_sleep_max;
|
||||||
|
} else {
|
||||||
|
current_phase = PHASE_AWAKE;
|
||||||
|
min = phase_awake_min;
|
||||||
|
max = phase_awake_max;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t phase_change_seconds = min + (((uint32_t) rand()) % (max - min));
|
||||||
|
ticks_until_phase_change = phase_change_seconds * 1000 / animation_timeout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns true if new frame is needed. */
|
/** Returns true if new frame is needed. */
|
||||||
static bool animation_next_state (void)
|
static bool animation_next_state (void)
|
||||||
{
|
{
|
||||||
|
check_phase();
|
||||||
|
|
||||||
if ( animation_ticks_until_next_frame > 0 )
|
if ( animation_ticks_until_next_frame > 0 )
|
||||||
{
|
{
|
||||||
animation_ticks_until_next_frame--;
|
animation_ticks_until_next_frame--;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool idle = false;
|
||||||
|
|
||||||
struct Seat *seat;
|
struct Seat *seat;
|
||||||
wl_list_for_each(seat, &seats, link)
|
wl_list_for_each(seat, &seats, link) {
|
||||||
{
|
if (seat->currently_idle) idle = true;
|
||||||
if (seat->currently_idle)
|
|
||||||
return animation_next_state_with_idle();
|
|
||||||
}
|
}
|
||||||
wl_list_for_each(seat, &seats, link)
|
|
||||||
{
|
if (false) {
|
||||||
if (seat->on_surface)
|
wl_list_for_each(seat, &seats, link) {
|
||||||
return animation_next_state_with_hotspot(seat->surface_x);
|
if (seat->on_surface)
|
||||||
|
return animation_next_state_with_hotspot(seat->surface_x);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return animation_next_state_normal();
|
|
||||||
|
Phase phase = current_phase;
|
||||||
|
if (idle) phase = PHASE_SLEEP;
|
||||||
|
|
||||||
|
if (phase == PHASE_SLEEP)
|
||||||
|
return animation_next_state_sleep();
|
||||||
|
else
|
||||||
|
return animation_next_state_awake();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************
|
/*************
|
||||||
|
@ -1397,6 +1395,9 @@ int main (int argc, char *argv[])
|
||||||
}
|
}
|
||||||
else if ( strcmp(argv[i], "--follow-pointer") == 0 )
|
else if ( strcmp(argv[i], "--follow-pointer") == 0 )
|
||||||
{
|
{
|
||||||
|
fprintf(stderr, "ERROR: Functionality for flag '--follow-pointer' is not yet implemented in this fork.\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
const char *t = get_argument(argc, argv, &i);
|
const char *t = get_argument(argc, argv, &i);
|
||||||
if ( t == NULL )
|
if ( t == NULL )
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
@ -1435,27 +1436,49 @@ int main (int argc, char *argv[])
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( strcmp(argv[i], "--sleepiness") == 0 )
|
else if ( strcmp(argv[i], "--awake-phase") == 0 )
|
||||||
{
|
{
|
||||||
const char *a = get_argument(argc, argv, &i);
|
char* a = get_argument(argc, argv, &i);
|
||||||
int i = atoi(a);
|
char* b = a;
|
||||||
if (i != 0)
|
|
||||||
sleepiness = abs(i) + 1;
|
while (*b != '-' && *b != 0) b++;
|
||||||
else
|
if (*b == 0) {
|
||||||
{
|
fprintf(stderr, "ERROR: Values in '%s' for flag '--awake-phase' are must be split by a dash.\n", a);
|
||||||
fprintf(stderr, "ERROR: Invalid argument '%s' for flag '--sleepiness'.\n", a);
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*b++ = 0;
|
||||||
|
int min = atoi(a);
|
||||||
|
int max = atoi(b);
|
||||||
|
|
||||||
|
if (min != 0 && max != 0 && max != min) {
|
||||||
|
phase_awake_min = (uint32_t) abs(min);
|
||||||
|
phase_awake_max = (uint32_t) abs(max);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "ERROR: Invalid numbers in argument '%s-%s' for flag '--awake-phase'.\n", a, b);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( strcmp(argv[i], "--sleepiness-night") == 0 )
|
else if ( strcmp(argv[i], "--sleep-phase") == 0 )
|
||||||
{
|
{
|
||||||
const char *a = get_argument(argc, argv, &i);
|
char* a = get_argument(argc, argv, &i);
|
||||||
int i = atoi(a);
|
char* b = a;
|
||||||
if (i != 0)
|
|
||||||
sleepiness_night = abs(i) + 1;
|
while (*b != '-' && *b != 0) b++;
|
||||||
else
|
if (*b == 0) {
|
||||||
{
|
fprintf(stderr, "ERROR: Values in '%s' for flag '--sleep-phase' are must be split by a dash.\n", a);
|
||||||
fprintf(stderr, "ERROR: Invalid argument '%s' for flag '--sleepiness-night'.\n", a);
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*b++ = 0;
|
||||||
|
int min = atoi(a);
|
||||||
|
int max = atoi(b);
|
||||||
|
|
||||||
|
if (min != 0 && max != 0 && max != min) {
|
||||||
|
phase_sleep_min = (uint32_t) abs(min);
|
||||||
|
phase_sleep_max = (uint32_t) abs(max);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "ERROR: Invalid numbers in argument '%s-%s' for flag '--sleep-phase'.\n", a, b);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue