mortie / swaylock-effects

Swaylock, with fancy effects
MIT License
708 stars 45 forks source link

Feature: GIF playback on input #27

Open LordCMonkey opened 3 years ago

LordCMonkey commented 3 years ago

I added a --gif <path> option, which allows for any GIF to be chosen and displayed on the lock screen, where the frames advance only while typing. For regular password input, the GIF advances by one frame per keystroke, backspace reverses one frame, and clearing (Ctrl+C), password rejection (wrong password) aswell as idling resets the GIF to the first frame.

All GIF related variables are stored in the form of struct swaylock_gif from include/swaylock.h in swaylock_state.

The GIF itself is loaded by gdk as an pixbuf animation in main.c, via the function static void load_gif(char *arg, struct swaylock_state *state) (line 717) where the arg is the path given in the CLI option.

To advance the GIF by one frame per Keystroke (and currently also once a second when the clock is updated, although this behaviour is not intended), an iterator (state->gif.iter) provided by gdk pixbuf is tricked. The iterator chooses the frame to display based on a timestamp in this function: gdk_pixbuf_animation_iter_advance(state->gif.iter, state->gif.time);, where gif.time is a struct called GTimeVal which contains seconds and microseconds. The timestamp is updated upon every call to void render_frame(struct swaylock_surface *surface) in render.c. The first frame is always shown when the seconds and microseconds in gif.time are set to 0. When the frame should switch to the next frame, the GIF specific delay (found in state->gif.delay) is added to or substracted from the current microseconds. Thereafter, the new frame is returned as a pixbuf and painted to the current surface using gdk_cairo_set_source_pixbuf(cairo, state->gif.pixbuf, 0, 0); und applied via cairo_paint(cairo);.

Currently, the GIF is painted to the same surface the indicator is on, as i did not entirely catch on to the window/surface handling in the project, and only unsuccesfully fumbled around with it (the struct wl_list link in state->gif is a remnant of this), aswell as https://github.com/mortie/swaylock-effects/issues/17#issuecomment-628587297.

Since the GIF does not feature its own surface, the indicator radius is set to double its width in line 1498 of main.c. This is necessary to fit the whole gif onto the indicator surface, as they will get clipped and not shown entirely if the radius and thus the surface is too small. This is rather ugly and only works properly (centers) square GIFs.

This feature adds gtk as a dependency to the project.

Anyways, i like the result, especially with this GIF (works well with the clock inside and a long password). For the clock and the datestring to be properly formatted, and the indicator invisible, i use the following swaylock command: ./swaylock --gif ~/Pictures/lockgif.gif --inside-color 00000000 --ring-color 00000000 --line-color 00000000 --indicator-thickness 0 -e --font-size 26 --text-color AAAAAAAA --inside-ver-color 00000000 --inside-clear-color 00000000 --inside-wrong-color FF000044 and changed two options of text handling in render.c, on line 362 and 368 to have the datestring follow the --font-size option and have its y-offset be independent from the indicator radius.

I do invite you to give it a try (maybe with the suggested GIF and command), and would like to hear your opinion.

mortie commented 3 years ago

Hmm, I'm not sure if I see the need for this feature. I checked out your branch and tried your example command, but it feels like a very niche feature which I can't really see the use case for. It's possible I could be convinced otherwise though if I saw some impressive example uses. If that doesn't happen, feel free to maintain your own fork.

Regardless, some comments about the code:

LordCMonkey commented 3 years ago

Hey there, thanks for your feedback! I will try to change the _GTimeVal usage, and then play around with different settings and gifs to (hopefully) produce some cool lockscreen effects. The gtk dependency stems from gdk_cairo_set_source_pixbuf(), as cairo paints directly from a pixbuf to a separate surface. This is not needed in the already existing background image option, as there the image does not change and upon loading a new surface gets created, which is later on attached and commited to the buffer swaylock surface using wl_surface functions. Maybe this behaviour could be copied for the gif though, i'll have a look.

damianatorrpm commented 3 years ago

would this allow to show password while you type?

LordCMonkey commented 3 years ago

well, you could create a gif of your password being typed frame by frame.