~ubuntu-branches/ubuntu/natty/lunar-applet/natty

« back to all changes in this revision

Viewing changes to src/lunar.c

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Fok
  • Date: 2007-10-06 05:49:22 UTC
  • Revision ID: james.westby@ubuntu.com-20071006054922-01fgv0533z0c2331
Tags: upstream-1.6
ImportĀ upstreamĀ versionĀ 1.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
 
2
/*
 
3
 * clock.c: the GNOME clock applet
 
4
 *
 
5
 * Copyright (C) 1997-2003 Free Software Foundation, Inc.
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or
 
8
 * modify it under the terms of the GNU General Public License as
 
9
 * published by the Free Software Foundation; either version 2 of the
 
10
 * License, or (at your option) any later version.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful, but
 
13
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
 * General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
20
 * 02111-1307, USA.
 
21
 *
 
22
 * Authors:
 
23
 *      Miguel de Icaza
 
24
 *      Frederico Mena
 
25
 *      Stuart Parmenter
 
26
 *      Alexander Larsson
 
27
 *      George Lebl
 
28
 *      Gediminas Paulauskas
 
29
 *      Mark McLoughlin
 
30
 */
 
31
 
 
32
 /*
 
33
  * Evolution calendar integration TODO:
 
34
  *   + Fix treeview scrolling and sizing
 
35
  *   + Tooltips for tasks/appointments
 
36
  *   + Do everything backwards if the clock is on the bottom
 
37
  *   + Double clicking appointments/tasks should open them in evo
 
38
  *   + Consider using different colours for different sources
 
39
  *   + Consider doing a GtkMenu tearoff type thing
 
40
  */
 
41
 
 
42
#include "config.h"
 
43
 
 
44
#include <stdio.h>
 
45
#include <sys/stat.h>
 
46
#include <unistd.h>
 
47
#include <dirent.h>
 
48
#include <string.h>
 
49
#include <time.h>
 
50
#include <langinfo.h>
 
51
 
 
52
#include <panel-applet.h>
 
53
#include <panel-applet-gconf.h>
 
54
 
 
55
#include <gtk/gtk.h>
 
56
#include <gdk/gdkkeysyms.h>
 
57
#include <gconf/gconf-client.h>
 
58
#include <libgnomeui/gnome-help.h>
 
59
#include <libgnomeui/gnome-url.h>
 
60
 
 
61
#ifdef HAVE_LIBECAL
 
62
#include "calendar-client.h"
 
63
#endif
 
64
#include "gtkchinesecalendar.h"
 
65
 
 
66
#define CLOCK_ICON "lunar-applet"
 
67
#define INTERNETSECOND (864)
 
68
#define INTERNETBEAT   (86400)
 
69
 
 
70
#define N_GCONF_PREFS 7
 
71
 
 
72
#define NEVER_SENSITIVE "never_sensitive"
 
73
 
 
74
static const char* KEY_FORMAT        = "format";
 
75
static const char* KEY_SHOW_SECONDS  = "show_seconds";
 
76
static const char* KEY_SHOW_DATE     = "show_date";
 
77
static const char* KEY_SHOW_LUNARDATE     = "show_lunardate";
 
78
static const char* KEY_GMT_TIME      = "gmt_time";
 
79
static const char* KEY_CONFIG_TOOL   = "config_tool";
 
80
static const char* KEY_CUSTOM_FORMAT = "custom_format";
 
81
static const char* KEY_SHOW_WEEK     = "show_week_numbers";
 
82
 
 
83
static const char *clock_config_tools [] = {
 
84
        "system-config-date",
 
85
        "redhat-config-date",
 
86
        "/sbin/yast2 timezone",
 
87
        "gksu time-admin",
 
88
};
 
89
 
 
90
/* Needs to match the indices in the combo */
 
91
typedef enum {
 
92
        CLOCK_FORMAT_INVALID = 0,
 
93
        CLOCK_FORMAT_12,
 
94
        CLOCK_FORMAT_24,
 
95
        CLOCK_FORMAT_UNIX,
 
96
        CLOCK_FORMAT_INTERNET,
 
97
        CLOCK_FORMAT_CUSTOM
 
98
} ClockFormat;
 
99
 
 
100
static GConfEnumStringPair format_type_enum_map [] = {
 
101
        { CLOCK_FORMAT_12,       "12-hour"  },
 
102
        { CLOCK_FORMAT_24,       "24-hour"  },
 
103
        { CLOCK_FORMAT_UNIX,     "unix"     },
 
104
        { CLOCK_FORMAT_INTERNET, "internet" },
 
105
        { CLOCK_FORMAT_CUSTOM,   "custom"   },
 
106
        { 0, NULL }
 
107
};
 
108
 
 
109
typedef struct _ClockData ClockData;
 
110
 
 
111
struct _ClockData {
 
112
        /* widgets */
 
113
        GtkWidget *applet;
 
114
        GtkWidget *clockw;
 
115
        GtkWidget *toggle;
 
116
        GtkWidget *props;
 
117
        GtkWidget *about;
 
118
        GtkWidget *calendar_popup;
 
119
        GtkWidget *calendar;
 
120
 
 
121
#ifdef HAVE_LIBECAL
 
122
        GtkWidget *task_list;
 
123
        GtkWidget *appointment_list;
 
124
        
 
125
        GtkListStore       *appointments_model;
 
126
        GtkListStore       *tasks_model;
 
127
        GtkTreeModelFilter *tasks_filter;
 
128
 
 
129
        CalendarClient *client;
 
130
#endif /* HAVE_LIBECAL */
 
131
 
 
132
        /* preferences */
 
133
        ClockFormat  format;
 
134
        char        *custom_format;
 
135
        gboolean     showseconds;
 
136
        gboolean     showdate;
 
137
        gboolean     showlunardate;
 
138
        gboolean     gmt_time;
 
139
        gboolean     showweek;
 
140
 
 
141
        char *config_tool;
 
142
 
 
143
        /* runtime data */
 
144
        time_t             current_time;
 
145
        char              *timeformat;
 
146
        guint              timeout;
 
147
        PanelAppletOrient  orient;
 
148
        int                size;
 
149
        GtkAllocation      old_allocation;
 
150
 
 
151
        int fixed_width;
 
152
        int fixed_height;
 
153
 
 
154
        GtkWidget *showseconds_check;
 
155
        GtkWidget *showdate_check;
 
156
        GtkWidget *showlunardate_check;
 
157
        GtkWidget *gmt_time_check;
 
158
        GtkWidget *custom_hbox;
 
159
        GtkWidget *custom_label;
 
160
        GtkWidget *custom_entry;
 
161
        gboolean   custom_format_shown;
 
162
 
 
163
        gboolean   can_handle_format_12;
 
164
 
 
165
        guint listeners [N_GCONF_PREFS];
 
166
};
 
167
 
 
168
static void  update_clock (ClockData * cd);
 
169
static float get_itime    (time_t current_time);
 
170
 
 
171
static void set_atk_name_description (GtkWidget *widget,
 
172
                                      const char *name,
 
173
                                      const char *desc);
 
174
static void display_properties_dialog (BonoboUIComponent *uic,
 
175
                                       ClockData         *cd,
 
176
                                       const gchar       *verbname);
 
177
static void display_help_dialog       (BonoboUIComponent *uic,
 
178
                                       ClockData         *cd,
 
179
                                       const gchar       *verbname);
 
180
static void display_about_dialog      (BonoboUIComponent *uic,
 
181
                                       ClockData         *cd,
 
182
                                       const gchar       *verbname);
 
183
static void position_calendar_popup   (ClockData         *cd,
 
184
                                       GtkWidget         *window,
 
185
                                       GtkWidget         *button);
 
186
static void update_orient (ClockData *cd);
 
187
 
 
188
static void
 
189
unfix_size (ClockData *cd)
 
190
{
 
191
        cd->fixed_width = -1;
 
192
        cd->fixed_height = -1;
 
193
        gtk_widget_queue_resize (cd->toggle);
 
194
}
 
195
 
 
196
static int
 
197
calculate_minimum_width (GtkWidget   *widget,
 
198
                         const gchar *text)
 
199
{
 
200
        PangoContext *context;
 
201
        PangoLayout  *layout;
 
202
        int           width, height;
 
203
        int           focus_width = 0;
 
204
        int           focus_pad = 0;
 
205
 
 
206
        context = gtk_widget_get_pango_context (widget);
 
207
 
 
208
        layout = pango_layout_new (context);
 
209
        pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT);
 
210
        pango_layout_set_text (layout, text, -1);
 
211
        pango_layout_get_pixel_size (layout, &width, &height);
 
212
        g_object_unref (G_OBJECT (layout));
 
213
        layout = NULL;
 
214
 
 
215
        gtk_widget_style_get (widget,
 
216
                              "focus-line-width", &focus_width,
 
217
                              "focus-padding", &focus_pad,
 
218
                              NULL);
 
219
 
 
220
        width += 2 * (focus_width + focus_pad + widget->style->xthickness);
 
221
 
 
222
        return width;
 
223
}
 
224
 
 
225
static void
 
226
set_tooltip (GtkWidget  *applet,
 
227
             GtkWidget  *widget,
 
228
             const char *tip)
 
229
{
 
230
        GtkTooltips *tooltips;
 
231
 
 
232
        tooltips = g_object_get_data (G_OBJECT (applet), "tooltips");
 
233
        if (!tooltips) {
 
234
                tooltips = gtk_tooltips_new ();
 
235
                g_object_ref (tooltips);
 
236
                gtk_object_sink (GTK_OBJECT (tooltips));
 
237
                g_object_set_data_full (
 
238
                        G_OBJECT (applet), "tooltips", tooltips,
 
239
                        (GDestroyNotify) g_object_unref);
 
240
        }
 
241
 
 
242
        gtk_tooltips_set_tip (tooltips, widget, tip, NULL);
 
243
}
 
244
 
 
245
static int
 
246
clock_timeout_callback (gpointer data)
 
247
{
 
248
        ClockData *cd = data;
 
249
        time_t new_time;
 
250
 
 
251
        time (&new_time);
 
252
 
 
253
        if (!cd->showseconds &&
 
254
            cd->format != CLOCK_FORMAT_UNIX &&
 
255
            cd->format != CLOCK_FORMAT_CUSTOM) {
 
256
                if (cd->format == CLOCK_FORMAT_INTERNET && 
 
257
                    (long)get_itime (new_time) !=
 
258
                    (long)get_itime (cd->current_time)) {
 
259
                        update_clock (cd);
 
260
                } else if ((cd->format == CLOCK_FORMAT_12 ||
 
261
                            cd->format == CLOCK_FORMAT_24) &&
 
262
                           new_time / 60 != cd->current_time / 60) {
 
263
                        update_clock (cd);
 
264
                }
 
265
        } else {
 
266
                update_clock (cd);
 
267
        }
 
268
 
 
269
        return TRUE;
 
270
}
 
271
 
 
272
static float
 
273
get_itime (time_t current_time)
 
274
{
 
275
        struct tm *tm;
 
276
        float itime;
 
277
        time_t bmt;
 
278
 
 
279
        /* BMT (Biel Mean Time) is GMT+1 */
 
280
        bmt = current_time + 3600;
 
281
        tm = gmtime (&bmt);
 
282
        itime = (tm->tm_hour*3600.0 + tm->tm_min*60.0 + tm->tm_sec)/86.4;
 
283
 
 
284
        return itime;
 
285
}
 
286
 
 
287
/* adapted from panel-toplevel.c */
 
288
static int
 
289
calculate_minimum_height (GtkWidget        *widget,
 
290
                          PanelAppletOrient orientation)
 
291
{
 
292
        PangoContext     *context;
 
293
        PangoFontMetrics *metrics;
 
294
        int               focus_width = 0;
 
295
        int               focus_pad = 0;
 
296
        int               ascent;
 
297
        int               descent;
 
298
        int               thickness;
 
299
  
 
300
        context = gtk_widget_get_pango_context (widget);
 
301
        metrics = pango_context_get_metrics (context,
 
302
                                             widget->style->font_desc,
 
303
                                             pango_context_get_language (context));
 
304
  
 
305
        ascent  = pango_font_metrics_get_ascent  (metrics);
 
306
        descent = pango_font_metrics_get_descent (metrics);
 
307
  
 
308
        pango_font_metrics_unref (metrics);
 
309
 
 
310
        gtk_widget_style_get (widget,
 
311
                              "focus-line-width", &focus_width,
 
312
                              "focus-padding", &focus_pad,
 
313
                              NULL);
 
314
 
 
315
        if (orientation == PANEL_APPLET_ORIENT_UP
 
316
            || orientation == PANEL_APPLET_ORIENT_DOWN) {
 
317
                thickness = widget->style->ythickness;
 
318
        } else {
 
319
                thickness = widget->style->xthickness;
 
320
        }
 
321
 
 
322
        return PANGO_PIXELS (ascent + descent) + 2 * (focus_width + focus_pad + thickness);
 
323
}
 
324
 
 
325
static gboolean
 
326
use_two_line_format (ClockData *cd)
 
327
{
 
328
        if (cd->size >= 2 * calculate_minimum_height (cd->toggle, cd->orient))
 
329
                return TRUE;
 
330
 
 
331
        return FALSE;
 
332
}
 
333
 
 
334
static void
 
335
update_timeformat (ClockData *cd)
 
336
{
 
337
 /* Show date in another line if panel is vertical, or
 
338
  * horizontal but large enough to hold two lines of text
 
339
  */
 
340
        const char *time_format;
 
341
        const char *date_format;
 
342
        char       *clock_format;
 
343
 
 
344
        if (cd->format == CLOCK_FORMAT_12)
 
345
                time_format = cd->showseconds ? _("%l:%M:%S %p") : _("%l:%M %p");
 
346
        else
 
347
                time_format = cd->showseconds ? _("%H:%M:%S") : _("%H:%M");
 
348
 
 
349
        if (!cd->showdate)
 
350
                clock_format = g_strdup (time_format);
 
351
 
 
352
        else {
 
353
                /* translators: replace %e with %d if, when the day of the
 
354
                 *              month as a decimal number is a single digit, it
 
355
                 *              should begin with a 0 in your locale (e.g. "May
 
356
                 *              01" instead of "May  1").
 
357
                 */
 
358
                date_format = _("%a %b %e");
 
359
 
 
360
                if (use_two_line_format (cd))
 
361
                        /* translators: reverse the order of these arguments
 
362
                         *              if the time should come before the
 
363
                         *              date on a clock in your locale.
 
364
                         */
 
365
                        clock_format = g_strdup_printf (_("%1$s\n%2$s"),
 
366
                                                        date_format, time_format);
 
367
                else
 
368
                        /* translators: reverse the order of these arguments
 
369
                         *              if the time should come before the
 
370
                         *              date on a clock in your locale.
 
371
                         */
 
372
                        clock_format = g_strdup_printf (_("%1$s, %2$s"),
 
373
                                                        date_format, time_format);
 
374
        }
 
375
 
 
376
        g_free (cd->timeformat);
 
377
        cd->timeformat = g_locale_from_utf8 (clock_format, -1, NULL, NULL, NULL);
 
378
        /* let's be paranoid */
 
379
        if (!cd->timeformat)
 
380
                cd->timeformat = g_strdup ("???");
 
381
 
 
382
        g_free (clock_format);
 
383
}
 
384
 
 
385
/* sets accessible name and description for the widget */
 
386
static void
 
387
set_atk_name_description (GtkWidget  *widget,
 
388
                          const char *name,
 
389
                          const char *desc)
 
390
{
 
391
        AtkObject *obj;
 
392
        obj = gtk_widget_get_accessible (widget);
 
393
 
 
394
        /* return if gail is not loaded */
 
395
        if (!GTK_IS_ACCESSIBLE (obj))
 
396
                return;
 
397
 
 
398
        if (desc != NULL)
 
399
                atk_object_set_description (obj, desc);
 
400
        if (name != NULL)
 
401
                atk_object_set_name (obj, name);
 
402
}
 
403
 
 
404
static void
 
405
update_clock (ClockData * cd)
 
