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

Revision 20910, 40.6 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/* GNOME modemlights applet
2 * (C) 2000 John Ellis
3 *
4 * Authors: John Ellis
5 *          Martin Baulig
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Cambridge, MA
20 * 02139, USA.
21 *
22 */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include "modemlights.h"
29#include <panel-applet.h>
30#include <libgnomeui/gnome-help.h>
31#include "digits.xpm"
32
33#include <stdlib.h>
34#include <signal.h>
35#include <errno.h>
36#include <ctype.h>
37#include <sys/stat.h>
38
39#ifdef __OpenBSD__
40#include <net/if_ppp.h>
41#endif
42
43#ifdef __linux__
44#include <linux/if_ppp.h>
45#include <sys/ioctl.h>
46#include <sys/types.h>
47#include <fcntl.h>
48
49#ifndef ISDN_MAX_CHANNELS
50#define ISDN_MAX_CHANNELS 64
51#endif
52
53#ifndef IIOCGETCPS
54#define IIOCGETCPS  _IO('I',21)
55#endif
56
57#endif
58
59/* this holds all the possible layout configurations */
60static DisplayData layout_data[] = {
61        { LAYOUT_HORIZONTAL, 46, 22,
62          0, 0, 16, 22,
63          16, 0, 30, 22,
64          1, 1, 18, 20,
65          19, 1, 19, 10,
66          -1, -1, -1, -1, FALSE
67        },
68        { LAYOUT_HORIZONTAL_EXTENDED, 74, 22,
69          0, 0, 16, 22,
70          16, 0, 58, 22,
71          29, 1, 18, 20,
72          47, 1, 47, 10,
73          2, 3, 2, 12, TRUE
74        },
75        { LAYOUT_VERTICAL, 20, 46,
76          0, 30, 20, 16,
77          0, 0, 20, 30,
78          1, 11, 18, 18,
79          1, 1, 10, 1,
80          -1, -1, -1, -1, FALSE
81        },
82        { LAYOUT_VERTICAL_EXTENDED, 30, 58,
83          0, 42, 30, 16,
84          0, 0, 30, 42,
85          1, 1, 18, 20,
86          19, 1, 19, 10,
87          2, 23, 2, 32, TRUE
88        },
89        { LAYOUT_SQUARE, 46, 46,
90          0, 0, 16, 46,
91          16, 0, 30, 46,
92          1, 1, 18, 20,
93          19, 1, 19, 10,
94          2, 24, 2, 36, FALSE
95        }
96};
97
98static void about_cb (BonoboUIComponent *uic,
99                      MLData       *mldata,
100                      const gchar       *verbname)
101{
102        PanelApplet *applet = PANEL_APPLET (mldata->applet);
103        GdkPixbuf        *pixbuf;
104        GError           *error = NULL;
105        gchar            *file;
106       
107        static const gchar *authors[] = {
108                "John Ellis <johne@bellatlantic.net>",
109                "Martin Baulig <martin@home-of-linux.org> - ISDN",
110                NULL
111        };
112
113        const gchar *documenters[] = {
114                "Chee Bin HOH <cbhoh@gnome.org>",
115                NULL
116        };
117
118        const gchar *translator_credits = _("translator_credits");
119
120        if (mldata->about_dialog) {
121                gtk_window_set_screen (GTK_WINDOW (mldata->about_dialog),
122                                       gtk_widget_get_screen (GTK_WIDGET (applet)));
123               
124                gtk_window_present (GTK_WINDOW (mldata->about_dialog));
125                return;
126        }
127
128        file = gnome_program_locate_file (NULL, GNOME_FILE_DOMAIN_PIXMAP,
129                                          "gnome-modem.png", FALSE, NULL);
130        pixbuf = gdk_pixbuf_new_from_file (file, &error);
131        g_free (file);
132       
133        if (error) {
134                g_warning (G_STRLOC ": cannot open %s: %s", file, error->message);
135                g_error_free (error);
136        }
137
138        mldata->about_dialog = gnome_about_new ( _("Modem Lights"), VERSION,
139                                                "(C) 2000",
140                                                _("Released under the GNU general public license.\n"
141                                                "A modem status indicator and dialer.\n"
142                                                "Lights in order from the top or left are Send data and Receive data."),
143                                                authors,
144                                                documenters,
145                                                strcmp (translator_credits, "translator_credits") != 0 ? translator_credits : NULL,
146                                                pixbuf);
147
148        if (pixbuf)
149                g_object_unref (pixbuf);
150
151        gtk_window_set_screen (GTK_WINDOW (mldata->about_dialog),
152                               gtk_widget_get_screen (GTK_WIDGET (applet)));
153
154        gtk_window_set_wmclass (GTK_WINDOW (mldata->about_dialog),
155                                "modem lights", "Modem Lights");
156
157        g_signal_connect (G_OBJECT (mldata->about_dialog), "destroy",
158                          G_CALLBACK (gtk_widget_destroyed), &mldata->about_dialog);
159
160        gtk_widget_show (mldata->about_dialog);
161}
162
163static int is_Modem_on(MLData *mldata)
164{
165        FILE *f = NULL;
166        gchar buf[64];
167        pid_t pid = -1;
168
169        f = fopen(mldata->lock_file, "r");
170
171        if(!f) return FALSE;
172
173        if (mldata->verify_lock_file)
174                {
175                if (fgets(buf, sizeof(buf), f) == NULL)
176                        {
177                        fclose(f);
178                        return FALSE;
179                        }
180                }
181
182        fclose(f);
183
184        if (mldata->verify_lock_file)
185                {
186                pid = (pid_t)strtol(buf, NULL, 10);
187                if (pid < 1 || (kill (pid, 0) == -1 && errno != EPERM)) return FALSE;
188                }
189
190        return TRUE;
191}
192
193static int is_ISDN_on(MLData *mldata)
194{
195#ifdef __linux__
196
197        /* Perhaps I should try to explain this code a little bit.
198         *
199         * ------------------------------------------------------------
200         * This is from the manpage of isdninfo(4):
201         *
202         * DESCRIPTION
203         *   /dev/isdninfo  is  a character device with major number 45
204         *   and minor number 255.  It delivers status information from
205         *   the Linux ISDN subsystem to user level.
206         *
207         * DATA FORMAT
208         *   When  reading  from this device, the current status of the
209         *   Linux ISDN subsystem is delivered in 6 lines of text. Each
210         *   line  starts  with  a  tag  string followed by a colon and
211         *   whitespace. After that the status values are appended sep-
212         *   arated by whitespace.
213         *
214         *   flags  is the tag of line 5. In this line for every driver
215         *          slot, it's B-Channel status is shown. If no  driver
216         *          is  registered  in a slot, a ? is shown.  For every
217         *          established B-Channel of the driver, a bit  is  set
218         *          in  the  shown value. The driver's first channel is
219         *          mapped to bit 0, the second channel to bit 1 and so
220         *          on.
221         * ------------------------------------------------------------
222         *
223         * So we open /dev/isdninfo, discard the first four lines of text
224         * and then check whether we have something that is not `0' or `?'
225         * in one of the flags fields.
226         *
227         * Sounds complicated, but I don't see any other way to check whether
228         * we are connected. Also, this is the method some other ISDN tools
229         * for Linux use.
230         *
231         * Martin
232         *
233         * ---
234         *
235         * With Linux kernel 2.4, glibc 2.2 (*) and certain providers with
236         * long phone numbers, the contents of /dev/isdninfo can be more than
237         * 1024 bytes and not be properly processed by multiple subsequent
238         * fgets()'s, so we (try to atomically) read() BUFSIZE bytes into
239         * buffer[] and process this instead of /dev/isdninfo directly.
240         *
241         * (*): dont't nail me on this combination
242         *
243         * Nils
244         */
245
246        char buffer [BUFSIZ], *p;
247        int i;
248        int fd;
249        int length;
250
251        fd = open ("/dev/isdninfo", O_RDONLY | O_NDELAY);
252
253        if (fd < 0) {
254                perror ("/dev/isdninfo");
255                return FALSE;
256        }
257
258        if ((length = read (fd, buffer, BUFSIZ - 1)) < 0) {
259                perror ("/dev/isdninfo");
260                close (fd);
261                return FALSE;
262        }
263
264        buffer[length+1] = (char)0;
265
266        p = buffer;
267
268        /* Seek for the fifth line */
269        for (i = 1; i < 5; i++) {
270                if ((p = strchr (p, '\n')) == NULL) {
271                        close (fd);
272                        return FALSE;
273                }
274                p++;
275        }
276
277        /* *p is the first character of the fifth line now */
278        if (strncmp (p, "flags:", 6)) {
279                close (fd);
280                return FALSE;
281        }
282
283        p += 6;
284
285        while (*p && (*p != '\n')) {
286                char *end = p;
287
288                if (isspace (*p)) {
289                        p++;
290                        continue;
291                }
292
293                for (end = p; *end && !isspace (*end); end++)
294                        ;
295
296                if (*end == 0)
297                        break;
298                else
299                        *end = 0;
300
301                if (!strcmp (p, "?") || !strcmp (p, "0")) {
302                        p = end+1;
303                        continue;
304                }
305
306                close (fd);
307                return TRUE;
308        }
309
310        close (fd);
311
312        return FALSE;
313#else
314        return FALSE;
315#endif
316}
317
318static int is_connected(MLData *mldata)
319{
320        if (mldata->use_ISDN)
321                return is_ISDN_on(mldata);
322        else
323                return is_Modem_on(mldata);
324}
325
326static int get_modem_stats(MLData *mldata, int *in, int *out)
327{
328        struct  ifreq ifreq;
329        struct  ppp_stats stats;
330
331        memset(&ifreq, 0, sizeof(ifreq));
332        strncpy(ifreq.ifr_name, mldata->device_name, IFNAMSIZ);
333        ifreq.ifr_name[IFNAMSIZ-1] = '\0';
334        ifreq.ifr_ifru.ifru_data = (caddr_t)&stats;
335
336#ifdef SIOCGPPPSTATS
337        if (ioctl(mldata->ip_socket, SIOCGPPPSTATS, (caddr_t)&ifreq) < 0)
338#else
339        if (TRUE)
340#endif
341                {
342                /* failure means ppp is not up */
343                *in = *out = 0;
344                return FALSE;
345                }
346        else
347                {
348                *in = stats.p.ppp_ibytes;
349                *out = stats.p.ppp_obytes;
350                return TRUE;
351                }
352}
353
354static int get_ISDN_stats(MLData *mldata, int *in, int *out)
355{
356#ifdef __linux__
357        int fd, i;
358        unsigned long *ptr;
359
360        *in = *out = 0;
361
362        if (!mldata->isdn_stats)
363                mldata->isdn_stats = g_new0 (unsigned long, ISDN_MAX_CHANNELS  *  2);
364
365        fd = open("/dev/isdninfo", O_RDONLY);
366
367        if (fd < 0)
368                return FALSE;
369
370        if ((ioctl (fd, IIOCGETCPS, mldata->isdn_stats) < 0) && (errno != 0)) {
371                close (fd);
372               
373                return FALSE;
374        }
375
376        for (i = 0, ptr = mldata->isdn_stats; i < ISDN_MAX_CHANNELS; i++) {
377                *in  += *ptr++; *out += *ptr++;
378        }
379
380        close (fd);
381
382        return TRUE;
383
384#else
385        *in = *out = 0;
386
387        return FALSE;
388#endif
389}
390
391static int get_stats(MLData *mldata, int *in, int *out)
392{
393        if (mldata->use_ISDN)
394                return get_ISDN_stats(mldata, in, out);
395        else
396                return get_modem_stats(mldata, in, out);
397}
398
399static gint get_ISDN_connect_time(MLData *mldata, gint recalc_start)
400{
401        /* this is a bad hack just to get some (not very accurate) timing */
402
403        if (recalc_start)
404                {
405                mldata->start_time = time(NULL);
406                }
407
408        if (mldata->start_time != (time_t)0)
409                return (gint)(time(NULL) - mldata->start_time);
410        else
411                return -1;
412}
413
414static gint get_modem_connect_time(MLData *mldata, gint recalc_start)
415{
416        struct stat st;
417
418        if (recalc_start)
419                {
420                if (stat (mldata->lock_file, &st) == 0)
421                        mldata->start_time = st.st_mtime;
422                else
423                        mldata->start_time = (time_t)0;
424                }
425
426        if (mldata->start_time != (time_t)0)
427                return (gint)(time(NULL) - mldata->start_time);
428        else
429                return -1;
430}
431
432static gint get_connect_time(MLData *mldata, gint recalc_start)
433{
434        if (mldata->use_ISDN)
435                return get_ISDN_connect_time(mldata, recalc_start);
436        else
437                return get_modem_connect_time(mldata, recalc_start);
438}
439
440static void
441run_response_cb(GtkDialog *dialog, gint id, MLData *mldata)
442{
443        gtk_widget_destroy(GTK_WIDGET (dialog));
444
445        mldata->run_dialog = NULL;
446}
447
448static void execute_command(gchar *command, GtkWidget *parent, MLData *mldata)
449{
450        gboolean ret;
451        GError *error = NULL;
452
453        if (mldata->run_dialog) {
454                gtk_window_set_screen(GTK_WINDOW(mldata->run_dialog),
455                                      gtk_widget_get_screen (parent));
456
457                gtk_window_present(GTK_WINDOW(mldata->run_dialog));
458
459                return;
460        }
461
462        ret = g_spawn_command_line_async(command, &error);
463        if (!ret) {
464                mldata->run_dialog = gtk_message_dialog_new(NULL, 0,
465                                                            GTK_MESSAGE_ERROR,
466                                                            GTK_BUTTONS_CLOSE,
467                                                            error->message);
468
469                gtk_window_set_screen(GTK_WINDOW(mldata->run_dialog),
470                                      gtk_widget_get_screen(parent));
471
472                gtk_widget_show_all(mldata->run_dialog);
473               
474                gtk_window_present(GTK_WINDOW(mldata->run_dialog));
475
476                g_signal_connect(mldata->run_dialog, "response",
477                                 G_CALLBACK(run_response_cb),
478                                 mldata);
479        }
480}
481
482static void disconnect_dialog_response(GtkDialog *dialog, gint response, MLData *mldata)
483{
484                if (response == GTK_RESPONSE_OK)
485                        execute_command(mldata->command_disconnect, GTK_WIDGET (dialog), mldata);
486
487                gtk_widget_destroy(GTK_WIDGET(dialog));
488                mldata->connect_dialog = NULL;
489}
490
491static void connect_dialog_response(GtkDialog *dialog, gint response, MLData *mldata)
492{
493                if (response == GTK_RESPONSE_OK)
494                        execute_command(mldata->command_connect, GTK_WIDGET (dialog), mldata);
495
496                gtk_widget_destroy(GTK_WIDGET(dialog));
497                mldata->connect_dialog = NULL;
498}
499
500static void dial_cb(GtkWidget *widget, MLData *mldata)
501{
502        if (is_connected(mldata)) {
503
504                if (!mldata->ask_for_confirmation) {
505                        execute_command(mldata->command_disconnect, mldata->applet, mldata);
506                        return;
507                }                       
508
509                if (mldata->connect_dialog) {
510                        gtk_window_set_screen(GTK_WINDOW(mldata->connect_dialog),
511                                              gtk_widget_get_screen(mldata->applet));
512
513                        gtk_window_present(GTK_WINDOW(mldata->connect_dialog));
514
515                        return;
516                }
517
518                mldata->connect_dialog = gtk_message_dialog_new(NULL, 0,
519                                                                GTK_MESSAGE_QUESTION,
520                                                                GTK_BUTTONS_NONE,
521                                                                _("You are currently connected.\n"
522                                                                "Do you want to disconnect?"));
523
524                gtk_window_set_screen(GTK_WINDOW(mldata->connect_dialog),
525                                      gtk_widget_get_screen(mldata->applet));
526               
527                gtk_dialog_add_buttons(GTK_DIALOG(mldata->connect_dialog),
528                                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
529                                       _("_Disconnect"), GTK_RESPONSE_OK,
530                                       NULL);
531
532                g_signal_connect(G_OBJECT(mldata->connect_dialog), "response",
533                                 G_CALLBACK(disconnect_dialog_response), mldata);
534
535                gtk_widget_show_all(mldata->connect_dialog);
536
537        } else {
538
539                if (!mldata->ask_for_confirmation) {
540                        execute_command(mldata->command_connect, mldata->applet, mldata);
541                        return;
542                }
543
544                if (mldata->connect_dialog) {
545                        gtk_window_set_screen(GTK_WINDOW(mldata->connect_dialog),
546                                              gtk_widget_get_screen(mldata->applet));
547
548                        gtk_window_present(GTK_WINDOW(mldata->connect_dialog));
549
550                        return;
551                }
552 
553                mldata->connect_dialog = gtk_message_dialog_new(NULL, 0,
554                                                                GTK_MESSAGE_QUESTION,
555                                                                GTK_BUTTONS_NONE,
556                                                                _("Do you want to connect?"));
557
558                gtk_window_set_screen(GTK_WINDOW(mldata->connect_dialog),
559                                      gtk_widget_get_screen(mldata->applet));
560               
561                gtk_dialog_add_buttons(GTK_DIALOG(mldata->connect_dialog),
562                                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
563                                       _("C_onnect"), GTK_RESPONSE_OK,
564                                       NULL);
565
566                g_signal_connect(GTK_DIALOG(mldata->connect_dialog), "response",
567                                 G_CALLBACK(connect_dialog_response), mldata);
568
569                gtk_widget_show_all(mldata->connect_dialog);
570        }
571}
572
573static void update_tooltip(MLData *mldata, int connected, int rx, int tx)
574{
575        gchar *text;
576
577        if (connected)
578                {
579                gint t;
580                gint t1, t2;
581
582                t = get_connect_time(mldata, FALSE);
583
584                if (t < 360000) {
585                  t1 = t / 3600; /* hours */
586                  t2 = (t1 - (t1 * 3600)) / 60; /* minutes */
587                } else {
588                  t1 = (t/3600)/24; /* days */
589                  t2 = (t1 - (t1*3600*24)) / 3600; /* hours */
590                }
591                text = g_strdup_printf(_("%#.1fMb received / %#.1fMb sent / time: %.1d:%.2d"),
592                                       (float)rx / 1000000, (float)tx / 1000000, t1, t2);
593                }
594        else
595                {
596                text = g_strdup(_("not connected"));
597                }
598
599        gtk_tooltips_set_tip(mldata->tooltips, mldata->applet, text, NULL);
600        g_free(text);
601
602}
603
604
605/*
606 *-------------------------------------
607 * display drawing
608 *-------------------------------------
609 */
610
611static void redraw_display(MLData *mldata)
612{
613        gdk_window_set_back_pixmap(mldata->display_area->window,mldata->display,FALSE);
614
615        gdk_window_clear(mldata->display_area->window);
616
617}
618
619static void draw_digit(MLData *mldata, gint n, gint x, gint y)
620{
621        gdk_draw_drawable (mldata->display,
622                           mldata->display_area->style->fg_gc[GTK_WIDGET_STATE(mldata->display_area)],
623                           mldata->digits, n * 5, 0, x, y, 5, 7);
624}
625
626static void draw_timer(MLData *mldata, gint seconds, gint force)
627{
628        gint x, y;
629
630        if (!mldata->layout_current || mldata->layout_current->time_x < 0) return;
631
632        x = mldata->layout_current->time_x;
633        y = mldata->layout_current->time_y;
634
635        if (seconds > -1)
636                {
637                gint a, b;
638
639                if (seconds >= 3600) seconds /= 60; /* HH:MM, else MM:SS */
640
641                a = seconds / 60;
642                b = seconds % 60;
643
644                draw_digit(mldata, a / 10, x, y);
645                draw_digit(mldata, a % 10, x+5, y);
646
647                draw_digit(mldata, b / 10, x+15, y);
648                draw_digit(mldata, b % 10, x+20, y);
649
650                draw_digit(mldata, 15, x+10, y);
651                }
652        else
653                {
654                if (force)
655                        {
656                        draw_digit(mldata, 10, x, y);
657                        draw_digit(mldata, 10, x+5, y);
658
659                        draw_digit(mldata, 10, x+15, y);
660                        draw_digit(mldata, 10, x+20, y);
661                        }
662
663                draw_digit(mldata, 14, x+10, y);
664                }
665}
666
667static void draw_bytes(MLData *mldata, gint bytes)
668{
669        gint x, y;
670
671        if (!mldata->layout_current || mldata->layout_current->bytes_x < 0) return;
672
673        x = mldata->layout_current->bytes_x;
674        y = mldata->layout_current->bytes_y;
675
676        if (bytes > -1)
677                {
678                gint dig;
679                if (bytes > 9999)
680                        {
681                        bytes /= 1024;
682                        draw_digit(mldata, 12, x + 20, y);
683                        }
684                else
685                        {
686                        draw_digit(mldata, 13, x + 20, y);
687                        }
688
689                dig = bytes / 1000;
690                draw_digit(mldata, dig, x, y);
691                bytes %= 1000;
692                dig = bytes / 100;
693                draw_digit(mldata, dig, x+5, y);
694                bytes %= 100;
695                dig = bytes / 10;
696                draw_digit(mldata, dig, x+10, y);
697                bytes %= 10;
698                draw_digit(mldata, bytes, x+15, y);
699                }
700        else
701                {
702                draw_digit(mldata, 10, x, y);
703                draw_digit(mldata, 10, x+5, y);
704                draw_digit(mldata, 10, x+10, y);
705                draw_digit(mldata, 10, x+15, y);
706
707                draw_digit(mldata, 11, x+20, y);
708                }
709}
710
711static gint update_extra_info(MLData *mldata, int rx_bytes, gint force)
712{       
713        gint redraw = FALSE;
714        gint new_timer;
715        gint new_bytes;
716
717        if (!mldata->layout_current || (mldata->layout_current->bytes_x < 0 && mldata->layout_current->time_x < 0)) return FALSE;
718
719        mldata->update_counter++;
720        if (mldata->update_counter < mldata->UPDATE_DELAY && !force) return FALSE;
721        mldata->update_counter = 0;
722
723        if (rx_bytes != -1)
724                new_timer = get_connect_time(mldata, FALSE);
725        else
726                new_timer = -1;
727
728        if (new_timer != mldata->old_timer)
729                {
730                mldata->old_timer = new_timer;
731                redraw = TRUE;
732                draw_timer(mldata, new_timer, FALSE);
733                }
734        else if (force)
735                {
736                redraw = TRUE;
737                draw_timer(mldata, mldata->old_timer, TRUE);
738                }
739
740        if (rx_bytes == -1 || mldata->old_rx_bytes == -1)
741                {
742                new_bytes = -1;
743                }
744        else
745                {
746                new_bytes = rx_bytes - mldata->old_rx_bytes;
747                }
748
749        if (new_bytes != mldata->old_bytes)
750                {
751                mldata->old_bytes = new_bytes;
752                redraw = TRUE;
753                draw_bytes(mldata, new_bytes);
754                }
755        else if (force)
756                {
757                redraw = TRUE;
758                draw_bytes(mldata, mldata->old_bytes);
759                }
760
761        mldata->old_rx_bytes = rx_bytes;
762
763        return redraw;
764}
765
766static void draw_load(MLData *mldata, int rxbytes, int txbytes)
767{
768        int load_max = 0;
769        int i;
770        int x, y, dot_height;
771        float bytes_per_dot;
772
773        if (!mldata->layout_current) return;
774
775        x = mldata->layout_current->load_x + 1;
776        y = mldata->layout_current->load_y + mldata->layout_current->load_h - 2;
777        dot_height = mldata->layout_current->load_h - 2;
778
779        /* sanity check: */
780        if (rxbytes <0) rxbytes = 0;
781        if (txbytes <0) txbytes = 0;
782
783        mldata->load_hist_pos++;
784        if (mldata->load_hist_pos > 119) mldata->load_hist_pos = 0;
785        if (txbytes > rxbytes)
786                mldata->load_hist[mldata->load_hist_pos] = txbytes;
787        else
788                mldata->load_hist[mldata->load_hist_pos] = rxbytes;
789        for (i=0;i<120;i++)
790                if (load_max < mldata->load_hist[i]) load_max = mldata->load_hist[i];
791
792        for (i=0;i<15;i++)
793                {
794                mldata->load_hist_rx[i] = mldata->load_hist_rx[i+1];
795                mldata->load_hist_tx[i] = mldata->load_hist_tx[i+1];
796                }
797        mldata->load_hist_rx[15] = rxbytes;
798        mldata->load_hist_tx[15] = txbytes;
799
800        if (load_max < dot_height)
801                bytes_per_dot = 1.0;
802        else
803                bytes_per_dot = (float)load_max / (dot_height - 1);
804
805        gdk_gc_set_foreground( mldata->gc, &mldata->display_color[COLOR_TEXT_BG] );
806        gdk_draw_rectangle(mldata->display, mldata->gc, TRUE, x, y - dot_height + 1, 16, dot_height);
807
808        gdk_gc_set_foreground( mldata->gc, &mldata->display_color[COLOR_RX] );
809        for (i=0;i<16;i++)
810                {
811                if( mldata->load_hist_rx[i] )
812                        gdk_draw_line(mldata->display, mldata->gc, x+i, y ,
813                                x+i, y - ((float)mldata->load_hist_rx[i] / bytes_per_dot) + 1);
814                }
815
816        gdk_gc_set_foreground( mldata->gc, &mldata->display_color[COLOR_TX] );
817        for (i=0;i<16;i++)
818                {
819                if( mldata->load_hist_tx[i] )
820                        gdk_draw_line(mldata->display, mldata->gc, x+i, y,
821                                x+i, y - ((float)mldata->load_hist_tx[i] / bytes_per_dot) + 1);
822                }
823
824        redraw_display(mldata);
825}
826
827static void draw_light(MLData *mldata, int lit, int x, int y, ColorType color)
828{
829        gint p;
830
831        if (lit)
832                p = 9;
833        else
834                p = 0;
835
836        if (color == COLOR_RX) p += 18;
837       
838
839        gdk_draw_drawable (mldata->display,
840                           mldata->display_area->style->fg_gc[GTK_WIDGET_STATE(mldata->display_area)],
841                           mldata->lights, 0, p, x, y, 9, 9);
842}
843
844static void update_button(MLData *mldata, StatusType type)
845{
846        switch(type)
847                {
848                case STATUS_ON:
849                        gtk_image_set_from_pixmap(GTK_IMAGE(mldata->button_image), mldata->button_on, mldata->button_mask);
850                        break;
851                case STATUS_WAIT:
852                        gtk_image_set_from_pixmap(GTK_IMAGE(mldata->button_image), mldata->button_wait, mldata->button_mask);
853                        break;
854                default:
855                        gtk_image_set_from_pixmap(GTK_IMAGE(mldata->button_image), mldata->button_off, mldata->button_mask);
856                        break;
857                }
858}
859
860/* to minimize drawing (pixmap manipulations) we only draw a light if it has changed */
861static void update_lights(MLData *mldata, int rx, int tx, int cd, int rx_bytes, gint force)
862{       
863        int redraw_required = FALSE;
864
865        if (!mldata->layout_current) return;
866
867        if (rx != mldata->o_rx || force)
868                {
869                mldata->o_rx = rx;
870                draw_light(mldata, rx , mldata->layout_current->rx_x, mldata->layout_current->rx_y, COLOR_RX);
871                redraw_required = TRUE;
872                }
873        if (tx != mldata->o_tx || force)
874                {
875                mldata->o_tx = tx;
876                draw_light(mldata, tx, mldata->layout_current->tx_x, mldata->layout_current->tx_y, COLOR_TX);
877                redraw_required = TRUE;
878                }
879        if ((cd != mldata->o_cd && !mldata->button_blinking) || force)
880                {
881                mldata->o_cd = cd;
882                update_button(mldata, cd ? STATUS_ON : STATUS_OFF);
883                }
884
885        /* we do the extra info redraws here too */
886        if (mldata->show_extra_info && update_extra_info(mldata, rx_bytes, force))
887                {
888                redraw_required = TRUE;
889                }
890
891        if (redraw_required) redraw_display(mldata);
892}
893
894static gint button_blink_cb(gpointer data)
895{
896        MLData *mldata = data;
897        if (mldata->button_blink_on && mldata->status_wait_blink)
898                {
899                mldata->button_blink_on = FALSE;
900                }
901        else
902                {
903                mldata->button_blink_on = TRUE;
904                }
905        update_button(mldata, mldata->button_blink_on ? STATUS_WAIT : STATUS_OFF);
906
907        return TRUE;
908        data = NULL;
909}
910
911static void button_blink(MLData *mldata, gint blink, gint status)
912{
913        if (mldata->button_blinking == blink) return;
914
915        if (blink)
916                {
917                if (mldata->button_blink_id == -1)
918                        {
919                        mldata->button_blink_id = g_timeout_add(BUTTON_BLINK_INTERVAL, button_blink_cb, mldata);
920                        }
921                }
922        else
923                {
924                if (mldata->button_blink_id != -1)
925                        {
926                        g_source_remove(mldata->button_blink_id);
927                        mldata->button_blink_id = -1;
928                        }
929                }
930
931        mldata->button_blinking = blink;
932        mldata->button_blink_on = status;
933        if (blink)
934                {
935                update_button(mldata, mldata->button_blink_on ? STATUS_WAIT : STATUS_OFF);
936                }       
937        else
938                {
939                update_button(mldata, mldata->button_blink_on ? STATUS_ON : STATUS_OFF);
940                }
941}
942
943
944/*
945 *-------------------------------------
946 * the main callback loop (1 sec)
947 *-------------------------------------
948 */
949
950static gint update_display(MLData *mldata)
951{       
952        int rx, tx;
953        int light_rx = FALSE;
954        int light_tx = FALSE;
955
956        mldata->load_count++;
957
958        if (is_connected(mldata))
959                {
960                if (!mldata->last_time_was_connected)
961                        {
962                        get_connect_time(mldata, TRUE); /* reset start time */
963                        mldata->last_time_was_connected = TRUE;
964                        }
965
966                if (!get_stats (mldata, &rx, &tx) || (rx == 0 && tx == 0))
967                        {
968                        mldata->old_rx = mldata->old_tx = 0;
969                        button_blink(mldata, TRUE, TRUE);
970                        }
971                else
972                        {
973                        button_blink(mldata, FALSE, TRUE);
974                        if (rx > mldata->old_rx) light_rx = TRUE;
975                        if (tx > mldata->old_tx) light_tx = TRUE;
976                        }
977               
978                update_lights(mldata, light_rx, light_tx, TRUE, rx, FALSE);
979                if (mldata->load_count > mldata->UPDATE_DELAY * 2)
980                        {
981                        mldata->tooltip_counter++;
982                        if (mldata->tooltip_counter > 10)
983                                {
984                                update_tooltip(mldata,TRUE, rx, tx);
985                                mldata->tooltip_counter = 0;
986                                }
987
988        /* This is a check to see if the modem was running before the program
989        started. if it was, we set the past bytes to the current bytes. Otherwise
990        the first load calculation could have a very high number of bytes.
991        (the bytes that accumulated before program start will make max_load too high) */
992                        if (!mldata->modem_was_on)
993                                {
994                                mldata->load_rx = rx;
995                                mldata->load_tx = tx;
996                                update_tooltip(mldata, TRUE,rx,tx);
997                                mldata->modem_was_on = TRUE;
998                                }
999               
1000                        mldata->load_count = 0;
1001                        draw_load(mldata, rx - mldata->load_rx, tx - mldata->load_tx);
1002                        mldata->load_rx = rx;
1003                        mldata->load_tx = tx;
1004                        }
1005                mldata->old_rx = rx;
1006                mldata->old_tx = tx;
1007                }
1008        else
1009                {
1010                if (mldata->load_count > mldata->UPDATE_DELAY * 2)
1011                        {
1012                        mldata->load_count = 0;
1013                        draw_load(mldata, 0,0);
1014                        }
1015                button_blink(mldata, FALSE, FALSE);
1016                update_lights(mldata, FALSE, FALSE, FALSE, -1, FALSE);
1017                if (mldata->tooltip_counter > 0)
1018                        {
1019                        update_tooltip(mldata, FALSE, 0, 0);
1020                        mldata->tooltip_counter = 0;
1021                        }
1022                if (mldata->last_time_was_connected)
1023                        {
1024                        mldata->last_time_was_connected = FALSE;
1025                        }
1026                }
1027
1028        return TRUE;
1029}
1030
1031/*
1032 *-------------------------------------
1033 * setup and init
1034 *-------------------------------------
1035 */
1036
1037/* start or change the update callback timeout interval */
1038void start_callback_update(MLData *mldata)
1039{
1040        gint delay;
1041        delay = 1000 / mldata->UPDATE_DELAY;
1042        if (mldata->update_timeout_id) g_source_remove(mldata->update_timeout_id);
1043        mldata->update_timeout_id = g_timeout_add(delay, (GSourceFunc)update_display, mldata);
1044
1045}
1046
1047static void draw_shadow_box(MLData *mldata, GdkPixmap *window, gint x, gint y, gint w, gint h,
1048                            gint etched_in, GdkGC *bgc)
1049{
1050        GdkGC *gc1;
1051        GdkGC *gc2;
1052
1053        if (!etched_in)
1054                {
1055                gc1 = mldata->applet->style->light_gc[GTK_STATE_NORMAL];
1056                gc2 = mldata->applet->style->dark_gc[GTK_STATE_NORMAL];
1057                }
1058        else
1059                {
1060                gc1 = mldata->applet->style->dark_gc[GTK_STATE_NORMAL];
1061                gc2 = mldata->applet->style->light_gc[GTK_STATE_NORMAL];
1062                }
1063
1064        gdk_draw_line(window, gc1, x, y + h - 1, x, y);
1065        gdk_draw_line(window, gc1, x, y, x + w - 2, y);
1066        gdk_draw_line(window, gc2, x + w - 1, y, x + w - 1, y + h - 1);
1067        gdk_draw_line(window, gc2, x + w - 2, y + h - 1, x + 1, y + h - 1);
1068
1069        if (bgc)
1070                {
1071                gdk_draw_rectangle(window, bgc, TRUE, x + 1, y + 1, w - 2, h - 2);
1072                }
1073
1074}
1075
1076static void create_background_pixmap(MLData *mldata)
1077{
1078        if (!mldata->layout_current) return;
1079
1080        if (mldata->display) g_object_unref(mldata->display);
1081
1082        mldata->display = gdk_pixmap_new(mldata->display_area->window,
1083                                 mldata->layout_current->display_w, mldata->layout_current->display_h, -1);
1084
1085        /* main border */
1086        draw_shadow_box(mldata, mldata->display, 0, 0, mldata->layout_current->display_w, mldata->layout_current->display_h,
1087                        FALSE, mldata->applet->style->bg_gc[GTK_STATE_NORMAL]);
1088
1089        /* load border */
1090        gdk_gc_set_foreground( mldata->gc, &mldata->display_color[COLOR_TEXT_BG] );
1091        draw_shadow_box(mldata, mldata->display, mldata->layout_current->load_x, mldata->layout_current->load_y,
1092                        mldata->layout_current->load_w, mldata->layout_current->load_h, TRUE, mldata->gc);
1093
1094        /* text border(s) */
1095        if (mldata->layout_current->bytes_x >= 0)
1096                {
1097                draw_shadow_box(mldata, mldata->display, mldata->layout_current->bytes_x - 1, mldata->layout_current->bytes_y - 2,
1098                                28, mldata->layout_current->merge_extended_box ? 20 : 11,
1099                                TRUE, mldata->gc);
1100                }
1101        if (mldata->layout_current->time_x >= 0 && !mldata->layout_current->merge_extended_box)
1102                {
1103                draw_shadow_box(mldata, mldata->display, mldata->layout_current->time_x - 1, mldata->layout_current->time_y - 2,
1104                                28, 11, TRUE, mldata->gc);
1105                }
1106}
1107
1108static void draw_button_light(MLData *mldata, GdkPixmap *pixmap, gint x, gint y, gint s, gint etched_in, ColorType color)
1109{
1110        GdkGC *gc1;
1111        GdkGC *gc2;
1112
1113        s -= 8;
1114
1115        gdk_gc_set_foreground( mldata->gc, &mldata->display_color[color] );
1116
1117        if (etched_in)
1118                {
1119                gc1 = mldata->applet->style->dark_gc[GTK_STATE_NORMAL];
1120                gc2 = mldata->applet->style->light_gc[GTK_STATE_NORMAL];
1121                }
1122        else
1123                {
1124                gc1 = mldata->applet->style->light_gc[GTK_STATE_NORMAL];
1125                gc2 = mldata->applet->style->dark_gc[GTK_STATE_NORMAL];
1126                }
1127
1128        /* gdk_draw_arc was always off by one in my attempts (?) */
1129
1130        gdk_draw_line(pixmap, gc1, x, y + 3, x, y + 4 + s);
1131        gdk_draw_line(pixmap, gc1, x + 3, y, x + 4 + s, y);
1132        gdk_draw_line(pixmap, gc1, x + 1, y + 2, x + 1, y + 5 + s);
1133        gdk_draw_line(pixmap, gc1, x + 2, y + 1, x + 5 + s, y + 1);
1134
1135        gdk_draw_line(pixmap, gc2, x + 7 + s, y + 3, x + 7 + s, y + 4 + s);
1136        gdk_draw_line(pixmap, gc2, x + 3, y + 7 + s, x + 4 + s, y + 7 + s);
1137        gdk_draw_line(pixmap, gc2, x + 6 + s, y + 2, x + 6 + s, y + 5 + s);
1138        gdk_draw_line(pixmap, gc2, x + 2, y + 6 + s, x + 5 + s, y + 6 + s);
1139
1140        gdk_draw_rectangle(pixmap, mldata->gc, TRUE, x + 3, y + 1, 2 + s, 6 + s);
1141        gdk_draw_rectangle(pixmap, mldata->gc, TRUE, x + 1, y + 3, 6 + s, 2 + s);
1142        gdk_draw_rectangle(pixmap, mldata->gc, TRUE, x + 2, y + 2, 4 + s, 4 + s);
1143}
1144
1145static void pixmap_set_colors(MLData *mldata, GdkPixmap *pixmap, GdkColor *bg, GdkColor *fg, GdkColor *mid)
1146{
1147        gint w;
1148        gint h;
1149        gint x, y;
1150        GdkImage *image;
1151        guint32 bg_pixel = 0x00000000;
1152        guint32 fg_pixel = 0x00000000;
1153        gint have_fg = FALSE;
1154
1155        gdk_drawable_get_size(pixmap, &w, &h);
1156
1157        image = gdk_drawable_get_image(pixmap, 0, 0, w, h);
1158
1159        /* always assume 0, 0 is background color */
1160        bg_pixel = gdk_image_get_pixel(image, 0, 0);
1161
1162        for (x = 0; x < w; x++)
1163                {
1164                for (y = 0; y < h; y++)
1165                        {
1166                        guint32 pixel;
1167
1168                        pixel = gdk_image_get_pixel(image, x, y);
1169                        if (pixel == bg_pixel)
1170                                {
1171                                gdk_gc_set_foreground( mldata->gc, bg );
1172                                }
1173                        else if (!have_fg || pixel == fg_pixel)
1174                                {
1175                                if (!have_fg)
1176                                        {
1177                                        have_fg = TRUE;
1178                                        fg_pixel = pixel;
1179                                        }
1180                                gdk_gc_set_foreground( mldata->gc, fg );
1181                                }
1182                        else
1183                                {
1184                                gdk_gc_set_foreground( mldata->gc, mid );
1185                                }
1186                        gdk_draw_point(pixmap, mldata->gc, x, y);
1187                        }
1188                }
1189
1190        g_object_unref(image);
1191}
1192
1193static void update_pixmaps(MLData *mldata)
1194{
1195        GtkStyle *style;
1196        style = gtk_widget_get_style(mldata->applet);
1197
1198        if (!mldata->digits)
1199                {
1200                mldata->digits = gdk_pixmap_create_from_xpm_d(mldata->display_area->window, NULL,
1201                        &style->bg[GTK_STATE_NORMAL], (gchar **)digits_xpm);
1202                }
1203        /* change digit colors */
1204        pixmap_set_colors(mldata, mldata->digits,
1205                          &mldata->display_color[COLOR_TEXT_BG],
1206                          &mldata->display_color[COLOR_TEXT_FG],
1207                          &mldata->display_color[COLOR_TEXT_MID]);
1208
1209        if (!mldata->button_on) mldata->button_on = gdk_pixmap_new(mldata->display_area->window, 10, 10, -1);
1210        if (!mldata->button_off) mldata->button_off = gdk_pixmap_new(mldata->display_area->window, 10, 10, -1);
1211        if (!mldata->button_wait) mldata->button_wait = gdk_pixmap_new(mldata->display_area->window, 10, 10, -1);
1212        if (!mldata->button_mask)
1213                {
1214                GdkGC *mask_gc = NULL;
1215
1216                mldata->button_mask = gdk_pixmap_new(mldata->display_area->window, 10, 10, 1);
1217
1218                mask_gc = gdk_gc_new(mldata->button_mask);
1219
1220                gdk_gc_set_foreground(mask_gc, &style->black);
1221                gdk_draw_rectangle(mldata->button_mask, mask_gc, TRUE, 0, 0, 10, 10);
1222                gdk_gc_set_foreground(mask_gc, &style->white);
1223                /* gdk_draw_arc was always off by one in my attempts (?) */
1224                gdk_draw_rectangle(mldata->button_mask, mask_gc, TRUE, 3, 0, 4, 10);
1225                gdk_draw_rectangle(mldata->button_mask, mask_gc, TRUE, 0, 3, 10, 4);
1226                gdk_draw_rectangle(mldata->button_mask, mask_gc, TRUE, 2, 1, 6, 8);
1227                gdk_draw_rectangle(mldata->button_mask, mask_gc, TRUE, 1, 2, 8, 6);
1228
1229                g_object_unref(mask_gc);
1230                }
1231
1232        draw_button_light(mldata, mldata->button_on, 0, 0, 10, TRUE, COLOR_STATUS_OK);
1233        draw_button_light(mldata, mldata->button_off, 0, 0, 10, TRUE, COLOR_STATUS_BG);
1234        draw_button_light(mldata, mldata->button_wait, 0, 0, 10, TRUE, COLOR_STATUS_WAIT);
1235
1236        if (!mldata->lights) mldata->lights = gdk_pixmap_new(mldata->display_area->window, 9, 36, -1);
1237
1238        gdk_draw_rectangle(mldata->lights, mldata->applet->style->bg_gc[GTK_STATE_NORMAL], TRUE, 0, 0, 9, 36);
1239        draw_button_light(mldata, mldata->lights, 0, 0, 9, FALSE, COLOR_TX_BG);
1240        draw_button_light(mldata, mldata->lights, 0, 9, 9, FALSE, COLOR_TX);
1241        draw_button_light(mldata, mldata->lights, 0, 18, 9, FALSE, COLOR_RX_BG);
1242        draw_button_light(mldata, mldata->lights, 0, 27, 9, FALSE, COLOR_RX);
1243}
1244
1245static void setup_colors(MLData *mldata)
1246{
1247        GdkColormap *colormap;
1248        gint i;
1249        gboolean success[COLOR_COUNT];
1250
1251        colormap = gtk_widget_get_colormap(mldata->display_area);
1252
1253        if (mldata->allocated)
1254                {
1255                gdk_colormap_free_colors(colormap, mldata->display_color, COLOR_COUNT);
1256                }
1257
1258        for (i = 0; i < COLOR_COUNT; i++)
1259                {
1260                if (!mldata->display_color_text[i]) mldata->display_color_text[i] = g_strdup("#000000");
1261                gdk_color_parse(mldata->display_color_text[i], &mldata->display_color[i]);
1262                }
1263        gdk_colormap_alloc_colors(colormap, mldata->display_color,
1264                                                COLOR_COUNT, FALSE, TRUE, success);
1265        for (i = 0; i < COLOR_COUNT; i++)
1266                {
1267                if (!success[i]) printf("unable to allocate color %s\n", mldata->display_color_text[i]);
1268                }
1269
1270        mldata->allocated = TRUE;
1271
1272        if (!mldata->gc)
1273                {
1274                mldata->gc = gdk_gc_new( mldata->display_area->window );
1275                gdk_gc_copy( mldata->gc, mldata->display_area->style->white_gc );
1276                }
1277
1278}
1279
1280void reset_orientation(MLData *mldata)
1281{
1282        if (mldata->sizehint >= GNOME_Vertigo_PANEL_MEDIUM)
1283                {
1284                if (mldata->show_extra_info)
1285                        {
1286                        if (mldata->orient == PANEL_APPLET_ORIENT_LEFT || mldata->orient == PANEL_APPLET_ORIENT_RIGHT)
1287                              {
1288                              if (mldata->sizehint >= 74)
1289                                      mldata->layout = LAYOUT_HORIZONTAL_EXTENDED;
1290                              else
1291                                      mldata->layout = LAYOUT_SQUARE;
1292                              }
1293                        else
1294                              {
1295                              if (mldata->sizehint >= 58)
1296                                      mldata->layout = LAYOUT_VERTICAL_EXTENDED;
1297                              else
1298                                      mldata->layout = LAYOUT_SQUARE;
1299                              }
1300                        }
1301                else if (mldata->orient == PANEL_APPLET_ORIENT_LEFT || mldata->orient == PANEL_APPLET_ORIENT_RIGHT)
1302                        {
1303                        mldata->layout = LAYOUT_HORIZONTAL;
1304                        }
1305                else
1306                        {
1307                        mldata->layout = LAYOUT_VERTICAL;
1308                        }
1309                }
1310        else
1311                {
1312                if (mldata->orient == PANEL_APPLET_ORIENT_LEFT || mldata->orient == PANEL_APPLET_ORIENT_RIGHT)
1313                        {
1314                        if (mldata->show_extra_info)
1315                                {
1316                                mldata->layout = LAYOUT_VERTICAL_EXTENDED;
1317                                }
1318                        else
1319                                {
1320                                mldata->layout = LAYOUT_VERTICAL;
1321                                }
1322                        }
1323                else
1324                        {
1325                        if (mldata->show_extra_info)
1326                                {
1327                                mldata->layout = LAYOUT_HORIZONTAL_EXTENDED;
1328                                }
1329                        else
1330                                {
1331                                mldata->layout = LAYOUT_HORIZONTAL;
1332                                }
1333                        }
1334                }
1335
1336        if (mldata->layout < LAYOUT_HORIZONTAL || mldata->layout > LAYOUT_SQUARE) mldata->layout = LAYOUT_HORIZONTAL;
1337        mldata->layout_current = &layout_data[mldata->layout];
1338       
1339        create_background_pixmap(mldata);
1340        update_pixmaps(mldata);
1341
1342        gtk_widget_set_size_request(mldata->frame, mldata->layout_current->width, mldata->layout_current->height);
1343        gtk_widget_set_size_request(GTK_WIDGET(mldata->display_area),
1344                              mldata->layout_current->display_w, mldata->layout_current->display_h);
1345
1346        gtk_widget_set_size_request(mldata->button, mldata->layout_current->button_w, mldata->layout_current->button_h);
1347        gtk_fixed_move(GTK_FIXED(mldata->frame), mldata->display_area, mldata->layout_current->display_x, mldata->layout_current->display_y);
1348        gtk_fixed_move(GTK_FIXED(mldata->frame), mldata->button, mldata->layout_current->button_x, mldata->layout_current->button_y);
1349
1350        /* we set the lights to off so they will be correct on the next update */
1351        update_lights(mldata, FALSE, FALSE, FALSE, -1, TRUE);
1352        redraw_display(mldata);
1353}
1354
1355void reset_colors(MLData *mldata)
1356{
1357        setup_colors(mldata);
1358        create_background_pixmap(mldata);
1359        update_pixmaps(mldata);
1360        update_lights(mldata, FALSE, FALSE, FALSE, -1, TRUE);
1361        redraw_display(mldata);
1362}
1363
1364/* this is called when the applet's style changes (meaning probably a theme/color change) */
1365static void applet_style_change_cb(GtkWidget *widget, GtkStyle *previous_style, gpointer data)
1366{
1367        MLData *mldata = data;
1368        reset_orientation(mldata);
1369        return;
1370}
1371
1372static void applet_change_orient(PanelApplet *applet, PanelAppletOrient o, gpointer data)
1373{
1374        MLData *mldata = data;
1375        mldata->orient = o;
1376        if (mldata->setup_done) reset_orientation(mldata);
1377        return;
1378}
1379
1380
1381static void applet_change_pixel_size(PanelApplet *applet, gint size, gpointer data)
1382{
1383        MLData *mldata = data;
1384        mldata->sizehint = size;
1385        if (mldata->setup_done) reset_orientation(mldata);
1386        return;
1387}
1388
1389/* This is a hack around the fact that gtk+ doesn't
1390 * propogate button presses on button2/3.
1391 */
1392static gboolean
1393button_press_hack (GtkWidget      *widget,
1394                   GdkEventButton *event,
1395                   GtkWidget      *applet)
1396{
1397    if (event->button == 3 || event->button == 2) {
1398        gtk_propagate_event (applet, (GdkEvent *) event);
1399
1400        return TRUE;
1401    }
1402
1403    return FALSE;
1404}
1405
1406
1407static void show_help_cb (BonoboUIComponent *uic,
1408                          MLData       *mldata,
1409                          const char        *verbname)
1410{
1411        PanelApplet *applet = PANEL_APPLET (mldata->applet);
1412        gnome_help_display_on_screen (
1413                "modemlights", NULL,
1414                gtk_widget_get_screen (GTK_WIDGET (applet)),
1415                NULL);
1416}
1417
1418static const BonoboUIVerb modem_applet_menu_verbs [] = {
1419        BONOBO_UI_UNSAFE_VERB ("Props", property_show),
1420        BONOBO_UI_UNSAFE_VERB ("Help", show_help_cb),
1421        BONOBO_UI_UNSAFE_VERB ("About", about_cb),
1422
1423        BONOBO_UI_VERB_END
1424};
1425
1426static void
1427destroy_cb (GtkWidget *widget, gpointer data)
1428{
1429        MLData *mldata = data;
1430
1431        g_source_remove (mldata->update_timeout_id);
1432       
1433        if (mldata->about_dialog)
1434                gtk_widget_destroy (mldata->about_dialog);
1435        if (mldata->propwindow)
1436                gtk_widget_destroy (mldata->propwindow);
1437        if (mldata->connect_dialog)
1438                gtk_widget_destroy (mldata->connect_dialog);
1439        if (mldata->run_dialog)
1440                gtk_widget_destroy (mldata->run_dialog);
1441        if (mldata->tooltips)
1442                g_object_unref (mldata->tooltips);
1443        g_free (data);
1444}
1445
1446static gboolean
1447modemlights_applet_fill (PanelApplet *applet)
1448{
1449        MLData *mldata;
1450        gint i;
1451        AtkObject *atk_obj;
1452
1453        mldata = g_new0 (MLData, 1);
1454       
1455        mldata->applet = GTK_WIDGET (applet);
1456        mldata->layout = LAYOUT_HORIZONTAL;
1457        mldata->tooltips = gtk_tooltips_new ();
1458        g_object_ref (mldata->tooltips);
1459        gtk_object_sink (GTK_OBJECT (mldata->tooltips));
1460        mldata->button_blinking = FALSE;
1461        mldata->button_blink_on = 0;
1462        mldata->button_blink_id = -1;
1463        mldata->update_timeout_id = FALSE;
1464        mldata->about_dialog = NULL;
1465        mldata->setup_done = FALSE;
1466        mldata->start_time = (time_t)0;
1467        mldata->old_timer = -1;
1468        mldata->old_bytes = -1;
1469        mldata->old_rx_bytes = -1;
1470        mldata->update_counter = 0;
1471        mldata->o_rx = FALSE;
1472        mldata->o_tx = FALSE;
1473        mldata->o_cd = FALSE;
1474        mldata->modem_was_on = FALSE;
1475        mldata->last_time_was_connected = FALSE;
1476        mldata->allocated = FALSE;
1477        mldata->isdn_stats = NULL;
1478        mldata->connect_dialog = NULL;
1479        mldata->run_dialog = NULL;
1480
1481        gnome_window_icon_set_default_from_file (GNOME_ICONDIR"/gnome-modem.png");
1482       
1483        panel_applet_add_preferences (applet, "/schemas/apps/modemlights/prefs", NULL);
1484               
1485        mldata->load_hist_pos = 0;
1486        for (i=0;i<119;i++)
1487                mldata->load_hist[i] = 0;
1488
1489        for (i=0;i<19;i++)
1490                {
1491                mldata->load_hist_rx[i] = 0;
1492                mldata->load_hist_tx[i] = 0;
1493                }
1494        for (i = 0; i < COLOR_COUNT; i++)
1495                {
1496                mldata->display_color_text[i] = NULL;
1497                mldata->display_color[i] = (GdkColor){ 0, 0, 0, 0 };
1498                }
1499
1500        mldata->layout_current = &layout_data[LAYOUT_HORIZONTAL];
1501       
1502        if (g_file_test("/dev/modem", G_FILE_TEST_EXISTS))
1503                mldata->lock_file = g_strdup("/var/lock/LCK..modem");
1504        else
1505                mldata->lock_file = g_strdup("/var/lock/LCK..ttyS0");
1506
1507
1508        mldata->device_name = g_strdup("ppp0");
1509        mldata->command_connect = g_strdup("pppon");
1510        mldata->command_disconnect = g_strdup("pppoff");
1511        mldata->orient = panel_applet_get_orient (applet);
1512
1513        /* open ip socket */
1514#ifdef AF_INET6
1515        if ((mldata->ip_socket = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1516#endif
1517                {
1518                if ((mldata->ip_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1519                        {
1520                        g_print("could not open an ip socket\n");
1521                        return FALSE;
1522                        }
1523                }
1524
1525
1526        property_load(mldata);
1527
1528        /* frame for all widgets */
1529        mldata->frame = gtk_fixed_new();
1530        gtk_widget_show(mldata->frame);
1531       
1532        gtk_container_add (GTK_CONTAINER (applet), mldata->frame);
1533
1534        mldata->display_area = gtk_drawing_area_new();
1535        gtk_widget_set_size_request(GTK_WIDGET(mldata->display_area),5,5);
1536        gtk_fixed_put(GTK_FIXED(mldata->frame),mldata->display_area,0,0);
1537        gtk_widget_show(mldata->display_area);
1538
1539        mldata->button = gtk_button_new();
1540        gtk_widget_set_size_request(mldata->button,5,5);
1541        gtk_fixed_put(GTK_FIXED(mldata->frame),mldata->button,5,0);
1542        g_signal_connect(G_OBJECT(mldata->button), "clicked",
1543                         G_CALLBACK(dial_cb), mldata);
1544        g_signal_connect(G_OBJECT (mldata->button), "button_press_event",
1545                         G_CALLBACK(button_press_hack), GTK_WIDGET (applet));
1546        gtk_widget_show(mldata->button);
1547
1548        gtk_widget_realize(GTK_WIDGET (applet));
1549        gtk_widget_realize(mldata->display_area);
1550       
1551        setup_colors(mldata);
1552        update_pixmaps(mldata);
1553
1554        mldata->button_image = gtk_image_new_from_pixmap(mldata->button_off, mldata->button_mask);
1555        gtk_container_add(GTK_CONTAINER(mldata->button), mldata->button_image);
1556        gtk_widget_show(mldata->button_image);
1557       
1558
1559        g_signal_connect(G_OBJECT(applet),"change_orient",
1560                         G_CALLBACK(applet_change_orient),
1561                         mldata);
1562
1563        g_signal_connect(G_OBJECT(applet),"change_size",
1564                         G_CALLBACK(applet_change_pixel_size),
1565                         mldata);
1566
1567        g_signal_connect(G_OBJECT(applet),"style_set",
1568                         G_CALLBACK(applet_style_change_cb), mldata);
1569               
1570        g_signal_connect (G_OBJECT (applet), "destroy",
1571                          G_CALLBACK (destroy_cb), mldata);
1572                               
1573        mldata->sizehint = panel_applet_get_size (PANEL_APPLET (applet));
1574       
1575        panel_applet_setup_menu_from_file (PANEL_APPLET (applet),
1576                                           NULL,
1577                                           "GNOME_ModemlightsApplet.xml",
1578                                           NULL,
1579                                           modem_applet_menu_verbs,
1580                                           mldata);
1581
1582        if (panel_applet_get_locked_down (PANEL_APPLET (applet))) {
1583                BonoboUIComponent *popup_component;
1584
1585                popup_component = panel_applet_get_popup_component (PANEL_APPLET (applet));
1586
1587                bonobo_ui_component_set_prop (popup_component,
1588                                              "/commands/Props",
1589                                              "hidden", "1",
1590                                              NULL);
1591        }
1592        update_tooltip(mldata, FALSE, 0, 0);
1593
1594        /* by now we know the geometry */
1595        mldata->setup_done = TRUE;
1596
1597        reset_orientation(mldata);
1598       
1599        start_callback_update(mldata);
1600
1601        atk_obj = gtk_widget_get_accessible (mldata->button);
1602        if (GTK_IS_ACCESSIBLE (atk_obj))
1603                atk_object_set_name (atk_obj, _("Modem Lights"));
1604
1605        gtk_widget_show_all (GTK_WIDGET (applet));
1606         
1607        return TRUE;
1608}
1609
1610
1611static gboolean
1612modemlights_applet_factory (PanelApplet *applet,
1613                            const gchar *iid,
1614                            gpointer     data)
1615{
1616        gboolean retval;
1617   
1618        if (!strcmp (iid, "OAFIID:GNOME_ModemLightsApplet"))
1619                retval = modemlights_applet_fill (applet);
1620   
1621        return retval;
1622}
1623
1624PANEL_APPLET_BONOBO_FACTORY ("OAFIID:GNOME_ModemLightsApplet_Factory",
1625                             PANEL_TYPE_APPLET,
1626                             "modemlights",
1627                             "0",
1628                             modemlights_applet_factory,
1629                             NULL)
Note: See TracBrowser for help on using the repository browser.