Gtk Window Motion Animation

GTK window motion animation?

You haven't said what sort of path you want the window to follow. If the path is some simple function of time -- that is, if you have a way to compute where you want the window to be at any given time -- you could try the method illustrated in following code. For the quite-simple menu in the example, it works ok on my Linux system and produces fairly smooth motion.

The key to the method is that instead of moving the window a given distance per timer event, it finds out the current time and moves the window to the location it should be at, at that time. Thus, the time derivative of speed of motion should be constant, which avoids ragged or choppy motion even if timer events occur irregularly. (As noted in g-timeout-add() description, irregularity can easily occur.)

In this example, the path is from top left of window to bottom left and back, repeatedly. The constant 'HalfTime' in timerEvent() controls how long it takes to move from corner to corner. The constant 3 in the g_timeout_add() call sets the timer interval to 0.003 seconds, or about 333 moves per second (MPS). (You may want to try more-reasonable rates, such as 20, 30, 40, etc MPS; I used the number 3 because I didn't look up g-timeout-add() before using it, and assumed the delay was hundreths of seconds, for about 33 MPS, rather than milliseconds, for about 333 MPS.) If your window contents are quite complex, fewer MPS will be practical. Also, I tried some slower rates and got more of an impression of choppiness.

/* $Id: app12.c $
Re: animating position of a top-level Gtk window
jiw July 2011 -- Offered without warranty under GPL v3
terms per http://www.gnu.org/licenses/gpl.html */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <gtk/gtk.h>
typedef struct DATA { GTimer *timer; GtkWidget *window; int w, h; }
DataStruct;

gboolean timerEvent(void *dataset) {
enum { HalfTime=8, CycTime=2*HalfTime };
gulong micros;
DataStruct *data =dataset;
double t = fabs(fmod (g_timer_elapsed (data->timer, µs), CycTime));
int x = (t*data->w)/HalfTime, y = (t*data->h)/HalfTime;
gtk_window_move (GTK_WINDOW(data->window),
t<HalfTime? x : 2*data->w-x, t<HalfTime? y : 2*data->h-y);
return TRUE; /* Keep timeout running */
}

int main(int argc, char **argv) {
GtkWidget *vbox, *b;
GdkScreen *gds;
DataStruct data;
data.timer = g_timer_new();
gtk_init (&argc, &argv);
data.window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW(data.window), 200, 150);
g_signal_connect (G_OBJECT(data.window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
vbox = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER(data.window), vbox);
b = gtk_button_new_with_label ("Click to Exit");
gtk_box_pack_start (GTK_BOX(vbox), b, TRUE, TRUE, TRUE);
g_signal_connect (b, "clicked", G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all (data.window);

gds = gdk_screen_get_default (); /* Get pointer to screen */
data.w = gdk_screen_get_width (gds); /* Find out screen width */
data.h = gdk_screen_get_height (gds); /* Find out screen height */
printf ("Screen size = %d by %d\n", data.w, data.h); fflush(stdout);
g_timeout_add(3, timerEvent, &data); /* Create .003 sec timer */
gtk_main();
return (0);
}

A way to animate transition with Python, Gtk and Cairo?

gobject.timeout_add() can be used for finite animations. The callback you set up will keep being called until it returns False, at which point your method won't be called again.

For example, if you want a ball to be animated for 5 seconds, you would be responsible for determining how long the animation has been going, and then once it has passed 5 seconds, your method would return False to end the animation. When you want the animation to start again, simply re-register the callback with timeout_add and reset your time counter.

See: http://www.pygtk.org/pygtk2reference/gobject-functions.html#function-gobject--timeout-add for more information.

Very Simple Smooth Animation with GTK+2 and Cairo

Not so smooth ? Well, with a period of 100ms, you're drawing at best 10 frames per second, no wonder it's not smooth... You should aim for 60 fps. Furthermore, you're invalidating the whole widget by calling gtk_widget_queue_draw, so your call to cairo_clip is mostly useless, as the clipping region is the whole widget. You should call gtk_widget_queue_draw_area instead so your clipping region is useful, and determining the area by keeping a record of the animation at frame n and n-1, so you redraw both areas to avoid the previous frame not being deleted.

There are lots of interesting stuff on animation perception on Owen Tailor's blog, starting with this post and more recent:

http://blog.fishsoup.net/2009/05/28/frames-not-idles/

Give a look at all the posts with figures, it's a gold mine.

GTK subclass component

There is the "draw" signal, RTM g_signal_connect (widget, "draw", G_CALLBACK (your_callback), fancy_extra_state_data_you_may_need_or_not);

gtk3/gtk2hs: panning in a scrolledWindow flickers

Your problem is caused by the fact that you keep yanking the viewport around while you are also listening to motion events on it.

The simple solution I've found is to wrap your scrolledWindow in a GtkEventBox (I've called in eventbox in my code) and then attach the event listener to that. This way, the widget you are listening on doesn't move around (it's the fixed GtkEventBox).

eventbox <- builderGetObject builder castToEventBox "eventbox"
viewport <- builderGetObject builder castToViewport "viewport"
initViewportPanning eventbox viewport

with initViewportPanning changed slightly to allow a different event source than its target:

initViewportPanning :: (WidgetClass src, ViewportClass target)
=> src -> target -> IO (ConnectId src)
initViewportPanning src target = do
widgetAddEvents src [Button1MotionMask]
-- ...
on src buttonPressEvent $ do
-- unchanged
on src motionNotifyEvent $ do
-- unchanged

I'm getting silky-smooth panning this way.

How do I change the `prefers-reduced-motion` setting in browsers?

Oh, I didn't see the "User Preferences" section in the mdn documentation. ‍♂️

For Firefox, the reduce request is honoured if:

  • In GTK/Gnome, if gtk-enable-animations is set to false. This is configurable via GNOME Tweaks (Appearance tab or General tab, depending on version).
    • Alternately, add gtk-enable-animations = false to the [Settings] block of the GTK 3 configuration file (~/.config/gtk-3.0/settings.ini).
  • In Windows 10: Settings > Ease of Access > Display > Show animations in Windows.
  • In Window 7 [& 8]: Control Panel > Ease of Access > Make the computer easier to see > Turn off all unnecessary animations (when possible).
  • In macOS: System Preferences > Accessibility > Display > Reduce motion.
  • In iOS: Settings > General > Accessibility > Reduce Motion.
  • In Android 9+: Settings > Accessibility > Remove animations.

Source: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion#User_Preferences

It says "for Firefox" however since this is a system setting at the OS level, this is likely how you change the setting for all browsers that support this media query.

Weird Post-Run Animation Error

Most likely your tiemout_add fires while the application is destroyed.
Your options are:

  1. Wire a destroy handler and remove the timer before exit.
  2. Topmost inside move_fish, check if the widget is destroyed and return False to end the timer.

Accessing a widget that no longer exists can fail silently but when your application logic changes, it may even segfault noisily.

Pango Markup on Expander Label

Pango font sizes are not in points (like HTML/CSS), but rather thousandths of points. So size="18" means your font size is 0.018 points, which is too small to read. Change it to size="18000" and it will work as intended.



Related Topics



Leave a reply



Submit