9156cdc8d34379cedef31f28a6f878ea6df48294
[eyes-widget] / src / eyes.c
1 /* $Id: eyes.c 2397 2007-01-17 17:46:35Z nick $
2  * 
3  * Copyright (c) Benedikt Meurer <benedikt.meurer@unix-ag.uni-siegen.de>>
4  * Copyright (c) Danny Milosavljevic <danny_milo@gmx.net>
5  * Copyright (c) Dave Camp
6  * Copyright (c) Davyd Madeley  <davyd@madeley.id.au>
7  * Copyright (c) Nick Schermer <nick@xfce.org>
8  * Copyright (c) Mikko Vartiainen <mvartiainen@gmail.com>
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License as published by the Free
12  * Software Foundation; either version 2 of the License, or (at your option)
13  * any later version.
14  *
15  * This program is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
18  * more details.
19  *
20  * You should have received a copy of the GNU General Public License along with
21  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22  * Place, Suite 330, Boston, MA  02111-1307  USA
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #ifdef HAVE_MATH_H
30 #include <math.h>
31 #endif
32
33 #include <sys/types.h>
34 #include <dirent.h>
35 #include <string.h>
36
37 #include <libhildondesktop/libhildondesktop.h>
38
39 #include "eyes.h"
40 #include "themes.h"
41 #include "accelerometer.h"
42
43 /* for xml: */
44 #define EYES_ROOT      "Eyes"
45 #define DEFAULTTHEME   "Default"
46 #define UPDATE_TIMEOUT 100
47
48 #define EYES_PLUGIN_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE (obj, \
49                                                                    EYES_TYPE_HOME_PLUGIN, \
50                                                                    EyesPluginContent))
51
52 HD_DEFINE_PLUGIN_MODULE (EyesPlugin, eyes_plugin,      HD_TYPE_HOME_PLUGIN_ITEM)
53
54 /*****************************
55  *** Eyes Plugin Functions ***
56  *****************************/
57 static void
58 calculate_pupil_xy (EyesPluginContent *eyes_applet,
59                     gint x, gint y,
60                     gint *pupil_x, gint *pupil_y, GtkWidget* widget)
61 {
62   double sina;
63   double cosa;
64   double h;
65   double temp;
66   double nx, ny;
67
68   gfloat xalign, yalign;
69   gint width, height;
70
71   width = GTK_WIDGET(widget)->allocation.width;
72   height = GTK_WIDGET(widget)->allocation.height;
73   gtk_misc_get_alignment(GTK_MISC(widget),  &xalign, &yalign);
74
75   nx = width*x/1000.0;
76   ny = height*y/1000.0;
77
78   h = hypot (nx, ny);
79
80   if ( nx*nx/((eyes_applet->eye_width/2.0 - eyes_applet->pupil_width / 2)*(eyes_applet->eye_width/2.0 - eyes_applet->pupil_width/2)) + ny*ny/((eyes_applet->eye_height/2 - eyes_applet->pupil_height/2)*(eyes_applet->eye_height/2 - eyes_applet->pupil_height/2)) < 1 )
81     {
82       *pupil_x = nx + eyes_applet->eye_width / 2;
83       *pupil_y = ny + eyes_applet->eye_height / 2;
84       return;
85     }
86
87   sina = nx / h;
88   cosa = ny / h;
89
90   temp = hypot ((eyes_applet->eye_width / 2) * sina, (eyes_applet->eye_height / 2) * cosa);
91   temp -= hypot ((eyes_applet->pupil_width / 2) * sina, (eyes_applet->pupil_height / 2) * cosa);
92   temp -= hypot ((eyes_applet->wall_thickness / 2) * sina, (eyes_applet->wall_thickness / 2) * cosa);
93
94   *pupil_x = temp * sina + (eyes_applet->eye_width / 2);
95   *pupil_y = temp * cosa + (eyes_applet->eye_height / 2);
96 }
97
98 static void
99 draw_eye (EyesPluginContent *eyes,
100           gint    eye_num,
101           gint    pupil_x,
102           gint    pupil_y)
103 {
104   GdkPixbuf *pixbuf;
105   GdkRectangle rect, r1, r2;
106
107   pixbuf = gdk_pixbuf_copy (eyes->eye_image);
108   r1.x = pupil_x - eyes->pupil_width / 2;
109   r1.y = pupil_y - eyes->pupil_height / 2;
110   r1.width = eyes->pupil_width;
111   r1.height = eyes->pupil_height;
112   r2.x = 0;
113   r2.y = 0;
114   r2.width = eyes->eye_width;
115   r2.height = eyes->eye_height;
116   if (gdk_rectangle_intersect (&r1, &r2, &rect))
117     {
118       gdk_pixbuf_composite (eyes->pupil_image, pixbuf,
119                             rect.x,
120                             rect.y,
121                             rect.width,
122                             rect.height,
123                             pupil_x - eyes->pupil_width / 2,
124                             pupil_y - eyes->pupil_height / 2, 1.0, 1.0,
125                             GDK_INTERP_BILINEAR,
126                             255);
127       gtk_image_set_from_pixbuf (GTK_IMAGE (eyes->eyes[eye_num]),
128                                  pixbuf);
129     }
130   g_object_unref (G_OBJECT (pixbuf));
131 }
132
133 static gint
134 timer_cb(EyesPluginContent *eyes)
135 {
136   gint x, y, z;
137   gint pupil_x, pupil_y;
138   gint i;
139
140   for (i = 0; i < eyes->num_eyes; i++)
141     {
142       if (GTK_WIDGET_REALIZED(eyes->eyes[i]))
143         {
144           accel_read(&x, &y, &z);
145           x = -x;
146           y = -y;
147
148           if ((x != eyes->pointer_last_x[i]) || (y != eyes->pointer_last_y[i]))
149             {
150
151               calculate_pupil_xy (eyes, x, y, &pupil_x, &pupil_y, eyes->eyes[i]);
152               draw_eye (eyes, i, pupil_x, pupil_y);
153
154               eyes->pointer_last_x[i] = x;
155               eyes->pointer_last_y[i] = y;
156             }
157         }
158     }
159
160   return TRUE;
161 }
162
163 static void
164 properties_load(EyesPluginContent *eyes)
165 {
166   gchar *path;
167
168   if (eyes->active_theme)
169     path = g_build_filename(THEMESDIR, eyes->active_theme, NULL);
170   else
171     path = g_build_filename(THEMESDIR, DEFAULTTHEME, NULL);
172
173   load_theme(eyes, path);
174
175   g_free(path);
176 }
177
178
179
180 static void
181 setup_eyes(EyesPluginContent *eyes)
182 {
183   g_warning ("setup_eyes");
184   int i;
185
186   if (eyes->hbox != NULL)
187     {
188       gtk_widget_destroy(eyes->hbox);
189       eyes->hbox = NULL;
190     }
191
192   eyes->hbox = gtk_hbox_new(FALSE, 0);
193   gtk_container_add(GTK_CONTAINER(eyes->align), GTK_WIDGET(eyes->hbox));
194
195   eyes->eyes = g_new0 (GtkWidget *, eyes->num_eyes);
196   eyes->pointer_last_x = g_new0 (gint, eyes->num_eyes);
197   eyes->pointer_last_y = g_new0 (gint, eyes->num_eyes);
198
199   for (i = 0; i < eyes->num_eyes; i++)
200     {
201       eyes->eyes[i] = gtk_image_new ();
202
203       gtk_widget_set_size_request(GTK_WIDGET(eyes->eyes[i]),
204                                   eyes->eye_width,
205                                   eyes->eye_height);
206
207       gtk_widget_show(eyes->eyes[i]);
208
209       gtk_box_pack_start(GTK_BOX(eyes->hbox), eyes->eyes[i],
210                          FALSE, FALSE, 0);
211
212       if ((eyes->num_eyes != 1) && (i == 0))
213         gtk_misc_set_alignment (GTK_MISC (eyes->eyes[i]), 1.0, 0.5);
214       else if ((eyes->num_eyes != 1) && (i == eyes->num_eyes - 1))
215         gtk_misc_set_alignment (GTK_MISC (eyes->eyes[i]), 0.0, 0.5);
216       else
217         gtk_misc_set_alignment (GTK_MISC (eyes->eyes[i]), 0.5, 0.5);
218
219       eyes->pointer_last_x[i] = G_MAXINT;
220       eyes->pointer_last_y[i] = G_MAXINT;
221
222       draw_eye (eyes, i,
223                 eyes->eye_width / 2,
224                 eyes->eye_height / 2);
225     }
226
227   gtk_widget_show(eyes->hbox);
228 }
229
230
231
232 static gboolean
233 eyes_applet_fill(EyesPluginContent *eyes)
234 {
235   gtk_widget_show_all(GTK_WIDGET(eyes->align));
236
237   if (eyes->timeout_id == 0)
238     {
239       eyes->timeout_id = g_timeout_add (UPDATE_TIMEOUT,
240                                         (GtkFunction)timer_cb, eyes);
241     }
242
243   return TRUE;
244 }
245
246 /******************************
247  *** Panel Plugin Functions ***
248  ******************************/
249 static void
250 eyes_free_data(EyesPluginContent      *eyes)
251 {
252   g_warning("eyes_free_data");
253   g_return_if_fail(eyes != NULL);
254
255   if (eyes->timeout_id != 0)
256     g_source_remove (eyes->timeout_id);
257
258   g_free (eyes->eyes);
259   g_free (eyes->pointer_last_x);
260   g_free (eyes->pointer_last_y);
261
262   if (eyes->active_theme != NULL)
263     g_free (eyes->active_theme);
264
265   if (eyes->eye_image != NULL)
266     g_object_unref (G_OBJECT (eyes->eye_image));
267
268   if (eyes->pupil_image != NULL)
269     g_object_unref (G_OBJECT (eyes->pupil_image));
270
271   if (eyes->theme_dir != NULL)
272     g_free(eyes->theme_dir);
273
274   if (eyes->theme_name != NULL)
275     g_free(eyes->theme_name);
276
277   if (eyes->eye_filename != NULL)
278     g_free(eyes->eye_filename);
279
280   if (eyes->pupil_filename != NULL)
281     g_free(eyes->pupil_filename);
282
283   g_free(eyes);
284 }
285
286 static void
287 eyes_read_rc_file (EyesPluginContent      *eyes)
288 {
289   g_warning ("eyes_read_rc");
290   if (eyes->active_theme == NULL)
291     eyes->active_theme = g_strdup (DEFAULTTHEME);
292 }
293
294 static EyesPluginContent *
295 eyes_plugin_new ()
296 {
297   g_warning ("eyes_plugin_new");
298   EyesPluginContent *eyes;
299
300   eyes = g_new0(EyesPluginContent, 1);
301
302   eyes->align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
303
304   gtk_widget_show(GTK_WIDGET(eyes->align));
305
306   eyes_read_rc_file (eyes);
307
308   properties_load(eyes);
309   setup_eyes(eyes);
310   eyes_applet_fill(eyes);
311
312   return eyes;
313 }
314
315 static void
316 eyes_check_desktop (GObject *gobject, GParamSpec *pspec, EyesPluginContent *eyes)
317 {
318   g_warning ("eyes_check_desktop");
319   gchar *name = pspec->name;
320   gboolean status;
321   g_object_get (gobject, name, &status, NULL);
322   if (status) {
323     eyes_applet_fill(eyes);
324   } else if (eyes->timeout_id != 0) {
325     g_source_remove (eyes->timeout_id);
326     eyes->timeout_id = 0;
327   }
328 }
329
330 static void
331 eyes_plugin_dispose (GObject *object)
332 {
333   g_warning ("eyes_plugin_dispose");
334
335   G_OBJECT_CLASS (eyes_plugin_parent_class)->dispose (object);
336 }
337
338 static void eyes_plugin_finalize (GObject *object)
339 {
340   g_warning ("eyes_plugin_finalize");
341   EyesPlugin *self = EYES_HOME_PLUGIN (object);
342
343   eyes_free_data(self->priv);
344
345   G_OBJECT_CLASS (eyes_plugin_parent_class)->finalize (object);
346 }
347
348 static void
349 eyes_plugin_realize (GtkWidget *widget)
350 {
351   g_warning ("eyes_plugin_realize");
352   GdkScreen *screen = gtk_widget_get_screen (widget);
353   gtk_widget_set_colormap (widget, gdk_screen_get_rgba_colormap (screen));
354   gtk_widget_set_app_paintable (widget, TRUE);
355
356   GTK_WIDGET_CLASS (eyes_plugin_parent_class)->realize (widget);
357 }
358
359 static gboolean
360 eyes_plugin_expose_event (GtkWidget *widget, GdkEventExpose *event)
361 {
362   g_warning ("eyes_plugin_expose_event");
363   cairo_t *cr;
364
365   cr = gdk_cairo_create (GDK_DRAWABLE (widget->window));
366   gdk_cairo_region (cr, event->region);
367   cairo_clip (cr);
368
369   cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
370   cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
371   cairo_paint (cr);
372   
373   cairo_destroy (cr);
374
375   return GTK_WIDGET_CLASS (eyes_plugin_parent_class)->expose_event (widget, event);
376 }
377
378 static void
379 eyes_plugin_init (EyesPlugin *desktop_plugin)
380 {
381   g_warning ("eyes_plugin_init");
382   EyesPluginContent *eyes;
383
384   eyes = eyes_plugin_new (desktop_plugin);
385   desktop_plugin->priv = eyes;
386
387   g_signal_connect (desktop_plugin, "notify::is-on-current-desktop",
388                     G_CALLBACK (eyes_check_desktop), eyes);
389
390   gtk_container_add (GTK_CONTAINER (desktop_plugin), eyes->align);
391
392
393 static void
394 eyes_plugin_class_init (EyesPluginClass *klass) {
395   g_warning ("eyes_plugin_class_init");
396   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
397   GObjectClass *object_class = G_OBJECT_CLASS (klass);
398
399   object_class->dispose = eyes_plugin_dispose;
400   object_class->finalize = eyes_plugin_finalize;
401
402   widget_class->realize = eyes_plugin_realize;
403   widget_class->expose_event = eyes_plugin_expose_event;
404   g_type_class_add_private (klass, sizeof (EyesPluginContent));
405
406
407 static void
408 eyes_plugin_class_finalize (EyesPluginClass *class) {} 
409