406
{
 
407
        struct tm *tm;
 
408
        char date[256], hour[256];
 
409
        char *utf8, *loc;
 
410
 
 
411
        time (&cd->current_time);
 
412
        
 
413
        if (cd->gmt_time)
 
414
                tm = gmtime (&cd->current_time);
 
415
        else
 
416
                tm = localtime (&cd->current_time);
 
417
 
 
418
        if (cd->format == CLOCK_FORMAT_UNIX) {
 
419
                if (use_two_line_format (cd)) {
 
420
                        g_snprintf (hour, sizeof(hour), "%lu\n%05lu",
 
421
                                    (unsigned long)(cd->current_time / 100000L),
 
422
                                    (unsigned long)(cd->current_time % 100000L));
 
423
                } else {
 
424
                        g_snprintf (hour, sizeof(hour), "%lu", (unsigned long)cd->current_time);
 
425
                }
 
426
        } else if (cd->format == CLOCK_FORMAT_INTERNET) {
 
427
                float itime = get_itime (cd->current_time);
 
428
                if (cd->showseconds)
 
429
                        g_snprintf (hour, sizeof (hour), "@%3.2f", itime);
 
430
                else
 
431
                        g_snprintf (hour, sizeof (hour), "@%3.0f", itime);
 
432
        } else if (cd->format == CLOCK_FORMAT_CUSTOM) {
 
433
                char *timeformat = g_locale_from_utf8 (cd->custom_format, -1,
 
434
                                                       NULL, NULL, NULL);
 
435
                if (!timeformat)
 
436
                        strcpy (hour, "???");
 
437
                else if (strftime (hour, sizeof (hour), timeformat, tm) <= 0)
 
438
                        strcpy (hour, "???");
 
439
                g_free (timeformat);
 
440
        } else {
 
441
                if (strftime (hour, sizeof (hour), cd->timeformat, tm) <= 0)
 
442
                        strcpy (hour, "???");
 
443
        }
 
444
 
 
445
        utf8 = g_locale_to_utf8 (hour, -1, NULL, NULL, NULL);
 
446
        gtk_label_set_text (GTK_LABEL (cd->clockw), utf8);
 
447
        g_free (utf8);
 
448
 
 
449
        update_orient (cd);
 
450
        gtk_widget_queue_resize (cd->toggle);
 
451
 
 
452
        if (!cd->showdate) {
 
453
                /* Show date in tooltip */
 
454
                loc = g_locale_from_utf8 (_("%A %B %d"), -1, NULL, NULL, NULL);
 
455
                if (!loc)
 
456
                        strcpy (date, "???");
 
457
                else if (strftime (date, sizeof (date), loc, tm) <= 0)
 
458
                        strcpy (date, "???");
 
459
                g_free (loc);
 
460
 
 
461
                utf8 = g_locale_to_utf8 (date, -1, NULL, NULL, NULL);
 
462
                set_tooltip (cd->applet, cd->toggle, utf8);
 
463
                g_free (utf8);
 
464
        } else {
 
465
#ifdef HAVE_LIBECAL
 
466
                set_tooltip (cd->applet, cd->toggle, _("Click to view your appointments and tasks"));
 
467
#else
 
468
                set_tooltip (cd->applet, cd->toggle, _("Click to view month calendar"));
 
469
#endif
 
470
        }
 
471
}
 
472
 
 
473
static void
 
474
refresh_clock (ClockData *cd)
 
475
{
 
476
        unfix_size (cd);
 
477
        update_clock (cd);
 
478
}
 
479
 
 
480
static void
 
481
refresh_clock_timeout(ClockData *cd)
 
482
{
 
483
        int timeouttime;
 
484
 
 
485
        unfix_size (cd);
 
486
        
 
487
        update_timeformat (cd);
 
488
 
 
489
        if (cd->timeout)
 
490
                g_source_remove (cd->timeout);
 
491
 
 
492
        update_clock (cd);
 
493
        
 
494
        if (cd->format == CLOCK_FORMAT_INTERNET)
 
495
                timeouttime = INTERNETSECOND;
 
496
        else
 
497
                timeouttime = 1000;
 
498
        
 
499
        cd->timeout = g_timeout_add (timeouttime,
 
500
                                     clock_timeout_callback,
 
501
                                     cd);
 
502
}
 
503
 
 
504
static void
 
505
destroy_clock(GtkWidget * widget, ClockData *cd)
 
506
{
 
507
        GConfClient *client;
 
508
        int          i;
 
509
 
 
510
        client = gconf_client_get_default ();
 
511
 
 
512
        for (i = 0; i < N_GCONF_PREFS; i++)
 
513
                gconf_client_notify_remove (
 
514
                                client, cd->listeners [i]);
 
515
 
 
516
        g_object_unref (G_OBJECT (client));
 
517
 
 
518
        if (cd->timeout)
 
519
                g_source_remove (cd->timeout);
 
520
        cd->timeout = 0;
 
521
 
 
522
#ifdef HAVE_LIBECAL
 
523
        if (cd->client)
 
524
                g_object_unref (cd->client);
 
525
        cd->client = NULL;
 
526
 
 
527
        if (cd->appointments_model)
 
528
                g_object_unref (cd->appointments_model);
 
529
        cd->appointments_model = NULL;
 
530
 
 
531
        if (cd->tasks_model)
 
532
                g_object_unref (cd->tasks_model);
 
533
        cd->tasks_model = NULL;
 
534
        
 
535
        if (cd->tasks_filter)
 
536
                g_object_unref (cd->tasks_filter);
 
537
        cd->tasks_filter = NULL;
 
538
#endif /* HAVE_LIBECAL */
 
539
 
 
540
        if (cd->about)
 
541
                gtk_widget_destroy (cd->about);
 
542
        cd->about = NULL;
 
543
 
 
544
        if (cd->props)
 
545
                gtk_widget_destroy (cd->props);
 
546
        cd->props = NULL;
 
547
 
 
548
        if (cd->calendar_popup)
 
549
                gtk_widget_destroy (cd->calendar_popup);
 
550
        cd->calendar_popup = NULL;
 
551
 
 
552
        g_free (cd->timeformat);
 
553
        g_free (cd->config_tool);
 
554
        g_free (cd->custom_format);
 
555
        g_free (cd);
 
556
}
 
557
 
 
558
static gboolean
 
559
close_on_escape (GtkWidget   *widget,
 
560
                 GdkEventKey *event,
 
561
                 ClockData   *cd)
 
562
{
 
563
        if (event->keyval == GDK_Escape) {
 
564
                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cd->toggle), FALSE);
 
565
                return TRUE;
 
566
        }
 
567
 
 
568
        return FALSE;
 
569
}
 
570
 
 
571
static gboolean
 
572
delete_event (GtkWidget   *widget,
 
573
              GdkEvent    *event,
 
574
              ClockData   *cd)
 
575
{
 
576
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cd->toggle), FALSE);
 
577
        return TRUE;
 
578
}
 
579
 
 
580
static inline ClockFormat
 
581
clock_locale_format (void)
 
582
{
 
583
        const char *am;
 
584
 
 
585
        am = nl_langinfo (AM_STR);
 
586
        return (am[0] == '\0') ? CLOCK_FORMAT_24 : CLOCK_FORMAT_12;
 
587
}
 
588
 
 
589
#ifdef HAVE_LIBECAL
 
590
 
 
591
static void
 
592
update_frame_visibility (GtkWidget    *frame,
 
593
                         GtkTreeModel *model)
 
594
{
 
595
        GtkTreeIter iter;
 
596
        gboolean    model_empty;
 
597
 
 
598
        if (!frame)
 
599
                return;
 
600
 
 
601
        model_empty = !gtk_tree_model_get_iter_first (model, &iter);
 
602
 
 
603
        if (model_empty)
 
604
                gtk_widget_hide (frame);
 
605
        else
 
606
                gtk_widget_show (frame);
 
607
}
 
608
 
 
609
enum {
 
610
        APPOINTMENT_COLUMN_UID,
 
611
        APPOINTMENT_COLUMN_SUMMARY,
 
612
        APPOINTMENT_COLUMN_DESCRIPTION,
 
613
        APPOINTMENT_COLUMN_START_TIME,
 
614
        APPOINTMENT_COLUMN_START_TEXT,
 
615
        APPOINTMENT_COLUMN_END_TIME,
 
616
        APPOINTMENT_COLUMN_ALL_DAY,
 
617
        APPOINTMENT_COLUMN_COLOR,
 
618
        N_APPOINTMENT_COLUMNS
 
619
};
 
620
 
 
621
enum {
 
622
        TASK_COLUMN_UID,
 
623
        TASK_COLUMN_SUMMARY,
 
624
        TASK_COLUMN_DESCRIPTION,
 
625
        TASK_COLUMN_START_TIME,
 
626
        TASK_COLUMN_DUE_TIME,
 
627
        TASK_COLUMN_PERCENT_COMPLETE,
 
628
        TASK_COLUMN_PERCENT_COMPLETE_TEXT,
 
629
        TASK_COLUMN_COMPLETED,
 
630
        TASK_COLUMN_COMPLETED_TIME,
 
631
        TASK_COLUMN_OVERDUE_ATTR,
 
632
        TASK_COLUMN_COLOR,
 
633
        TASK_COLUMN_URL,
 
634
        TASK_COLUMN_PRIORITY,
 
635
        N_TASK_COLUMNS
 
636
};
 
637
 
 
638
static char *
 
639
format_time (ClockFormat format,
 
640
             time_t      t,
 
641
             guint       year,
 
642
             guint       month,
 
643
             guint       day,
 
644
             gboolean    use_utc)
 
645
{
 
646
        struct tm *tm;
 
647
        char      *time_format;
 
648
        char       result [256] = { 0, };
 
649
 
 
650
        if (!t)
 
651
                return NULL;
 
652
 
 
653
        if (use_utc)
 
654
                tm = gmtime (&t);
 
655
        else
 
656
                tm = localtime (&t);
 
657
        if (!tm)
 
658
                return NULL;
 
659
 
 
660
        if (year  == (tm->tm_year + 1900) &&
 
661
            month == tm->tm_mon &&
 
662
            day   == tm->tm_mday) {
 
663
                if (format != CLOCK_FORMAT_12 && format != CLOCK_FORMAT_24)
 
664
                        format = clock_locale_format ();
 
665
 
 
666
                if (format == CLOCK_FORMAT_12)
 
667
                        time_format = g_locale_from_utf8 (_("%l:%M %p"), -1, NULL, NULL, NULL);
 
668
                else
 
669
                        time_format = g_locale_from_utf8 (_("%H:%M"), -1, NULL, NULL, NULL);
 
670
        }
 
671
        else {
 
672
                /* Translators: If the event did not start on the current day
 
673
                 we will display the start date in the most abbreviated way possible. */
 
674
                time_format = g_locale_from_utf8 (_("%b %d"), -1, NULL, NULL, NULL);
 
675
        }
 
676
 
 
677
        strftime (result, sizeof (result), time_format, tm);
 
678
        g_free (time_format);
 
679
 
 
680
        return g_locale_to_utf8 (result, -1, NULL, NULL, NULL);
 
681
}
 
682
 
 
683
static void
 
684
handle_tasks_changed (ClockData *cd)
 
685
{
 
686
        GSList *events, *l;
 
687
 
 
688
        gtk_list_store_clear (cd->tasks_model);
 
689
 
 
690
        events = calendar_client_get_events (cd->client, CALENDAR_EVENT_TASK);
 
691
        for (l = events; l; l = l->next) {
 
692
                CalendarTask *task = l->data;
 
693
                GtkTreeIter   iter;
 
694
                char         *percent_complete_text;
 
695
 
 
696
                g_assert (CALENDAR_EVENT (task)->type == CALENDAR_EVENT_TASK);
 
697
      
 
698
                /* FIXME: should this format be locale specific ? */
 
699
                percent_complete_text = g_strdup_printf ("%d%%", task->percent_complete);
 
700
 
 
701
                gtk_list_store_append (cd->tasks_model, &iter);
 
702
                gtk_list_store_set (cd->tasks_model, &iter,
 
703
                                    TASK_COLUMN_UID,                   task->uid,
 
704
                                    TASK_COLUMN_SUMMARY,               task->summary,
 
705
                                    TASK_COLUMN_DESCRIPTION,           task->description,
 
706
                                    TASK_COLUMN_START_TIME,            task->start_time,
 
707
                                    TASK_COLUMN_DUE_TIME,              task->due_time,
 
708
                                    TASK_COLUMN_PERCENT_COMPLETE,      task->percent_complete,
 
709
                                    TASK_COLUMN_PERCENT_COMPLETE_TEXT, percent_complete_text,
 
710
                                    TASK_COLUMN_COMPLETED,             task->percent_complete == 100,
 
711
                                    TASK_COLUMN_COMPLETED_TIME,        task->completed_time,
 
712
                                    TASK_COLUMN_COLOR,                 task->color_string,
 
713
                                    TASK_COLUMN_URL,                   task->url,
 
714
                                    TASK_COLUMN_PRIORITY,              task->priority,
 
715
                                    -1);
 
716
 
 
717
                g_free (percent_complete_text);
 
718
                calendar_event_free (CALENDAR_EVENT (task));
 
719
        }
 
720
        g_slist_free (events);
 
721
 
 
722
        update_frame_visibility (cd->task_list, GTK_TREE_MODEL (cd->tasks_filter));
 
723
}
 
724
 
 
725
static void
 
726
handle_task_completed_toggled (ClockData             *cd,
 
727
                               const char            *path_str,
 
728
                               GtkCellRendererToggle *cell)
 
729
{
 
730
        GtkTreePath *child_path, *path;
 
731
        GtkTreeIter  iter;
 
732
        char        *uid;
 
733
        gboolean     task_completed;
 
734
        guint        percent_complete;
 
735
        
 
736
        path       = gtk_tree_path_new_from_string (path_str);
 
737
        child_path = gtk_tree_model_filter_convert_path_to_child_path (cd->tasks_filter, path);
 
738
        gtk_tree_model_get_iter (GTK_TREE_MODEL (cd->tasks_model), &iter, child_path);
 
739
        gtk_tree_model_get (GTK_TREE_MODEL (cd->tasks_model), &iter,
 
740
                            TASK_COLUMN_UID,                  &uid,
 
741
                            TASK_COLUMN_COMPLETED,            &task_completed,
 
742
                            TASK_COLUMN_PERCENT_COMPLETE,     &percent_complete,
 
743
                            -1);
 
744
 
 
745
        task_completed   = !task_completed;
 
746
        percent_complete = task_completed ? 100 : 0;
 
747
 
 
748
        calendar_client_set_task_completed (cd->client,
 
749
                                            uid,
 
750
                                            task_completed,
 
751
                                            percent_complete);
 
752
 
 
753
        g_free (uid);
 
754
        gtk_tree_path_free (path);
 
755
        gtk_tree_path_free (child_path);
 
756
}
 
757
 
 
758
static void
 
759
handle_task_percent_complete_edited (ClockData           *cd,
 
760
                                     const char          *path_str,
 
761
                                     const char          *text,
 
762
                                     GtkCellRendererText *cell)
 
763
{
 
764
        GtkTreePath *child_path, *path;
 
765
        GtkTreeIter  iter;
 
766
        char        *uid;
 
767
        int          percent_complete;
 
768
        char        *error = NULL, *text_copy;
 
769
 
 
770
        path       = gtk_tree_path_new_from_string (path_str);
 
771
        child_path = gtk_tree_model_filter_convert_path_to_child_path (cd->tasks_filter, path);
 
772
        gtk_tree_model_get_iter (GTK_TREE_MODEL (cd->tasks_model), &iter, child_path);
 
773
        gtk_tree_model_get (GTK_TREE_MODEL (cd->tasks_model), &iter,
 
774
                            TASK_COLUMN_UID, &uid,
 
775
                            -1);
 
776
 
 
777
        text_copy = g_strdup (text);
 
778
        text_copy = g_strdelimit (text_copy, "%", ' ');
 
779
        text_copy = g_strstrip (text_copy);
 
780
        percent_complete = (int) g_strtod (text_copy, &error);
 
781
        if (!error || !error [0]) {
 
782
                gboolean task_completed;
 
783
 
 
784
                percent_complete = CLAMP (percent_complete, 0, 100);
 
785
                task_completed = (percent_complete == 100);
 
786
 
 
787
                calendar_client_set_task_completed (cd->client,
 
788
                                                    uid,
 
789
                                                    task_completed,
 
790
                                                    percent_complete);
 
791
        }
 
792
 
 
793
        g_free (uid);
 
794
        g_free (text_copy);
 
795
        gtk_tree_path_free (path);
 
796
        gtk_tree_path_free (child_path);
 
797
}
 
798
 
 
799
static gboolean
 
800
filter_out_tasks (GtkTreeModel *model,
 
801
                  GtkTreeIter  *iter,
 
802
                  ClockData    *cd)
 
