source: trunk/third/gnome-applets/geyes/geyes.c @ 20910

Revision 20910, 13.9 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20909, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C++; c-basic-offset: 8 -*-
2 * geyes.c - A cheap xeyes ripoff.
3 * Copyright (C) 1999 Dave Camp
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20#include <config.h>
21#include <math.h>
22#include <gnome.h>
23#include <panel-applet.h>
24#include <panel-applet-gconf.h>
25#include "geyes.h"
26
27#define UPDATE_TIMEOUT 100
28
29/* FIXME crashes, need to fix */
30static void
31applet_set_back_pixmap (PanelApplet *applet, GtkWidget *widget, GdkPixmap *pixmap)
32{
33        GtkStyle *new_style;
34
35        new_style = gtk_style_copy (widget->style);
36        gtk_style_ref (new_style);
37/* FIXME should this be done ? */
38/*
39        if (new_style->bg_pixmap [GTK_STATE_NORMAL])
40                g_object_unref (new_style->bg_pixmap [GTK_STATE_NORMAL]);
41*/
42        new_style->bg_pixmap [GTK_STATE_NORMAL] = pixmap;
43        gtk_widget_set_style (widget, new_style);
44        gtk_style_unref (new_style);
45}
46
47static void
48applet_back_change (PanelApplet                 *a,
49                    PanelAppletBackgroundType   type,
50                    GdkColor                    *color,
51                    GdkPixmap                   *pixmap,
52                    EyesApplet                  *eyes_applet)
53{
54        GtkRcStyle *rc_style = gtk_rc_style_new ();
55
56        switch (type) {
57        case PANEL_PIXMAP_BACKGROUND:
58                gtk_widget_modify_style (GTK_WIDGET (eyes_applet->applet), rc_style);
59/* FIXME can't get to work */
60//              applet_set_back_pixmap (a, GTK_WIDGET (eyes_applet->applet), pixmap);
61                break;
62
63        case PANEL_COLOR_BACKGROUND:
64                gtk_widget_modify_bg (GTK_WIDGET (eyes_applet->applet), GTK_STATE_NORMAL, color);
65                break;
66
67        case PANEL_NO_BACKGROUND:
68                gtk_widget_modify_style (GTK_WIDGET (eyes_applet->applet), rc_style);
69                break;
70
71        default:
72                gtk_widget_modify_style (GTK_WIDGET (eyes_applet->applet), rc_style);
73                break;
74        }
75
76        gtk_rc_style_unref (rc_style);
77}
78
79/* TODO - Optimize this a bit */
80static void
81calculate_pupil_xy (EyesApplet *eyes_applet,
82                    gint x, gint y,
83                    gint *pupil_x, gint *pupil_y)
84{
85        double angle;
86        double sina;
87        double cosa;
88        double nx;
89        double ny;
90        double h;
91        double temp;
92     
93        nx = x - ((double) eyes_applet->eye_width / 2);
94        ny = y - ((double) eyes_applet->eye_height / 2);
95       
96        h = hypot (nx, ny);
97        if (abs (h)
98            < (abs (hypot (eyes_applet->eye_height / 2, eyes_applet->eye_width / 2)) - eyes_applet->wall_thickness - eyes_applet->pupil_height)) {
99                *pupil_x = x;
100                *pupil_y = y;
101                return;
102        }
103       
104        angle = atan2 (nx, ny);
105        sina = sin (angle);
106        cosa = cos (angle);
107       
108        temp = hypot ((eyes_applet->eye_height / 2) * cosa, (eyes_applet->eye_width / 2)* sina);
109        *pupil_x = temp * sina;
110        *pupil_y = temp * cosa;
111       
112        temp = hypot ((eyes_applet->pupil_width / 2) * sina, (eyes_applet->pupil_height / 2)* cosa);
113        *pupil_x -= temp * sina;
114        *pupil_y -= temp * cosa;
115       
116        temp = hypot ((eyes_applet->wall_thickness / 2) * sina, (eyes_applet->wall_thickness / 2) * cosa);
117        *pupil_x -= temp * sina;
118        *pupil_y -= temp * cosa;
119       
120        *pupil_x += (eyes_applet->eye_width / 2);
121        *pupil_y += (eyes_applet->eye_height / 2);
122}
123
124static void
125draw_eye (EyesApplet *eyes_applet,
126          gint eye_num,
127          gint pupil_x,
128          gint pupil_y)
129{
130        GdkPixbuf *pixbuf;
131        GdkRectangle rect, r1, r2;
132
133        pixbuf = gdk_pixbuf_copy (eyes_applet->eye_image);
134        r1.x = pupil_x - eyes_applet->pupil_width / 2;
135        r1.y = pupil_y - eyes_applet->pupil_height / 2;
136        r1.width = eyes_applet->pupil_width;
137        r1.height = eyes_applet->pupil_height;
138        r2.x = 0;
139        r2.y = 0;
140        r2.width = eyes_applet->eye_width;
141        r2.height = eyes_applet->eye_height;
142        gdk_rectangle_intersect (&r1, &r2, &rect);
143        gdk_pixbuf_composite (eyes_applet->pupil_image, pixbuf,
144                                           rect.x,
145                                           rect.y,
146                                           rect.width,
147                                           rect.height,
148                                           pupil_x - eyes_applet->pupil_width / 2,
149                                           pupil_y - eyes_applet->pupil_height / 2, 1.0, 1.0,
150                                           GDK_INTERP_BILINEAR,
151                                           255);
152        gtk_image_set_from_pixbuf (GTK_IMAGE (eyes_applet->eyes[eye_num]),
153                                                  pixbuf);
154        g_object_unref (pixbuf);
155
156}
157
158static gint
159timer_cb (EyesApplet *eyes_applet)
160{
161        gint x, y;
162        gint pupil_x, pupil_y;
163        gint i;
164       
165        for (i = 0; i < eyes_applet->num_eyes; i++) {
166                if (GTK_WIDGET_REALIZED (eyes_applet->eyes[i])) {
167                        gtk_widget_get_pointer (eyes_applet->eyes[i],
168                                                &x, &y);
169                        if ((x != eyes_applet->pointer_last_x) || (y != eyes_applet->pointer_last_y)) {
170                                calculate_pupil_xy (eyes_applet, x, y, &pupil_x, &pupil_y);
171                                draw_eye (eyes_applet, i, pupil_x, pupil_y);
172                        }
173                }
174        }
175        eyes_applet->pointer_last_x = x;
176        eyes_applet->pointer_last_y = y;
177        return TRUE;
178}
179
180static void
181about_cb (BonoboUIComponent *uic,
182          EyesApplet        *eyes_applet,
183          const gchar       *verbname)
184{
185        GdkPixbuf        *pixbuf;
186        GError           *error = NULL;
187        gchar            *file;
188       
189        static const gchar *authors [] = {
190                "Dave Camp <campd@oit.edu>",
191                NULL
192        };
193
194        const gchar *documenters[] = {
195                "Arjan Scherpenisse <acscherp@wins.uva.nl>",
196                "Telsa Gwynne <hobbit@aloss.ukuu.org.uk>",
197                "Sun GNOME Documentation Team <gdocteam@sun.com>",
198                NULL
199        };
200
201        const gchar *translator_credits = _("translator_credits");
202
203        if (eyes_applet->about_dialog) {
204                gtk_window_set_screen (GTK_WINDOW (eyes_applet->about_dialog),
205                                       gtk_widget_get_screen (GTK_WIDGET (eyes_applet->applet)));
206               
207                gtk_window_present (GTK_WINDOW (eyes_applet->about_dialog));
208                return;
209        }
210       
211        file = gnome_program_locate_file (NULL, GNOME_FILE_DOMAIN_PIXMAP, "gnome-eyes.png", FALSE, NULL);
212        pixbuf = gdk_pixbuf_new_from_file (file, &error);
213        g_free (file);
214       
215        if (error) {
216                g_warning (G_STRLOC ": cannot open %s: %s", file, error->message);
217                g_error_free (error);
218        }
219       
220        eyes_applet->about_dialog = gnome_about_new (
221                _("Geyes"), VERSION,
222                _("Copyright (C) 1999 Dave Camp"),
223                _("A goofy little xeyes clone for the GNOME panel."),
224                authors,
225                documenters,
226                strcmp (translator_credits, "translator_credits") != 0 ? translator_credits : NULL,
227                pixbuf);
228               
229        if (pixbuf)
230                gdk_pixbuf_unref (pixbuf);
231                       
232        gtk_window_set_wmclass (GTK_WINDOW (eyes_applet->about_dialog), "geyes", "Geyes");
233        gtk_window_set_screen (GTK_WINDOW (eyes_applet->about_dialog),
234                               gtk_widget_get_screen (GTK_WIDGET (eyes_applet->applet)));
235        g_signal_connect (eyes_applet->about_dialog, "destroy",
236                          G_CALLBACK (gtk_widget_destroyed),
237                          &eyes_applet->about_dialog);
238        gtk_widget_show (eyes_applet->about_dialog);
239}
240
241static int
242properties_load (EyesApplet *eyes_applet)
243{
244        gchar *theme_path = NULL;
245
246        theme_path = panel_applet_gconf_get_string (
247                eyes_applet->applet, "theme_path", NULL);
248
249        if (theme_path == NULL)
250                theme_path = g_strdup (GEYES_THEMES_DIR "Default-tiny");
251       
252        if (load_theme (eyes_applet, theme_path) == FALSE) {
253                g_free (theme_path);
254
255                return FALSE;
256        }
257
258        g_free (theme_path);
259       
260        return TRUE;
261}
262
263void
264setup_eyes (EyesApplet *eyes_applet)
265{
266        int i;
267
268        eyes_applet->hbox = gtk_hbox_new (FALSE, 0);
269        gtk_box_pack_start (GTK_BOX (eyes_applet->vbox), eyes_applet->hbox, TRUE, TRUE, 0);
270
271        eyes_applet->eyes = g_new0 (GtkWidget *, eyes_applet->num_eyes);
272
273        for (i = 0; i < eyes_applet->num_eyes; i++) {
274                eyes_applet->eyes[i] = gtk_image_new ();
275                if (eyes_applet->eyes[i] == NULL)
276                        g_error ("Error creating geyes\n");
277               
278                gtk_widget_set_size_request (GTK_WIDGET (eyes_applet->eyes[i]),
279                                             eyes_applet->eye_width,
280                                             eyes_applet->eye_height);
281 
282                gtk_widget_show (eyes_applet->eyes[i]);
283               
284                gtk_box_pack_start (GTK_BOX (eyes_applet->hbox),
285                                    eyes_applet->eyes [i],
286                                    TRUE,
287                                    TRUE,
288                                    0);
289               
290                if ((eyes_applet->num_eyes != 1) && (i == 0)) {
291                        gtk_misc_set_alignment (GTK_MISC (eyes_applet->eyes[i]), 1.0, 0.5);
292                }
293                else if ((eyes_applet->num_eyes != 1) && (i == eyes_applet->num_eyes - 1)) {
294                        gtk_misc_set_alignment (GTK_MISC (eyes_applet->eyes[i]), 0.0, 0.5);
295                }
296                else {
297                        gtk_misc_set_alignment (GTK_MISC (eyes_applet->eyes[i]), 0.5, 0.5);
298                }
299               
300                gtk_widget_realize (eyes_applet->eyes[i]);
301                draw_eye (eyes_applet, i,
302                          eyes_applet->eye_width / 2,
303                          eyes_applet->eye_height / 2);
304               
305        }
306        gtk_widget_show (eyes_applet->hbox);
307}
308
309void
310destroy_eyes (EyesApplet *eyes_applet)
311{
312        gtk_widget_destroy (eyes_applet->hbox);
313        eyes_applet->hbox = NULL;
314
315        g_free (eyes_applet->eyes);
316}
317
318static EyesApplet *
319create_eyes (PanelApplet *applet)
320{
321        EyesApplet *eyes_applet = g_new0 (EyesApplet, 1);
322
323        eyes_applet->applet = applet;
324        eyes_applet->vbox = gtk_vbox_new (FALSE, 0);
325
326        gtk_container_add (GTK_CONTAINER (applet), eyes_applet->vbox);
327
328        return eyes_applet;
329}
330
331static void
332destroy_cb (GtkObject *object, EyesApplet *eyes_applet)
333{
334        g_return_if_fail (eyes_applet);
335
336        gtk_timeout_remove (eyes_applet->timeout_id);
337        if (eyes_applet->hbox)
338                destroy_eyes (eyes_applet);
339        if (eyes_applet->tooltips)
340                g_object_unref (eyes_applet->tooltips);
341        eyes_applet->timeout_id = 0;
342        if (eyes_applet->eye_image)
343                g_object_unref (eyes_applet->eye_image);
344        eyes_applet->eye_image = NULL;
345        if (eyes_applet->pupil_image)
346                g_object_unref (eyes_applet->pupil_image);
347        eyes_applet->pupil_image = NULL;
348        if (eyes_applet->theme_dir)
349                g_free (eyes_applet->theme_dir);
350        eyes_applet->theme_dir = NULL;
351        if (eyes_applet->theme_name)
352                g_free (eyes_applet->theme_name);
353        eyes_applet->theme_name = NULL;
354        if (eyes_applet->eye_filename)
355                g_free (eyes_applet->eye_filename);
356        eyes_applet->eye_filename = NULL;
357        if (eyes_applet->pupil_filename)
358                g_free (eyes_applet->pupil_filename);
359        eyes_applet->pupil_filename = NULL;
360       
361        if (eyes_applet->about_dialog)
362                gtk_widget_destroy (eyes_applet->about_dialog);
363
364        if (eyes_applet->prop_box.pbox)
365                gtk_widget_destroy (eyes_applet->prop_box.pbox);
366
367        g_free (eyes_applet);
368}
369
370static void
371help_cb (BonoboUIComponent *uic,
372         EyesApplet        *eyes_applet,
373         const char        *verbname)
374{
375        GError *error = NULL;
376
377        gnome_help_display_on_screen (
378                "geyes", NULL,
379                gtk_widget_get_screen (GTK_WIDGET (eyes_applet->applet)),
380                &error);
381
382        if (error) { /* FIXME: the user needs to see this */
383                g_warning ("help error: %s\n", error->message);
384                g_error_free (error);
385                error = NULL;
386        }
387}
388
389
390static const BonoboUIVerb geyes_applet_menu_verbs [] = {
391        BONOBO_UI_UNSAFE_VERB ("Props", properties_cb),
392        BONOBO_UI_UNSAFE_VERB ("Help", help_cb),
393        BONOBO_UI_UNSAFE_VERB ("About", about_cb),
394
395        BONOBO_UI_VERB_END
396};
397
398static void
399set_atk_name_description (GtkWidget *widget, const gchar *name,
400    const gchar *description)
401{
402        AtkObject *aobj;
403   
404        aobj = gtk_widget_get_accessible (widget);
405        /* Check if gail is loaded */
406        if (GTK_IS_ACCESSIBLE (aobj) == FALSE)
407                return;
408
409        atk_object_set_name (aobj, name);
410        atk_object_set_description (aobj, description);
411}
412
413static gboolean
414geyes_applet_fill (PanelApplet *applet)
415{
416        EyesApplet *eyes_applet;
417       
418        gnome_window_icon_set_default_from_file (GNOME_ICONDIR"/gnome-eyes.png");
419        panel_applet_set_flags (applet, PANEL_APPLET_EXPAND_MINOR);
420       
421        eyes_applet = create_eyes (applet);
422
423        panel_applet_add_preferences (applet, "/schemas/apps/geyes/prefs", NULL);
424
425        eyes_applet->about_dialog = NULL;
426
427        eyes_applet->timeout_id = gtk_timeout_add (
428                UPDATE_TIMEOUT, (GtkFunction) timer_cb, eyes_applet);
429                       
430        panel_applet_setup_menu_from_file (eyes_applet->applet,
431                                           NULL,
432                                           "GNOME_GeyesApplet.xml",
433                                           NULL,
434                                           geyes_applet_menu_verbs,
435                                           eyes_applet);
436
437        if (panel_applet_get_locked_down (eyes_applet->applet)) {
438                BonoboUIComponent *popup_component;
439
440                popup_component = panel_applet_get_popup_component (eyes_applet->applet);
441
442                bonobo_ui_component_set_prop (popup_component,
443                                              "/commands/Props",
444                                              "hidden", "1",
445                                              NULL);
446        }
447
448        eyes_applet->tooltips = gtk_tooltips_new ();
449        g_object_ref (eyes_applet->tooltips);
450        gtk_object_sink (GTK_OBJECT (eyes_applet->tooltips));
451        gtk_tooltips_set_tip (eyes_applet->tooltips, GTK_WIDGET (eyes_applet->applet), _("Geyes"), NULL);
452
453        set_atk_name_description (GTK_WIDGET (eyes_applet->applet), _("Geyes"),
454                        _("The eyes look in the direction of the mouse pointer"));
455
456        g_signal_connect (eyes_applet->applet,
457                          "change_background",
458                          G_CALLBACK (applet_back_change),
459                          eyes_applet);
460        g_signal_connect (eyes_applet->vbox,
461                          "destroy",
462                          G_CALLBACK (destroy_cb),
463                          eyes_applet);
464
465        gtk_widget_show_all (GTK_WIDGET (eyes_applet->applet));
466
467        /* setup here and not in create eyes so the destroy signal is set so
468         * that when there is an error within loading the theme
469         * we can emit this signal */
470        if (properties_load (eyes_applet) == FALSE)
471                return FALSE;
472
473        setup_eyes (eyes_applet);
474
475        return TRUE;
476}
477
478static gboolean
479geyes_applet_factory (PanelApplet *applet,
480                      const gchar *iid,
481                      gpointer     data)
482{
483        gboolean retval = FALSE;
484
485        theme_dirs_create ();
486
487        if (!strcmp (iid, "OAFIID:GNOME_GeyesApplet"))
488                retval = geyes_applet_fill (applet);
489   
490        if (retval == FALSE) {
491                exit (-1);
492        }
493
494        return retval;
495}
496
497PANEL_APPLET_BONOBO_FACTORY ("OAFIID:GNOME_GeyesApplet_Factory",
498                             PANEL_TYPE_APPLET,
499                             "geyes",
500                             "0",
501                             geyes_applet_factory,
502                             NULL)
Note: See TracBrowser for help on using the repository browser.