diff --git a/README b/README index 0b17aab..92b2e69 100644 --- a/README +++ b/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. diff --git a/wayneko.1 b/wayneko.1 index 6eb8775..eb2016a 100644 --- a/wayneko.1 +++ b/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. diff --git a/wayneko.c b/wayneko.c index 4dfb36e..cb6199b 100644 --- a/wayneko.c +++ b/wayneko.c @@ -32,11 +32,10 @@ const char usage[] = " --background-colour 0xRRGGBB[AA]\n" " --outline-colour 0xRRGGBB[AA]\n" " --type neko|inu|random\n" - " --idle-sleep num\n" - " --sleepiness num\n" - " --sleepiness-night num\n" + " --idle-sleep 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); - } + if ( rand() % 2 == 0 ) + animation_neko_do_shock(); 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 (seat->on_surface) - return animation_next_state_with_hotspot(seat->surface_x); + + 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; } }