803
{
 
804
        GTime    start_time;
 
805
        GTime    completed_time;
 
806
        GTime    one_day_ago;
 
807
        gboolean visible;
 
808
 
 
809
        gtk_tree_model_get (model, iter,
 
810
                            TASK_COLUMN_START_TIME,     &start_time,
 
811
                            TASK_COLUMN_COMPLETED_TIME, &completed_time,
 
812
                            -1);
 
813
 
 
814
        one_day_ago = cd->current_time - (24 * 60 * 60);
 
815
 
 
816
        visible = !start_time || start_time <= cd->current_time;
 
817
        if (visible)
 
818
                visible = !completed_time || completed_time >= one_day_ago;
 
819
 
 
820
        return visible;
 
821
}
 
822
 
 
823
static void
 
824
modify_task_text_attributes (GtkTreeModel *model,
 
825
                             GtkTreeIter  *iter,
 
826
                             GValue       *value,
 
827
                             gint          column,
 
828
                             ClockData    *cd)
 
829
{
 
830
        GTime           due_time;
 
831
        PangoAttrList  *attr_list;
 
832
        PangoAttribute *attr;
 
833
        GtkTreeIter     child_iter;
 
834
 
 
835
        gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model),
 
836
                                                          &child_iter,
 
837
                                                          iter);
 
838
 
 
839
        if (column != TASK_COLUMN_OVERDUE_ATTR) {
 
840
                memset (value, 0, sizeof (GValue));
 
841
                gtk_tree_model_get_value (GTK_TREE_MODEL (cd->tasks_model),
 
842
                                          &child_iter, column, value);
 
843
 
 
844
                return;
 
845
        }
 
846
 
 
847
        gtk_tree_model_get (GTK_TREE_MODEL (cd->tasks_model), &child_iter,
 
848
                            TASK_COLUMN_DUE_TIME, &due_time,
 
849
                            -1);
 
850
        if (due_time && due_time > cd->current_time)
 
851
                return;
 
852
 
 
853
        attr_list = pango_attr_list_new ();
 
854
 
 
855
        attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
 
856
        attr->start_index = 0;
 
857
        attr->end_index = G_MAXINT;
 
858
        pango_attr_list_insert (attr_list, attr);
 
859
 
 
860
        g_value_take_boxed (value, attr_list);
 
861
}
 
862
 
 
863
static GtkWidget *
 
864
create_hig_frame (const char  *title)
 
865
{
 
866
        GtkWidget *vbox;
 
867
        GtkWidget *alignment;
 
868
        GtkWidget *label;
 
869
        char      *bold_title;
 
870
 
 
871
        vbox = gtk_vbox_new (FALSE, 6);
 
872
 
 
873
        bold_title = g_strdup_printf ("<b>%s</b>", title);
 
874
 
 
875
        alignment = gtk_alignment_new (0, 0.5, 0, 0);
 
876
        gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
 
877
        gtk_widget_show (alignment);
 
878
        
 
879
        label = gtk_label_new (bold_title);
 
880
        gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
 
881
        gtk_container_add (GTK_CONTAINER (alignment), label);
 
882
        gtk_widget_show (label);
 
883
 
 
884
        g_free (bold_title);
 
885
 
 
886
        return vbox;
 
887
}
 
888
 
 
889
static gboolean
 
890
task_activated_cb (GtkTreeView       *view,
 
891
                   GtkTreePath       *path,
 
892
                   GtkTreeViewColumn *column,
 
893
                   ClockData         *cd)
 
894
{
 
895
        GtkTreeIter  iter;
 
896
        GtkTreePath *child_path;
 
897
        char        *uri;
 
898
 
 
899
        child_path = gtk_tree_model_filter_convert_path_to_child_path (cd->tasks_filter, path);
 
900
 
 
901
        gtk_tree_model_get_iter (GTK_TREE_MODEL (cd->tasks_model), &iter, child_path);
 
902
        gtk_tree_model_get (GTK_TREE_MODEL (cd->tasks_model), &iter,
 
903
                            TASK_COLUMN_URL, &uri, -1);
 
904
 
 
905
        if (uri) {
 
906
                gnome_url_show_on_screen (uri,
 
907
                                          gtk_widget_get_screen (cd->applet),
 
908
                                          NULL);
 
909
        }
 
910
 
 
911
        g_free (uri);
 
912
        gtk_tree_path_free (child_path);
 
913
 
 
914
        return TRUE;
 
915
}
 
916
 
 
917
static void
 
918
set_renderer_pixbuf_color_by_column (GtkCellRenderer *renderer,
 
919
                                     GtkTreeModel    *model,
 
920
                                     GtkTreeIter     *iter,
 
921
                                     gint             column_number)
 
922
{
 
923
        char      *color_string;
 
924
        GdkPixbuf *pixbuf = NULL;
 
925
        guint32    color;
 
926
 
 
927
        gtk_tree_model_get (model, iter, column_number, &color_string, -1);
 
928
 
 
929
        if (color_string) {
 
930
                sscanf (color_string, "%06x", &color);
 
931
                pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, 16, 16);
 
932
                gdk_pixbuf_fill (pixbuf, color << 8);
 
933
 
 
934
                g_object_set (renderer, "visible", pixbuf != NULL, "pixbuf", pixbuf, NULL);
 
935
 
 
936
                if (pixbuf)
 
937
                        g_object_unref (pixbuf);
 
938
 
 
939
                g_free (color_string);
 
940
        }
 
941
}
 
942
 
 
943
static void
 
944
task_pixbuf_cell_data_func (GtkTreeViewColumn *column,
 
945
                            GtkCellRenderer   *renderer,
 
946
                            GtkTreeModel      *model,
 
947
                            GtkTreeIter       *iter,
 
948
                            gpointer           data)
 
949
{
 
950
        set_renderer_pixbuf_color_by_column (renderer,
 
951
                                             model,
 
952
                                             iter,
 
953
                                             TASK_COLUMN_COLOR);
 
954
}
 
955
 
 
956
static void
 
957
appointment_pixbuf_cell_data_func (GtkTreeViewColumn *column,
 
958
                                   GtkCellRenderer   *renderer,
 
959
                                   GtkTreeModel      *model,
 
960
                                   GtkTreeIter       *iter,
 
961
                                   gpointer           data)
 
962
{
 
963
        set_renderer_pixbuf_color_by_column (renderer,
 
964
                                             model,
 
965
                                             iter,
 
966
                                             APPOINTMENT_COLUMN_COLOR);
 
967
}
 
968
 
 
969
static int
 
970
compare_tasks  (GtkTreeModel *model,
 
971
                GtkTreeIter  *a,
 
972
                GtkTreeIter  *b,
 
973
                gpointer      user_data)
 
974
{
 
975
        int priority_a;
 
976
        int priority_b;
 
977
 
 
978
        gtk_tree_model_get (model, a, TASK_COLUMN_PRIORITY, &priority_a, -1);
 
979
        gtk_tree_model_get (model, b, TASK_COLUMN_PRIORITY, &priority_b, -1);
 
980
 
 
981
        /* We change undefined priorities so they appear after 'Low'. */
 
982
        if (priority_a <= 0)
 
983
                priority_a = 10;
 
984
        if (priority_b <= 0)
 
985
                priority_b = 10;
 
986
 
 
987
        /* We'll just use the ordering of the priority values. */
 
988
        if (priority_a < priority_b)
 
989
                return -1;
 
990
        else if (priority_a > priority_b)
 
991
                return 1;
 
992
        else {
 
993
                GTime due_time_a, due_time_b;
 
994
 
 
995
                gtk_tree_model_get (model, a,
 
996
                                    TASK_COLUMN_DUE_TIME, &due_time_a, -1);
 
997
                gtk_tree_model_get (model, b,
 
998
                                    TASK_COLUMN_DUE_TIME, &due_time_b, -1);
 
999
 
 
1000
                if (due_time_a < due_time_b)
 
1001
                        return -1;
 
1002
                else if (due_time_a > due_time_b)
 
1003
                        return 1;
 
1004
                else
 
1005
                        return 0;
 
1006
        }
 
1007
}
 
1008
 
 
1009
static GtkWidget *
 
1010
create_task_list (ClockData  *cd,
 
1011
                  GtkWidget **tree_view,
 
1012
                  GtkWidget **scrolled_window)
 
1013
{
 
1014
        GtkWidget         *vbox;
 
1015
        GtkWidget         *view;
 
1016
        GtkWidget         *scrolled;
 
1017
        GtkCellRenderer   *cell;
 
1018
        GtkTreeViewColumn *column;
 
1019
 
 
1020
        vbox = create_hig_frame (_("Tasks"));
 
1021
 
 
1022
        *scrolled_window = scrolled = gtk_scrolled_window_new (NULL, NULL);
 
1023
        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
 
1024
                                             GTK_SHADOW_IN);
 
1025
        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
 
1026
                                        GTK_POLICY_NEVER,
 
1027
                                        GTK_POLICY_AUTOMATIC);
 
1028
        gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
 
1029
        gtk_widget_show (scrolled);
 
1030
 
 
1031
        if (!cd->tasks_model) {
 
1032
                GType column_types [N_TASK_COLUMNS] = {
 
1033
                        G_TYPE_STRING,         /* uid                     */
 
1034
                        G_TYPE_STRING,         /* summary                 */
 
1035
                        G_TYPE_STRING,         /* description             */
 
1036
                        G_TYPE_LONG,           /* start time              */
 
1037
                        G_TYPE_LONG,           /* due time                */
 
1038
                        G_TYPE_UINT,           /* percent complete        */
 
1039
                        G_TYPE_STRING,         /* percent complete text   */
 
1040
                        G_TYPE_BOOLEAN,        /* completed               */
 
1041
                        G_TYPE_LONG,           /* completed time          */
 
1042
                        PANGO_TYPE_ATTR_LIST,  /* summary text attributes */
 
1043
                        G_TYPE_STRING,         /* color                   */
 
1044
                        G_TYPE_STRING,         /* url                     */
 
1045
                        G_TYPE_INT             /* priority                */
 
1046
                };
 
1047
 
 
1048
                cd->tasks_model = gtk_list_store_newv (N_TASK_COLUMNS, column_types);
 
1049
 
 
1050
                gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (cd->tasks_model),
 
1051
                                                 TASK_COLUMN_PRIORITY,
 
1052
                                                 compare_tasks,
 
1053
                                                 NULL, NULL);
 
1054
 
 
1055
                gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (cd->tasks_model),
 
1056
                                                      TASK_COLUMN_PRIORITY,
 
1057
                                                      GTK_SORT_ASCENDING);
 
1058
 
 
1059
                cd->tasks_filter = GTK_TREE_MODEL_FILTER (
 
1060
                        gtk_tree_model_filter_new (GTK_TREE_MODEL (cd->tasks_model),
 
1061
                                                   NULL));
 
1062
                gtk_tree_model_filter_set_visible_func (
 
1063
                         cd->tasks_filter,
 
1064
                         (GtkTreeModelFilterVisibleFunc) filter_out_tasks,
 
1065
                         cd,
 
1066
                         NULL);
 
1067
                gtk_tree_model_filter_set_modify_func (
 
1068
                         cd->tasks_filter,
 
1069
                         N_TASK_COLUMNS,
 
1070
                         column_types,
 
1071
                         (GtkTreeModelFilterModifyFunc) modify_task_text_attributes,
 
1072
                         cd,
 
1073
                         NULL);
 
1074
        }
 
1075
 
 
1076
        *tree_view = view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (cd->tasks_filter));
 
1077
        gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE);
 
1078
 
 
1079
        g_signal_connect (view, "row-activated",
 
1080
                          G_CALLBACK (task_activated_cb), cd);
 
1081
 
 
1082
        /* Source color */
 
1083
        column = gtk_tree_view_column_new ();
 
1084
        cell = gtk_cell_renderer_pixbuf_new ();
 
1085
        gtk_tree_view_column_pack_start (column, cell, TRUE);
 
1086
        gtk_tree_view_column_set_cell_data_func (column, cell,
 
1087
                                                 (GtkTreeCellDataFunc) task_pixbuf_cell_data_func,
 
1088
                                                 NULL, NULL);
 
1089
        gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
 
1090
 
 
1091
        /* Completed toggle */
 
1092
        column = gtk_tree_view_column_new ();
 
1093
        cell = gtk_cell_renderer_toggle_new ();
 
1094
        g_object_set (cell,
 
1095
                      "activatable", TRUE,
 
1096
                      NULL);
 
1097
        g_signal_connect_swapped (cell, "toggled",
 
1098
                                  G_CALLBACK (handle_task_completed_toggled), cd);
 
1099
        gtk_tree_view_column_pack_start (column, cell, TRUE);
 
1100
        gtk_tree_view_column_add_attribute (column, cell,
 
1101
                                            "active", TASK_COLUMN_COMPLETED);
 
1102
        gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
 
1103
 
 
1104
        /* Percent complete */
 
1105
        column = gtk_tree_view_column_new ();
 
1106
        cell = gtk_cell_renderer_text_new ();
 
1107
        g_object_set (cell,
 
1108
                      "editable", TRUE,
 
1109
                      NULL);
 
1110
        g_signal_connect_swapped (cell, "edited",
 
1111
                                  G_CALLBACK (handle_task_percent_complete_edited), cd);
 
1112
        gtk_tree_view_column_pack_start (column, cell, TRUE);
 
1113
        gtk_tree_view_column_add_attribute (column, cell,
 
1114
                                            "text", TASK_COLUMN_PERCENT_COMPLETE_TEXT);
 
1115
        gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
 
1116
 
 
1117
        /* Summary */
 
1118
        column = gtk_tree_view_column_new ();
 
1119
        cell = gtk_cell_renderer_text_new ();
 
1120
        g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
 
1121
        gtk_tree_view_column_pack_start (column, cell, TRUE);
 
1122
        gtk_tree_view_column_set_attributes (column, cell,
 
1123
                                             "text", TASK_COLUMN_SUMMARY,
 
1124
                                             "strikethrough", TASK_COLUMN_COMPLETED,
 
1125
                                             "attributes", TASK_COLUMN_OVERDUE_ATTR,
 
1126
                                             NULL);
 
1127
        gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
 
1128
 
 
1129
        gtk_container_add (GTK_CONTAINER (scrolled), view);
 
1130
 
 
1131
        gtk_widget_show (view);
 
1132
 
 
1133
        return vbox;
 
1134
}
 
1135
 
 
1136
static void
 
1137
mark_day_on_calendar (CalendarClient *client,
 
1138
                      guint           day,
 
1139
                      ClockData      *cd)
 
1140
{
 
1141
        gtk_chinese_calendar_mark_day (GTK_CHINESE_CALENDAR (cd->calendar), day);
 
1142
}
 
1143
 
 
1144
static void
 
1145
handle_appointments_changed (ClockData *cd)
 
1146
{
 
1147
        GSList *events, *l;
 
1148
        guint   year, month, day;
 
1149
 
 
1150
        if (cd->calendar) {
 
1151
                gtk_chinese_calendar_clear_marks (GTK_CHINESE_CALENDAR (cd->calendar));
 
1152
 
 
1153
                calendar_client_foreach_appointment_day (cd->client,
 
1154
                                                         (CalendarDayIter) mark_day_on_calendar,
 
1155
                                                         cd);
 
1156
        }
 
1157
 
 
1158
        gtk_list_store_clear (cd->appointments_model);
 
1159
 
 
1160
        events = calendar_client_get_events (cd->client, CALENDAR_EVENT_APPOINTMENT);
 
1161
        calendar_client_get_date (cd->client, &year, &month, &day);
 
1162
        for (l = events; l; l = l->next) {
 
1163
                CalendarAppointment *appointment = l->data;
 
1164
                GtkTreeIter          iter;
 
1165
                char                *start_text;
 
1166
 
 
1167
                g_assert (CALENDAR_EVENT (appointment)->type == CALENDAR_EVENT_APPOINTMENT);
 
1168
 
 
1169
                if (appointment->is_all_day)
 
1170
                        start_text = g_strdup (_("All Day"));
 
1171
                else
 
1172
                        start_text = format_time (cd->format,
 
1173
                                                  appointment->start_time,
 
1174
                                                  year, month, day,
 
1175
                                                  cd->gmt_time);
 
1176
 
 
1177
 
 
1178
                gtk_list_store_append (cd->appointments_model, &iter);
 
1179
                gtk_list_store_set (cd->appointments_model, &iter,
 
1180
                                    APPOINTMENT_COLUMN_UID,         appointment->uid,
 
1181
                                    APPOINTMENT_COLUMN_SUMMARY,     appointment->summary,
 
1182
                                    APPOINTMENT_COLUMN_DESCRIPTION, appointment->description,
 
1183
                                    APPOINTMENT_COLUMN_START_TIME,  appointment->start_time,
 
1184
                                    APPOINTMENT_COLUMN_START_TEXT,  start_text,
 
1185
                                    APPOINTMENT_COLUMN_END_TIME,    appointment->end_time,
 
1186
                                    APPOINTMENT_COLUMN_ALL_DAY,     appointment->is_all_day,
 
1187
                                    APPOINTMENT_COLUMN_COLOR  ,     appointment->color_string,
 
1188
                                    -1);
 
1189
 
 
1190
                g_free (start_text);
 
1191
                calendar_event_free (CALENDAR_EVENT (appointment));
 
1192
        }
 
1193
        g_slist_free (events);
 
1194
 
 
1195
        update_frame_visibility (cd->appointment_list, GTK_TREE_MODEL (cd->appointments_model));
 
1196
}
 
