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
|
||||
server to implement zwlr-layer-shell-unstable-v1. All code is licensed under
|
||||
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
|
||||
.P
|
||||
wayneko \- Neko on Wayland
|
||||
wayneko \- Neko on Wayland but with phases
|
||||
.
|
||||
.
|
||||
.SH SYNOPSIS
|
||||
|
@ -17,10 +17,9 @@ wayneko \- Neko on Wayland
|
|||
.OP \-\-outline\-colour 0xRRGGBB[AA]
|
||||
.OP \-\-type neko|inu|random
|
||||
.OP \-\-idle-sleep seconds
|
||||
.OP \-\-sleepiness num
|
||||
.OP \-\-sleepiness-night num
|
||||
.OP \-\-phase-sleep seconds-seconds
|
||||
.OP \-\-phase-awake seconds-seconds
|
||||
.OP \-\-layer background|bottom|top|overlay
|
||||
.OP \-\-follow\-pointer true|false
|
||||
.OP \-\-survive\-close
|
||||
.YS
|
||||
.
|
||||
|
@ -70,18 +69,19 @@ idle.
|
|||
.RE
|
||||
.
|
||||
.P
|
||||
\fB\-\-sleepiness\fR \fInum\fR
|
||||
\fB\-\-phase-awake\fR \fIseconds-seconds\fR
|
||||
.RS
|
||||
Set neko's sleepiness as an integer (greater than 0). Higher values make neko
|
||||
more sleepy. Defaults to 4.
|
||||
Set the duration of how long neko will be awake at a time. Takes a minimum
|
||||
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
|
||||
.
|
||||
.P
|
||||
\fB\-\-sleepiness-night\fR \fInum\fR
|
||||
\fB\-\-phase-sleep\fR \fIseconds-seconds\fR
|
||||
.RS
|
||||
Set neko's sleepiness at night as an integer (greater than 0). Higher values
|
||||
make neko more sleepy. This setting acts as an additional sleepiness on top of
|
||||
the normal sleepiness. Defaults to 5.
|
||||
Set the duration of how long neko will sleep at a time. Takes a minimum
|
||||
and a maximum amount of seconds, separated by a dash. Actual duration will
|
||||
be drawn uniformly at random between the two values. Defaults to 450-1800.
|
||||
.RE
|
||||
.
|
||||
.P
|
||||
|
@ -95,12 +95,6 @@ Background may conflict with wallpaper clients.
|
|||
.RE
|
||||
.
|
||||
.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
|
||||
.RS
|
||||
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
|
||||
.P
|
||||
Code by
|
||||
Original code by
|
||||
.MT leonhenrik.plickat@stud.uni-goettingen.de
|
||||
Leon Henrik Plickat
|
||||
.ME .
|
||||
.P
|
||||
Fork with phases made by
|
||||
.MT virtinstance@gmail.com
|
||||
Virt
|
||||
.ME .
|
||||
.
|
||||
.P
|
||||
Neko bitmaps taken from public domain.
|
||||
|
|
197
wayneko.c
197
wayneko.c
|
@ -33,10 +33,9 @@ const char usage[] =
|
|||
" --outline-colour 0xRRGGBB[AA]\n"
|
||||
" --type neko|inu|random\n"
|
||||
" --idle-sleep num\n"
|
||||
" --sleepiness num\n"
|
||||
" --sleepiness-night num\n"
|
||||
" --phase-sleep num-num\n"
|
||||
" --phase-awake num-num\n"
|
||||
" --layer background|bottom|top|overlay\n"
|
||||
" --follow-pointer true|false\n"
|
||||
" --survive-close\n"
|
||||
"\n";
|
||||
|
||||
|
@ -73,19 +72,31 @@ enum Neko
|
|||
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;
|
||||
enum Neko current_neko = NEKO_STARE;
|
||||
enum Type type = NEKO;
|
||||
bool follow_pointer = true;
|
||||
bool follow_pointer = false; // TODO: implement this again
|
||||
bool recreate_surface_on_close = false;
|
||||
enum zwlr_layer_shell_v1_layer layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
|
||||
|
||||
struct ext_idle_notifier_v1 *idle_notifier = NULL;
|
||||
uint32_t neko_idle_timeout_ms = 180000; /* 3 minutes. */
|
||||
|
||||
int sleepiness = 4;
|
||||
int sleepiness_night = 5;
|
||||
enum Phase {
|
||||
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
|
||||
{
|
||||
|
@ -167,15 +178,15 @@ static void handle_error (int signum)
|
|||
{
|
||||
const char *msg =
|
||||
"\n"
|
||||
"🐈 🐈 🐈\n"
|
||||
"┌──────────────────────────────────────────┐\n"
|
||||
"│ │\n"
|
||||
"│ wayneko has crashed. │\n"
|
||||
"│ wayneko has crashed :( │\n"
|
||||
"│ │\n"
|
||||
"│ This is likely a bug, so please │\n"
|
||||
"│ report this to the mailing list. │\n"
|
||||
"│ This is likely a bug in the fork │\n"
|
||||
"│ you are running, so feel free to │\n"
|
||||
"│ report your stuff there. │\n"
|
||||
"│ │\n"
|
||||
"│ ~leon_plickat/public-inbox@lists.sr.ht │\n"
|
||||
"│ https://copeberg.org/virt/wayneko │\n"
|
||||
"│ │\n"
|
||||
"└──────────────────────────────────────────┘\n"
|
||||
"\n";
|
||||
|
@ -823,11 +834,8 @@ static bool animtation_neko_wants_sleep (void)
|
|||
}
|
||||
|
||||
/** Returns true if new frame is needed. */
|
||||
static bool animation_next_state_with_idle (void)
|
||||
{
|
||||
/* If no one is there (system is idle), neko gets bored and will sleep. */
|
||||
switch (current_neko)
|
||||
{
|
||||
static bool animation_next_state_sleep(void) {
|
||||
switch (current_neko) {
|
||||
case NEKO_SLEEP_1:
|
||||
case NEKO_SLEEP_2:
|
||||
case NEKO_YAWN:
|
||||
|
@ -919,39 +927,9 @@ static bool animation_next_state_with_hotspot (uint32_t x)
|
|||
}
|
||||
|
||||
/** 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.
|
||||
* 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)
|
||||
{
|
||||
switch (current_neko) {
|
||||
case NEKO_STARE:
|
||||
switch (rand() % 24)
|
||||
{
|
||||
|
@ -960,9 +938,6 @@ static bool animation_next_state_normal (void)
|
|||
break;
|
||||
|
||||
case 1:
|
||||
animation_neko_do_sleep();
|
||||
break;
|
||||
|
||||
case 2:
|
||||
animation_neko_do_yawn();
|
||||
break;
|
||||
|
@ -1014,15 +989,10 @@ static bool animation_next_state_normal (void)
|
|||
|
||||
case NEKO_SLEEP_1:
|
||||
case NEKO_SLEEP_2:
|
||||
if ( rand() % sleepiness == 0 )
|
||||
{
|
||||
if ( rand() % 2 == 0 )
|
||||
animation_neko_do_shock();
|
||||
else
|
||||
animation_neko_do_stare(false);
|
||||
}
|
||||
else
|
||||
animation_neko_do_sleep();
|
||||
animation_neko_do_yawn();
|
||||
return true;
|
||||
|
||||
case NEKO_SCRATCH_1:
|
||||
|
@ -1041,12 +1011,6 @@ static bool animation_next_state_normal (void)
|
|||
return true;
|
||||
|
||||
case NEKO_YAWN:
|
||||
if ( rand() % 2 == 0 )
|
||||
animation_neko_do_stare(false);
|
||||
else
|
||||
animation_neko_do_sleep();
|
||||
return true;
|
||||
|
||||
case NEKO_SHOCK:
|
||||
animation_neko_do_stare(true);
|
||||
return true;
|
||||
|
@ -1056,27 +1020,61 @@ static bool animation_next_state_normal (void)
|
|||
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. */
|
||||
static bool animation_next_state (void)
|
||||
{
|
||||
check_phase();
|
||||
|
||||
if ( animation_ticks_until_next_frame > 0 )
|
||||
{
|
||||
animation_ticks_until_next_frame--;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool idle = false;
|
||||
|
||||
struct Seat *seat;
|
||||
wl_list_for_each(seat, &seats, link)
|
||||
{
|
||||
if (seat->currently_idle)
|
||||
return animation_next_state_with_idle();
|
||||
wl_list_for_each(seat, &seats, link) {
|
||||
if (seat->currently_idle) idle = true;
|
||||
}
|
||||
wl_list_for_each(seat, &seats, link)
|
||||
{
|
||||
|
||||
if (false) {
|
||||
wl_list_for_each(seat, &seats, link) {
|
||||
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 )
|
||||
{
|
||||
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);
|
||||
if ( t == NULL )
|
||||
return EXIT_FAILURE;
|
||||
|
@ -1435,27 +1436,49 @@ int main (int argc, char *argv[])
|
|||
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);
|
||||
int i = atoi(a);
|
||||
if (i != 0)
|
||||
sleepiness = abs(i) + 1;
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "ERROR: Invalid argument '%s' for flag '--sleepiness'.\n", a);
|
||||
char* a = get_argument(argc, argv, &i);
|
||||
char* b = a;
|
||||
|
||||
while (*b != '-' && *b != 0) b++;
|
||||
if (*b == 0) {
|
||||
fprintf(stderr, "ERROR: Values in '%s' for flag '--awake-phase' are must be split by a dash.\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;
|
||||
}
|
||||
}
|
||||
else if ( strcmp(argv[i], "--sleepiness-night") == 0 )
|
||||
else if ( strcmp(argv[i], "--sleep-phase") == 0 )
|
||||
{
|
||||
const char *a = get_argument(argc, argv, &i);
|
||||
int i = atoi(a);
|
||||
if (i != 0)
|
||||
sleepiness_night = abs(i) + 1;
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "ERROR: Invalid argument '%s' for flag '--sleepiness-night'.\n", a);
|
||||
char* a = get_argument(argc, argv, &i);
|
||||
char* b = a;
|
||||
|
||||
while (*b != '-' && *b != 0) b++;
|
||||
if (*b == 0) {
|
||||
fprintf(stderr, "ERROR: Values in '%s' for flag '--sleep-phase' are must be split by a dash.\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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue