1 /* Clearlooks theme engine
3 * Copyright (C) 2006 Kulyk Nazar <schamane@myeburg.net>
4 * Copyright (C) 2006 Benjamin Berg <benjamin@sipsolutions.net>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
23 /* This code is responsible for the clearlooks animation support. The code
24 * works by forcing a redraw on the animated widget.
27 #include "animation.h"
30 #include <glib/gtimer.h>
32 struct _AnimationInfo
{
35 gdouble start_modifier
;
39 typedef struct _AnimationInfo AnimationInfo
;
45 typedef struct _SignalInfo SignalInfo
;
47 static GSList
*connected_widgets
= NULL
;
48 static GHashTable
*animated_widgets
= NULL
;
49 static int animation_timer_id
= 0;
52 static gboolean
animation_timeout_handler (gpointer data
);
54 /* This forces a redraw on a widget */
56 force_widget_redraw (GtkWidget
*widget
)
58 if (GE_IS_PROGRESS_BAR (widget
))
59 gtk_widget_queue_resize (widget
);
61 gtk_widget_queue_draw (widget
);
64 /* ensures that the timer is running */
68 if (animation_timer_id
== 0)
69 animation_timer_id
= g_timeout_add (ANIMATION_DELAY
, animation_timeout_handler
, NULL
);
72 /* ensures that the timer is stopped */
76 if (animation_timer_id
!= 0)
78 g_source_remove(animation_timer_id
);
79 animation_timer_id
= 0;
84 /* destroys an AnimationInfo structure including the GTimer */
86 animation_info_destroy (AnimationInfo
*animation_info
)
88 g_timer_destroy (animation_info
->timer
);
89 g_free (animation_info
);
93 /* This function does not unref the weak reference, because the object
94 * is beeing destroyed currently. */
96 on_animated_widget_destruction (gpointer data
, GObject
*object
)
98 /* steal the animation info from the hash table (destroying it would
99 * result in the weak reference to be unrefed, which does not work
100 * as the widget is already destroyed. */
101 g_hash_table_steal (animated_widgets
, object
);
102 animation_info_destroy ((AnimationInfo
*) data
);
105 /* This function also needs to unref the weak reference. */
107 destroy_animation_info_and_weak_unref (gpointer data
)
109 AnimationInfo
*animation_info
= data
;
111 /* force a last redraw. This is so that if the animation is removed,
112 * the widget is left in a sane state. */
113 force_widget_redraw (animation_info
->widget
);
115 g_object_weak_unref (G_OBJECT (animation_info
->widget
), on_animated_widget_destruction
, data
);
116 animation_info_destroy (animation_info
);
119 /* Find and return a pointer to the data linked to this widget, if it exists */
120 static AnimationInfo
*
121 lookup_animation_info (const GtkWidget
*widget
)
123 if (animated_widgets
)
124 return g_hash_table_lookup (animated_widgets
, widget
);
129 /* Create all the relevant information for the animation, and insert it into the hash table. */
131 add_animation (const GtkWidget
*widget
, gdouble stop_time
)
133 AnimationInfo
*value
;
135 /* object already in the list, do not add it twice */
136 if (lookup_animation_info (widget
))
139 if (animated_widgets
== NULL
)
140 animated_widgets
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
141 NULL
, destroy_animation_info_and_weak_unref
);
143 value
= g_new(AnimationInfo
, 1);
145 value
->widget
= (GtkWidget
*) widget
;
147 value
->timer
= g_timer_new ();
148 value
->stop_time
= stop_time
;
149 value
->start_modifier
= 0.0;
151 g_object_weak_ref (G_OBJECT (widget
), on_animated_widget_destruction
, value
);
152 g_hash_table_insert (animated_widgets
, (GtkWidget
*) widget
, value
);
157 /* update the animation information for each widget. This will also queue a redraw
158 * and stop the animation if it is done. */
160 update_animation_info (gpointer key
, gpointer value
, gpointer user_data
)
164 AnimationInfo
*animation_info
= value
;
165 GtkWidget
*widget
= key
;
167 g_assert ((widget
!= NULL
) && (animation_info
!= NULL
));
169 /* remove the widget from the hash table if it is not drawable */
170 if (!GTK_WIDGET_DRAWABLE (widget
))
175 if (GE_IS_PROGRESS_BAR (widget
))
177 gfloat fraction
= gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR (widget
));
179 /* stop animation for filled/not filled progress bars */
180 if (fraction
<= 0.0 || fraction
>= 1.0)
184 force_widget_redraw (widget
);
186 /* stop at stop_time */
187 if (animation_info
->stop_time
!= 0 &&
188 g_timer_elapsed (animation_info
->timer
, NULL
) > animation_info
->stop_time
)
194 /* This gets called by the glib main loop every once in a while. */
196 animation_timeout_handler (gpointer data
)
200 /*g_print("** TICK **\n");*/
202 /* enter threads as update_animation_info will use gtk/gdk. */
203 gdk_threads_enter ();
204 g_hash_table_foreach_remove (animated_widgets
, update_animation_info
, NULL
);
205 /* leave threads again */
206 gdk_threads_leave ();
208 if(g_hash_table_size(animated_widgets
)==0)
218 on_checkbox_toggle (GtkWidget
*widget
, gpointer data
)
222 AnimationInfo
*animation_info
= lookup_animation_info (widget
);
224 if (animation_info
!= NULL
)
226 gfloat elapsed
= g_timer_elapsed (animation_info
->timer
, NULL
);
228 animation_info
->start_modifier
= elapsed
- animation_info
->start_modifier
;
232 add_animation (widget
, CHECK_ANIMATION_TIME
);
237 on_connected_widget_destruction (gpointer data
, GObject
*widget
)
241 connected_widgets
= g_slist_remove (connected_widgets
, data
);
246 disconnect_all_signals ()
248 GSList
* item
= connected_widgets
;
251 SignalInfo
*signal_info
= (SignalInfo
*) item
->data
;
253 g_signal_handler_disconnect (signal_info
->widget
, signal_info
->handler_id
);
254 g_object_weak_unref (G_OBJECT (signal_info
->widget
), on_connected_widget_destruction
, signal_info
);
255 g_free (signal_info
);
257 item
= g_slist_next (item
);
260 g_slist_free (connected_widgets
);
261 connected_widgets
= NULL
;
264 /* helper function for clearlooks_animation_connect_checkbox */
266 find_signal_info (gconstpointer signal_info
, gconstpointer widget
)
268 if (((SignalInfo
*)signal_info
)->widget
== widget
)
275 /* external interface */
277 /* adds a progress bar */
279 clearlooks_animation_progressbar_add (GtkWidget
*progressbar
)
281 gdouble fraction
= gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR (progressbar
));
283 if (fraction
< 1.0 && fraction
> 0.0)
284 add_animation ((GtkWidget
*) progressbar
, 0.0);
287 /* hooks up the signals for check and radio buttons */
289 clearlooks_animation_connect_checkbox (GtkWidget
*widget
)
291 if (GE_IS_CHECK_BUTTON (widget
))
293 if (!g_slist_find_custom (connected_widgets
, widget
, find_signal_info
))
295 SignalInfo
* signal_info
= g_new (SignalInfo
, 1);
297 signal_info
->widget
= widget
;
298 signal_info
->handler_id
= g_signal_connect ((GObject
*)widget
, "toggled", G_CALLBACK (on_checkbox_toggle
), NULL
);
300 connected_widgets
= g_slist_append (connected_widgets
, signal_info
);
301 g_object_weak_ref (G_OBJECT (widget
), on_connected_widget_destruction
, signal_info
);
306 /* returns TRUE if the widget is animated, and FALSE otherwise */
308 clearlooks_animation_is_animated (GtkWidget
*widget
)
310 return lookup_animation_info (widget
) != NULL
? TRUE
: FALSE
;
313 /* returns the elapsed time for the animation */
315 clearlooks_animation_elapsed (gpointer data
)
317 AnimationInfo
*animation_info
= lookup_animation_info (data
);
320 return g_timer_elapsed (animation_info
->timer
, NULL
)
321 - animation_info
->start_modifier
;
326 /* cleans up all resources of the animation system */
328 clearlooks_animation_cleanup ()
330 disconnect_all_signals ();
332 if (animated_widgets
!= NULL
)
334 g_hash_table_destroy (animated_widgets
);
335 animated_widgets
= NULL
;
340 #else /* !HAVE_ANIMATION */
341 static void clearlooks_animation_dummy_function_so_wall_shuts_up_when_animations_is_disabled()
343 clearlooks_animation_dummy_function_so_wall_shuts_up_when_animations_is_disabled();
345 #endif /* HAVE_ANIMATION */