1197
 
 
1198
static GtkWidget *
 
1199
create_appointment_list (ClockData  *cd,
 
1200
                         GtkWidget **tree_view,
 
1201
                         GtkWidget **scrolled_window)
 
1202
{
 
1203
        GtkWidget         *vbox;
 
1204
        GtkWidget         *view;
 
1205
        GtkWidget         *scrolled;
 
1206
        GtkCellRenderer   *cell;
 
1207
        GtkTreeViewColumn *column;
 
1208
 
 
1209
        vbox = create_hig_frame ( _("Appointments"));
 
1210
 
 
1211
        *scrolled_window = scrolled = gtk_scrolled_window_new (NULL, NULL);
 
1212
        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
 
1213
                                             GTK_SHADOW_IN);
 
1214
        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
 
1215
                                        GTK_POLICY_NEVER,
 
1216
                                        GTK_POLICY_AUTOMATIC);
 
1217
        gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
 
1218
        gtk_widget_show (scrolled);
 
1219
 
 
1220
        if (!cd->appointments_model) {
 
1221
                cd->appointments_model =
 
1222
                        gtk_list_store_new (N_APPOINTMENT_COLUMNS,
 
1223
                                            G_TYPE_STRING,   /* uid              */
 
1224
                                            G_TYPE_STRING,   /* summary          */
 
1225
                                            G_TYPE_STRING,   /* description      */
 
1226
                                            G_TYPE_LONG,     /* start time       */
 
1227
                                            G_TYPE_STRING,   /* start time text  */
 
1228
                                            G_TYPE_LONG,     /* end time         */
 
1229
                                            G_TYPE_BOOLEAN,  /* all day          */
 
1230
                                            G_TYPE_STRING);  /* color            */
 
1231
 
 
1232
                gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (cd->appointments_model),
 
1233
                                                      APPOINTMENT_COLUMN_START_TIME,
 
1234
                                                      GTK_SORT_ASCENDING);
 
1235
 
 
1236
        }
 
1237
 
 
1238
        *tree_view = view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (cd->appointments_model));
 
1239
        gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE);
 
1240
 
 
1241
        /* Source color */
 
1242
        column = gtk_tree_view_column_new ();
 
1243
        cell = gtk_cell_renderer_pixbuf_new ();
 
1244
        gtk_tree_view_column_pack_start (column, cell, TRUE);
 
1245
        gtk_tree_view_column_set_cell_data_func (column, cell,
 
1246
                                                 (GtkTreeCellDataFunc) appointment_pixbuf_cell_data_func,
 
1247
                                                 NULL, NULL);
 
1248
        gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
 
1249
 
 
1250
        /* Start time */
 
1251
        column = gtk_tree_view_column_new ();
 
1252
        cell = gtk_cell_renderer_text_new ();
 
1253
        gtk_tree_view_column_pack_start (column, cell, TRUE);
 
1254
        gtk_tree_view_column_add_attribute (column, cell,
 
1255
                                            "text", APPOINTMENT_COLUMN_START_TEXT);
 
1256
        gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
 
1257
  
 
1258
        /* Summary */
 
1259
        column = gtk_tree_view_column_new ();
 
1260
        cell = gtk_cell_renderer_text_new ();
 
1261
        g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
 
1262
        gtk_tree_view_column_pack_start (column, cell, TRUE);
 
1263
        gtk_tree_view_column_add_attribute (column, cell,
 
1264
                                            "text", APPOINTMENT_COLUMN_SUMMARY);
 
1265
        gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
 
1266
 
 
1267
        gtk_container_add (GTK_CONTAINER (scrolled), view);
 
1268
 
 
1269
        gtk_widget_show (view);
 
1270
 
 
1271
        return vbox;
 
1272
}
 
1273
 
 
1274
static void
 
1275
calendar_day_activated (ClockData   *cd,
 
1276
                        GtkCalendar *calendar)
 
1277
{
 
1278
        unsigned int  day;
 
1279
        unsigned int  month;
 
1280
        unsigned int  year;
 
1281
        char         *command_line;
 
1282
        GError       *error;
 
1283
 
 
1284
        gtk_chinese_calendar_get_date (GTK_CHINESE_CALENDAR (cd->calendar),
 
1285
                               &year, &month, &day);
 
1286
 
 
1287
        command_line = g_strdup_printf ("evolution "
 
1288
                                        "calendar:///?startdate=%.4d%.2d%.2d",
 
1289
                                        year, month + 1, day);
 
1290
 
 
1291
        error = NULL;
 
1292
 
 
1293
        if (!gdk_spawn_command_line_on_screen (gtk_widget_get_screen (cd->calendar),
 
1294
                                               command_line, &error)) {
 
1295
                g_printerr ("Cannot launch calendar: %s\n", error->message);
 
1296
                g_error_free (error);
 
1297
        }
 
1298
 
 
1299
        g_free (command_line);
 
1300
}
 
1301
 
 
1302
static void
 
1303
calendar_day_selected (ClockData *cd)
 
1304
{
 
1305
        guint day;
 
1306
 
 
1307
        gtk_chinese_calendar_get_date (GTK_CHINESE_CALENDAR (cd->calendar), NULL, NULL, &day);
 
1308
 
 
1309
        calendar_client_select_day (cd->client, day);
 
1310
 
 
1311
        handle_appointments_changed (cd);
 
1312
        handle_tasks_changed (cd);
 
1313
}
 
1314
 
 
1315
static void
 
1316
calendar_month_selected (ClockData *cd)
 
1317
{
 
1318
        guint year, month;
 
1319
 
 
1320
        gtk_chinese_calendar_get_date (GTK_CHINESE_CALENDAR (cd->calendar), &year, &month, NULL);
 
1321
 
 
1322
        calendar_client_select_month (cd->client, month, year);
 
1323
 
 
1324
        handle_appointments_changed (cd);
 
1325
        handle_tasks_changed (cd);
 
1326
}
 
1327
 
 
1328
typedef struct
 
1329
{
 
1330
        GtkWidget *calendar;
 
1331
        GtkWidget *tree;
 
1332
} ConstraintData;
 
1333
 
 
1334
static void
 
1335
constrain_list_size (GtkWidget      *widget,
 
1336
                     GtkRequisition *requisition,
 
1337
                     ConstraintData *constraint)
 
1338
{
 
1339
        GtkRequisition req;
 
1340
        int            max_height;
 
1341
 
 
1342
        /* constrain width to the calendar width */
 
1343
        gtk_widget_size_request (constraint->calendar, &req);
 
1344
        requisition->width = MIN (requisition->width, req.width);
 
1345
 
 
1346
        /* constrain height to be the tree height up to a max */
 
1347
        max_height = (gdk_screen_get_height (gtk_widget_get_screen (widget)) - req.height) / 3;
 
1348
        gtk_widget_size_request (constraint->tree, &req);
 
1349
 
 
1350
        requisition->height = MIN (req.height, max_height);
 
1351
        requisition->height += 2 * widget->style->ythickness;
 
1352
}
 
1353
 
 
1354
static void
 
1355
setup_list_size_constraint (GtkWidget *widget,
 
1356
                            GtkWidget *calendar,
 
1357
                            GtkWidget *tree)
 
1358
{
 
1359
        ConstraintData *constraint;
 
1360
 
 
1361
        constraint           = g_new0 (ConstraintData, 1);
 
1362
        constraint->calendar = calendar;
 
1363
        constraint->tree     = tree;
 
1364
 
 
1365
        g_signal_connect_data (widget, "size-request",
 
1366
                               G_CALLBACK (constrain_list_size), constraint,
 
1367
                               (GClosureNotify) g_free, 0);
 
1368
}
 
1369
 
 
1370
#endif /* HAVE_LIBECAL */
 
1371
 
 
1372
static void
 
1373
add_appointments_and_tasks (ClockData *cd,
 
1374
                            GtkWidget *vbox)
 
1375
{
 
1376
#ifdef HAVE_LIBECAL
 
1377
        GtkWidget *tree_view;
 
1378
        GtkWidget *scrolled_window;
 
1379
        guint      year, month, day;
 
1380
        
 
1381
        cd->task_list = create_task_list (cd, &tree_view, &scrolled_window);
 
1382
        g_object_add_weak_pointer (G_OBJECT (cd->task_list),
 
1383
                                   (gpointer *) &cd->task_list);
 
1384
        setup_list_size_constraint (scrolled_window, cd->calendar, tree_view);
 
1385
        update_frame_visibility (cd->task_list, GTK_TREE_MODEL (cd->tasks_model));
 
1386
 
 
1387
        cd->appointment_list = create_appointment_list (cd, &tree_view, &scrolled_window);
 
1388
        g_object_add_weak_pointer (G_OBJECT (cd->appointment_list),
 
1389
                                   (gpointer *) &cd->appointment_list);
 
1390
        setup_list_size_constraint (scrolled_window, cd->calendar, tree_view);
 
1391
        update_frame_visibility (cd->appointment_list, GTK_TREE_MODEL (cd->appointments_model));
 
1392
 
 
1393
        switch (cd->orient) {
 
1394
        case PANEL_APPLET_ORIENT_UP:
 
1395
                gtk_box_pack_start (GTK_BOX (vbox), cd->appointment_list, TRUE, TRUE, 0);
 
1396
                gtk_box_pack_start (GTK_BOX (vbox), cd->task_list, TRUE, TRUE, 0);
 
1397
                break;
 
1398
        default:
 
1399
                gtk_box_pack_start (GTK_BOX (vbox), cd->task_list, TRUE, TRUE, 0);
 
1400
                gtk_box_pack_start (GTK_BOX (vbox), cd->appointment_list, TRUE, TRUE, 0);
 
1401
                break;
 
1402
        }
 
1403
 
 
1404
        if (!cd->client) {
 
1405
                cd->client = calendar_client_new ();
 
1406
 
 
1407
                g_signal_connect_swapped (cd->client, "tasks-changed",
 
1408
                                          G_CALLBACK (handle_tasks_changed), cd);
 
1409
                g_signal_connect_swapped (cd->client, "appointments-changed",
 
1410
                                          G_CALLBACK (handle_appointments_changed), cd);
 
1411
        }
 
1412
 
 
1413
        gtk_chinese_calendar_get_date (GTK_CHINESE_CALENDAR (cd->calendar), &year, &month, &day);
 
1414
 
 
1415
        calendar_client_select_day   (cd->client, day);
 
1416
        calendar_client_select_month (cd->client, month, year);
 
1417
 
 
1418
        handle_tasks_changed (cd);
 
1419
        handle_appointments_changed (cd);
 
1420
 
 
1421
        g_signal_connect_swapped (cd->calendar, "day-selected-double-click",
 
1422
                                  G_CALLBACK (calendar_day_activated), cd);
 
1423
        g_signal_connect_swapped (cd->calendar, "day-selected",
 
1424
                                  G_CALLBACK (calendar_day_selected), cd);
 
1425
        g_signal_connect_swapped (cd->calendar, "month-changed",
 
1426
                                  G_CALLBACK (calendar_month_selected), cd);
 
1427
#endif /* HAVE_LIBECAL */
 
1428
}
 
1429
 
 
1430
static GtkWidget *
 
1431
create_calendar (ClockData *cd,
 
1432
                 GdkScreen *screen)
 
1433
{
 
1434
        GtkWindow                 *window;
 
1435
        GtkWidget                 *frame;
 
1436
        GtkWidget                 *vbox;
 
1437
        GtkCalendarDisplayOptions  options;
 
1438
        struct tm                 *tm;
 
1439
 
 
1440
        window = GTK_WINDOW (gtk_window_new (GTK_WINDOW_TOPLEVEL));
 
1441
        gtk_window_set_icon_name (window, CLOCK_ICON);
 
1442
        gtk_window_set_screen (window, screen);
 
1443
 
 
1444
        frame = gtk_frame_new (NULL);
 
1445
        gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
 
1446
        gtk_container_add (GTK_CONTAINER (window), frame);
 
1447
        gtk_widget_show (frame);
 
1448
 
 
1449
        vbox = gtk_vbox_new (FALSE, 6);
 
1450
        gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
 
1451
        gtk_container_add (GTK_CONTAINER (frame), vbox);
 
1452
        gtk_widget_show (vbox);
 
1453
 
 
1454
        gtk_window_set_type_hint (window, GDK_WINDOW_TYPE_HINT_DOCK);
 
1455
        gtk_window_set_decorated (window, FALSE);
 
1456
        gtk_window_set_resizable (window, FALSE);
 
1457
        gtk_window_stick (window);
 
1458
        gtk_window_set_title (window, _("Calendar"));
 
1459
 
 
1460
        g_signal_connect (window, "delete_event",
 
1461
                          G_CALLBACK (delete_event), cd);
 
1462
                        
 
1463
        g_signal_connect (window, "key_press_event",
 
1464
                          G_CALLBACK (close_on_escape), cd);
 
1465
                        
 
1466
        cd->calendar = gtk_chinese_calendar_new ();
 
1467
        g_object_add_weak_pointer (G_OBJECT (cd->calendar),
 
1468
                                   (gpointer *) &cd->calendar);
 
1469
 
 
1470
        options = gtk_chinese_calendar_get_display_options (GTK_CHINESE_CALENDAR (cd->calendar));
 
1471
        if (cd->showweek)
 
1472
                options |= GTK_CHINESE_CALENDAR_SHOW_WEEK_NUMBERS;
 
1473
        if (cd->showlunardate)
 
1474
            options |= GTK_CHINESE_CALENDAR_SHOW_LUNAR_DATE;
 
1475
        else
 
1476
            options &= ~GTK_CHINESE_CALENDAR_SHOW_LUNAR_DATE;
 
1477
        gtk_chinese_calendar_set_display_options (GTK_CHINESE_CALENDAR (cd->calendar), options);
 
1478
 
 
1479
        if (cd->gmt_time)
 
1480
                tm = gmtime (&cd->current_time);
 
1481
        else
 
1482
                tm = localtime (&cd->current_time);
 
1483
        gtk_chinese_calendar_select_month (GTK_CHINESE_CALENDAR (cd->calendar),
 
1484
                                   tm->tm_mon,
 
1485
                                   tm->tm_year + 1900);
 
1486
        gtk_chinese_calendar_select_day (GTK_CHINESE_CALENDAR (cd->calendar), tm->tm_mday);
 
1487
 
 
1488
        switch (cd->orient) {
 
1489
        case PANEL_APPLET_ORIENT_UP:
 
1490
                add_appointments_and_tasks (cd, vbox);
 
1491
                gtk_box_pack_start (GTK_BOX (vbox), cd->calendar, TRUE, FALSE, 0);
 
1492
                break;
 
1493
        default:
 
1494
                gtk_box_pack_start (GTK_BOX (vbox), cd->calendar, TRUE, FALSE, 0);
 
1495
                add_appointments_and_tasks (cd, vbox);
 
1496
                break;
 
1497
        }
 
1498
        gtk_widget_show (cd->calendar);
 
1499
 
 
1500
        return GTK_WIDGET (window);
 
1501
}
 
1502
 
 
1503
static void
 
1504
position_calendar_popup (ClockData *cd,
 
1505
                         GtkWidget *window,
 
1506
                         GtkWidget *button)
 
1507
{
 
1508
        GtkRequisition  req;
 
1509
        GdkScreen      *screen;
 
1510
        GdkRectangle    monitor;
 
1511
        GdkGravity      gravity = GDK_GRAVITY_NORTH_WEST;
 
1512
        int             button_w, button_h;
 
1513
        int             x, y;
 
1514
        int             w, h;
 
1515
        int             i, n;
 
1516
        gboolean        found_monitor = FALSE;
 
1517
 
 
1518
        /* Get root origin of the toggle button, and position above that. */
 
1519
        gdk_window_get_origin (button->window, &x, &y);
 
1520
 
 
1521
        gtk_window_get_size (GTK_WINDOW (window), &w, &h);
 
1522
        gtk_widget_size_request (window, &req);
 
1523
        w = req.width;
 
1524
        h = req.height;
 
1525
 
 
1526
        button_w = button->allocation.width;
 
1527
        button_h = button->allocation.height;
 
1528
 
 
1529
        screen = gtk_window_get_screen (GTK_WINDOW (window));
 
1530
 
 
1531
        n = gdk_screen_get_n_monitors (screen);
 
1532
        for (i = 0; i < n; i++) {
 
1533
                gdk_screen_get_monitor_geometry (screen, i, &monitor);
 
1534
                if (x >= monitor.x && x <= monitor.x + monitor.width &&
 
1535
                    y >= monitor.y && y <= monitor.y + monitor.height) {
 
1536
                        found_monitor = TRUE;
 
1537
                        break;
 
1538
                }
 
1539
        }
 
1540
 
 
1541
        if ( ! found_monitor) {
 
1542
                /* eek, we should be on one of those xinerama
 
1543
                   monitors */
 
1544
                monitor.x = 0;
 
1545
                monitor.y = 0;
 
1546
                monitor.width = gdk_screen_get_width (screen);
 
1547
                monitor.height = gdk_screen_get_height (screen);
 
1548
        }
 
1549
                
 
1550
        /* Based on panel orientation, position the popup.
 
1551
         * Ignore window gravity since the window is undecorated.
 
1552
         * The orientations are all named backward from what
 
1553
         * I expected.
 
1554
         */
 
1555
        switch (cd->orient) {
 
1556
        case PANEL_APPLET_ORIENT_RIGHT:
 
1557
                x += button_w;
 
1558
                if ((y + h) > monitor.y + monitor.height)
 
1559
                        y -= (y + h) - (monitor.y + monitor.height);
 
1560
 
 
1561
                if ((y + h) > (monitor.height / 2))
 
1562
                        gravity = GDK_GRAVITY_SOUTH_WEST;
 
1563
                else
 
1564
                        gravity = GDK_GRAVITY_NORTH_WEST;
 
1565
 
 
1566
                break;
 
1567
        case PANEL_APPLET_ORIENT_LEFT:
 
1568
                x -= w;
 
1569
                if ((y + h) > monitor.y + monitor.height)
 
1570
                        y -= (y + h) - (monitor.y + monitor.height);
 
1571
 
 
1572
                if ((y + h) > (monitor.height / 2))
 
1573
                        gravity = GDK_GRAVITY_SOUTH_EAST;
 
1574
                else
 
1575
                        gravity = GDK_GRAVITY_NORTH_EAST;
 
1576
 
 
1577
                break;
 
1578
        case PANEL_APPLET_ORIENT_DOWN:
 
1579
                y += button_h;
 
1580
                if ((x + w) > monitor.x + monitor.width)
 
1581
                        x -= (x + w) - (monitor.x + monitor.width);
 
1582
 
 
1583
                gravity = GDK_GRAVITY_NORTH_WEST;
 
1584
 
 
1585
                break;
 
1586
        case PANEL_APPLET_ORIENT_UP:
 
1587
                y -= h;
 
1588
                if ((x + w) > monitor.x + monitor.width)
 
1589
                        x -= (x + w) - (monitor.x + monitor.width);
 
1590
 
 
1591
                gravity = GDK_GRAVITY_SOUTH_WEST;
 
1592
 
 
1593
                break;
 
1594
        }
 
1595
                
 
1596
        gtk_window_move (GTK_WINDOW (window), x, y);
 
1597
        gtk_window_set_gravity (GTK_WINDOW (window), gravity);
 
1598
}
 
1599
 
 
1600
static void
 
1601
present_calendar_popup (ClockData *cd,
 
1602
                        GtkWidget *window,
 
1603
                        GtkWidget *button)
 
1604
{
 
1605
        position_calendar_popup (cd, window, button);
 
1606
        gtk_window_present (GTK_WINDOW (window));
 
1607
}
 
1608
 
 
1609
static void
 
1610
refresh_calendar (ClockData *cd)
 
1611
{
 
1612
    if (cd->calendar_popup)
 
1613
        gtk_widget_destroy (cd->calendar_popup);
 
1614
    cd->calendar_popup = NULL;
 
1615
    if (!cd->calendar_popup) {
 
1616
        cd->calendar_popup = create_calendar (cd, gtk_widget_get_screen (cd->applet));
 
1617
        g_object_add_weak_pointer (G_OBJECT (cd->calendar_popup),
 
1618
                (gpointer *) &cd->calendar_popup);
 
1619
    }
 
1620
 
 
1621
    if (cd->calendar_popup && GTK_WIDGET_REALIZED (cd->toggle)) {
 
1622
#ifdef HAVE_LIBECAL
 
1623
        if (cd->tasks_filter && cd->task_list)
 
1624
            gtk_tree_model_filter_refilter (cd->tasks_filter);
 
1625
#endif
 
1626
 
 
1627
        present_calendar_popup (cd, cd->calendar_popup, cd->toggle);
 
1628
        gtk_window_present (GTK_WINDOW (cd->calendar_popup));
 
1629
    }
 
1630
 
 
1631
}
 
1632
static void
 
1633
update_popup (ClockData *cd)
 
1634
{
 
1635
        if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (cd->toggle))) {
 
1636
                if (cd->calendar_popup)
 
1637
                        gtk_widget_destroy (cd->calendar_popup);
 
1638
                cd->calendar_popup = NULL;
 
1639
                return;
 
1640
        }
 
1641
 
 
1642
        if (!cd->calendar_popup) {
 
1643
                cd->calendar_popup = create_calendar (cd, gtk_widget_get_screen (cd->applet));
 
1644
                g_object_add_weak_pointer (G_OBJECT (cd->calendar_popup),
 
1645
                                           (gpointer *) &cd->calendar_popup);
 
1646
        }
 
1647
 
 
1648
        if (cd->calendar_popup && GTK_WIDGET_REALIZED (cd->toggle)) {
 
1649
#ifdef HAVE_LIBECAL
 
1650
                if (cd->tasks_filter && cd->task_list)
 
1651
                        gtk_tree_model_filter_refilter (cd->tasks_filter);
 
1652
#endif
 
1653
 
 
1654
                present_calendar_popup (cd, cd->calendar_popup, cd->toggle);
 
1655
                gtk_window_present (GTK_WINDOW (cd->calendar_popup));
 
1656
        }
 
1657
}
 
1658
 
 
1659
static void
 
1660
toggle_calendar (GtkWidget *button,
 
1661
                 ClockData *cd)
 
1662
{
 
1663
        update_popup (cd);
 
1664
}
 
1665
 
 
1666
static gboolean
 
1667
do_not_eat_button_press (GtkWidget      *widget,
 
1668
                         GdkEventButton *event)
 
1669
{
 
1670
        if (event->button != 1)
 
1671
                g_signal_stop_emission_by_name (widget, "button_press_event");
 
1672
 
 
1673
        return FALSE;
 
1674
}
 
1675
 
 
1676
/* Don't request smaller size then the last one we did, this avoids
 
1677
   jumping when proportional fonts are used.  We must take care to
 
1678
   call "unfix_size" whenever options are changed or such where
 
1679
   we'd want to forget the fixed size */
 
1680
static void
 
1681
clock_size_request (GtkWidget *clock, GtkRequisition *req, gpointer data)
 
1682
{
 
1683
        ClockData *cd = data;
 
1684
 
 
1685
        if (req->width > cd->fixed_width)
 
1686
                cd->fixed_width = req->width;
 
1687
        if (req->height > cd->fixed_height)
 
1688
                cd->fixed_height = req->height;
 
1689
        req->width = cd->fixed_width;
 
1690
        req->height = cd->fixed_height;
 
1691
}
 
1692
 
 
1693
static inline void
 
1694
force_no_focus_padding (GtkWidget *widget)
 
1695
{
 
1696
        gboolean first_time = TRUE;
 
1697
 
 
1698
        if (first_time) {
 
1699
                gtk_rc_parse_string ("\n"
 
1700
                                     "   style \"clock-applet-button-style\"\n"
 
1701
                                     "   {\n"
 
1702
                                     "      GtkWidget::focus-line-width=0\n"
 
1703
                                     "      GtkWidget::focus-padding=0\n"
 
1704
                                     "   }\n"
 
1705
                                     "\n"
 
1706
                                     "    widget \"*.clock-applet-button\" style \"clock-applet-button-style\"\n"
 
1707
                                     "\n");
 
1708
                first_time = FALSE;
 
1709
        }
 
1710
 
 
1711
        gtk_widget_set_name (widget, "clock-applet-button");
 
1712
}
 
1713
 
 
1714
static void
 
1715
create_clock_widget (ClockData *cd)
 
1716
{
 
1717
        GtkWidget *clock;
 
1718
        GtkWidget *toggle;
 
1719
        GtkWidget *alignment;
 
1720
 
 
1721
        clock = gtk_label_new ("hmm?");
 
1722
        g_signal_connect (clock, "size_request",
 
1723
                          G_CALLBACK (clock_size_request),
 
1724
                          cd);
 
1725
        g_signal_connect_swapped (clock, "style_set",
 
1726
                                  G_CALLBACK (unfix_size),
 
1727
                                  cd);
 
1728
        gtk_label_set_justify (GTK_LABEL (clock), GTK_JUSTIFY_CENTER);
 
1729
        gtk_widget_show (clock);
 
1730
 
 
1731
        toggle = gtk_toggle_button_new ();
 
1732
        gtk_container_set_resize_mode (GTK_CONTAINER (toggle), GTK_RESIZE_IMMEDIATE);
 
1733
        gtk_button_set_relief (GTK_BUTTON (toggle), GTK_RELIEF_NONE);
 
1734
 
 
1735
        force_no_focus_padding (toggle);
 
1736
 
 
1737
        alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
 
1738
        gtk_container_add (GTK_CONTAINER (alignment), clock);
 
1739
        gtk_container_set_resize_mode (GTK_CONTAINER (alignment), GTK_RESIZE_IMMEDIATE);
 
1740
        gtk_widget_show (alignment);
 
1741
        gtk_container_add (GTK_CONTAINER (toggle), alignment);
 
1742
 
 
1743
        g_signal_connect (toggle, "button_press_event",
 
1744
                          G_CALLBACK (do_not_eat_button_press), NULL);
 
1745
 
 
1746
        g_signal_connect (toggle, "toggled",
 
1747
                          G_CALLBACK (toggle_calendar), cd);
 
1748
 
 
1749
        gtk_widget_show (toggle);
 
1750
 
 
1751
        cd->toggle = toggle;
 
1752
 
 
1753
        cd->clockw = clock;
 
1754
 
 
1755
        cd->props = NULL;
 
1756
 
 
1757
        cd->orient = panel_applet_get_orient (PANEL_APPLET (cd->applet));
 
1758
 
 
1759
        cd->size = panel_applet_get_size (PANEL_APPLET (cd->applet));
 
1760
 
 
1761
        g_signal_connect (G_OBJECT(clock), "destroy",
 
1762
                          G_CALLBACK (destroy_clock),
 
1763
                          cd);
 
1764
        
 
1765
        set_atk_name_description (GTK_WIDGET (cd->applet), NULL,
 
1766
                                  _("Computer Clock"));
 
1767
 
 
1768
        /* Refresh the clock so that it paints its first state */
 
1769
        refresh_clock_timeout(cd);
 
1770
}
 
1771
 
 
1772
static void
 
1773
update_orient (ClockData *cd)
 
1774
{
 
1775
        const gchar *text;
 
1776
        int          min_width;
 
1777
        gdouble      new_angle;
 
1778
        gdouble      angle;
 
1779
 
 
1780
        text = gtk_label_get_text (GTK_LABEL (cd->clockw));
 
1781
        min_width = calculate_minimum_width (cd->toggle, text);
 
1782
 
 
1783
        if (cd->orient == PANEL_APPLET_ORIENT_LEFT &&
 
1784
            min_width > cd->toggle->allocation.width)
 
1785
                new_angle = 270;
 
1786
        else if (cd->orient == PANEL_APPLET_ORIENT_RIGHT &&
 
1787
                 min_width > cd->toggle->allocation.width)
 
1788
                new_angle = 90;
 
1789
        else
 
1790
                new_angle = 0;
 
1791
 
 
1792
        angle = gtk_label_get_angle (GTK_LABEL (cd->clockw));
 
1793
        if (angle != new_angle) {
 
1794
                unfix_size (cd);
 
1795
                gtk_label_set_angle (GTK_LABEL (cd->clockw), new_angle);
 
1796
        }
 
1797
}
 
1798
 
 
1799
/* this is when the panel orientation changes */
 
1800
static void
 
1801
applet_change_orient (PanelApplet       *applet,
 
1802
                      PanelAppletOrient  orient,
 
1803
                      ClockData         *cd)
 
1804
{
 
1805
        if (orient == cd->orient)
 
1806
                return;
 
1807
 
 
1808
        cd->orient = orient;
 
1809
        
 
1810
        unfix_size (cd);
 
1811
        update_clock (cd);
 
1812
        update_popup (cd);
 
1813
}
 
1814
 
 
1815
/* this is when the panel size changes */
 
1816
static void
 
1817
toggle_change_pixel_size (GtkWidget     *widget,
 
1818
                          GtkAllocation *allocation,
 
1819
                          ClockData     *cd)
 
1820
{
 
1821
        int new_size;
 
1822
 
 
1823
        if (cd->old_allocation.width  == allocation->width &&
 
1824
            cd->old_allocation.height == allocation->height)
 
1825
                return;
 
1826
 
 
1827
        cd->old_allocation.width  = allocation->width;
 
1828
        cd->old_allocation.height = allocation->height;
 
1829
 
 
1830
        if (cd->orient == PANEL_APPLET_ORIENT_LEFT ||
 
1831
            cd->orient == PANEL_APPLET_ORIENT_RIGHT)
 
1832
                new_size = allocation->width;
 
1833
        else
 
1834
                new_size = allocation->height;
 
1835
 
 
1836
        cd->size = new_size;
 
1837
 
 
1838
        unfix_size (cd);
 
1839
        update_timeformat (cd);
 
1840
        update_clock (cd);
 
1841
}
 
1842
 
 
1843
static void
 
1844
copy_time (BonoboUIComponent *uic,
 
1845
           ClockData         *cd,
 
1846
           const gchar       *verbname)
 
1847
{
 
1848
        char string[256];
 
1849
        char *utf8;
 
1850
 
 
1851
        if (cd->format == CLOCK_FORMAT_UNIX) {
 
1852
                g_snprintf (string, sizeof(string), "%lu",
 
1853
                            (unsigned long)cd->current_time);
 
1854
        } else if (cd->format == CLOCK_FORMAT_INTERNET) {
 
1855
                float itime = get_itime (cd->current_time);
 
1856
                if (cd->showseconds)
 
1857
                        g_snprintf (string, sizeof (string), "@%3.2f", itime);
 
1858
                else
 
1859
                        g_snprintf (string, sizeof (string), "@%3.0f", itime);
 
1860
        } else {
 
1861
                struct tm *tm;
 
1862
                char      *format;
 
1863
 
 
1864
                if (cd->format == CLOCK_FORMAT_CUSTOM) {
 
1865
                        format = g_locale_from_utf8 (cd->custom_format, -1,
 
1866
                                                     NULL, NULL, NULL);
 
1867
                } else if (cd->format == CLOCK_FORMAT_12) {
 
1868
                        if (cd->showseconds)
 
1869
                                format = g_locale_from_utf8 (_("%I:%M:%S %p"), -1, NULL, NULL, NULL);
 
1870
                        else
 
1871
                                format = g_locale_from_utf8 (_("%I:%M %p"), -1, NULL, NULL, NULL);
 
1872
                } else {
 
1873
                        if (cd->showseconds)
 
1874
                                format = g_locale_from_utf8 (_("%H:%M:%S"), -1, NULL, NULL, NULL);
 
1875
                        else
 
1876
                                format = g_locale_from_utf8 (_("%H:%M"), -1, NULL, NULL, NULL);
 
1877
                }
 
1878
 
 
1879
                if (cd->gmt_time)
 
1880
                        tm = gmtime (&cd->current_time);
 
1881
                else
 
1882
                        tm = localtime (&cd->current_time);
 
1883
 
 
1884
                if (!format)
 
1885
                        strcpy (string, "???");
 
1886
                else if (strftime (string, sizeof (string), format, tm) <= 0)
 
1887
                        strcpy (string, "???");
 
1888
                g_free (format);
 
1889
        }
 
1890
 
 
1891
        utf8 = g_locale_to_utf8 (string, -1, NULL, NULL, NULL);
 
1892
        gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
 
1893
                                utf8, -1);
 
1894
        gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
 
1895
                                utf8, -1);
 
1896
        g_free (utf8);
 
1897
}
 
1898
 
 
1899
static void
 
1900
copy_date (BonoboUIComponent *uic,
 
1901
           ClockData         *cd,
 
1902
           const gchar       *verbname)
 
1903
{
 
1904
        struct tm *tm;
 
1905
        char string[256];
 
1906
        char *utf8, *loc;
 
1907
 
 
1908
        if (cd->gmt_time)
 
1909
                tm = gmtime (&cd->current_time);
 
1910
        else
 
1911
                tm = localtime (&cd->current_time);
 
1912
 
 
1913
        loc = g_locale_from_utf8 (_("%A, %B %d %Y"), -1, NULL, NULL, NULL);
 
1914
        if (!loc)
 
1915
                strcpy (string, "???");
 
1916
        else if (strftime (string, sizeof (string), loc, tm) <= 0)
 
1917
                strcpy (string, "???");
 
1918
        g_free (loc);
 
1919
        
 
1920
        utf8 = g_locale_to_utf8 (string, -1, NULL, NULL, NULL);
 
1921
        gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
 
1922
                                utf8, -1);
 
1923
        gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
 
1924
                                utf8, -1);
 
1925
        g_free (utf8);
 
1926
}
 
1927
 
 
1928
static gboolean
 
1929
try_config_tool (GdkScreen  *screen,
 
1930
                 const char *tool)
 
1931
{
 
1932
        GtkWidget *dialog;
 
1933
        GError    *err;
 
1934
        char     **argv;
 
1935
        char      *path;
 
1936
 
 
1937
        if (!tool || tool[0] == '\0')
 
1938
                return FALSE;
 
1939
 
 
1940
        if (!g_shell_parse_argv (tool, NULL, &argv, NULL))
 
1941
                return FALSE;
 
1942
 
 
1943
        if (!(path = g_find_program_in_path (argv [0]))) {
 
1944
                g_strfreev (argv);
 
1945
                return FALSE;
 
1946
        }
 
1947
 
 
1948
        g_free (path);
 
1949
 
 
1950
        err = NULL;
 
1951
        if (gdk_spawn_on_screen (screen,
 
1952
                                 NULL,
 
1953
                                 argv,
 
1954
                                 NULL,
 
1955
                                 G_SPAWN_SEARCH_PATH,
 
1956
                                 NULL,
 
1957
                                 NULL,
 
1958
                                 NULL,
 
1959
                                 &err)) {
 
1960
                g_strfreev (argv);
 
1961
                return TRUE;
 
1962
        }
 
1963
 
 
1964
        g_strfreev (argv);
 
1965
 
 
1966
        dialog = gtk_message_dialog_new (NULL,
 
1967
                                         GTK_DIALOG_DESTROY_WITH_PARENT,
 
1968
                                         GTK_MESSAGE_ERROR,
 
1969
                                         GTK_BUTTONS_OK,
 
1970
                                         _("Failed to launch time configuration tool: %s"),
 
1971
                                         err->message);
 
1972
        g_error_free (err);
 
1973
                
 
1974
        g_signal_connect (dialog, "response",
 
1975
                          G_CALLBACK (gtk_widget_destroy), NULL);
 
1976
 
 
1977
        gtk_window_set_icon_name (GTK_WINDOW (dialog), CLOCK_ICON);
 
1978
        gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
 
1979
        gtk_window_set_screen (GTK_WINDOW (dialog), screen);
 
1980
                        
 
1981
        gtk_widget_show_all (dialog);                   
 
1982
                
 
1983
        return TRUE;
 
1984
}
 
1985
 
 
1986
static void
 
1987
config_date (BonoboUIComponent *uic,
 
1988
             ClockData         *cd,
 
1989
             const char        *verbname)
 
1990
{
 
1991
        GtkWidget *dialog;
 
1992
        GdkScreen *screen;
 
1993
        int i;
 
1994
 
 
1995
        screen = gtk_widget_get_screen (cd->applet);
 
1996
 
 
1997
        if (try_config_tool (screen, cd->config_tool))
 
1998
                return;
 
1999
        
 
2000
        for (i = 0; i < G_N_ELEMENTS (clock_config_tools); i++)
 
2001
                if (try_config_tool (screen, clock_config_tools [i]))
 
2002
                        return;
 
2003
                
 
2004
        dialog = gtk_message_dialog_new (NULL,
 
2005
                                         GTK_DIALOG_DESTROY_WITH_PARENT,
 
2006
                                         GTK_MESSAGE_ERROR,
 
2007
                                         GTK_BUTTONS_OK,
 
2008
                                         _("Failed to locate a program for configuring "
 
2009
                                           "the date and time. Perhaps none is installed?"));
 
2010
                
 
2011
        g_signal_connect (dialog, "response",
 
2012
                          G_CALLBACK (gtk_widget_destroy), NULL);
 
2013
                
 
2014
        gtk_window_set_icon_name (GTK_WINDOW (dialog), CLOCK_ICON);
 
2015
        gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
 
2016
        gtk_window_set_screen (GTK_WINDOW (dialog), screen);
 
2017
 
 
2018
        gtk_widget_show_all (dialog);
 
2019
}
 
2020
 
 
2021
/* current timestamp */
 
2022
static const BonoboUIVerb clock_menu_verbs [] = {
 
2023
        BONOBO_UI_UNSAFE_VERB ("ClockPreferences", display_properties_dialog),
 
2024
        BONOBO_UI_UNSAFE_VERB ("ClockHelp",        display_help_dialog),
 
2025
        BONOBO_UI_UNSAFE_VERB ("ClockAbout",       display_about_dialog),
 
2026
        BONOBO_UI_UNSAFE_VERB ("ClockCopyTime",    copy_time),
 
2027
        BONOBO_UI_UNSAFE_VERB ("ClockCopyDate",    copy_date),
 
2028
        BONOBO_UI_UNSAFE_VERB ("ClockConfig",      config_date),
 
2029
        BONOBO_UI_VERB_END
 
2030
};
 
2031
 
 
2032
static void
 
2033
format_changed (GConfClient  *client,
 
2034
                guint         cnxn_id,
 
2035
                GConfEntry   *entry,
 
2036
                ClockData    *clock)
 
2037
{
 
2038
        const char  *value;
 
2039
        int          new_format;
 
2040
        
 
2041
        if (!entry->value || entry->value->type != GCONF_VALUE_STRING)
 
2042
                return;
 
2043
 
 
2044
        value = gconf_value_get_string (entry->value);
 
2045
        if (!gconf_string_to_enum (format_type_enum_map, value, &new_format))
 
2046
                return;
 
2047
 
 
2048
        if (!clock->can_handle_format_12 && new_format == CLOCK_FORMAT_12)
 
2049
                new_format = CLOCK_FORMAT_24;
 
2050
 
 
2051
        if (new_format == clock->format)
 
2052
                return;
 
2053
 
 
2054
        clock->format = new_format;
 
2055
        update_timeformat (clock);
 
2056
        refresh_clock_timeout (clock);
 
2057
}
 
2058
 
 
2059
static void
 
2060
show_seconds_changed (GConfClient  *client,
 
2061
                   guint         cnxn_id,
 
2062
                   GConfEntry   *entry,
 
2063
                   ClockData    *clock)
 
2064
{
 
2065
        gboolean value;
 
2066
        
 
2067
        if (!entry->value || entry->value->type != GCONF_VALUE_BOOL)
 
2068
                return;
 
2069
 
 
2070
        value = gconf_value_get_bool (entry->value);
 
2071
        
 
2072
        clock->showseconds = (value != 0);
 
2073
        refresh_clock_timeout (clock);
 
2074
}
 
2075
 
 
2076
static void
 
2077
show_date_changed (GConfClient  *client,
 
2078
                   guint         cnxn_id,
 
2079
                   GConfEntry   *entry,
 
2080
                   ClockData    *clock)
 
2081
{
 
2082
        gboolean value;
 
2083
        
 
2084
        if (!entry->value || entry->value->type != GCONF_VALUE_BOOL)
 
2085
                return;
 
2086
 
 
2087
        value = gconf_value_get_bool (entry->value);
 
2088
        
 
2089
        clock->showdate = (value != 0);
 
2090
        update_timeformat (clock);
 
2091
        refresh_clock (clock);
 
2092
}
 
2093
 
 
2094
static void
 
2095
show_lunardate_changed (GConfClient  *client,
 
2096
                   guint         cnxn_id,
 
2097
                   GConfEntry   *entry,
 
2098
                   ClockData    *clock)
 
2099
{
 
2100
        gboolean value;
 
2101
        
 
2102
        if (!entry->value || entry->value->type != GCONF_VALUE_BOOL)
 
2103
                return;
 
2104
 
 
2105
        value = gconf_value_get_bool (entry->value);
 
2106
        
 
2107
        clock->showlunardate = (value != 0);
 
2108
        refresh_calendar(clock);
 
2109
        //update_popup (clock);
 
2110
}
 
2111
 
 
2112
static void
 
2113
gmt_time_changed (GConfClient  *client,
 
2114
                  guint         cnxn_id,
 
2115
                  GConfEntry   *entry,
 
2116
                  ClockData    *clock)
 
2117
{
 
2118
        gboolean value;
 
2119
        
 
2120
        if (!entry->value || entry->value->type != GCONF_VALUE_BOOL)
 
2121
                return;
 
2122
 
 
2123
        value = gconf_value_get_bool (entry->value);
 
2124
        
 
2125
        clock->gmt_time = (value != 0);
 
2126
        refresh_clock_timeout (clock);
 
2127
}
 
2128
 
 
2129
static gboolean
 
2130
check_config_tool_command (const char *config_tool)
 
2131
{
 
2132
        char **argv;
 
2133
        char  *path;
 
2134
 
 
2135
        if (!config_tool || config_tool[0] == '\0')
 
2136
                return FALSE;
 
2137
 
 
2138
        argv = NULL;
 
2139
        if (!g_shell_parse_argv (config_tool, NULL, &argv, NULL))
 
2140
                return FALSE;
 
2141
 
 
2142
        if (!(path = g_find_program_in_path (argv [0]))) {
 
2143
                g_strfreev (argv);
 
2144
                return FALSE;
 
2145
        }
 
2146
 
 
2147
        g_free (path);
 
2148
        g_strfreev (argv);
 
2149
 
 
2150
        return TRUE;
 
2151
}
 
2152
 
 
2153
static void
 
2154
config_tool_changed (GConfClient  *client,
 
2155
                     guint         cnxn_id,
 
2156
                     GConfEntry   *entry,
 
2157
                     ClockData    *clock)
 
2158
{
 
2159
        const char *value;
 
2160
        
 
2161
        if (!entry->value || entry->value->type != GCONF_VALUE_STRING)
 
2162
                return;
 
2163
 
 
2164
        value = gconf_value_get_string (entry->value);
 
2165
 
 
2166
        if (check_config_tool_command (value)) {
 
2167
                g_free (clock->config_tool);
 
2168
                clock->config_tool = g_strdup (value);
 
2169
        }
 
2170
}
 
2171
 
 
2172
static void
 
2173
custom_format_changed (GConfClient  *client,
 
2174
                       guint         cnxn_id,
 
2175
                       GConfEntry   *entry,
 
2176
                       ClockData    *clock)
 
2177
{
 
2178
        const char *value;
 
2179
        
 
2180
        if (!entry->value || entry->value->type != GCONF_VALUE_STRING)
 
2181
                return;
 
2182
 
 
2183
        value = gconf_value_get_string (entry->value);
 
2184
 
 
2185
        g_free (clock->custom_format);
 
2186
        clock->custom_format = g_strdup (value);
 
2187
 
 
2188
        if (clock->format == CLOCK_FORMAT_CUSTOM)
 
2189
                refresh_clock (clock);
 
2190
}
 
2191
 
 
2192
static void
 
2193
show_week_changed (GConfClient  *client,
 
2194
                   guint         cnxn_id,
 
2195
                   GConfEntry   *entry,
 
2196
                   ClockData    *clock)
 
2197
{
 
2198
        GtkCalendarDisplayOptions options;
 
2199
        gboolean value;
 
2200
        
 
2201
        if (!entry->value || entry->value->type != GCONF_VALUE_BOOL)
 
2202
                return;
 
2203
 
 
2204
        value = gconf_value_get_bool (entry->value);
 
2205
        
 
2206
        if (clock->showweek == (value != 0))
 
2207
                return;
 
2208
 
 
2209
        clock->showweek = (value != 0);
 
2210
 
 
2211
        if (clock->calendar_popup != NULL) {
 
2212
                options = gtk_chinese_calendar_get_display_options (GTK_CHINESE_CALENDAR (clock->calendar));
 
2213
 
 
2214
                if (clock->showweek)
 
2215
                        options |= GTK_CHINESE_CALENDAR_SHOW_WEEK_NUMBERS;
 
2216
                else
 
2217
                        options &= ~(GTK_CHINESE_CALENDAR_SHOW_WEEK_NUMBERS);
 
2218
 
 
2219
                gtk_chinese_calendar_set_display_options (GTK_CHINESE_CALENDAR (clock->calendar),
 
2220
                                                  options);
 
2221
 
 
2222
                position_calendar_popup (clock, clock->calendar_popup,
 
2223
                                         clock->toggle);
 
2224
        }
 
2225
}
 
2226
 
 
2227
static void
 
2228
setup_gconf (ClockData *clock)
 
2229
{
 
2230
        GConfClient *client;
 
2231
        char        *key;
 
2232
 
 
2233
        client = gconf_client_get_default ();
 
2234
 
 
2235
        key = panel_applet_gconf_get_full_key (PANEL_APPLET (clock->applet),
 
2236
                                               KEY_FORMAT);
 
2237
        clock->listeners [0] =
 
2238
                gconf_client_notify_add (
 
2239
                                client, key,
 
2240
                                (GConfClientNotifyFunc) format_changed,
 
2241
                                clock, NULL, NULL);
 
2242
        g_free (key);
 
2243
 
 
2244
        key = panel_applet_gconf_get_full_key (PANEL_APPLET (clock->applet),
 
2245
                                               KEY_SHOW_SECONDS);
 
2246
        clock->listeners [1] =
 
2247
                        gconf_client_notify_add (
 
2248
                                client, key,
 
2249
                                (GConfClientNotifyFunc)show_seconds_changed,
 
2250
                                clock, NULL, NULL);
 
2251
        g_free (key);
 
2252
 
 
2253
        key = panel_applet_gconf_get_full_key (PANEL_APPLET (clock->applet),
 
2254
                                               KEY_SHOW_DATE);
 
2255
        clock->listeners [2] =
 
2256
                        gconf_client_notify_add (
 
2257
                                client, key,
 
2258
                                (GConfClientNotifyFunc) show_date_changed,
 
2259
                                clock, NULL, NULL);
 
2260
        g_free (key);
 
2261
 
 
2262
        key = panel_applet_gconf_get_full_key (PANEL_APPLET (clock->applet),
 
2263
                                               KEY_SHOW_LUNARDATE);
 
2264
        clock->listeners [3] =
 
2265
                        gconf_client_notify_add (
 
2266
                                client, key,
 
2267
                                (GConfClientNotifyFunc) show_lunardate_changed,
 
2268
                                clock, NULL, NULL);
 
2269
        g_free (key);
 
2270
 
 
2271
        key = panel_applet_gconf_get_full_key (PANEL_APPLET (clock->applet),
 
2272
                                               KEY_GMT_TIME);
 
2273
        clock->listeners [4] =
 
2274
                        gconf_client_notify_add (
 
2275
                                client, key,
 
2276
                                (GConfClientNotifyFunc) gmt_time_changed,
 
2277
                                clock, NULL, NULL);
 
2278
        g_free (key);
 
2279
 
 
2280
        key = panel_applet_gconf_get_full_key (PANEL_APPLET (clock->applet),
 
2281
                                               KEY_CONFIG_TOOL);
 
2282
        clock->listeners [5] =
 
2283
                gconf_client_notify_add (
 
2284
                                client, key,
 
2285
                                (GConfClientNotifyFunc) config_tool_changed,
 
2286
                                clock, NULL, NULL);
 
2287
        g_free (key);
 
2288
 
 
2289
        key = panel_applet_gconf_get_full_key (PANEL_APPLET (clock->applet),
 
2290
                                               KEY_CUSTOM_FORMAT);
 
2291
        clock->listeners [6] =
 
2292
                gconf_client_notify_add (
 
2293
                                client, key,
 
2294
                                (GConfClientNotifyFunc) custom_format_changed,
 
2295
                                clock, NULL, NULL);
 
2296
        g_free (key);
 
2297
        
 
2298
        key = panel_applet_gconf_get_full_key (PANEL_APPLET (clock->applet),
 
2299
                                               KEY_SHOW_WEEK);
 
2300
        clock->listeners [7] =
 
2301
                        gconf_client_notify_add (
 
2302
                                client, key,
 
2303
                                (GConfClientNotifyFunc) show_week_changed,
 
2304
                                clock, NULL, NULL);
 
2305
        g_free (key);
 
2306
 
 
2307
        g_object_unref (G_OBJECT (client));
 
2308
}
 
2309
 
 
2310
static void
 
2311
clock_migrate_to_26 (ClockData *clock)
 
2312
{
 
2313
        gboolean  unixtime;
 
2314
        gboolean  internettime;
 
2315
        int       hourformat;
 
2316
 
 
2317
        internettime = panel_applet_gconf_get_bool (PANEL_APPLET (clock->applet),
 
2318
                                                    "internet_time",
 
2319
                                                    NULL);
 
2320
        unixtime = panel_applet_gconf_get_bool (PANEL_APPLET (clock->applet),
 
2321
                                                "unix_time",
 
2322
                                                NULL);
 
2323
        hourformat = panel_applet_gconf_get_int (PANEL_APPLET (clock->applet),
 
2324
                                                 "hour_format",
 
2325
                                                 NULL);
 
2326
 
 
2327
        if (unixtime)
 
2328
                clock->format = CLOCK_FORMAT_UNIX;
 
2329
        else if (internettime)
 
2330
                clock->format = CLOCK_FORMAT_INTERNET;
 
2331
        else if (hourformat == 12)
 
2332
                clock->format = CLOCK_FORMAT_12;
 
2333
        else if (hourformat == 24)
 
2334
                clock->format = CLOCK_FORMAT_24;
 
2335
 
 
2336
        panel_applet_gconf_set_string (PANEL_APPLET (clock->applet),
 
2337
                                       KEY_FORMAT,
 
2338
                                       gconf_enum_to_string (format_type_enum_map,
 
2339
                                                             clock->format),
 
2340
                                       NULL);
 
2341
}
 
2342
 
 
2343
static gboolean
 
2344
fill_clock_applet (PanelApplet *applet)
 
2345
{
 
2346
        ClockData         *cd;
 
2347
        BonoboUIComponent *popup_component;
 
2348
        GError            *error;
 
2349
        int                format;
 
2350
        char              *format_str;
 
2351
        
 
2352
        panel_applet_add_preferences (applet, "/schemas/apps/clock_applet/prefs", NULL);
 
2353
        panel_applet_set_flags (applet, PANEL_APPLET_EXPAND_MINOR);
 
2354
        
 
2355
        cd = g_new0 (ClockData, 1);
 
2356
        cd->fixed_width = -1;
 
2357
        cd->fixed_height = -1;
 
2358
 
 
2359
        cd->applet = GTK_WIDGET (applet);
 
2360
 
 
2361
        setup_gconf (cd);
 
2362
 
 
2363
        cd->format = CLOCK_FORMAT_INVALID;
 
2364
 
 
2365
        format_str = panel_applet_gconf_get_string (applet, KEY_FORMAT, NULL);
 
2366
        if (format_str &&
 
2367
            gconf_string_to_enum (format_type_enum_map, format_str, &format))
 
2368
                cd->format = format;
 
2369
        else
 
2370
                clock_migrate_to_26 (cd);
 
2371
 
 
2372
        g_free (format_str);
 
2373
 
 
2374
        if (cd->format == CLOCK_FORMAT_INVALID)
 
2375
                cd->format = clock_locale_format ();
 
2376
 
 
2377
        cd->custom_format = panel_applet_gconf_get_string (applet, KEY_CUSTOM_FORMAT, NULL);
 
2378
        cd->showseconds = panel_applet_gconf_get_bool (applet, KEY_SHOW_SECONDS, NULL);
 
2379
        
 
2380
        error = NULL;
 
2381
        cd->showdate = panel_applet_gconf_get_bool (applet, KEY_SHOW_DATE, &error);
 
2382
        if (error) {
 
2383
                g_error_free (error);
 
2384
                /* if on a small screen don't show date by default */
 
2385
                if (gdk_screen_width () <= 800)
 
2386
                        cd->showdate = FALSE;
 
2387
                else
 
2388
                        cd->showdate = TRUE;
 
2389
        }
 
2390
 
 
2391
        error = NULL;
 
2392
        cd->showlunardate = panel_applet_gconf_get_bool (applet, KEY_SHOW_LUNARDATE, &error);
 
2393
        if (error) {
 
2394
                g_error_free (error);
 
2395
                /* if on a small screen don't show date by default */
 
2396
                if (gdk_screen_width () <= 800)
 
2397
                        cd->showlunardate = FALSE;
 
2398
                else
 
2399
                        cd->showlunardate = TRUE;
 
2400
        }
 
2401
 
 
2402
        cd->gmt_time = panel_applet_gconf_get_bool (applet, KEY_GMT_TIME, NULL);
 
2403
        cd->showweek = panel_applet_gconf_get_bool (applet, KEY_SHOW_WEEK, NULL);
 
2404
        cd->config_tool = panel_applet_gconf_get_string (applet, KEY_CONFIG_TOOL, NULL);
 
2405
 
 
2406
        cd->timeformat = NULL;
 
2407
 
 
2408
        cd->can_handle_format_12 = (clock_locale_format () == CLOCK_FORMAT_12);
 
2409
        if (!cd->can_handle_format_12 && cd->format == CLOCK_FORMAT_12)
 
2410
                cd->format = CLOCK_FORMAT_24;
 
2411
 
 
2412
        create_clock_widget (cd);
 
2413
 
 
2414
        gtk_container_set_border_width (GTK_CONTAINER (cd->applet), 0);
 
2415
        gtk_container_set_border_width (GTK_CONTAINER (cd->toggle), 0);
 
2416
        gtk_container_add (GTK_CONTAINER (cd->applet), cd->toggle);
 
2417
 
 
2418
#ifndef CLOCK_INPROCESS
 
2419
        gtk_window_set_default_icon_name (CLOCK_ICON);
 
2420
#endif
 
2421
        gtk_widget_show (cd->applet);
 
2422
 
 
2423
        /* FIXME: Update this comment. */
 
2424
        /* we have to bind change_orient before we do applet_widget_add
 
2425
           since we need to get an initial change_orient signal to set our
 
2426
           initial oriantation, and we get that during the _add call */
 
2427
        g_signal_connect (G_OBJECT (cd->applet),
 
2428
                          "change_orient",
 
2429
                          G_CALLBACK (applet_change_orient),
 
2430
                          cd);
 
2431
 
 
2432
        g_signal_connect (G_OBJECT (cd->toggle),
 
2433
                          "size_allocate",
 
2434
                          G_CALLBACK (toggle_change_pixel_size),
 
2435
                          cd);
 
2436
 
 
2437
        panel_applet_set_background_widget (PANEL_APPLET (cd->applet),
 
2438
                                            GTK_WIDGET (cd->applet));
 
2439
 
 
2440
        panel_applet_setup_menu_from_file (PANEL_APPLET (cd->applet),
 
2441
                                           NULL,
 
2442
                                           "GNOME_LunarApplet.xml",
 
2443
                                           NULL,
 
2444
                                           clock_menu_verbs,
 
2445
                                           cd);
 
2446
 
 
2447
        popup_component = panel_applet_get_popup_component (PANEL_APPLET (cd->applet));
 
2448
 
 
2449
        if (panel_applet_get_locked_down (PANEL_APPLET (cd->applet))) {
 
2450
                bonobo_ui_component_set_prop (popup_component,
 
2451
                                              "/commands/ClockPreferences",
 
2452
                                              "hidden", "1",
 
2453
                                              NULL);
 
2454
                bonobo_ui_component_set_prop (popup_component,
 
2455
                                              "/commands/ClockConfig",
 
2456
                                              "hidden", "1",
 
2457
                                              NULL);
 
2458
        }
 
2459
 
 
2460
        if (!check_config_tool_command (cd->config_tool)) {
 
2461
                g_free (cd->config_tool);
 
2462
                cd->config_tool = NULL;
 
2463
        }
 
2464
 
 
2465
        if (!cd->config_tool) {
 
2466
                int i;
 
2467
 
 
2468
                for (i = 0; i < G_N_ELEMENTS (clock_config_tools); i++)
 
2469
                        if (check_config_tool_command (clock_config_tools [i])) {
 
2470
                                cd->config_tool = g_strdup (clock_config_tools [i]);
 
2471
                                break;
 
2472
                        }
 
2473
        }
 
2474
 
 
2475
        bonobo_ui_component_set_prop (popup_component,
 
2476
                                      "/commands/ClockConfig",
 
2477
                                      "hidden", cd->config_tool ? "0" : "1",
 
2478
                                      NULL);
 
2479
 
 
2480
        return TRUE;
 
2481
}
 
2482
 
 
2483
static void
 
2484
setup_writability_sensitivity (ClockData *clock, GtkWidget *w, GtkWidget *label, const char *key)
 
2485
{
 
2486
        char *fullkey;
 
2487
        GConfClient *client;
 
2488
 
 
2489
        client = gconf_client_get_default ();
 
2490
 
 
2491
        fullkey = panel_applet_gconf_get_full_key
 
2492
                (PANEL_APPLET (clock->applet), key);
 
2493
 
 
2494
        if ( ! gconf_client_key_is_writable (client, fullkey, NULL)) {
 
2495
                g_object_set_data (G_OBJECT (w), NEVER_SENSITIVE,
 
2496
                                   GINT_TO_POINTER (1));
 
2497
                gtk_widget_set_sensitive (w, FALSE);
 
2498
                if (label != NULL) {
 
2499
                        g_object_set_data (G_OBJECT (label), NEVER_SENSITIVE,
 
2500
                                           GINT_TO_POINTER (1));
 
2501
                        gtk_widget_set_sensitive (label, FALSE);
 
2502
                }
 
2503
        }
 
2504
 
 
2505
        g_free (fullkey);
 
2506
 
 
2507
        g_object_unref (G_OBJECT (client));
 
2508
}
 
2509
 
 
2510
static void
 
2511
update_properties_for_format (ClockData   *cd,
 
2512
                              GtkComboBox *combo,
 
2513
                              ClockFormat  format)
 
2514
{
 
2515
 
 
2516
        /* show the custom format things the first time we actually
 
2517
         * have a custom format set in GConf, but after that don't
 
2518
         * unshow it if the format changes
 
2519
         */
 
2520
        if (!cd->custom_format_shown &&
 
2521
            (cd->format == CLOCK_FORMAT_CUSTOM ||
 
2522
             (cd->custom_format && cd->custom_format [0]))) {
 
2523
                gtk_widget_show (cd->custom_hbox);
 
2524
                gtk_widget_show (cd->custom_label);
 
2525
                gtk_widget_show (cd->custom_entry);
 
2526
                
 
2527
                gtk_combo_box_append_text (combo, _("Custom format"));
 
2528
 
 
2529
                cd->custom_format_shown = TRUE;
 
2530
        }
 
2531
 
 
2532
        /* Some combinations of options do not make sense */
 
2533
        switch (format) {
 
2534
        case CLOCK_FORMAT_12:
 
2535
        case CLOCK_FORMAT_24:
 
2536
                gtk_widget_set_sensitive (cd->showseconds_check, TRUE);
 
2537
                gtk_widget_set_sensitive (cd->showdate_check, TRUE);
 
2538
                gtk_widget_set_sensitive (cd->gmt_time_check, TRUE);
 
2539
                gtk_widget_set_sensitive (cd->custom_entry, FALSE);
 
2540
                gtk_widget_set_sensitive (cd->custom_label, FALSE);
 
2541
                break;
 
2542
        case CLOCK_FORMAT_UNIX:
 
2543
                gtk_widget_set_sensitive (cd->showseconds_check, FALSE);
 
2544
                gtk_widget_set_sensitive (cd->showdate_check, FALSE);
 
2545
                gtk_widget_set_sensitive (cd->gmt_time_check, FALSE);
 
2546
                gtk_widget_set_sensitive (cd->custom_entry, FALSE);
 
2547
                gtk_widget_set_sensitive (cd->custom_label, FALSE);
 
2548
                break;
 
2549
        case CLOCK_FORMAT_INTERNET:
 
2550
                gtk_widget_set_sensitive (cd->showseconds_check, TRUE);
 
2551
                gtk_widget_set_sensitive (cd->showdate_check, FALSE);
 
2552
                gtk_widget_set_sensitive (cd->gmt_time_check, FALSE);
 
2553
                gtk_widget_set_sensitive (cd->custom_entry, FALSE);
 
2554
                gtk_widget_set_sensitive (cd->custom_label, FALSE);
 
2555
                break;
 
2556
        case CLOCK_FORMAT_CUSTOM:
 
2557
                gtk_widget_set_sensitive (cd->showseconds_check, FALSE);
 
2558
                gtk_widget_set_sensitive (cd->showdate_check, FALSE);
 
2559
                gtk_widget_set_sensitive (cd->gmt_time_check, TRUE);
 
2560
                gtk_widget_set_sensitive (cd->custom_entry, TRUE);
 
2561
                gtk_widget_set_sensitive (cd->custom_label, TRUE);
 
2562
                break;
 
2563
        default:
 
2564
                g_assert_not_reached ();
 
2565
                break;
 
2566
        }
 
2567
}
 
2568
 
 
2569
static void
 
2570
set_format_cb (GtkComboBox *combo,
 
2571
               ClockData   *cd)
 
2572
{
 
2573
        ClockFormat format;
 
2574
 
 
2575
        /* valid values begin from 1 */
 
2576
        if (cd->can_handle_format_12)
 
2577
                format = gtk_combo_box_get_active (combo) + 1;
 
2578
        else
 
2579
                format = gtk_combo_box_get_active (combo) + 2;
 
2580
 
 
2581
        update_properties_for_format (cd, combo, format);
 
2582
 
 
2583
        if (cd->format != format)
 
2584
                panel_applet_gconf_set_string (PANEL_APPLET (cd->applet),
 
2585
                                               KEY_FORMAT,
 
2586
                                               gconf_enum_to_string (format_type_enum_map, format),
 
2587
                                               NULL);
 
2588
}
 
2589
 
 
2590
static void
 
2591
set_show_seconds_cb (GtkWidget *w,
 
2592
                     ClockData *clock)
 
2593
{
 
2594
        panel_applet_gconf_set_bool (PANEL_APPLET (clock->applet),
 
2595
                                     KEY_SHOW_SECONDS,
 
2596
                                     GTK_TOGGLE_BUTTON (w)->active,
 
2597
                                     NULL);
 
2598
}
 
2599
 
 
2600
static void
 
2601
set_show_date_cb (GtkWidget *w,
 
2602
                  ClockData *clock)
 
2603
{
 
2604
        panel_applet_gconf_set_bool (PANEL_APPLET (clock->applet),
 
2605
                                     KEY_SHOW_DATE,
 
2606
                                     GTK_TOGGLE_BUTTON (w)->active,
 
2607
                                     NULL);
 
2608
}
 
2609
 
 
2610
static void
 
2611
set_show_lunardate_cb (GtkWidget *w,
 
2612
                  ClockData *clock)
 
2613
{
 
2614
        panel_applet_gconf_set_bool (PANEL_APPLET (clock->applet),
 
2615
                                     KEY_SHOW_LUNARDATE,
 
2616
                                     GTK_TOGGLE_BUTTON (w)->active,
 
2617
                                     NULL);
 
2618
}
 
2619
static void
 
2620
set_gmt_time_cb (GtkWidget *w,
 
2621
                 ClockData *clock)
 
2622
{
 
2623
        panel_applet_gconf_set_bool (PANEL_APPLET (clock->applet),
 
2624
                                     KEY_GMT_TIME,
 
2625
                                     GTK_TOGGLE_BUTTON (w)->active,
 
2626
                                     NULL);
 
2627
}
 
2628
 
 
2629
static void
 
2630
set_custom_format_cb (GtkEntry  *entry,
 
2631
                      ClockData *cd)
 
2632
{
 
2633
        const char *custom_format;
 
2634
 
 
2635
        custom_format = gtk_entry_get_text (entry);
 
2636
        panel_applet_gconf_set_string (PANEL_APPLET (cd->applet),
 
2637
                                       KEY_CUSTOM_FORMAT, custom_format, NULL);
 
2638
}
 
2639
 
 
2640
static void
 
2641
properties_response_cb (GtkWidget *widget,
 
2642
                        int        id,
 
2643
                        ClockData *cd)
 
2644
{
 
2645
        
 
2646
        if (id == GTK_RESPONSE_HELP) {
 
2647
                GError *error = NULL;
 
2648
 
 
2649
                gnome_help_display_desktop_on_screen (
 
2650
                                NULL, "clock", "clock", "clock-settings",
 
2651
                                gtk_widget_get_screen (cd->applet),
 
2652
                                &error);
 
2653
 
 
2654
                if (error) {
 
2655
                        GtkWidget *dialog;
 
2656
                        dialog = gtk_message_dialog_new (GTK_WINDOW (widget),
 
2657
                                                         GTK_DIALOG_DESTROY_WITH_PARENT,
 
2658
                                                         GTK_MESSAGE_ERROR,
 
2659
                                                         GTK_BUTTONS_OK,
 
2660
                                                          _("There was an error displaying help: %s"),
 
2661
                                                         error->message);
 
2662
 
 
2663
                        g_signal_connect (G_OBJECT (dialog), "response",
 
2664
                                          G_CALLBACK (gtk_widget_destroy),
 
2665
                                          NULL);
 
2666
 
 
2667
                        gtk_window_set_icon_name (GTK_WINDOW (dialog),
 
2668
                                                  CLOCK_ICON);
 
2669
                        gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
 
2670
                        gtk_window_set_screen (GTK_WINDOW (dialog),
 
2671
                                               gtk_widget_get_screen (cd->applet));
 
2672
                        gtk_widget_show (dialog);
 
2673
                        g_error_free (error);
 
2674
                }
 
2675
        } else {
 
2676
                gtk_widget_destroy (widget);
 
2677
        }
 
2678
}
 
2679
 
 
2680
static void
 
2681
display_properties_dialog (BonoboUIComponent *uic,
 
2682
                           ClockData         *cd,
 
2683
                           const gchar       *verbname)
 
2684
{
 
2685
        GtkWidget *hbox;
 
2686
        GtkWidget *vbox;
 
2687
        GtkWidget *combo;
 
2688
        GtkWidget *label;
 
2689
 
 
2690
        if (cd->props) {
 
2691
                gtk_window_set_screen (GTK_WINDOW (cd->props),
 
2692
                                       gtk_widget_get_screen (cd->applet));
 
2693
                gtk_window_present (GTK_WINDOW (cd->props));
 
2694
                return;
 
2695
        }
 
2696
 
 
2697
        cd->props = gtk_dialog_new_with_buttons (_("Lunar Preferences"), NULL, 0,
 
2698
                                                 GTK_STOCK_HELP,
 
2699
                                                 GTK_RESPONSE_HELP,
 
2700
                                                 GTK_STOCK_CLOSE,
 
2701
                                                 GTK_RESPONSE_CLOSE,
 
2702
                                                 NULL);
 
2703
 
 
2704
        gtk_window_set_icon_name (GTK_WINDOW (cd->props), CLOCK_ICON);
 
2705
        gtk_dialog_set_has_separator (GTK_DIALOG (cd->props), FALSE);
 
2706
        gtk_dialog_set_default_response (GTK_DIALOG (cd->props), GTK_RESPONSE_CLOSE);
 
2707
        gtk_window_set_resizable (GTK_WINDOW (cd->props), FALSE);
 
2708
        gtk_window_set_screen (GTK_WINDOW (cd->props),
 
2709
                               gtk_widget_get_screen (cd->applet));
 
2710
        gtk_container_set_border_width (GTK_CONTAINER (cd->props), 5);
 
2711
        gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (cd->props)->vbox), 2);
 
2712
                
 
2713
        vbox = gtk_vbox_new (FALSE, 6);
 
2714
        gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
 
2715
        gtk_box_pack_start (GTK_BOX (GTK_DIALOG (cd->props)->vbox), vbox, FALSE, FALSE, 0);
 
2716
        gtk_widget_show (vbox);
 
2717
 
 
2718
        hbox = gtk_hbox_new (FALSE, 12);
 
2719
        gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
 
2720
        gtk_widget_show (hbox);
 
2721
 
 
2722
        label = gtk_label_new_with_mnemonic (_("Clock _type:"));
 
2723
        gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
 
2724
        gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
 
2725
        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
 
2726
        gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
 
2727
        gtk_widget_show (label);
 
2728
 
 
2729
        combo = gtk_combo_box_new_text ();
 
2730
        gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
 
2731
 
 
2732
        if (cd->can_handle_format_12)
 
2733
                gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("12 hour"));
 
2734
        gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("24 hour"));
 
2735
        gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("UNIX time"));
 
2736
        gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Internet time"));
 
2737
 
 
2738
        gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
 
2739
        gtk_widget_show (combo);
 
2740
 
 
2741
        cd->custom_hbox = gtk_hbox_new (FALSE, 12);
 
2742
        gtk_box_pack_start (GTK_BOX (vbox), cd->custom_hbox, TRUE, TRUE, 0);
 
2743
 
 
2744
        cd->custom_label = gtk_label_new_with_mnemonic (_("Custom _format:"));
 
2745
        gtk_label_set_use_markup (GTK_LABEL (cd->custom_label), TRUE);
 
2746
        gtk_label_set_justify (GTK_LABEL (cd->custom_label),
 
2747
                               GTK_JUSTIFY_LEFT);
 
2748
        gtk_misc_set_alignment (GTK_MISC (cd->custom_label), 0, 0.5);
 
2749
        gtk_box_pack_start (GTK_BOX (cd->custom_hbox),
 
2750
                            cd->custom_label,
 
2751
                            FALSE, FALSE, 0);
 
2752
 
 
2753
        cd->custom_entry = gtk_entry_new ();
 
2754
        gtk_box_pack_start (GTK_BOX (cd->custom_hbox), 
 
2755
                            cd->custom_entry,
 
2756
                            FALSE, FALSE, 0);
 
2757
        gtk_entry_set_text (GTK_ENTRY (cd->custom_entry),
 
2758
                            cd->custom_format);
 
2759
        g_signal_connect (cd->custom_entry, "changed",
 
2760
                          G_CALLBACK (set_custom_format_cb),
 
2761
                          cd);
 
2762
 
 
2763
        cd->showseconds_check = gtk_check_button_new_with_mnemonic (_("Show _seconds"));
 
2764
        gtk_box_pack_start (GTK_BOX (vbox), cd->showseconds_check, FALSE, FALSE, 0);
 
2765
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cd->showseconds_check),
 
2766
                                      cd->showseconds);
 
2767
        g_signal_connect (cd->showseconds_check, "toggled",
 
2768
                          G_CALLBACK (set_show_seconds_cb),
 
2769
                          cd);
 
2770
        gtk_widget_show (cd->showseconds_check);
 
2771
 
 
2772
        cd->showdate_check = gtk_check_button_new_with_mnemonic (_("Show _date"));
 
2773
        gtk_box_pack_start (GTK_BOX (vbox), cd->showdate_check, FALSE, FALSE, 0);
 
2774
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cd->showdate_check),
 
2775
                                      cd->showdate);
 
2776
        g_signal_connect (cd->showdate_check, "toggled",
 
2777
                          G_CALLBACK (set_show_date_cb),
 
2778
                          cd);
 
2779
        gtk_widget_show (cd->showdate_check);
 
2780
 
 
2781
        //yetist
 
2782
        cd->showlunardate_check = gtk_check_button_new_with_mnemonic (_("Show _lunar date"));
 
2783
        gtk_box_pack_start (GTK_BOX (vbox), cd->showlunardate_check, FALSE, FALSE, 0);
 
2784
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cd->showlunardate_check),
 
2785
                                      cd->showlunardate);
 
2786
        g_signal_connect (cd->showlunardate_check, "toggled",
 
2787
                          G_CALLBACK (set_show_lunardate_cb),
 
2788
                          cd);
 
2789
        gtk_widget_show (cd->showlunardate_check);
 
2790
 
 
2791
        cd->gmt_time_check = gtk_check_button_new_with_mnemonic (_("Use _UTC"));
 
2792
        gtk_box_pack_start (GTK_BOX (vbox), cd->gmt_time_check, FALSE, FALSE, 0);
 
2793
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cd->gmt_time_check),
 
2794
                                      cd->gmt_time);
 
2795
        g_signal_connect (cd->gmt_time_check, "toggled",
 
2796
                          G_CALLBACK (set_gmt_time_cb),
 
2797
                          cd);  
 
2798
        gtk_widget_show (cd->gmt_time_check);
 
2799
 
 
2800
        g_signal_connect (cd->props, "destroy",
 
2801
                          G_CALLBACK (gtk_widget_destroyed),
 
2802
                          &cd->props);
 
2803
        g_signal_connect (cd->props, "response",
 
2804
                          G_CALLBACK (properties_response_cb),
 
2805
                          cd);
 
2806
 
 
2807
        update_properties_for_format (cd, GTK_COMBO_BOX (combo), cd->format);
 
2808
 
 
2809
        /* valid values begin from 1 */
 
2810
        if (cd->can_handle_format_12)
 
2811
                gtk_combo_box_set_active (GTK_COMBO_BOX (combo),
 
2812
                                          cd->format - 1);
 
2813
        else
 
2814
                gtk_combo_box_set_active (GTK_COMBO_BOX (combo),
 
2815
                                          cd->format - 2);
 
2816
 
 
2817
        g_signal_connect (combo, "changed",
 
2818
                          G_CALLBACK (set_format_cb), cd);
 
2819
 
 
2820
        /* Now set up the sensitivity based on gconf key writability */
 
2821
        setup_writability_sensitivity (cd, combo, label, KEY_FORMAT);
 
2822
        setup_writability_sensitivity (cd, cd->custom_entry, cd->custom_label,
 
2823
                                       KEY_CUSTOM_FORMAT);
 
2824
        setup_writability_sensitivity (cd, cd->showseconds_check, NULL, KEY_SHOW_SECONDS);
 
2825
        setup_writability_sensitivity (cd, cd->showdate_check, NULL, KEY_SHOW_DATE);
 
2826
        setup_writability_sensitivity (cd, cd->showlunardate_check, NULL, KEY_SHOW_LUNARDATE);
 
2827
        setup_writability_sensitivity (cd, cd->gmt_time_check, NULL, KEY_GMT_TIME);
 
2828
 
 
2829
        gtk_widget_show (cd->props);
 
2830
}
 
2831
 
 
2832
static void
 
2833
display_help_dialog (BonoboUIComponent *uic,
 
2834
                     ClockData         *cd,
 
2835
                     const gchar       *verbname)
 
2836
{
 
2837
        GError *error = NULL;
 
2838
 
 
2839
        gnome_help_display_desktop_on_screen (NULL, "clock", "clock", NULL,
 
2840
                                              gtk_widget_get_screen (cd->applet),
 
2841
                                              &error);
 
2842
        if (error) {
 
2843
                GtkWidget *dialog;
 
2844
                dialog = gtk_message_dialog_new (NULL,
 
2845
                                                 GTK_DIALOG_MODAL,
 
2846
                                                 GTK_MESSAGE_ERROR,
 
2847
                                                 GTK_BUTTONS_OK,
 
2848
                                                  _("There was an error displaying help: %s"),
 
2849
                                                 error->message);
 
2850
 
 
2851
                g_signal_connect (G_OBJECT (dialog), "response",
 
2852
                                  G_CALLBACK (gtk_widget_destroy),
 
2853
                                  NULL);
 
2854
 
 
2855
                gtk_window_set_icon_name (GTK_WINDOW (dialog), CLOCK_ICON);
 
2856
                gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
 
2857
                gtk_window_set_screen (GTK_WINDOW (dialog),
 
2858
                                       gtk_widget_get_screen (cd->applet));
 
2859
                gtk_widget_show (dialog);
 
2860
                g_error_free (error);
 
2861
        }
 
2862
}
 
2863
 
 
2864
static void
 
2865
display_about_dialog (BonoboUIComponent *uic,
 
2866
                      ClockData         *cd,
 
2867
                      const gchar       *verbname)
 
2868
{
 
2869
        static const gchar *authors[] =
 
2870
        {
 
2871
                "yetist <yetist@gmail.com>",
 
2872
                "George Lebl <jirka@5z.com>",
 
2873
                "Gediminas Paulauskas <menesis@delfi.lt>",
 
2874
                NULL
 
2875
        };
 
2876
        static const char *documenters[] =
 
2877
        {
 
2878
                "Dan Mueth <d-mueth@uchicago.edu>",
 
2879
                NULL
 
2880
        };
 
2881
 
 
2882
        if (cd->about) {
 
2883
                gtk_window_set_screen (GTK_WINDOW (cd->about),
 
2884
                                       gtk_widget_get_screen (cd->applet));
 
2885
                gtk_window_present (GTK_WINDOW (cd->about));
 
2886
                return;
 
2887
        }
 
2888
 
 
2889
        cd->about = gtk_about_dialog_new ();
 
2890
        g_object_set (cd->about,
 
2891
                      "name",  _("Lunar"),
 
2892
                      "version", VERSION,
 
2893
                      "copyright", "Copyright \xc2\xa9 1998-2004 Free Software Foundation, Inc.",
 
2894
                      "comments", _("The Lunar displays the current time and lunar date"),
 
2895
                      "authors", authors,
 
2896
                      "documenters", documenters,
 
2897
                      "translator-credits", _("translator-credits"),
 
2898
                      "logo-icon-name", CLOCK_ICON,
 
2899
                      NULL);
 
2900
        
 
2901
        gtk_window_set_icon_name (GTK_WINDOW (cd->about), CLOCK_ICON);
 
2902
        gtk_window_set_wmclass (GTK_WINDOW (cd->about), "clock", "Clock");
 
2903
        gtk_window_set_screen (GTK_WINDOW (cd->about),
 
2904
                               gtk_widget_get_screen (cd->applet));
 
2905
 
 
2906
        g_signal_connect (G_OBJECT(cd->about), "destroy",
 
2907
                          (GCallback)gtk_widget_destroyed, &cd->about);
 
2908
        
 
2909
        g_signal_connect (cd->about, "response",
 
2910
                          G_CALLBACK (gtk_widget_destroy),
 
2911
                          NULL);
 
2912
 
 
2913
        gtk_widget_show (cd->about);
 
2914
}
 
2915
 
 
2916
static gboolean
 
2917
clock_factory (PanelApplet *applet,
 
2918
               const char  *iid,
 
2919
               gpointer     data)
 
2920
{
 
2921
        gboolean retval = FALSE;
 
2922
 
 
2923
        if (!strcmp (iid, "OAFIID:GNOME_LunarApplet"))
 
2924
                retval = fill_clock_applet (applet);
 
2925
 
 
2926
        return retval;
 
2927
}
 
2928
 
 
2929
#ifdef CLOCK_INPROCESS
 
2930
PANEL_APPLET_BONOBO_SHLIB_FACTORY ("OAFIID:GNOME_LunarApplet_Factory",
 
2931
                                   PANEL_TYPE_APPLET,
 
2932
                                   "LunarApplet",
 
2933
                                   clock_factory,
 
2934
                                   NULL);
 
2935
#else
 
2936
PANEL_APPLET_BONOBO_FACTORY ("OAFIID:GNOME_LunarApplet_Factory",
 
2937
                             PANEL_TYPE_APPLET,
 
2938
                             "LunarApplet",
 
2939
                             "0",
 
2940
                             clock_factory,
 
2941
                             NULL);
 
2942
#endif