~matttbe/ubuntu/precise/gnome-panel/975299

« back to all changes in this revision

Viewing changes to .pc/14_revert-timedate-change.patch/applets/clock/clock.c

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha
  • Date: 2012-02-08 00:17:11 UTC
  • mfrom: (1.13.15)
  • Revision ID: package-import@ubuntu.com-20120208001711-npwmthl0c6iy3s9a
Tags: 1:3.3.5-0ubuntu1
* New upstream release.
* debian/control.in:
  - Bump minimum glib to 2.31.14
* debian/patches/13_disable_missing_help.patch:
  Updated patch from bugzilla
* debian/patches/14_revert-timedate-change.patch:
  - Revert switch to systemd timedate protocol until ubuntu-system-
    services supports it

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
#include "config.h"
 
33
 
 
34
#include <stdio.h>
 
35
#include <sys/stat.h>
 
36
#include <unistd.h>
 
37
#include <dirent.h>
 
38
#include <string.h>
 
39
#include <time.h>
 
40
#include <sys/time.h>
 
41
#include <math.h>
 
42
#include <locale.h>
 
43
 
 
44
#include <panel-applet.h>
 
45
#include <panel-applet-gconf.h>
 
46
 
 
47
#include <glib/gi18n.h>
 
48
#include <gio/gdesktopappinfo.h>
 
49
 
 
50
#include <gtk/gtk.h>
 
51
#include <gdk/gdkkeysyms.h>
 
52
#include <gdk/gdkx.h>
 
53
#include <gconf/gconf-client.h>
 
54
 
 
55
#include <libgweather/gweather-prefs.h>
 
56
#include <libgweather/gweather-xml.h>
 
57
#include <libgweather/location-entry.h>
 
58
#include <libgweather/timezone-menu.h>
 
59
 
 
60
#ifdef HAVE_LIBECAL
 
61
#include <libedataserverui/e-passwords.h>
 
62
#endif
 
63
 
 
64
#include "clock.h"
 
65
 
 
66
#include "calendar-window.h"
 
67
#include "clock-location.h"
 
68
#include "clock-location-tile.h"
 
69
#include "clock-map.h"
 
70
#include "clock-utils.h"
 
71
#include "system-timezone.h"
 
72
 
 
73
#define INTERNETSECOND (864)
 
74
#define INTERNETBEAT   (86400)
 
75
 
 
76
#define NEVER_SENSITIVE "never_sensitive"
 
77
 
 
78
#define N_GCONF_PREFS 11 /* Keep this in sync with the number of keys below! */
 
79
#define KEY_FORMAT              "format"
 
80
#define KEY_SHOW_SECONDS        "show_seconds"
 
81
#define KEY_SHOW_DATE           "show_date"
 
82
#define KEY_SHOW_WEATHER        "show_weather"
 
83
#define KEY_SHOW_TEMPERATURE    "show_temperature"
 
84
#define KEY_CUSTOM_FORMAT       "custom_format"
 
85
#define KEY_SHOW_WEEK           "show_week_numbers"
 
86
#define KEY_CITIES              "cities"
 
87
#define KEY_TEMPERATURE_UNIT    "temperature_unit"
 
88
#define KEY_SPEED_UNIT          "speed_unit"
 
89
 
 
90
static GConfEnumStringPair format_type_enum_map [] = {
 
91
        { CLOCK_FORMAT_12,       "12-hour"  },
 
92
        { CLOCK_FORMAT_24,       "24-hour"  },
 
93
        { CLOCK_FORMAT_UNIX,     "unix"     },
 
94
        { CLOCK_FORMAT_INTERNET, "internet" },
 
95
        { CLOCK_FORMAT_CUSTOM,   "custom"   },
 
96
        { 0, NULL }
 
97
};
 
98
 
 
99
enum {
 
100
        COL_CITY_NAME = 0,
 
101
        COL_CITY_TZ,
 
102
        COL_CITY_LOC,
 
103
        COL_CITY_LAST
 
104
};
 
105
 
 
106
typedef struct _ClockData ClockData;
 
107
 
 
108
struct _ClockData {
 
109
        /* widgets */
 
110
        GtkWidget *applet;
 
111
 
 
112
        GtkWidget *panel_button;        /* main toggle button for the whole clock */
 
113
 
 
114
        GtkWidget *main_obox;           /* orientable box inside panel_button */
 
115
        GtkWidget *weather_obox;        /* orientable box for the weather widgets */
 
116
 
 
117
        GtkWidget *clockw;              /* main label for the date/time display */
 
118
 
 
119
        GtkWidget *panel_weather_icon;
 
120
        GtkWidget *panel_temperature_label;
 
121
 
 
122
        GtkWidget *props;
 
123
        GtkWidget *calendar_popup;
 
124
 
 
125
        GtkWidget *clock_vbox;
 
126
        GtkSizeGroup *clock_group;
 
127
 
 
128
        GtkBuilder *builder;
 
129
 
 
130
        /* Preferences dialog */
 
131
        GtkWidget *prefs_window;
 
132
        GtkTreeView *prefs_locations;
 
133
 
 
134
        GtkWidget *prefs_location_add_button;
 
135
        GtkWidget *prefs_location_edit_button;
 
136
        GtkWidget *prefs_location_remove_button;
 
137
 
 
138
        GWeatherLocationEntry *location_entry;
 
139
        GWeatherTimezoneMenu *zone_combo;
 
140
 
 
141
        GtkWidget *time_settings_button;
 
142
        GAppInfo *datetime_appinfo;
 
143
 
 
144
        GtkListStore *cities_store;
 
145
        GtkWidget *cities_section;
 
146
        GtkWidget *map_section;
 
147
        GtkWidget *map_widget;
 
148
 
 
149
        /* preferences */
 
150
        ClockFormat  format;
 
151
        char        *custom_format;
 
152
        gboolean     showseconds;
 
153
        gboolean     showdate;
 
154
        gboolean     showweek;
 
155
        gboolean     show_weather;
 
156
        gboolean     show_temperature;
 
157
 
 
158
        gboolean     use_temperature_default;
 
159
        gboolean     use_speed_default;
 
160
        TempUnit     temperature_unit;
 
161
        SpeedUnit    speed_unit;
 
162
 
 
163
        /* Locations */
 
164
        GList *locations;
 
165
        GList *location_tiles;
 
166
 
 
167
        /* runtime data */
 
168
        time_t             current_time;
 
169
        char              *timeformat;
 
170
        guint              timeout;
 
171
        PanelAppletOrient  orient;
 
172
        int                size;
 
173
        GtkAllocation      old_allocation;
 
174
 
 
175
        SystemTimezone *systz;
 
176
 
 
177
        int fixed_width;
 
178
        int fixed_height;
 
179
 
 
180
        GtkWidget *showseconds_check;
 
181
        GtkWidget *showdate_check;
 
182
        GtkWidget *custom_hbox;
 
183
        GtkWidget *custom_label;
 
184
        GtkWidget *custom_entry;
 
185
        gboolean   custom_format_shown;
 
186
 
 
187
        gboolean   can_handle_format_12;
 
188
 
 
189
        guint listeners [N_GCONF_PREFS];
 
190
};
 
191
 
 
192
/* Used to count the number of clock instances. It's there to know when we
 
193
 * should free resources that are shared. */
 
194
static int clock_numbers = 0;
 
195
 
 
196
static void  update_clock (ClockData * cd);
 
197
static void  update_tooltip (ClockData * cd);
 
198
static void  update_panel_weather (ClockData *cd);
 
199
static int   clock_timeout_callback (gpointer data);
 
200
static float get_itime    (time_t current_time);
 
201
 
 
202
static void set_atk_name_description (GtkWidget *widget,
 
203
                                      const char *name,
 
204
                                      const char *desc);
 
205
static void verb_display_properties_dialog (GtkAction  *action,
 
206
                                            ClockData  *cd);
 
207
 
 
208
static void display_properties_dialog (ClockData  *cd,
 
209
                                       gboolean    start_in_locations_page);
 
210
static void position_calendar_popup   (ClockData  *cd);
 
211
static void update_orient (ClockData *cd);
 
212
static void applet_change_orient (PanelApplet       *applet,
 
213
                                  PanelAppletOrient  orient,
 
214
                                  ClockData         *cd);
 
215
 
 
216
static void edit_hide (GtkWidget *unused, ClockData *cd);
 
217
static gboolean edit_delete (GtkWidget *unused, GdkEvent *event, ClockData *cd);
 
218
static void save_cities_store (ClockData *cd);
 
219
 
 
220
/* ClockBox, an instantiable GtkBox */
 
221
 
 
222
typedef GtkBox      ClockBox;
 
223
typedef GtkBoxClass ClockBoxClass;
 
224
 
 
225
static GType clock_box_get_type (void);
 
226
 
 
227
G_DEFINE_TYPE (ClockBox, clock_box, GTK_TYPE_BOX)
 
228
 
 
229
static void
 
230
clock_box_init (ClockBox *box)
 
231
{
 
232
}
 
233
 
 
234
static void
 
235
clock_box_class_init (ClockBoxClass *klass)
 
236
{
 
237
}
 
238
 
 
239
/* Clock */
 
240
 
 
241
static inline GtkWidget *
 
242
_clock_get_widget (ClockData  *cd,
 
243
                   const char *name)
 
244
{
 
245
        return GTK_WIDGET (gtk_builder_get_object (cd->builder, name));
 
246
}
 
247
 
 
248
static void
 
249
unfix_size (ClockData *cd)
 
250
{
 
251
        cd->fixed_width = -1;
 
252
        cd->fixed_height = -1;
 
253
        gtk_widget_queue_resize (cd->panel_button);
 
254
}
 
255
 
 
256
static int
 
257
calculate_minimum_width (GtkWidget   *widget,
 
258
                         const gchar *text)
 
259
{
 
260
        PangoContext *pango_context;
 
261
        PangoLayout  *layout;
 
262
        int           width, height;
 
263
        int           focus_width = 0;
 
264
        int           focus_pad = 0;
 
265
        GtkStyleContext *style_context;
 
266
        GtkStateFlags    state;
 
267
        GtkBorder        padding;
 
268
 
 
269
        pango_context = gtk_widget_get_pango_context (widget);
 
270
 
 
271
        layout = pango_layout_new (pango_context);
 
272
        pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT);
 
273
        pango_layout_set_text (layout, text, -1);
 
274
        pango_layout_get_pixel_size (layout, &width, &height);
 
275
        g_object_unref (G_OBJECT (layout));
 
276
        layout = NULL;
 
277
 
 
278
        state = gtk_widget_get_state_flags (widget);
 
279
        style_context = gtk_widget_get_style_context (widget);
 
280
        gtk_style_context_get_padding (style_context, state, &padding);
 
281
        gtk_style_context_get_style (style_context,
 
282
                                     "focus-line-width", &focus_width,
 
283
                                     "focus-padding", &focus_pad,
 
284
                                     NULL);
 
285
 
 
286
        width += 2 * (focus_width + focus_pad) + padding.left + padding.right;
 
287
 
 
288
        return width;
 
289
}
 
290
 
 
291
static void
 
292
clock_set_timeout (ClockData *cd,
 
293
                   time_t     now)
 
294
{
 
295
        int timeouttime;
 
296
 
 
297
        if (cd->format == CLOCK_FORMAT_INTERNET) {
 
298
                int itime_ms;
 
299
 
 
300
                itime_ms = ((unsigned int) (get_itime (now) * 1000));
 
301
 
 
302
                if (!cd->showseconds)
 
303
                        timeouttime = (999 - itime_ms % 1000) * 86.4 + 1;
 
304
                else {
 
305
                        struct timeval tv;
 
306
                        gettimeofday (&tv, NULL);
 
307
                        itime_ms += (tv.tv_usec * 86.4) / 1000;
 
308
                        timeouttime = ((999 - itime_ms % 1000) * 86.4) / 100 + 1;
 
309
                }
 
310
        } else {
 
311
                struct timeval tv;
 
312
                struct tm *tm;
 
313
 
 
314
                gettimeofday (&tv, NULL);
 
315
                /* We can't expect the timer resolution to be < 10ms, so add
 
316
                 * 15ms to make sure we're fine; see
 
317
                 * https://bugzilla.gnome.org/show_bug.cgi?id=585668 */
 
318
                timeouttime = (G_USEC_PER_SEC - tv.tv_usec)/1000+15;
 
319
 
 
320
                /* timeout of one minute if we don't care about the seconds */
 
321
                if (cd->format != CLOCK_FORMAT_UNIX &&
 
322
                    !cd->showseconds) {
 
323
                        /* we use localtime() to handle leap seconds, see
 
324
                         * https://bugzilla.gnome.org/show_bug.cgi?id=604317 */
 
325
                        tm = localtime (&now);
 
326
                        if (tm->tm_sec < 60)
 
327
                                timeouttime += 1000 * (59 - tm->tm_sec);
 
328
                }
 
329
        }
 
330
 
 
331
        cd->timeout = g_timeout_add (timeouttime,
 
332
                                     clock_timeout_callback,
 
333
                                     cd);
 
334
}
 
335
 
 
336
static int
 
337
clock_timeout_callback (gpointer data)
 
338
{
 
339
        ClockData *cd = data;
 
340
        time_t new_time;
 
341
 
 
342
        time (&new_time);
 
343
 
 
344
        if (!cd->showseconds && 
 
345
            cd->format != CLOCK_FORMAT_UNIX &&
 
346
            cd->format != CLOCK_FORMAT_CUSTOM) {
 
347
                if (cd->format == CLOCK_FORMAT_INTERNET &&
 
348
                    (unsigned int)get_itime (new_time) !=
 
349
                    (unsigned int)get_itime (cd->current_time)) {
 
350
                        update_clock (cd);
 
351
                } else if ((cd->format == CLOCK_FORMAT_12 ||
 
352
                            cd->format == CLOCK_FORMAT_24) &&
 
353
                           new_time / 60 != cd->current_time / 60) {
 
354
                        update_clock (cd);
 
355
                }
 
356
        } else {
 
357
                update_clock (cd);
 
358
        }
 
359
 
 
360
        clock_set_timeout (cd, new_time);
 
361
 
 
362
        return FALSE;
 
363
}
 
364
 
 
365
static float
 
366
get_itime (time_t current_time)
 
367
{
 
368
        struct tm *tm;
 
369
        float itime;
 
370
        time_t bmt;
 
371
 
 
372
        /* BMT (Biel Mean Time) is GMT+1 */
 
373
        bmt = current_time + 3600;
 
374
        tm = gmtime (&bmt);
 
375
        itime = (tm->tm_hour*3600.0 + tm->tm_min*60.0 + tm->tm_sec)/86.4;
 
376
 
 
377
        return itime;
 
378
}
 
379
 
 
380
/* adapted from panel-toplevel.c */
 
381
static int
 
382
calculate_minimum_height (GtkWidget        *widget,
 
383
                          PanelAppletOrient orientation)
 
384
{
 
385
        GtkStateFlags     state;
 
386
        GtkStyleContext  *style_context;
 
387
        const PangoFontDescription *font_desc;
 
388
        PangoContext     *pango_context;
 
389
        PangoFontMetrics *metrics;
 
390
        GtkBorder         padding;
 
391
        int               focus_width = 0;
 
392
        int               focus_pad = 0;
 
393
        int               ascent;
 
394
        int               descent;
 
395
        int               thickness;
 
396
 
 
397
        state = gtk_widget_get_state_flags (widget);
 
398
        style_context = gtk_widget_get_style_context (widget);
 
399
        font_desc = gtk_style_context_get_font (style_context, state);
 
400
 
 
401
        pango_context = gtk_widget_get_pango_context (widget);
 
402
        metrics = pango_context_get_metrics (pango_context,
 
403
                                             font_desc,
 
404
                                             pango_context_get_language (pango_context));
 
405
 
 
406
        ascent  = pango_font_metrics_get_ascent  (metrics);
 
407
        descent = pango_font_metrics_get_descent (metrics);
 
408
 
 
409
        pango_font_metrics_unref (metrics);
 
410
 
 
411
        gtk_style_context_get_padding (style_context, state, &padding);
 
412
        gtk_style_context_get_style (style_context,
 
413
                                     "focus-line-width", &focus_width,
 
414
                                     "focus-padding", &focus_pad,
 
415
                                     NULL);
 
416
 
 
417
        if (orientation == PANEL_APPLET_ORIENT_UP
 
418
            || orientation == PANEL_APPLET_ORIENT_DOWN) {
 
419
                thickness = padding.top + padding.bottom;
 
420
        } else {
 
421
                thickness = padding.left + padding.right;
 
422
        }
 
423
 
 
424
        return PANGO_PIXELS (ascent + descent) + 2 * (focus_width + focus_pad) + thickness;
 
425
}
 
426
 
 
427
static gboolean
 
428
use_two_line_format (ClockData *cd)
 
429
{
 
430
        if (cd->size >= 2 * calculate_minimum_height (cd->panel_button, cd->orient))
 
431
                return TRUE;
 
432
 
 
433
        return FALSE;
 
434
}
 
435
 
 
436
static char *
 
437
get_updated_timeformat (ClockData *cd)
 
438
{
 
439
 /* Show date in another line if panel is vertical, or
 
440
  * horizontal but large enough to hold two lines of text
 
441
  */
 
442
        char       *result;
 
443
        const char *time_format;
 
444
        const char *date_format;
 
445
        char       *clock_format;
 
446
 
 
447
        if (cd->format == CLOCK_FORMAT_12)
 
448
                /* Translators: This is a strftime format string.
 
449
                 * It is used to display the time in 12-hours format (eg, like
 
450
                 * in the US: 8:10 am). The %p expands to am/pm. */
 
451
                time_format = cd->showseconds ? _("%l:%M:%S %p") : _("%l:%M %p");
 
452
        else
 
453
                /* Translators: This is a strftime format string.
 
454
                 * It is used to display the time in 24-hours format (eg, like
 
455
                 * in France: 20:10). */
 
456
                time_format = cd->showseconds ? _("%H:%M:%S") : _("%H:%M");
 
457
 
 
458
        if (!cd->showdate)
 
459
                clock_format = g_strdup (time_format);
 
460
 
 
461
        else {
 
462
                /* Translators: This is a strftime format string.
 
463
                 * It is used to display the date. Replace %e with %d if, when
 
464
                 * the day of the month as a decimal number is a single digit,
 
465
                 * it should begin with a 0 in your locale (e.g. "May 01"
 
466
                 * instead of "May  1"). */
 
467
                date_format = _("%a %b %e");
 
468
 
 
469
                if (use_two_line_format (cd))
 
470
                        /* translators: reverse the order of these arguments
 
471
                         *              if the time should come before the
 
472
                         *              date on a clock in your locale.
 
473
                         */
 
474
                        clock_format = g_strdup_printf (_("%1$s\n%2$s"),
 
475
                                                        date_format,
 
476
                                                        time_format);
 
477
                else
 
478
                        /* translators: reverse the order of these arguments
 
479
                         *              if the time should come before the
 
480
                         *              date on a clock in your locale.
 
481
                         */
 
482
                        clock_format = g_strdup_printf (_("%1$s, %2$s"),
 
483
                                                        date_format,
 
484
                                                        time_format);
 
485
        }
 
486
 
 
487
        result = g_locale_from_utf8 (clock_format, -1, NULL, NULL, NULL);
 
488
        g_free (clock_format);
 
489
 
 
490
        /* let's be paranoid */
 
491
        if (!result)
 
492
                result = g_strdup ("???");
 
493
 
 
494
        return result;
 
495
}
 
496
 
 
497
static void
 
498
update_timeformat (ClockData *cd)
 
499
{
 
500
        g_free (cd->timeformat);
 
501
        cd->timeformat = get_updated_timeformat (cd);
 
502
}
 
503
 
 
504
/* sets accessible name and description for the widget */
 
505
static void
 
506
set_atk_name_description (GtkWidget  *widget,
 
507
                          const char *name,
 
508
                          const char *desc)
 
509
{
 
510
        AtkObject *obj;
 
511
        obj = gtk_widget_get_accessible (widget);
 
512
 
 
513
        /* return if gail is not loaded */
 
514
        if (!GTK_IS_ACCESSIBLE (obj))
 
515
                return;
 
516
 
 
517
        if (desc != NULL)
 
518
                atk_object_set_description (obj, desc);
 
519
        if (name != NULL)
 
520
                atk_object_set_name (obj, name);
 
521
}
 
522
 
 
523
static void
 
524
update_location_tiles (ClockData *cd)
 
525
{
 
526
        GList *l;
 
527
 
 
528
        for (l = cd->location_tiles; l; l = l->next) {
 
529
                ClockLocationTile *tile;
 
530
 
 
531
                tile = CLOCK_LOCATION_TILE (l->data);
 
532
                clock_location_tile_refresh (tile, FALSE);
 
533
        }
 
534
}
 
535
 
 
536
static char *
 
537
format_time (ClockData *cd)
 
538
{
 
539
        struct tm *tm;
 
540
        char hour[256];
 
541
        char *utf8;
 
542
 
 
543
        utf8 = NULL;
 
544
 
 
545
        tm = localtime (&cd->current_time);
 
546
 
 
547
        if (cd->format == CLOCK_FORMAT_UNIX) {
 
548
                if (use_two_line_format (cd)) {
 
549
                        utf8 = g_strdup_printf ("%lu\n%05lu",
 
550
                                                (unsigned long)(cd->current_time / 100000L),
 
551
                                                (unsigned long)(cd->current_time % 100000L));
 
552
                } else {
 
553
                        utf8 = g_strdup_printf ("%lu",
 
554
                                                (unsigned long)cd->current_time);
 
555
                }
 
556
        } else if (cd->format == CLOCK_FORMAT_INTERNET) {
 
557
                float itime = get_itime (cd->current_time);
 
558
                if (cd->showseconds)
 
559
                        utf8 = g_strdup_printf ("@%3.2f", itime);
 
560
                else
 
561
                        utf8 = g_strdup_printf ("@%3d", (unsigned int) itime);
 
562
        } else if (cd->format == CLOCK_FORMAT_CUSTOM) {
 
563
                char *timeformat = g_locale_from_utf8 (cd->custom_format, -1,
 
564
                                                       NULL, NULL, NULL);
 
565
                if (!timeformat)
 
566
                        strcpy (hour, "???");
 
567
                else if (strftime (hour, sizeof (hour), timeformat, tm) <= 0)
 
568
                        strcpy (hour, "???");
 
569
                g_free (timeformat);
 
570
 
 
571
                utf8 = g_locale_to_utf8 (hour, -1, NULL, NULL, NULL);
 
572
        } else {
 
573
                if (strftime (hour, sizeof (hour), cd->timeformat, tm) <= 0)
 
574
                        strcpy (hour, "???");
 
575
 
 
576
                utf8 = g_locale_to_utf8 (hour, -1, NULL, NULL, NULL);
 
577
        }
 
578
 
 
579
        if (!utf8)
 
580
                utf8 = g_strdup (hour);
 
581
 
 
582
        return utf8;
 
583
}
 
584
 
 
585
static gchar *
 
586
format_time_24 (ClockData *cd)
 
587
{
 
588
        struct tm *tm;
 
589
        gchar buf[128];
 
590
 
 
591
        tm = localtime (&cd->current_time);
 
592
        strftime (buf, sizeof (buf) - 1, "%k:%M:%S", tm);
 
593
        return g_locale_to_utf8 (buf, -1, NULL, NULL, NULL);
 
594
}
 
595
 
 
596
static void
 
597
update_clock (ClockData * cd)
 
598
{
 
599
        gboolean use_markup;
 
600
        char *utf8;
 
601
 
 
602
        use_markup = FALSE;
 
603
 
 
604
        time (&cd->current_time);
 
605
        utf8 = format_time (cd);
 
606
 
 
607
        use_markup = FALSE;
 
608
        if (pango_parse_markup (utf8, -1, 0, NULL, NULL, NULL, NULL))
 
609
                use_markup = TRUE;
 
610
 
 
611
        if (use_markup)
 
612
                gtk_label_set_markup (GTK_LABEL (cd->clockw), utf8);
 
613
        else
 
614
                gtk_label_set_text (GTK_LABEL (cd->clockw), utf8);
 
615
 
 
616
        g_free (utf8);
 
617
 
 
618
        update_orient (cd);
 
619
        gtk_widget_queue_resize (cd->panel_button);
 
620
 
 
621
        update_tooltip (cd);
 
622
        update_location_tiles (cd);
 
623
 
 
624
        if (cd->map_widget && cd->calendar_popup && gtk_widget_get_visible (cd->calendar_popup))
 
625
                clock_map_update_time (CLOCK_MAP (cd->map_widget));
 
626
}
 
627
 
 
628
static void
 
629
update_tooltip (ClockData * cd)
 
630
{
 
631
        if (!cd->showdate) {
 
632
                struct tm *tm;
 
633
                char date[256];
 
634
                char *utf8, *loc;
 
635
                char *zone;
 
636
                time_t now_t;
 
637
                struct tm now;
 
638
                char *tip;
 
639
 
 
640
                tm = localtime (&cd->current_time);
 
641
 
 
642
                utf8 = NULL;
 
643
 
 
644
                /* Show date in tooltip. */
 
645
                /* Translators: This is a strftime format string.
 
646
                 * It is used to display a date. Please leave "%%s" as it is:
 
647
                 * it will be used to insert the timezone name later. */
 
648
                loc = g_locale_from_utf8 (_("%A %B %d (%%s)"), -1, NULL, NULL, NULL);
 
649
                if (!loc)
 
650
                        strcpy (date, "???");
 
651
                else if (strftime (date, sizeof (date), loc, tm) <= 0)
 
652
                        strcpy (date, "???");
 
653
                g_free (loc);
 
654
 
 
655
                utf8 = g_locale_to_utf8 (date, -1, NULL, NULL, NULL);
 
656
 
 
657
                /* Add the timezone name */
 
658
 
 
659
                tzset ();
 
660
                time (&now_t);
 
661
                localtime_r (&now_t, &now);
 
662
 
 
663
                if (now.tm_isdst > 0) {
 
664
                        zone = tzname[1];
 
665
                } else {
 
666
                        zone = tzname[0];
 
667
                }
 
668
 
 
669
                tip = g_strdup_printf (utf8, zone);
 
670
 
 
671
                gtk_widget_set_tooltip_text (cd->panel_button, tip);
 
672
                g_free (utf8);
 
673
                g_free (tip);
 
674
        } else {
 
675
#ifdef HAVE_LIBECAL
 
676
                if (cd->calendar_popup)
 
677
                        gtk_widget_set_tooltip_text (cd->panel_button,
 
678
                                                     _("Click to hide your appointments and tasks"));
 
679
                else
 
680
                        gtk_widget_set_tooltip_text (cd->panel_button,
 
681
                                                     _("Click to view your appointments and tasks"));
 
682
#else
 
683
                if (cd->calendar_popup)
 
684
                        gtk_widget_set_tooltip_text (cd->panel_button,
 
685
                                                     _("Click to hide month calendar"));
 
686
                else
 
687
                        gtk_widget_set_tooltip_text (cd->panel_button,
 
688
                                                     _("Click to view month calendar"));
 
689
#endif
 
690
        }
 
691
}
 
692
 
 
693
static void
 
694
refresh_clock (ClockData *cd)
 
695
{
 
696
        unfix_size (cd);
 
697
        update_clock (cd);
 
698
}
 
699
 
 
700
static void
 
701
refresh_clock_timeout(ClockData *cd)
 
702
{
 
703
        unfix_size (cd);
 
704
 
 
705
        update_timeformat (cd);
 
706
 
 
707
        if (cd->timeout)
 
708
                g_source_remove (cd->timeout);
 
709
 
 
710
        update_clock (cd);
 
711
 
 
712
        clock_set_timeout (cd, cd->current_time);
 
713
}
 
714
 
 
715
/**
 
716
 * This is like refresh_clock_timeout(), except that we only care about whether
 
717
 * the time actually changed. We don't care about the format.
 
718
 */
 
719
static void
 
720
refresh_click_timeout_time_only (ClockData *cd)
 
721
{
 
722
        if (cd->timeout)
 
723
                g_source_remove (cd->timeout);
 
724
        clock_timeout_callback (cd);
 
725
}
 
726
 
 
727
static void
 
728
free_locations (ClockData *cd)
 
729
{
 
730
        GList *l;
 
731
 
 
732
        for (l = cd->locations; l; l = l->next)
 
733
                g_object_unref (l->data);
 
734
 
 
735
        g_list_free (cd->locations);
 
736
        cd->locations = NULL;
 
737
}
 
738
 
 
739
static void
 
740
destroy_clock (GtkWidget * widget, ClockData *cd)
 
741
{
 
742
        GConfClient *client;
 
743
        int          i;
 
744
 
 
745
        client = gconf_client_get_default ();
 
746
 
 
747
        for (i = 0; i < N_GCONF_PREFS; i++)
 
748
                gconf_client_notify_remove (
 
749
                                client, cd->listeners [i]);
 
750
 
 
751
        g_object_unref (G_OBJECT (client));
 
752
 
 
753
        if (cd->timeout)
 
754
                g_source_remove (cd->timeout);
 
755
        cd->timeout = 0;
 
756
 
 
757
        if (cd->props)
 
758
                gtk_widget_destroy (cd->props);
 
759
        cd->props = NULL;
 
760
 
 
761
        if (cd->calendar_popup)
 
762
                gtk_widget_destroy (cd->calendar_popup);
 
763
        cd->calendar_popup = NULL;
 
764
 
 
765
        if (cd->datetime_appinfo)
 
766
                g_object_unref (cd->datetime_appinfo);
 
767
        cd->datetime_appinfo = NULL;
 
768
 
 
769
        g_free (cd->timeformat);
 
770
        g_free (cd->custom_format);
 
771
 
 
772
        free_locations (cd);
 
773
 
 
774
        g_list_free (cd->location_tiles);
 
775
        cd->location_tiles = NULL;
 
776
 
 
777
        if (cd->systz) {
 
778
                g_object_unref (cd->systz);
 
779
                cd->systz = NULL;
 
780
        }
 
781
 
 
782
        if (cd->cities_store) {
 
783
                g_object_unref (cd->cities_store);
 
784
                cd->cities_store = NULL;
 
785
        }
 
786
 
 
787
        if (cd->builder) {
 
788
                g_object_unref (cd->builder);
 
789
                cd->builder = NULL;
 
790
        }
 
791
 
 
792
        g_free (cd);
 
793
 
 
794
#ifdef HAVE_LIBECAL
 
795
        if (clock_numbers > 0) {
 
796
                e_passwords_shutdown ();
 
797
                clock_numbers--;
 
798
        }
 
799
#endif
 
800
}
 
801
 
 
802
static gboolean
 
803
close_on_escape (GtkWidget       *widget,
 
804
                 GdkEventKey     *event,
 
805
                 GtkToggleButton *toggle_button)
 
806
{
 
807
        if (event->keyval == GDK_KEY_Escape) {
 
808
                gtk_toggle_button_set_active (toggle_button, FALSE);
 
809
                return TRUE;
 
810
        }
 
811
 
 
812
        return FALSE;
 
813
}
 
814
 
 
815
static gboolean
 
816
delete_event (GtkWidget       *widget,
 
817
              GdkEvent        *event,
 
818
              GtkToggleButton *toggle_button)
 
819
{
 
820
        gtk_toggle_button_set_active (toggle_button, FALSE);
 
821
        return TRUE;
 
822
}
 
823
 
 
824
static void
 
825
edit_locations_cb (CalendarWindow *calwin, gpointer data)
 
826
{
 
827
        ClockData *cd;
 
828
 
 
829
        cd = data;
 
830
 
 
831
        display_properties_dialog (cd, TRUE);
 
832
}
 
833
 
 
834
static GtkWidget *
 
835
create_calendar (ClockData *cd)
 
836
{
 
837
        GtkWidget *window;
 
838
        char      *prefs_dir;
 
839
 
 
840
        prefs_dir = panel_applet_get_preferences_key (PANEL_APPLET (cd->applet));
 
841
        window = calendar_window_new (&cd->current_time,
 
842
                                      prefs_dir,
 
843
                                      cd->orient == PANEL_APPLET_ORIENT_UP);
 
844
        g_free (prefs_dir);
 
845
 
 
846
        g_object_bind_property (cd->applet, "locked-down",
 
847
                                window, "locked-down",
 
848
                                G_BINDING_DEFAULT|G_BINDING_SYNC_CREATE);
 
849
 
 
850
        calendar_window_set_show_weeks (CALENDAR_WINDOW (window),
 
851
                                        cd->showweek);
 
852
        calendar_window_set_time_format (CALENDAR_WINDOW (window),
 
853
                                         cd->format);
 
854
 
 
855
        gtk_window_set_screen (GTK_WINDOW (window),
 
856
                               gtk_widget_get_screen (cd->applet));
 
857
 
 
858
        g_signal_connect (window, "edit-locations",
 
859
                          G_CALLBACK (edit_locations_cb), cd);
 
860
 
 
861
        g_signal_connect (window, "delete_event",
 
862
                          G_CALLBACK (delete_event), cd->panel_button);
 
863
        g_signal_connect (window, "key_press_event",
 
864
                          G_CALLBACK (close_on_escape), cd->panel_button);
 
865
 
 
866
        return window;
 
867
}
 
868
 
 
869
static void
 
870
position_calendar_popup (ClockData *cd)
 
871
{
 
872
        GtkRequisition  req;
 
873
        GtkAllocation   allocation;
 
874
        GdkScreen      *screen;
 
875
        GdkRectangle    monitor;
 
876
        GdkGravity      gravity = GDK_GRAVITY_NORTH_WEST;
 
877
        int             button_w, button_h;
 
878
        int             x, y;
 
879
        int             w, h;
 
880
        int             i, n;
 
881
        gboolean        found_monitor = FALSE;
 
882
 
 
883
        /* Get root origin of the toggle button, and position above that. */
 
884
        gdk_window_get_origin (gtk_widget_get_window (cd->panel_button),
 
885
                               &x, &y);
 
886
 
 
887
        gtk_window_get_size (GTK_WINDOW (cd->calendar_popup), &w, &h);
 
888
        gtk_widget_get_preferred_size (cd->calendar_popup, &req, NULL);
 
889
        w = req.width;
 
890
        h = req.height;
 
891
 
 
892
        gtk_widget_get_allocation (cd->panel_button, &allocation);
 
893
        button_w = allocation.width;
 
894
        button_h = allocation.height;
 
895
 
 
896
        screen = gtk_window_get_screen (GTK_WINDOW (cd->calendar_popup));
 
897
 
 
898
        n = gdk_screen_get_n_monitors (screen);
 
899
        for (i = 0; i < n; i++) {
 
900
                gdk_screen_get_monitor_geometry (screen, i, &monitor);
 
901
                if (x >= monitor.x && x <= monitor.x + monitor.width &&
 
902
                    y >= monitor.y && y <= monitor.y + monitor.height) {
 
903
                        found_monitor = TRUE;
 
904
                        break;
 
905
                }
 
906
        }
 
907
 
 
908
        if (!found_monitor) {
 
909
                /* eek, we should be on one of those xinerama
 
910
                   monitors */
 
911
                monitor.x = 0;
 
912
                monitor.y = 0;
 
913
                monitor.width = gdk_screen_get_width (screen);
 
914
                monitor.height = gdk_screen_get_height (screen);
 
915
        }
 
916
 
 
917
        /* Based on panel orientation, position the popup.
 
918
         * Ignore window gravity since the window is undecorated.
 
919
         * The orientations are all named backward from what
 
920
         * I expected.
 
921
         */
 
922
        switch (cd->orient) {
 
923
        case PANEL_APPLET_ORIENT_RIGHT:
 
924
                x += button_w;
 
925
                if ((y + h) > monitor.y + monitor.height)
 
926
                        y -= (y + h) - (monitor.y + monitor.height);
 
927
 
 
928
                if ((y + h) > (monitor.height / 2))
 
929
                        gravity = GDK_GRAVITY_SOUTH_WEST;
 
930
                else
 
931
                        gravity = GDK_GRAVITY_NORTH_WEST;
 
932
 
 
933
                break;
 
934
        case PANEL_APPLET_ORIENT_LEFT:
 
935
                x -= w;
 
936
                if ((y + h) > monitor.y + monitor.height)
 
937
                        y -= (y + h) - (monitor.y + monitor.height);
 
938
 
 
939
                if ((y + h) > (monitor.height / 2))
 
940
                        gravity = GDK_GRAVITY_SOUTH_EAST;
 
941
                else
 
942
                        gravity = GDK_GRAVITY_NORTH_EAST;
 
943
 
 
944
                break;
 
945
        case PANEL_APPLET_ORIENT_DOWN:
 
946
                y += button_h;
 
947
                if ((x + w) > monitor.x + monitor.width)
 
948
                        x -= (x + w) - (monitor.x + monitor.width);
 
949
 
 
950
                gravity = GDK_GRAVITY_NORTH_WEST;
 
951
 
 
952
                break;
 
953
        case PANEL_APPLET_ORIENT_UP:
 
954
                y -= h;
 
955
                if ((x + w) > monitor.x + monitor.width)
 
956
                        x -= (x + w) - (monitor.x + monitor.width);
 
957
 
 
958
                gravity = GDK_GRAVITY_SOUTH_WEST;
 
959
 
 
960
                break;
 
961
        }
 
962
 
 
963
        gtk_window_move (GTK_WINDOW (cd->calendar_popup), x, y);
 
964
        gtk_window_set_gravity (GTK_WINDOW (cd->calendar_popup), gravity);
 
965
}
 
966
 
 
967
static void
 
968
add_to_group (GtkWidget *child, gpointer data)
 
969
{
 
970
        GtkSizeGroup *group = data;
 
971
 
 
972
        gtk_size_group_add_widget (group, child);
 
973
}
 
974
 
 
975
static void
 
976
create_clock_window (ClockData *cd)
 
977
{
 
978
        GtkWidget *locations_box;
 
979
 
 
980
        locations_box = calendar_window_get_locations_box (CALENDAR_WINDOW (cd->calendar_popup));
 
981
        gtk_widget_show (locations_box);
 
982
 
 
983
        cd->clock_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
 
984
        gtk_container_add (GTK_CONTAINER (locations_box), cd->clock_vbox);
 
985
 
 
986
        cd->clock_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
 
987
        gtk_size_group_set_ignore_hidden (cd->clock_group, FALSE);
 
988
 
 
989
        gtk_container_foreach (GTK_CONTAINER (locations_box),
 
990
                               (GtkCallback) add_to_group,
 
991
                               cd->clock_group);
 
992
}
 
993
 
 
994
static gint
 
995
sort_locations_by_name (gconstpointer a, gconstpointer b)
 
996
{
 
997
        ClockLocation *loc_a = (ClockLocation *) a;
 
998
        ClockLocation *loc_b = (ClockLocation *) b;
 
999
 
 
1000
        const char *name_a = clock_location_get_display_name (loc_a);
 
1001
        const char *name_b = clock_location_get_display_name (loc_b);
 
1002
 
 
1003
        return strcmp (name_a, name_b);
 
1004
}
 
1005
 
 
1006
static void
 
1007
create_cities_store (ClockData *cd)
 
1008
{
 
1009
        GtkTreeIter iter;
 
1010
        GList *cities = cd->locations;
 
1011
        GList *list = NULL;
 
1012
 
 
1013
        if (cd->cities_store) {
 
1014
                g_object_unref (G_OBJECT (cd->cities_store));
 
1015
                cd->cities_store = NULL;
 
1016
        }
 
1017
 
 
1018
        /* City name, Timezone name, Coordinates in lat/long */
 
1019
        cd->cities_store = g_object_ref (gtk_list_store_new (COL_CITY_LAST,
 
1020
                                                             G_TYPE_STRING,             /* COL_CITY_NAME */
 
1021
                                                             G_TYPE_STRING,             /* COL_CITY_TZ */
 
1022
                                                             CLOCK_LOCATION_TYPE));     /* COL_CITY_LOC */
 
1023
 
 
1024
        list = g_list_copy (cities);
 
1025
        list = g_list_sort (list, sort_locations_by_name);
 
1026
 
 
1027
        while (list) {
 
1028
                ClockLocation *loc = CLOCK_LOCATION (list->data);
 
1029
 
 
1030
                gtk_list_store_append (cd->cities_store, &iter);
 
1031
                gtk_list_store_set (cd->cities_store, &iter,
 
1032
                                    COL_CITY_NAME, clock_location_get_display_name (loc),
 
1033
                                    /* FIXME: translate the timezone */
 
1034
                                    COL_CITY_TZ, clock_location_get_timezone (loc),
 
1035
                                    COL_CITY_LOC, loc,
 
1036
                                    -1);
 
1037
 
 
1038
                list = list->next;
 
1039
        }
 
1040
 
 
1041
         
 
1042
        if (cd->prefs_window) {          
 
1043
                GtkWidget *widget = _clock_get_widget (cd, "cities_list");       
 
1044
                gtk_tree_view_set_model (GTK_TREE_VIEW (widget),         
 
1045
                GTK_TREE_MODEL (cd->cities_store));      
 
1046
        }
 
1047
}
 
1048
 
 
1049
static gint
 
1050
sort_locations_by_time (gconstpointer a, gconstpointer b)
 
1051
{
 
1052
        ClockLocation *loc_a = (ClockLocation *) a;
 
1053
        ClockLocation *loc_b = (ClockLocation *) b;
 
1054
 
 
1055
        struct tm tm_a;
 
1056
        struct tm tm_b;
 
1057
        gint ret;
 
1058
 
 
1059
        clock_location_localtime (loc_a, &tm_a);
 
1060
        clock_location_localtime (loc_b, &tm_b);
 
1061
 
 
1062
        ret = (tm_a.tm_year == tm_b.tm_year) ? 0 : 1;
 
1063
        if (ret) {
 
1064
                return (tm_a.tm_year < tm_b.tm_year) ? -1 : 1;
 
1065
        }
 
1066
 
 
1067
        ret = (tm_a.tm_mon == tm_b.tm_mon) ? 0 : 1;
 
1068
        if (ret) {
 
1069
                return (tm_a.tm_mon < tm_b.tm_mon) ? -1 : 1;
 
1070
        }
 
1071
 
 
1072
        ret = (tm_a.tm_mday == tm_b.tm_mday) ? 0 : 1;
 
1073
        if (ret) {
 
1074
                return (tm_a.tm_mday < tm_b.tm_mday) ? -1 : 1;
 
1075
        }
 
1076
 
 
1077
        ret = (tm_a.tm_hour == tm_b.tm_hour) ? 0 : 1;
 
1078
        if (ret) {
 
1079
                return (tm_a.tm_hour < tm_b.tm_hour) ? -1 : 1;
 
1080
        }
 
1081
 
 
1082
        ret = (tm_a.tm_min == tm_b.tm_min) ? 0 : 1;
 
1083
        if (ret) {
 
1084
                return (tm_a.tm_min < tm_b.tm_min) ? -1 : 1;
 
1085
        }
 
1086
 
 
1087
        ret = (tm_a.tm_sec == tm_b.tm_sec) ? 0 : 1;
 
1088
        if (ret) {
 
1089
                return (tm_a.tm_sec < tm_b.tm_sec) ? -1 : 1;
 
1090
        }
 
1091
 
 
1092
        return ret;
 
1093
}
 
1094
 
 
1095
static void
 
1096
location_tile_pressed_cb (ClockLocationTile *tile, gpointer data)
 
1097
{
 
1098
        ClockData *cd = data;
 
1099
        ClockLocation *loc;
 
1100
 
 
1101
        loc = clock_location_tile_get_location (tile);
 
1102
 
 
1103
        clock_map_blink_location (CLOCK_MAP (cd->map_widget), loc);
 
1104
 
 
1105
        g_object_unref (loc);
 
1106
}
 
1107
 
 
1108
static ClockFormat
 
1109
location_tile_need_clock_format_cb(ClockLocationTile *tile, gpointer data)
 
1110
{
 
1111
        ClockData *cd = data;
 
1112
 
 
1113
        return cd->format;
 
1114
}
 
1115
 
 
1116
static void
 
1117
create_cities_section (ClockData *cd)
 
1118
{
 
1119
        GList *node;
 
1120
        ClockLocationTile *city;
 
1121
        GList *cities;
 
1122
 
 
1123
        if (cd->cities_section) {
 
1124
                gtk_widget_destroy (cd->cities_section);
 
1125
                cd->cities_section = NULL;
 
1126
        }
 
1127
 
 
1128
        g_list_free (cd->location_tiles);
 
1129
        cd->location_tiles = NULL;
 
1130
 
 
1131
        cd->cities_section = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
 
1132
        gtk_container_set_border_width (GTK_CONTAINER (cd->cities_section), 0);
 
1133
 
 
1134
        cities = cd->locations;
 
1135
        if (g_list_length (cities) == 0) {
 
1136
                /* if the list is empty, don't bother showing the
 
1137
                   cities section */
 
1138
                gtk_widget_hide (cd->cities_section);
 
1139
                return;
 
1140
        }
 
1141
 
 
1142
        /* Copy the existing list, so we can sort it nondestructively */
 
1143
        node = g_list_copy (cities);
 
1144
        node = g_list_sort (node, sort_locations_by_time);
 
1145
        node = g_list_reverse (node);
 
1146
 
 
1147
        while (node) {
 
1148
                ClockLocation *loc = node->data;
 
1149
 
 
1150
                city = clock_location_tile_new (loc, CLOCK_FACE_SMALL);
 
1151
                g_signal_connect (city, "tile-pressed",
 
1152
                                  G_CALLBACK (location_tile_pressed_cb), cd);
 
1153
                g_signal_connect (city, "need-clock-format",
 
1154
                                  G_CALLBACK (location_tile_need_clock_format_cb), cd);
 
1155
 
 
1156
                gtk_box_pack_start (GTK_BOX (cd->cities_section),
 
1157
                                    GTK_WIDGET (city),
 
1158
                                    FALSE, FALSE, 0);
 
1159
 
 
1160
                cd->location_tiles = g_list_prepend (cd->location_tiles, city);
 
1161
 
 
1162
                clock_location_tile_refresh (city, TRUE);
 
1163
 
 
1164
                node = g_list_next (node);
 
1165
        }
 
1166
 
 
1167
        g_list_free (node);
 
1168
 
 
1169
        gtk_box_pack_end (GTK_BOX (cd->clock_vbox),
 
1170
                          cd->cities_section, FALSE, FALSE, 0);
 
1171
 
 
1172
        gtk_widget_show_all (cd->cities_section);
 
1173
}
 
1174
 
 
1175
static GList *
 
1176
map_need_locations_cb (ClockMap *map, gpointer data)
 
1177
{
 
1178
        ClockData *cd = data;
 
1179
 
 
1180
        return cd->locations;
 
1181
}
 
1182
 
 
1183
static void
 
1184
create_map_section (ClockData *cd)
 
1185
{
 
1186
        ClockMap *map;
 
1187
 
 
1188
        if (cd->map_widget) {
 
1189
                gtk_widget_destroy (GTK_WIDGET (cd->map_section));
 
1190
                cd->map_widget = NULL;
 
1191
        }
 
1192
 
 
1193
        map = clock_map_new ();
 
1194
        g_signal_connect (map, "need-locations",
 
1195
                          G_CALLBACK (map_need_locations_cb), cd);
 
1196
 
 
1197
        cd->map_section = gtk_alignment_new (0, 0, 1, 1);
 
1198
        cd->map_widget = GTK_WIDGET (map);
 
1199
 
 
1200
        gtk_container_add (GTK_CONTAINER (cd->map_section), cd->map_widget);
 
1201
 
 
1202
        gtk_alignment_set_padding (GTK_ALIGNMENT (cd->map_section), 1, 1, 1, 1);
 
1203
 
 
1204
        gtk_box_pack_start (GTK_BOX (cd->clock_vbox), cd->map_section, FALSE, FALSE, 0);
 
1205
        gtk_widget_show (cd->map_widget);
 
1206
        gtk_widget_show (cd->map_section);
 
1207
}
 
1208
 
 
1209
static void
 
1210
update_calendar_popup (ClockData *cd)
 
1211
{
 
1212
        if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (cd->panel_button))) {
 
1213
                if (cd->calendar_popup) {
 
1214
                        gtk_widget_destroy (cd->calendar_popup);
 
1215
                        cd->calendar_popup = NULL;
 
1216
                        cd->cities_section = NULL;
 
1217
                        cd->map_section = NULL;
 
1218
                        cd->map_widget = NULL;
 
1219
                        cd->clock_vbox = NULL;
 
1220
                        
 
1221
                        g_list_free (cd->location_tiles);
 
1222
                        cd->location_tiles = NULL;
 
1223
                }
 
1224
                update_tooltip (cd);
 
1225
                return;
 
1226
        }
 
1227
 
 
1228
        if (!cd->calendar_popup) {
 
1229
                cd->calendar_popup = create_calendar (cd);
 
1230
                g_object_add_weak_pointer (G_OBJECT (cd->calendar_popup),
 
1231
                                           (gpointer *) &cd->calendar_popup);
 
1232
                update_tooltip (cd);
 
1233
 
 
1234
                create_clock_window (cd);
 
1235
                create_cities_store (cd);
 
1236
                create_cities_section (cd);
 
1237
                create_map_section (cd);
 
1238
        }
 
1239
 
 
1240
        if (cd->calendar_popup && gtk_widget_get_realized (cd->panel_button)) {
 
1241
                calendar_window_refresh (CALENDAR_WINDOW (cd->calendar_popup));
 
1242
                position_calendar_popup (cd);
 
1243
                gtk_window_present (GTK_WINDOW (cd->calendar_popup));
 
1244
        }
 
1245
}
 
1246
 
 
1247
static void
 
1248
toggle_calendar (GtkWidget *button,
 
1249
                 ClockData *cd)
 
1250
{
 
1251
        /* if time is wrong, the user might try to fix it by clicking on the
 
1252
         * clock */
 
1253
        refresh_click_timeout_time_only (cd);
 
1254
        update_calendar_popup (cd);
 
1255
}
 
1256
 
 
1257
static gboolean
 
1258
do_not_eat_button_press (GtkWidget      *widget,
 
1259
                         GdkEventButton *event)
 
1260
{
 
1261
        if (event->button != 1)
 
1262
                g_signal_stop_emission_by_name (widget, "button_press_event");
 
1263
 
 
1264
        return FALSE;
 
1265
}
 
1266
 
 
1267
/* Don't request smaller size then the last one we did, this avoids
 
1268
   jumping when proportional fonts are used.  We must take care to
 
1269
   call "unfix_size" whenever options are changed or such where
 
1270
   we'd want to forget the fixed size */
 
1271
static void
 
1272
clock_size_request (GtkWidget *clock, GtkRequisition *req, gpointer data)
 
1273
{
 
1274
        ClockData *cd = data;
 
1275
 
 
1276
        if (req->width > cd->fixed_width)
 
1277
                cd->fixed_width = req->width;
 
1278
        if (req->height > cd->fixed_height)
 
1279
                cd->fixed_height = req->height;
 
1280
        req->width = cd->fixed_width;
 
1281
        req->height = cd->fixed_height;
 
1282
}
 
1283
 
 
1284
static void
 
1285
clock_update_text_gravity (GtkWidget *label)
 
1286
{
 
1287
        PangoLayout  *layout;
 
1288
        PangoContext *context;
 
1289
 
 
1290
        layout = gtk_label_get_layout (GTK_LABEL (label));
 
1291
        context = pango_layout_get_context (layout);
 
1292
        pango_context_set_base_gravity (context, PANGO_GRAVITY_AUTO);
 
1293
}
 
1294
 
 
1295
static inline void
 
1296
force_no_focus_padding (GtkWidget *widget)
 
1297
{
 
1298
        static gboolean first_time = TRUE;
 
1299
        GtkCssProvider  *provider;
 
1300
 
 
1301
        if (first_time) {
 
1302
                provider = gtk_css_provider_new ();
 
1303
                gtk_css_provider_load_from_data (provider,
 
1304
                                         "#clock-applet-button {\n"
 
1305
                                         " -GtkWidget-focus-line-width: 0px;\n"
 
1306
                                         " -GtkWidget-focus-padding: 0px;\n"
 
1307
                                         "}",
 
1308
                                         -1, NULL);
 
1309
                gtk_style_context_add_provider (gtk_widget_get_style_context (widget),
 
1310
                                        GTK_STYLE_PROVIDER (provider),
 
1311
                                        GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
 
1312
                g_object_unref (provider);
 
1313
 
 
1314
                first_time = FALSE;
 
1315
        }
 
1316
 
 
1317
        gtk_widget_set_name (widget, "clock-applet-button");
 
1318
}
 
1319
 
 
1320
static GtkWidget *
 
1321
create_main_clock_button (void)
 
1322
{
 
1323
        GtkWidget *button;
 
1324
 
 
1325
        button = gtk_toggle_button_new ();
 
1326
        gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
 
1327
 
 
1328
        force_no_focus_padding (button);
 
1329
 
 
1330
        return button;
 
1331
}
 
1332
 
 
1333
static GtkWidget *
 
1334
create_main_clock_label (ClockData *cd)
 
1335
{
 
1336
        GtkWidget *label;
 
1337
 
 
1338
        label = gtk_label_new (NULL);
 
1339
        g_signal_connect (label, "size_request",
 
1340
                          G_CALLBACK (clock_size_request),
 
1341
                          cd);
 
1342
        g_signal_connect_swapped (label, "style_set",
 
1343
                                  G_CALLBACK (unfix_size),
 
1344
                                  cd);
 
1345
        gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
 
1346
        clock_update_text_gravity (label);
 
1347
        g_signal_connect (label, "screen-changed",
 
1348
                          G_CALLBACK (clock_update_text_gravity),
 
1349
                          NULL);
 
1350
 
 
1351
        return label;
 
1352
}
 
1353
 
 
1354
static gboolean
 
1355
weather_tooltip (GtkWidget   *widget,
 
1356
                 gint         x,
 
1357
                 gint         y,
 
1358
                 gboolean     keyboard_mode,
 
1359
                 GtkTooltip  *tooltip,
 
1360
                 ClockData   *cd)
 
1361
{
 
1362
        GList *locations, *l;
 
1363
        WeatherInfo *info;
 
1364
 
 
1365
        locations = cd->locations;
 
1366
 
 
1367
        for (l = locations; l; l = l->next) {
 
1368
                ClockLocation *location = l->data;
 
1369
                if (clock_location_is_current (location)) {
 
1370
                        info = clock_location_get_weather_info (location);
 
1371
                        if (!info || !weather_info_is_valid (info))
 
1372
                                continue;
 
1373
 
 
1374
                        weather_info_setup_tooltip (info, location, tooltip, cd->format);
 
1375
 
 
1376
                        return TRUE;
 
1377
                }
 
1378
        }
 
1379
 
 
1380
        return FALSE;
 
1381
}
 
1382
 
 
1383
static void
 
1384
create_clock_widget (ClockData *cd)
 
1385
{
 
1386
#ifdef HAVE_LIBECAL
 
1387
        clock_numbers++;
 
1388
        e_passwords_init ();
 
1389
#endif
 
1390
 
 
1391
        /* Main toggle button */
 
1392
        cd->panel_button = create_main_clock_button ();
 
1393
        g_signal_connect (cd->panel_button, "button_press_event",
 
1394
                          G_CALLBACK (do_not_eat_button_press), NULL);
 
1395
        g_signal_connect (cd->panel_button, "toggled",
 
1396
                          G_CALLBACK (toggle_calendar), cd);
 
1397
        g_signal_connect (G_OBJECT (cd->panel_button), "destroy",
 
1398
                          G_CALLBACK (destroy_clock),
 
1399
                          cd);
 
1400
        gtk_widget_show (cd->panel_button);
 
1401
 
 
1402
        /* Main orientable box */
 
1403
        cd->main_obox = g_object_new (clock_box_get_type (), NULL);
 
1404
        gtk_box_set_spacing (GTK_BOX (cd->main_obox), 12); /* spacing between weather and time */
 
1405
        gtk_container_add (GTK_CONTAINER (cd->panel_button), cd->main_obox);
 
1406
        gtk_widget_show (cd->main_obox);
 
1407
 
 
1408
        /* Weather orientable box */
 
1409
        cd->weather_obox = g_object_new (clock_box_get_type (), NULL);
 
1410
        gtk_box_set_spacing (GTK_BOX (cd->weather_obox), 2); /* spacing between weather icon and temperature */
 
1411
        gtk_box_pack_start (GTK_BOX (cd->main_obox), cd->weather_obox, FALSE, FALSE, 0);
 
1412
        gtk_widget_set_has_tooltip (cd->weather_obox, TRUE);
 
1413
        g_signal_connect (cd->weather_obox, "query-tooltip",
 
1414
                          G_CALLBACK (weather_tooltip), cd);
 
1415
 
 
1416
        /* Weather widgets */
 
1417
        cd->panel_weather_icon = gtk_image_new ();
 
1418
        gtk_box_pack_start (GTK_BOX (cd->weather_obox), cd->panel_weather_icon, FALSE, FALSE, 0);
 
1419
 
 
1420
        cd->panel_temperature_label = gtk_label_new (NULL);
 
1421
        gtk_box_pack_start (GTK_BOX (cd->weather_obox), cd->panel_temperature_label, FALSE, FALSE, 0);
 
1422
 
 
1423
        /* Main label for time display */
 
1424
        cd->clockw = create_main_clock_label (cd);
 
1425
        gtk_box_pack_start (GTK_BOX (cd->main_obox), cd->clockw, FALSE, FALSE, 0);
 
1426
        gtk_widget_show (cd->clockw);
 
1427
 
 
1428
        /* Done! */
 
1429
 
 
1430
        set_atk_name_description (GTK_WIDGET (cd->applet), NULL,
 
1431
                                  _("Computer Clock"));
 
1432
 
 
1433
        gtk_container_add (GTK_CONTAINER (cd->applet), cd->panel_button);
 
1434
        gtk_container_set_border_width (GTK_CONTAINER (cd->applet), 0);
 
1435
 
 
1436
        cd->props = NULL;
 
1437
        cd->orient = -1;
 
1438
        cd->size = panel_applet_get_size (PANEL_APPLET (cd->applet));
 
1439
 
 
1440
        update_panel_weather (cd);
 
1441
 
 
1442
        /* Refresh the clock so that it paints its first state */
 
1443
        refresh_clock_timeout (cd);
 
1444
        applet_change_orient (PANEL_APPLET (cd->applet),
 
1445
                              panel_applet_get_orient (PANEL_APPLET (cd->applet)),
 
1446
                              cd);
 
1447
}
 
1448
 
 
1449
static void
 
1450
update_orient (ClockData *cd)
 
1451
{
 
1452
        const gchar   *text;
 
1453
        int            min_width;
 
1454
        GtkAllocation  allocation;
 
1455
        gdouble        new_angle;
 
1456
        gdouble        angle;
 
1457
 
 
1458
        text = gtk_label_get_text (GTK_LABEL (cd->clockw));
 
1459
        min_width = calculate_minimum_width (cd->panel_button, text);
 
1460
        gtk_widget_get_allocation (cd->panel_button, &allocation);
 
1461
 
 
1462
        if (cd->orient == PANEL_APPLET_ORIENT_LEFT &&
 
1463
            min_width > allocation.width)
 
1464
                new_angle = 270;
 
1465
        else if (cd->orient == PANEL_APPLET_ORIENT_RIGHT &&
 
1466
                 min_width > allocation.width)
 
1467
                new_angle = 90;
 
1468
        else
 
1469
                new_angle = 0;
 
1470
 
 
1471
        angle = gtk_label_get_angle (GTK_LABEL (cd->clockw));
 
1472
        if (angle != new_angle) {
 
1473
                unfix_size (cd);
 
1474
                gtk_label_set_angle (GTK_LABEL (cd->clockw), new_angle);
 
1475
                gtk_label_set_angle (GTK_LABEL (cd->panel_temperature_label), new_angle);
 
1476
        }
 
1477
}
 
1478
 
 
1479
/* this is when the panel orientation changes */
 
1480
static void
 
1481
applet_change_orient (PanelApplet       *applet,
 
1482
                      PanelAppletOrient  orient,
 
1483
                      ClockData         *cd)
 
1484
{
 
1485
        GtkOrientation o;
 
1486
 
 
1487
        if (orient == cd->orient)
 
1488
                return;
 
1489
 
 
1490
        cd->orient = orient;
 
1491
 
 
1492
        switch (cd->orient) {
 
1493
        case PANEL_APPLET_ORIENT_RIGHT:
 
1494
                o = GTK_ORIENTATION_VERTICAL;
 
1495
                break;
 
1496
        case PANEL_APPLET_ORIENT_LEFT:
 
1497
                o = GTK_ORIENTATION_VERTICAL;
 
1498
                break;
 
1499
        case PANEL_APPLET_ORIENT_DOWN:
 
1500
                o = GTK_ORIENTATION_HORIZONTAL;
 
1501
                break;
 
1502
        case PANEL_APPLET_ORIENT_UP:
 
1503
                o = GTK_ORIENTATION_HORIZONTAL;
 
1504
                break;
 
1505
        default:
 
1506
                g_assert_not_reached ();
 
1507
                return;
 
1508
        }
 
1509
 
 
1510
        gtk_orientable_set_orientation (GTK_ORIENTABLE (cd->main_obox), o);
 
1511
        gtk_orientable_set_orientation (GTK_ORIENTABLE (cd->weather_obox), o);
 
1512
 
 
1513
        unfix_size (cd);
 
1514
        update_clock (cd);
 
1515
        update_calendar_popup (cd);
 
1516
}
 
1517
 
 
1518
/* this is when the panel size changes */
 
1519
static void
 
1520
panel_button_change_pixel_size (GtkWidget     *widget,
 
1521
                                GtkAllocation *allocation,
 
1522
                                ClockData       *cd)
 
1523
{
 
1524
        int new_size;
 
1525
 
 
1526
        if (cd->old_allocation.width  == allocation->width &&
 
1527
            cd->old_allocation.height == allocation->height)
 
1528
                return;
 
1529
 
 
1530
        cd->old_allocation.width  = allocation->width;
 
1531
        cd->old_allocation.height = allocation->height;
 
1532
 
 
1533
        if (cd->orient == PANEL_APPLET_ORIENT_LEFT ||
 
1534
            cd->orient == PANEL_APPLET_ORIENT_RIGHT)
 
1535
                new_size = allocation->width;
 
1536
        else
 
1537
                new_size = allocation->height;
 
1538
 
 
1539
        cd->size = new_size;
 
1540
 
 
1541
        unfix_size (cd);
 
1542
        update_timeformat (cd);
 
1543
        update_clock (cd);
 
1544
}
 
1545
 
 
1546
static void
 
1547
copy_time (GtkAction *action,
 
1548
           ClockData *cd)
 
1549
{
 
1550
        char string[256];
 
1551
        char *utf8;
 
1552
 
 
1553
        if (cd->format == CLOCK_FORMAT_UNIX) {
 
1554
                g_snprintf (string, sizeof(string), "%lu",
 
1555
                            (unsigned long)cd->current_time);
 
1556
        } else if (cd->format == CLOCK_FORMAT_INTERNET) {
 
1557
                float itime = get_itime (cd->current_time);
 
1558
                if (cd->showseconds)
 
1559
                        g_snprintf (string, sizeof (string), "@%3.2f", itime);
 
1560
                else
 
1561
                        g_snprintf (string, sizeof (string), "@%3d",
 
1562
                                    (unsigned int) itime);
 
1563
        } else {
 
1564
                struct tm *tm;
 
1565
                char      *format;
 
1566
 
 
1567
                if (cd->format == CLOCK_FORMAT_CUSTOM) {
 
1568
                        format = g_locale_from_utf8 (cd->custom_format, -1,
 
1569
                                                     NULL, NULL, NULL);
 
1570
                } else if (cd->format == CLOCK_FORMAT_12) {
 
1571
                        if (cd->showseconds)
 
1572
                                /* Translators: This is a strftime format
 
1573
                                 * string.
 
1574
                                 * It is used to display the time in 12-hours
 
1575
                                 * format with a leading 0 if needed (eg, like
 
1576
                                 * in the US: 08:10 am). The %p expands to
 
1577
                                 * am/pm. */
 
1578
                                format = g_locale_from_utf8 (_("%I:%M:%S %p"), -1, NULL, NULL, NULL);
 
1579
                        else
 
1580
                                /* Translators: This is a strftime format
 
1581
                                 * string.
 
1582
                                 * It is used to display the time in 12-hours
 
1583
                                 * format with a leading 0 if needed (eg, like
 
1584
                                 * in the US: 08:10 am). The %p expands to
 
1585
                                 * am/pm. */
 
1586
                                format = g_locale_from_utf8 (_("%I:%M %p"), -1, NULL, NULL, NULL);
 
1587
                } else {
 
1588
                        if (cd->showseconds)
 
1589
                                /* Translators: This is a strftime format
 
1590
                                 * string.
 
1591
                                 * It is used to display the time in 24-hours
 
1592
                                 * format (eg, like in France: 20:10). */
 
1593
                                format = g_locale_from_utf8 (_("%H:%M:%S"), -1, NULL, NULL, NULL);
 
1594
                        else
 
1595
                                /* Translators: This is a strftime format
 
1596
                                 * string.
 
1597
                                 * It is used to display the time in 24-hours
 
1598
                                 * format (eg, like in France: 20:10). */
 
1599
                                format = g_locale_from_utf8 (_("%H:%M"), -1, NULL, NULL, NULL);
 
1600
                }
 
1601
 
 
1602
                tm = localtime (&cd->current_time);
 
1603
 
 
1604
                if (!format)
 
1605
                        strcpy (string, "???");
 
1606
                else if (strftime (string, sizeof (string), format, tm) <= 0)
 
1607
                        strcpy (string, "???");
 
1608
                g_free (format);
 
1609
        }
 
1610
 
 
1611
        utf8 = g_locale_to_utf8 (string, -1, NULL, NULL, NULL);
 
1612
        gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
 
1613
                                utf8, -1);
 
1614
        gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
 
1615
                                utf8, -1);
 
1616
        g_free (utf8);
 
1617
}
 
1618
 
 
1619
static void
 
1620
copy_date (GtkAction *action,
 
1621
           ClockData *cd)
 
1622
{
 
1623
        struct tm *tm;
 
1624
        char string[256];
 
1625
        char *utf8, *loc;
 
1626
 
 
1627
        tm = localtime (&cd->current_time);
 
1628
 
 
1629
        /* Translators: This is a strftime format string.
 
1630
         * It is used to display a date in the full format (so that people can
 
1631
         * copy and paste it elsewhere). */
 
1632
        loc = g_locale_from_utf8 (_("%A, %B %d %Y"), -1, NULL, NULL, NULL);
 
1633
        if (!loc)
 
1634
                strcpy (string, "???");
 
1635
        else if (strftime (string, sizeof (string), loc, tm) <= 0)
 
1636
                strcpy (string, "???");
 
1637
        g_free (loc);
 
1638
 
 
1639
        utf8 = g_locale_to_utf8 (string, -1, NULL, NULL, NULL);
 
1640
        gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
 
1641
                                utf8, -1);
 
1642
        gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
 
1643
                                utf8, -1);
 
1644
        g_free (utf8);
 
1645
}
 
1646
 
 
1647
static void
 
1648
ensure_datetime_appinfo (ClockData *cd)
 
1649
{
 
1650
        if (!cd->datetime_appinfo)
 
1651
                cd->datetime_appinfo = (GAppInfo *) g_desktop_app_info_new ("gnome-datetime-panel.desktop");
 
1652
}
 
1653
 
 
1654
static void
 
1655
update_set_time_button (ClockData *cd)
 
1656
{
 
1657
        if (!cd->time_settings_button)
 
1658
                return;
 
1659
 
 
1660
        ensure_datetime_appinfo (cd);
 
1661
 
 
1662
        gtk_widget_set_sensitive (cd->time_settings_button,
 
1663
                                  cd->datetime_appinfo != NULL);
 
1664
}
 
1665
 
 
1666
static void
 
1667
run_time_settings (GtkWidget *unused, ClockData *cd)
 
1668
{
 
1669
        GdkScreen           *screen;
 
1670
        GdkDisplay          *display;
 
1671
        GdkAppLaunchContext *context;
 
1672
        GError              *error;
 
1673
 
 
1674
        update_set_time_button (cd);
 
1675
        ensure_datetime_appinfo (cd);
 
1676
 
 
1677
        if (!cd->datetime_appinfo)
 
1678
                return;
 
1679
 
 
1680
        screen = gtk_widget_get_screen (cd->applet);
 
1681
        display = gdk_screen_get_display (screen);
 
1682
        context = gdk_display_get_app_launch_context (display);
 
1683
        gdk_app_launch_context_set_screen (context, screen);
 
1684
 
 
1685
        error = NULL;
 
1686
        g_app_info_launch (cd->datetime_appinfo, NULL,
 
1687
                           (GAppLaunchContext *) context, &error);
 
1688
 
 
1689
        g_object_unref (context);
 
1690
 
 
1691
        if (error) {
 
1692
                GtkWidget *dialog;
 
1693
 
 
1694
                dialog = gtk_message_dialog_new (NULL,
 
1695
                                                 0,
 
1696
                                                 GTK_MESSAGE_ERROR,
 
1697
                                                 GTK_BUTTONS_CLOSE,
 
1698
                                                 _("Failed to open the time settings"));
 
1699
 
 
1700
                gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error->message);
 
1701
                g_signal_connect (dialog, "response",
 
1702
                                  G_CALLBACK (gtk_widget_destroy), NULL);
 
1703
                gtk_window_present (GTK_WINDOW (dialog));
 
1704
 
 
1705
                g_error_free (error);
 
1706
        }
 
1707
}
 
1708
 
 
1709
static void
 
1710
config_date (GtkAction *action,
 
1711
             ClockData *cd)
 
1712
{
 
1713
        run_time_settings (NULL, cd);
 
1714
}
 
1715
 
 
1716
/* current timestamp */
 
1717
static const GtkActionEntry clock_menu_actions [] = {
 
1718
        { "ClockPreferences", GTK_STOCK_PROPERTIES, N_("_Preferences"),
 
1719
          NULL, NULL,
 
1720
          G_CALLBACK (verb_display_properties_dialog) },
 
1721
        { "ClockCopyTime", GTK_STOCK_COPY, N_("Copy _Time"),
 
1722
          NULL, NULL,
 
1723
          G_CALLBACK (copy_time) },
 
1724
        { "ClockCopyDate", GTK_STOCK_COPY, N_("Copy _Date"),
 
1725
          NULL, NULL,
 
1726
          G_CALLBACK (copy_date) },
 
1727
        { "ClockConfig", GTK_STOCK_PREFERENCES, N_("Ad_just Date & Time"),
 
1728
          NULL, NULL,
 
1729
          G_CALLBACK (config_date) }
 
1730
};
 
1731
 
 
1732
static void
 
1733
format_changed (GConfClient  *client,
 
1734
                guint         cnxn_id,
 
1735
                GConfEntry   *entry,
 
1736
                ClockData    *clock)
 
1737
{
 
1738
        const char  *value;
 
1739
        int          new_format;
 
1740
 
 
1741
        if (!entry->value || entry->value->type != GCONF_VALUE_STRING)
 
1742
                return;
 
1743
 
 
1744
        value = gconf_value_get_string (entry->value);
 
1745
        if (!gconf_string_to_enum (format_type_enum_map, value, &new_format))
 
1746
                return;
 
1747
 
 
1748
        if (!clock->can_handle_format_12 && new_format == CLOCK_FORMAT_12)
 
1749
                new_format = CLOCK_FORMAT_24;
 
1750
 
 
1751
        if (new_format == clock->format)
 
1752
                return;
 
1753
 
 
1754
        clock->format = new_format;
 
1755
        refresh_clock_timeout (clock);
 
1756
 
 
1757
        if (clock->calendar_popup != NULL) {
 
1758
                calendar_window_set_time_format (CALENDAR_WINDOW (clock->calendar_popup), clock->format);
 
1759
                position_calendar_popup (clock);
 
1760
        }
 
1761
 
 
1762
}
 
1763
 
 
1764
static void
 
1765
show_seconds_changed (GConfClient  *client,
 
1766
                   guint         cnxn_id,
 
1767
                   GConfEntry   *entry,
 
1768
                   ClockData    *clock)
 
1769
{
 
1770
        gboolean value;
 
1771
 
 
1772
        if (!entry->value || entry->value->type != GCONF_VALUE_BOOL)
 
1773
                return;
 
1774
 
 
1775
        value = gconf_value_get_bool (entry->value);
 
1776
 
 
1777
        clock->showseconds = (value != 0);
 
1778
        refresh_clock_timeout (clock);
 
1779
}
 
1780
 
 
1781
static void
 
1782
show_date_changed (GConfClient  *client,
 
1783
                   guint         cnxn_id,
 
1784
                   GConfEntry   *entry,
 
1785
                   ClockData    *clock)
 
1786
{
 
1787
        gboolean value;
 
1788
 
 
1789
        if (!entry->value || entry->value->type != GCONF_VALUE_BOOL)
 
1790
                return;
 
1791
 
 
1792
        value = gconf_value_get_bool (entry->value);
 
1793
 
 
1794
        clock->showdate = (value != 0);
 
1795
        update_timeformat (clock);
 
1796
        refresh_clock (clock);
 
1797
}
 
1798
 
 
1799
static void
 
1800
update_panel_weather (ClockData *cd)
 
1801
{
 
1802
        if (cd->show_weather)
 
1803
                gtk_widget_show (cd->panel_weather_icon);
 
1804
        else
 
1805
                gtk_widget_hide (cd->panel_weather_icon);
 
1806
 
 
1807
        if (cd->show_temperature)
 
1808
                gtk_widget_show (cd->panel_temperature_label);
 
1809
        else
 
1810
                gtk_widget_hide (cd->panel_temperature_label);
 
1811
 
 
1812
        if ((cd->show_weather || cd->show_temperature) &&
 
1813
            g_list_length (cd->locations) > 0)
 
1814
                gtk_widget_show (cd->weather_obox);
 
1815
        else
 
1816
                gtk_widget_hide (cd->weather_obox);
 
1817
 
 
1818
        gtk_widget_queue_resize (cd->applet);
 
1819
}
 
1820
 
 
1821
static void
 
1822
update_weather_bool_value_and_toggle_from_gconf (ClockData *cd, GConfEntry *entry,
 
1823
                                                 gboolean *value_loc, const char *widget_name)
 
1824
{
 
1825
        GtkWidget *widget;
 
1826
        gboolean value;
 
1827
 
 
1828
        if (!entry->value || entry->value->type != GCONF_VALUE_BOOL)
 
1829
                return;
 
1830
 
 
1831
        value = gconf_value_get_bool (entry->value);
 
1832
 
 
1833
        *value_loc = (value != 0);
 
1834
 
 
1835
        widget = _clock_get_widget (cd, widget_name);
 
1836
 
 
1837
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget),
 
1838
                                      *value_loc);
 
1839
 
 
1840
        update_panel_weather (cd);
 
1841
}
 
1842
 
 
1843
static void
 
1844
show_weather_changed (GConfClient  *client,
 
1845
                      guint         cnxn_id,
 
1846
                      GConfEntry   *entry,
 
1847
                      ClockData    *cd)
 
1848
{
 
1849
        update_weather_bool_value_and_toggle_from_gconf (cd, entry, &cd->show_weather, "weather_check");
 
1850
}
 
1851
 
 
1852
static void
 
1853
show_temperature_changed (GConfClient  *client,
 
1854
                          guint         cnxn_id,
 
1855
                          GConfEntry   *entry,
 
1856
                          ClockData    *cd)
 
1857
{
 
1858
        update_weather_bool_value_and_toggle_from_gconf (cd, entry, &cd->show_temperature, "temperature_check");
 
1859
}
 
1860
 
 
1861
static void
 
1862
location_weather_updated_cb (ClockLocation *location,
 
1863
                             WeatherInfo   *info,
 
1864
                             gpointer       data)
 
1865
{
 
1866
        ClockData *cd = data;
 
1867
        const gchar *icon_name;
 
1868
        const gchar *temp;
 
1869
        GtkIconTheme *theme;
 
1870
        GdkPixbuf *pixbuf;
 
1871
 
 
1872
        if (!info || !weather_info_is_valid (info))
 
1873
                return;
 
1874
 
 
1875
        if (!clock_location_is_current (location))
 
1876
                return;
 
1877
 
 
1878
        icon_name = weather_info_get_icon_name (info);
 
1879
        /* FIXME: mmh, screen please? Also, don't hardcode to 16 */
 
1880
        theme = gtk_icon_theme_get_default ();
 
1881
        pixbuf = gtk_icon_theme_load_icon (theme, icon_name, 16,
 
1882
                                           GTK_ICON_LOOKUP_GENERIC_FALLBACK, NULL);
 
1883
 
 
1884
        temp = weather_info_get_temp_summary (info);
 
1885
 
 
1886
        gtk_image_set_from_pixbuf (GTK_IMAGE (cd->panel_weather_icon), pixbuf);
 
1887
        gtk_label_set_text (GTK_LABEL (cd->panel_temperature_label), temp);
 
1888
}
 
1889
 
 
1890
static void
 
1891
location_set_current_cb (ClockLocation *loc, 
 
1892
                         gpointer       data)
 
1893
{
 
1894
        ClockData *cd = data;
 
1895
        WeatherInfo *info;
 
1896
 
 
1897
        info = clock_location_get_weather_info (loc);
 
1898
        location_weather_updated_cb (loc, info, cd);
 
1899
 
 
1900
        if (cd->map_widget)
 
1901
                clock_map_refresh (CLOCK_MAP (cd->map_widget));
 
1902
        update_location_tiles (cd);
 
1903
        save_cities_store (cd); 
 
1904
}
 
1905
 
 
1906
static void
 
1907
locations_changed (ClockData *cd)
 
1908
{
 
1909
        GList *l;
 
1910
        ClockLocation *loc;
 
1911
        glong id;
 
1912
 
 
1913
        if (!cd->locations) {
 
1914
                if (cd->weather_obox)
 
1915
                        gtk_widget_hide (cd->weather_obox);
 
1916
                if (cd->panel_weather_icon)
 
1917
                        gtk_image_set_from_pixbuf (GTK_IMAGE (cd->panel_weather_icon),
 
1918
                                                   NULL);
 
1919
                if (cd->panel_temperature_label)
 
1920
                        gtk_label_set_text (GTK_LABEL (cd->panel_temperature_label),
 
1921
                                            "");
 
1922
        } else {
 
1923
                if (cd->weather_obox)
 
1924
                        gtk_widget_show (cd->weather_obox);
 
1925
        }
 
1926
 
 
1927
        for (l = cd->locations; l; l = l->next) {
 
1928
                loc = l->data;
 
1929
 
 
1930
                id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (loc), "weather-updated"));
 
1931
                if (id == 0) {
 
1932
                        id = g_signal_connect (loc, "weather-updated",
 
1933
                                                G_CALLBACK (location_weather_updated_cb), cd);
 
1934
                        g_object_set_data (G_OBJECT (loc), "weather-updated", GINT_TO_POINTER (id));
 
1935
                        g_signal_connect (loc, "set-current", 
 
1936
                                          G_CALLBACK (location_set_current_cb), cd);
 
1937
                }
 
1938
        }
 
1939
 
 
1940
        if (cd->map_widget)
 
1941
                clock_map_refresh (CLOCK_MAP (cd->map_widget));
 
1942
 
 
1943
        if (cd->clock_vbox)
 
1944
                create_cities_section (cd);
 
1945
}
 
1946
 
 
1947
 
 
1948
static void
 
1949
set_locations (ClockData *cd, GList *locations)
 
1950
{
 
1951
        free_locations (cd);
 
1952
        cd->locations = locations;
 
1953
        locations_changed (cd);
 
1954
}
 
1955
 
 
1956
typedef struct {
 
1957
        GList *cities;
 
1958
        ClockData *cd;
 
1959
} LocationParserData;
 
1960
 
 
1961
/* Parser for our serialized locations in gconf */
 
1962
static void
 
1963
location_start_element (GMarkupParseContext *context,
 
1964
                        const gchar *element_name,
 
1965
                        const gchar **attribute_names,
 
1966
                        const gchar **attribute_values,
 
1967
                        gpointer user_data,
 
1968
                        GError **error)
 
1969
{
 
1970
        ClockLocation *loc;
 
1971
        LocationParserData *data = user_data;
 
1972
        ClockData *cd = data->cd;
 
1973
        WeatherPrefs prefs;
 
1974
        const gchar *att_name;
 
1975
 
 
1976
        gchar *name = NULL;
 
1977
        gchar *city = NULL;
 
1978
        gchar *timezone = NULL;
 
1979
        gfloat latitude = 0.0;
 
1980
        gfloat longitude = 0.0;
 
1981
        gchar *code = NULL;
 
1982
        gboolean current = FALSE;
 
1983
 
 
1984
        int index = 0;
 
1985
 
 
1986
        prefs.temperature_unit = cd->temperature_unit;
 
1987
        prefs.speed_unit = cd->speed_unit;
 
1988
 
 
1989
        if (strcmp (element_name, "location") != 0) {
 
1990
                return;
 
1991
        }
 
1992
 
 
1993
        setlocale (LC_NUMERIC, "POSIX");
 
1994
 
 
1995
        for (att_name = attribute_names[index]; att_name != NULL;
 
1996
             att_name = attribute_names[++index]) {
 
1997
                if (strcmp (att_name, "name") == 0) {
 
1998
                        name = (gchar *)attribute_values[index];
 
1999
                } else if (strcmp (att_name, "city") == 0) {
 
2000
                        city = (gchar *)attribute_values[index];
 
2001
                } else if (strcmp (att_name, "timezone") == 0) {
 
2002
                        timezone = (gchar *)attribute_values[index];
 
2003
                } else if (strcmp (att_name, "latitude") == 0) {
 
2004
                        sscanf (attribute_values[index], "%f", &latitude);
 
2005
                } else if (strcmp (att_name, "longitude") == 0) {
 
2006
                        sscanf (attribute_values[index], "%f", &longitude);
 
2007
                } else if (strcmp (att_name, "code") == 0) {
 
2008
                        code = (gchar *)attribute_values[index];
 
2009
                }
 
2010
                else if (strcmp (att_name, "current") == 0) {
 
2011
                        if (strcmp (attribute_values[index], "true") == 0) {
 
2012
                                current = TRUE;
 
2013
                        }
 
2014
                }
 
2015
        }
 
2016
 
 
2017
        setlocale (LC_NUMERIC, "");
 
2018
 
 
2019
        if ((!name && !city) || !timezone) {
 
2020
                return;
 
2021
        }
 
2022
 
 
2023
        /* migration from the old configuration, when name == city */
 
2024
        if (!city)
 
2025
                city = name;
 
2026
 
 
2027
        loc = clock_location_find_and_ref (cd->locations, name, city,
 
2028
                                           timezone, latitude, longitude, code);
 
2029
        if (!loc)
 
2030
                loc = clock_location_new (name, city, timezone,
 
2031
                                          latitude, longitude, code, &prefs);
 
2032
 
 
2033
        if (current && clock_location_is_current_timezone (loc))
 
2034
                clock_location_make_current (loc, NULL, NULL, NULL);
 
2035
 
 
2036
        data->cities = g_list_append (data->cities, loc);
 
2037
}
 
2038
 
 
2039
static GMarkupParser location_parser = {
 
2040
        location_start_element, NULL, NULL, NULL, NULL
 
2041
};
 
2042
 
 
2043
static void
 
2044
cities_changed (GConfClient  *client,
 
2045
                guint         cnxn_id,
 
2046
                GConfEntry   *entry,
 
2047
                ClockData    *cd)
 
2048
{
 
2049
        LocationParserData data;
 
2050
 
 
2051
        GSList *cur = NULL;
 
2052
 
 
2053
        GMarkupParseContext *context;
 
2054
 
 
2055
        data.cities = NULL;
 
2056
        data.cd = cd;
 
2057
 
 
2058
        if (!entry->value || entry->value->type != GCONF_VALUE_LIST)
 
2059
                return;
 
2060
 
 
2061
        context = g_markup_parse_context_new (&location_parser, 0, &data, NULL);
 
2062
 
 
2063
        cur = gconf_value_get_list (entry->value);
 
2064
 
 
2065
        while (cur) {
 
2066
                const char *str = gconf_value_get_string (cur->data);
 
2067
                g_markup_parse_context_parse (context, str, strlen (str), NULL);
 
2068
 
 
2069
                cur = cur->next;
 
2070
        }
 
2071
 
 
2072
        g_markup_parse_context_free (context);
 
2073
 
 
2074
        set_locations (cd, data.cities);
 
2075
        create_cities_store (cd);
 
2076
}
 
2077
 
 
2078
static void
 
2079
update_temperature_combo (ClockData *cd)
 
2080
{
 
2081
        GtkWidget *widget;
 
2082
        int active_index;
 
2083
 
 
2084
        widget = _clock_get_widget (cd, "temperature_combo");
 
2085
 
 
2086
        if (cd->use_temperature_default)
 
2087
                active_index = 0;
 
2088
        else
 
2089
                active_index = cd->temperature_unit - 1;
 
2090
 
 
2091
        gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active_index);
 
2092
}
 
2093
 
 
2094
static void
 
2095
update_weather_locations (ClockData *cd)
 
2096
{
 
2097
        GList *locations, *l;
 
2098
        WeatherPrefs prefs = {
 
2099
                FORECAST_STATE,
 
2100
                FALSE,
 
2101
                NULL,
 
2102
                TEMP_UNIT_CENTIGRADE,
 
2103
                SPEED_UNIT_MS,
 
2104
                PRESSURE_UNIT_MB,
 
2105
                DISTANCE_UNIT_KM
 
2106
        };
 
2107
 
 
2108
        prefs.temperature_unit = cd->temperature_unit;
 
2109
        prefs.speed_unit = cd->speed_unit;
 
2110
 
 
2111
        locations = cd->locations;
 
2112
 
 
2113
        for (l = locations; l; l = l->next) {
 
2114
                clock_location_set_weather_prefs (l->data, &prefs);
 
2115
        }
 
2116
}
 
2117
 
 
2118
static void
 
2119
clock_migrate_to_26 (ClockData *clock)
 
2120
{
 
2121
        gboolean  unixtime;
 
2122
        gboolean  internettime;
 
2123
        int       hourformat;
 
2124
 
 
2125
        internettime = panel_applet_gconf_get_bool (PANEL_APPLET (clock->applet),
 
2126
                                                    "internet_time",
 
2127
                                                    NULL);
 
2128
        unixtime = panel_applet_gconf_get_bool (PANEL_APPLET (clock->applet),
 
2129
                                                "unix_time",
 
2130
                                                NULL);
 
2131
        hourformat = panel_applet_gconf_get_int (PANEL_APPLET (clock->applet),
 
2132
                                                 "hour_format",
 
2133
                                                 NULL);
 
2134
 
 
2135
        if (unixtime)
 
2136
                clock->format = CLOCK_FORMAT_UNIX;
 
2137
        else if (internettime)
 
2138
                clock->format = CLOCK_FORMAT_INTERNET;
 
2139
        else if (hourformat == 12)
 
2140
                clock->format = CLOCK_FORMAT_12;
 
2141
        else if (hourformat == 24)
 
2142
                clock->format = CLOCK_FORMAT_24;
 
2143
 
 
2144
        /* It's still possible that we have none of the old keys, in which case
 
2145
         * we're not migrating from 2.6, but the config is simply wrong. So
 
2146
         * don't set the format key in this case. */
 
2147
        if (clock->format != CLOCK_FORMAT_INVALID)
 
2148
                panel_applet_gconf_set_string (PANEL_APPLET (clock->applet),
 
2149
                                               KEY_FORMAT,
 
2150
                                               gconf_enum_to_string (format_type_enum_map,
 
2151
                                                                     clock->format),
 
2152
                                               NULL);
 
2153
}
 
2154
 
 
2155
static void
 
2156
clock_timezone_changed (SystemTimezone *systz,
 
2157
                        const char     *new_tz,
 
2158
                        ClockData      *cd)
 
2159
{
 
2160
        /* This will refresh the current location */
 
2161
        save_cities_store (cd);
 
2162
 
 
2163
        refresh_click_timeout_time_only (cd);
 
2164
}
 
2165
 
 
2166
static void
 
2167
parse_and_set_temperature_string (const char *str, ClockData *cd)
 
2168
{
 
2169
        gint value = 0;
 
2170
        gboolean use_default = FALSE;
 
2171
 
 
2172
        value = gweather_prefs_parse_temperature (str, &use_default);
 
2173
 
 
2174
        cd->use_temperature_default = use_default;
 
2175
        cd->temperature_unit = value;
 
2176
}
 
2177
 
 
2178
static void
 
2179
parse_and_set_speed_string (const char *str, ClockData *cd)
 
2180
{
 
2181
        gint value = 0;
 
2182
        gboolean use_default = FALSE;
 
2183
 
 
2184
        value = gweather_prefs_parse_speed (str, &use_default);
 
2185
 
 
2186
        cd->use_speed_default = use_default;
 
2187
        cd->speed_unit = value;
 
2188
}
 
2189
 
 
2190
static void
 
2191
temperature_unit_changed (GConfClient  *client,
 
2192
                          guint         cnxn_id,
 
2193
                          GConfEntry   *entry,
 
2194
                          ClockData    *cd)
 
2195
{
 
2196
        const gchar *value;
 
2197
 
 
2198
        if (!entry->value || entry->value->type != GCONF_VALUE_STRING)
 
2199
                return;
 
2200
 
 
2201
        value = gconf_value_get_string (entry->value);
 
2202
        parse_and_set_temperature_string (value, cd);
 
2203
        update_temperature_combo (cd);
 
2204
        update_weather_locations (cd);
 
2205
}
 
2206
 
 
2207
static void
 
2208
update_speed_combo (ClockData *cd)
 
2209
{
 
2210
        GtkWidget *widget;
 
2211
        int active_index;
 
2212
 
 
2213
        widget = _clock_get_widget (cd, "wind_speed_combo");
 
2214
 
 
2215
        if (cd->use_speed_default)
 
2216
                active_index = 0;
 
2217
        else
 
2218
                active_index = cd->speed_unit - 1;
 
2219
 
 
2220
        gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active_index);
 
2221
}
 
2222
 
 
2223
static void
 
2224
speed_unit_changed (GConfClient  *client,
 
2225
                    guint         cnxn_id,
 
2226
                    GConfEntry   *entry,
 
2227
                    ClockData    *cd)
 
2228
{
 
2229
        const gchar *value;
 
2230
 
 
2231
        if (!entry->value || entry->value->type != GCONF_VALUE_STRING)
 
2232
                return;
 
2233
 
 
2234
        value = gconf_value_get_string (entry->value);
 
2235
        parse_and_set_speed_string (value, cd);
 
2236
        update_speed_combo (cd);
 
2237
        update_weather_locations (cd);
 
2238
}
 
2239
 
 
2240
static void
 
2241
custom_format_changed (GConfClient  *client,
 
2242
                       guint         cnxn_id,
 
2243
                       GConfEntry   *entry,
 
2244
                       ClockData    *clock)
 
2245
{
 
2246
        const char *value;
 
2247
 
 
2248
        if (!entry->value || entry->value->type != GCONF_VALUE_STRING)
 
2249
                return;
 
2250
 
 
2251
        value = gconf_value_get_string (entry->value);
 
2252
 
 
2253
        g_free (clock->custom_format);
 
2254
        clock->custom_format = g_strdup (value);
 
2255
 
 
2256
        if (clock->format == CLOCK_FORMAT_CUSTOM)
 
2257
                refresh_clock (clock);
 
2258
}
 
2259
 
 
2260
static void
 
2261
show_week_changed (GConfClient  *client,
 
2262
                   guint         cnxn_id,
 
2263
                   GConfEntry   *entry,
 
2264
                   ClockData    *clock)
 
2265
{
 
2266
        gboolean value;
 
2267
 
 
2268
        if (!entry->value || entry->value->type != GCONF_VALUE_BOOL)
 
2269
                return;
 
2270
 
 
2271
        value = gconf_value_get_bool (entry->value);
 
2272
 
 
2273
        if (clock->showweek == (value != 0))
 
2274
                return;
 
2275
 
 
2276
        clock->showweek = (value != 0);
 
2277
 
 
2278
        if (clock->calendar_popup != NULL) {
 
2279
                calendar_window_set_show_weeks (CALENDAR_WINDOW (clock->calendar_popup), clock->showweek);
 
2280
                position_calendar_popup (clock);
 
2281
        }
 
2282
}
 
2283
 
 
2284
static guint
 
2285
setup_gconf_preference (ClockData *cd, GConfClient *client, const char *key_name, GConfClientNotifyFunc callback)
 
2286
{
 
2287
        char *key;
 
2288
        guint id;
 
2289
 
 
2290
        key = panel_applet_gconf_get_full_key (PANEL_APPLET (cd->applet),
 
2291
                                               key_name);
 
2292
        id = gconf_client_notify_add (client, key,
 
2293
                                      callback,
 
2294
                                      cd, NULL, NULL);
 
2295
        g_free (key);
 
2296
 
 
2297
        return id;
 
2298
}
 
2299
 
 
2300
static void
 
2301
setup_gconf (ClockData *cd)
 
2302
{
 
2303
        struct {
 
2304
                const char *key_name;
 
2305
                GConfClientNotifyFunc callback;
 
2306
        } prefs[] = {
 
2307
                { KEY_FORMAT,           (GConfClientNotifyFunc) format_changed },
 
2308
                { KEY_SHOW_SECONDS,     (GConfClientNotifyFunc) show_seconds_changed },
 
2309
                { KEY_SHOW_DATE,        (GConfClientNotifyFunc) show_date_changed },
 
2310
                { KEY_SHOW_WEATHER,     (GConfClientNotifyFunc) show_weather_changed },
 
2311
                { KEY_SHOW_TEMPERATURE, (GConfClientNotifyFunc) show_temperature_changed },
 
2312
                { KEY_CUSTOM_FORMAT,    (GConfClientNotifyFunc) custom_format_changed },
 
2313
                { KEY_SHOW_WEEK,        (GConfClientNotifyFunc) show_week_changed },
 
2314
                { KEY_CITIES,           (GConfClientNotifyFunc) cities_changed },
 
2315
                { KEY_TEMPERATURE_UNIT, (GConfClientNotifyFunc) temperature_unit_changed },
 
2316
                { KEY_SPEED_UNIT,       (GConfClientNotifyFunc) speed_unit_changed },
 
2317
        };
 
2318
 
 
2319
        GConfClient *client;
 
2320
        int          i;
 
2321
 
 
2322
        client = gconf_client_get_default ();
 
2323
 
 
2324
        for (i = 0; i < G_N_ELEMENTS (prefs); i++)
 
2325
                cd->listeners[i] = setup_gconf_preference (cd, client, prefs[i].key_name, prefs[i].callback);
 
2326
 
 
2327
        g_object_unref (G_OBJECT (client));
 
2328
}
 
2329
 
 
2330
static GList *
 
2331
parse_gconf_cities (ClockData *cd, GSList *values)
 
2332
{
 
2333
        GSList *cur = values;
 
2334
        LocationParserData data;
 
2335
        GMarkupParseContext *context;
 
2336
 
 
2337
        data.cities = NULL;
 
2338
        data.cd = cd;
 
2339
 
 
2340
        context =
 
2341
                g_markup_parse_context_new (&location_parser, 0, &data, NULL);
 
2342
 
 
2343
        while (cur) {
 
2344
                const char *str = (char *)cur->data;
 
2345
                g_markup_parse_context_parse (context, str, strlen(str), NULL);
 
2346
 
 
2347
                cur = cur->next;
 
2348
        }
 
2349
 
 
2350
        g_markup_parse_context_free (context);
 
2351
 
 
2352
        return data.cities;
 
2353
}
 
2354
 
 
2355
static void
 
2356
load_gconf_settings (ClockData *cd)
 
2357
{
 
2358
        PanelApplet *applet;
 
2359
        int format;
 
2360
        char *format_str;
 
2361
        char *value;
 
2362
        GError *error;
 
2363
        GSList *values = NULL;
 
2364
        GList *cities = NULL;
 
2365
 
 
2366
        applet = PANEL_APPLET (cd->applet);
 
2367
 
 
2368
        cd->format = CLOCK_FORMAT_INVALID;
 
2369
 
 
2370
        format_str = panel_applet_gconf_get_string (applet, KEY_FORMAT, NULL);
 
2371
        if (format_str &&
 
2372
            gconf_string_to_enum (format_type_enum_map, format_str, &format))
 
2373
                cd->format = format;
 
2374
        else
 
2375
                clock_migrate_to_26 (cd);
 
2376
 
 
2377
        g_free (format_str);
 
2378
 
 
2379
        if (cd->format == CLOCK_FORMAT_INVALID)
 
2380
                cd->format = clock_locale_format ();
 
2381
 
 
2382
        cd->custom_format = panel_applet_gconf_get_string (applet, KEY_CUSTOM_FORMAT, NULL);
 
2383
        cd->showseconds = panel_applet_gconf_get_bool (applet, KEY_SHOW_SECONDS, NULL);
 
2384
 
 
2385
        error = NULL;
 
2386
        cd->showdate = panel_applet_gconf_get_bool (applet, KEY_SHOW_DATE, &error);
 
2387
        if (error) {
 
2388
                g_error_free (error);
 
2389
                /* if on a small screen don't show date by default */
 
2390
                if (gdk_screen_width () <= 800)
 
2391
                        cd->showdate = FALSE;
 
2392
                else
 
2393
                        cd->showdate = TRUE;
 
2394
        }
 
2395
 
 
2396
        cd->show_weather = panel_applet_gconf_get_bool (applet, KEY_SHOW_WEATHER, NULL);
 
2397
        cd->show_temperature = panel_applet_gconf_get_bool (applet, KEY_SHOW_TEMPERATURE, NULL);
 
2398
        cd->showweek = panel_applet_gconf_get_bool (applet, KEY_SHOW_WEEK, NULL);
 
2399
        cd->timeformat = NULL;
 
2400
 
 
2401
        cd->can_handle_format_12 = (clock_locale_format () == CLOCK_FORMAT_12);
 
2402
        if (!cd->can_handle_format_12 && cd->format == CLOCK_FORMAT_12)
 
2403
                cd->format = CLOCK_FORMAT_24;
 
2404
 
 
2405
        value = panel_applet_gconf_get_string (applet, KEY_TEMPERATURE_UNIT, NULL);
 
2406
        parse_and_set_temperature_string (value, cd);
 
2407
        g_free (value);
 
2408
 
 
2409
        value = panel_applet_gconf_get_string (applet, KEY_SPEED_UNIT, NULL);
 
2410
        parse_and_set_speed_string (value, cd);
 
2411
        g_free (value);
 
2412
 
 
2413
        values = panel_applet_gconf_get_list (PANEL_APPLET (cd->applet), KEY_CITIES,
 
2414
                                              GCONF_VALUE_STRING, NULL);
 
2415
 
 
2416
        if (g_slist_length (values) == 0) {
 
2417
                cities = NULL;
 
2418
        } else {
 
2419
                cities = parse_gconf_cities (cd, values);
 
2420
        }
 
2421
 
 
2422
        set_locations (cd, cities);
 
2423
}
 
2424
 
 
2425
static gboolean
 
2426
fill_clock_applet (PanelApplet *applet)
 
2427
{
 
2428
        ClockData      *cd;
 
2429
        GtkActionGroup *action_group;
 
2430
        GtkAction      *action;
 
2431
 
 
2432
        panel_applet_add_preferences (applet, CLOCK_SCHEMA_DIR, NULL);
 
2433
        panel_applet_set_flags (applet, PANEL_APPLET_EXPAND_MINOR);
 
2434
 
 
2435
        cd = g_new0 (ClockData, 1);
 
2436
        cd->fixed_width = -1;
 
2437
        cd->fixed_height = -1;
 
2438
 
 
2439
        cd->applet = GTK_WIDGET (applet);
 
2440
 
 
2441
        setup_gconf (cd);
 
2442
        load_gconf_settings (cd);
 
2443
 
 
2444
        cd->builder = gtk_builder_new ();
 
2445
        gtk_builder_set_translation_domain (cd->builder, GETTEXT_PACKAGE);
 
2446
        gtk_builder_add_from_resource (cd->builder, CLOCK_RESOURCE_PATH "clock.ui", NULL);
 
2447
 
 
2448
        create_clock_widget (cd);
 
2449
 
 
2450
#ifndef CLOCK_INPROCESS
 
2451
        gtk_window_set_default_icon_name (CLOCK_ICON);
 
2452
#endif
 
2453
        gtk_widget_show (cd->applet);
 
2454
 
 
2455
        /* FIXME: Update this comment. */
 
2456
        /* we have to bind change_orient before we do applet_widget_add
 
2457
           since we need to get an initial change_orient signal to set our
 
2458
           initial oriantation, and we get that during the _add call */
 
2459
        g_signal_connect (G_OBJECT (cd->applet),
 
2460
                          "change_orient",
 
2461
                          G_CALLBACK (applet_change_orient),
 
2462
                          cd);
 
2463
 
 
2464
        g_signal_connect (G_OBJECT (cd->panel_button),
 
2465
                          "size_allocate",
 
2466
                          G_CALLBACK (panel_button_change_pixel_size),
 
2467
                          cd);
 
2468
 
 
2469
        panel_applet_set_background_widget (PANEL_APPLET (cd->applet),
 
2470
                                            GTK_WIDGET (cd->applet));
 
2471
 
 
2472
        action_group = gtk_action_group_new ("ClockApplet Menu Actions");
 
2473
        gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
 
2474
        gtk_action_group_add_actions (action_group,
 
2475
                                      clock_menu_actions,
 
2476
                                      G_N_ELEMENTS (clock_menu_actions),
 
2477
                                      cd);
 
2478
        panel_applet_setup_menu_from_resource (PANEL_APPLET (cd->applet),
 
2479
                                               CLOCK_RESOURCE_PATH "clock-menu.xml",
 
2480
                                               action_group);
 
2481
 
 
2482
        action = gtk_action_group_get_action (action_group, "ClockPreferences");
 
2483
        g_object_bind_property (cd->applet, "locked-down",
 
2484
                                action, "visible",
 
2485
                                G_BINDING_DEFAULT|G_BINDING_INVERT_BOOLEAN|G_BINDING_SYNC_CREATE);
 
2486
 
 
2487
        action = gtk_action_group_get_action (action_group, "ClockConfig");
 
2488
        g_object_bind_property (cd->applet, "locked-down",
 
2489
                                action, "visible",
 
2490
                                G_BINDING_DEFAULT|G_BINDING_INVERT_BOOLEAN|G_BINDING_SYNC_CREATE);
 
2491
 
 
2492
        cd->systz = system_timezone_new ();
 
2493
        g_signal_connect (cd->systz, "changed",
 
2494
                          G_CALLBACK (clock_timezone_changed), cd);
 
2495
 
 
2496
        g_object_unref (action_group);
 
2497
 
 
2498
        return TRUE;
 
2499
}
 
2500
 
 
2501
/* FIXME old clock applet */
 
2502
#if 0
 
2503
static void
 
2504
setup_writability_sensitivity (ClockData *clock, GtkWidget *w, GtkWidget *label, const char *key)
 
2505
{
 
2506
        /* FMQ: was used from old preferences dialog; fix this up */
 
2507
        char *fullkey;
 
2508
        GConfClient *client;
 
2509
 
 
2510
        client = gconf_client_get_default ();
 
2511
 
 
2512
        fullkey = panel_applet_gconf_get_full_key
 
2513
                (PANEL_APPLET (clock->applet), key);
 
2514
 
 
2515
        if ( ! gconf_client_key_is_writable (client, fullkey, NULL)) {
 
2516
                g_object_set_data (G_OBJECT (w), NEVER_SENSITIVE,
 
2517
                                   GINT_TO_POINTER (1));
 
2518
                gtk_widget_set_sensitive (w, FALSE);
 
2519
                if (label != NULL) {
 
2520
                        g_object_set_data (G_OBJECT (label), NEVER_SENSITIVE,
 
2521
                                           GINT_TO_POINTER (1));
 
2522
                        gtk_widget_set_sensitive (label, FALSE);
 
2523
                }
 
2524
        }
 
2525
 
 
2526
        g_free (fullkey);
 
2527
 
 
2528
        g_object_unref (G_OBJECT (client));
 
2529
}
 
2530
 
 
2531
static void
 
2532
update_properties_for_format (ClockData   *cd,
 
2533
                              GtkComboBox *combo,
 
2534
                              ClockFormat  format)
 
2535
{
 
2536
 
 
2537
        /* show the custom format things the first time we actually
 
2538
         * have a custom format set in GConf, but after that don't
 
2539
         * unshow it if the format changes
 
2540
         */
 
2541
        if (!cd->custom_format_shown &&
 
2542
            (cd->format == CLOCK_FORMAT_CUSTOM ||
 
2543
             (cd->custom_format && cd->custom_format [0]))) {
 
2544
                gtk_widget_show (cd->custom_hbox);
 
2545
                gtk_widget_show (cd->custom_label);
 
2546
                gtk_widget_show (cd->custom_entry);
 
2547
 
 
2548
                gtk_combo_box_append_text (combo, _("Custom format"));
 
2549
 
 
2550
                cd->custom_format_shown = TRUE;
 
2551
        }
 
2552
 
 
2553
        /* Some combinations of options do not make sense */
 
2554
        switch (format) {
 
2555
        case CLOCK_FORMAT_12:
 
2556
        case CLOCK_FORMAT_24:
 
2557
                gtk_widget_set_sensitive (cd->showseconds_check, TRUE);
 
2558
                gtk_widget_set_sensitive (cd->showdate_check, TRUE);
 
2559
                gtk_widget_set_sensitive (cd->custom_entry, FALSE);
 
2560
                gtk_widget_set_sensitive (cd->custom_label, FALSE);
 
2561
                break;
 
2562
        case CLOCK_FORMAT_UNIX:
 
2563
                gtk_widget_set_sensitive (cd->showseconds_check, FALSE);
 
2564
                gtk_widget_set_sensitive (cd->showdate_check, FALSE);
 
2565
                gtk_widget_set_sensitive (cd->custom_entry, FALSE);
 
2566
                gtk_widget_set_sensitive (cd->custom_label, FALSE);
 
2567
                break;
 
2568
        case CLOCK_FORMAT_INTERNET:
 
2569
                gtk_widget_set_sensitive (cd->showseconds_check, TRUE);
 
2570
                gtk_widget_set_sensitive (cd->showdate_check, FALSE);
 
2571
                gtk_widget_set_sensitive (cd->custom_entry, FALSE);
 
2572
                gtk_widget_set_sensitive (cd->custom_label, FALSE);
 
2573
                break;
 
2574
        case CLOCK_FORMAT_CUSTOM:
 
2575
                gtk_widget_set_sensitive (cd->showseconds_check, FALSE);
 
2576
                gtk_widget_set_sensitive (cd->showdate_check, FALSE);
 
2577
                gtk_widget_set_sensitive (cd->custom_entry, TRUE);
 
2578
                gtk_widget_set_sensitive (cd->custom_label, TRUE);
 
2579
                break;
 
2580
        default:
 
2581
                g_assert_not_reached ();
 
2582
                break;
 
2583
        }
 
2584
}
 
2585
 
 
2586
static void
 
2587
set_format_cb (GtkComboBox *combo,
 
2588
               ClockData   *cd)
 
2589
{
 
2590
        /* FMQ: was used from old preferences dialog; fix this up */
 
2591
        ClockFormat format;
 
2592
 
 
2593
        /* valid values begin from 1 */
 
2594
        if (cd->can_handle_format_12)
 
2595
                format = gtk_combo_box_get_active (combo) + 1;
 
2596
        else
 
2597
                format = gtk_combo_box_get_active (combo) + 2;
 
2598
 
 
2599
        update_properties_for_format (cd, combo, format);
 
2600
 
 
2601
        if (cd->format != format)
 
2602
                panel_applet_gconf_set_string (PANEL_APPLET (cd->applet),
 
2603
                                               KEY_FORMAT,
 
2604
                                               gconf_enum_to_string (format_type_enum_map, format),
 
2605
                                               NULL);
 
2606
}
 
2607
#endif
 
2608
 
 
2609
static void
 
2610
set_show_seconds_cb (GtkWidget *w,
 
2611
                     ClockData *clock)
 
2612
{
 
2613
        panel_applet_gconf_set_bool (PANEL_APPLET (clock->applet),
 
2614
                                     KEY_SHOW_SECONDS,
 
2615
                                     gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)),
 
2616
                                     NULL);
 
2617
}
 
2618
 
 
2619
static void
 
2620
set_show_date_cb (GtkWidget *w,
 
2621
                  ClockData *clock)
 
2622
{
 
2623
        panel_applet_gconf_set_bool (PANEL_APPLET (clock->applet),
 
2624
                                     KEY_SHOW_DATE,
 
2625
                                     gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)),
 
2626
                                     NULL);
 
2627
}
 
2628
 
 
2629
static void
 
2630
set_show_weather_cb (GtkWidget *w,
 
2631
                     ClockData *clock)
 
2632
{
 
2633
        panel_applet_gconf_set_bool (PANEL_APPLET (clock->applet),
 
2634
                                     KEY_SHOW_WEATHER,
 
2635
                                     gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)),
 
2636
                                     NULL);
 
2637
}
 
2638
 
 
2639
static void
 
2640
set_show_temperature_cb (GtkWidget *w,
 
2641
                         ClockData *clock)
 
2642
{
 
2643
        panel_applet_gconf_set_bool (PANEL_APPLET (clock->applet),
 
2644
                                     KEY_SHOW_TEMPERATURE,
 
2645
                                     gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)),
 
2646
                                     NULL);
 
2647
}
 
2648
 
 
2649
#if 0
 
2650
static void
 
2651
set_show_zones_cb (GtkWidget *w,
 
2652
                   ClockData *clock)
 
2653
{
 
2654
        panel_applet_gconf_set_bool (PANEL_APPLET (clock->applet),
 
2655
                                     KEY_SHOW_ZONES,
 
2656
                                     GTK_TOGGLE_BUTTON (w)->active,
 
2657
                                     NULL);
 
2658
}
 
2659
#endif
 
2660
 
 
2661
/* FIXME old clock applet */
 
2662
#if 0
 
2663
static void
 
2664
set_custom_format_cb (GtkEntry  *entry,
 
2665
                      ClockData *cd)
 
2666
{
 
2667
        /* FMQ: was used from old preferences dialog; fix this up */
 
2668
        const char *custom_format;
 
2669
 
 
2670
        custom_format = gtk_entry_get_text (entry);
 
2671
        panel_applet_gconf_set_string (PANEL_APPLET (cd->applet),
 
2672
                                       KEY_CUSTOM_FORMAT, custom_format, NULL);
 
2673
}
 
2674
#endif
 
2675
 
 
2676
static void
 
2677
prefs_locations_changed (GtkTreeSelection *selection, ClockData *cd)
 
2678
{
 
2679
        gint n;
 
2680
 
 
2681
        n = gtk_tree_selection_count_selected_rows (selection);
 
2682
        gtk_widget_set_sensitive (cd->prefs_location_edit_button, n > 0);
 
2683
        gtk_widget_set_sensitive (cd->prefs_location_remove_button, n > 0);
 
2684
}
 
2685
 
 
2686
static gchar *
 
2687
loc_to_string (ClockLocation *loc)
 
2688
{
 
2689
        const gchar *name, *city;
 
2690
        gfloat latitude, longitude;
 
2691
        gchar *ret;
 
2692
 
 
2693
        name = clock_location_get_name (loc);
 
2694
        city = clock_location_get_city (loc);
 
2695
        clock_location_get_coords (loc, &latitude, &longitude);
 
2696
 
 
2697
        setlocale (LC_NUMERIC, "POSIX");
 
2698
        
 
2699
        ret = g_markup_printf_escaped
 
2700
                ("<location name=\"%s\" city=\"%s\" timezone=\"%s\" latitude=\"%f\" longitude=\"%f\" code=\"%s\" current=\"%s\"/>",
 
2701
                 name ? name : "",
 
2702
                 city ? city : "",
 
2703
                 clock_location_get_timezone (loc),
 
2704
                 latitude, longitude,
 
2705
                 clock_location_get_weather_code (loc),
 
2706
                 clock_location_is_current (loc) ? "true" : "false");
 
2707
 
 
2708
        setlocale (LC_NUMERIC, "");
 
2709
 
 
2710
        return ret;
 
2711
}
 
2712
 
 
2713
static void
 
2714
save_cities_store (ClockData *cd)
 
2715
{
 
2716
        ClockLocation *loc;
 
2717
        GList *node = cd->locations;
 
2718
 
 
2719
        GSList *root = NULL;
 
2720
        GSList *list = NULL;
 
2721
 
 
2722
        while (node) {
 
2723
                loc = CLOCK_LOCATION (node->data);
 
2724
                list = g_slist_prepend (list, loc_to_string (loc));
 
2725
                node = node->next;
 
2726
        }
 
2727
 
 
2728
        list = g_slist_reverse (list);
 
2729
        panel_applet_gconf_set_list (PANEL_APPLET (cd->applet),
 
2730
                                     KEY_CITIES, GCONF_VALUE_STRING, list, NULL);
 
2731
 
 
2732
        root = list;
 
2733
 
 
2734
        while (list) {
 
2735
                g_free (list->data);
 
2736
                list = g_slist_next (list);
 
2737
        }
 
2738
 
 
2739
        g_slist_free (root);
 
2740
}
 
2741
 
 
2742
static void
 
2743
run_prefs_edit_save (GtkButton *button, ClockData *cd)
 
2744
{
 
2745
        GtkWidget *edit_window = _clock_get_widget (cd, "edit-location-window");
 
2746
 
 
2747
        ClockLocation *loc = g_object_get_data (G_OBJECT (edit_window), "clock-location");
 
2748
 
 
2749
        GtkWidget *lat_entry = _clock_get_widget (cd, "edit-location-latitude-entry");
 
2750
        GtkWidget *lon_entry = _clock_get_widget (cd, "edit-location-longitude-entry");
 
2751
        GtkWidget *lat_combo = _clock_get_widget (cd, "edit-location-latitude-combo");
 
2752
        GtkWidget *lon_combo = _clock_get_widget (cd, "edit-location-longitude-combo");
 
2753
 
 
2754
        const gchar *timezone, *weather_code;
 
2755
        gchar *city, *name;
 
2756
 
 
2757
        GWeatherLocation *gloc;
 
2758
        gfloat lat = 0;
 
2759
        gfloat lon = 0;
 
2760
 
 
2761
        timezone = gweather_timezone_menu_get_tzid (cd->zone_combo);
 
2762
        if (!timezone) {
 
2763
                edit_hide (NULL, cd);
 
2764
                return;
 
2765
        }
 
2766
 
 
2767
        city = NULL;
 
2768
        weather_code = NULL;
 
2769
        name = NULL;
 
2770
 
 
2771
        gloc = gweather_location_entry_get_location (cd->location_entry);
 
2772
        if (gloc) {
 
2773
                city = gweather_location_get_city_name (gloc);
 
2774
                weather_code = gweather_location_get_code (gloc);
 
2775
        }
 
2776
 
 
2777
        if (gweather_location_entry_has_custom_text (cd->location_entry)) {
 
2778
                name = gtk_editable_get_chars (GTK_EDITABLE (cd->location_entry), 0, -1);
 
2779
        }
 
2780
 
 
2781
        sscanf (gtk_entry_get_text (GTK_ENTRY (lat_entry)), "%f", &lat);
 
2782
        sscanf (gtk_entry_get_text (GTK_ENTRY (lon_entry)), "%f", &lon);
 
2783
 
 
2784
        if (gtk_combo_box_get_active (GTK_COMBO_BOX (lat_combo)) != 0) {
 
2785
                lat = -lat;
 
2786
        }
 
2787
 
 
2788
        if (gtk_combo_box_get_active (GTK_COMBO_BOX (lon_combo)) != 0) {
 
2789
                lon = -lon;
 
2790
        }
 
2791
 
 
2792
        if (loc) {
 
2793
                clock_location_set_timezone (loc, timezone);
 
2794
                clock_location_set_name (loc, name);
 
2795
                clock_location_set_city (loc, city);
 
2796
                clock_location_set_coords (loc, lat, lon);
 
2797
                clock_location_set_weather_code (loc, weather_code);
 
2798
        } else {
 
2799
                WeatherPrefs prefs;
 
2800
 
 
2801
                prefs.temperature_unit = cd->temperature_unit;
 
2802
                prefs.speed_unit = cd->speed_unit;
 
2803
 
 
2804
                loc = clock_location_new (name, city, timezone, lat, lon, weather_code, &prefs);
 
2805
                /* has the side-effect of setting the current location if
 
2806
                 * there's none and this one can be considered as a current one
 
2807
                 */
 
2808
                clock_location_is_current (loc);
 
2809
 
 
2810
                cd->locations = g_list_append (cd->locations, loc);
 
2811
        }
 
2812
        g_free (name);
 
2813
        g_free (city);
 
2814
 
 
2815
        /* This will update everything related to locations to take into
 
2816
         * account the new location (via the gconf notification) */
 
2817
        save_cities_store (cd);
 
2818
 
 
2819
        edit_hide (edit_window, cd);
 
2820
}
 
2821
 
 
2822
static void
 
2823
update_coords_helper (gfloat value, GtkWidget *entry, GtkWidget *combo)
 
2824
{
 
2825
        gchar *tmp;
 
2826
 
 
2827
        tmp = g_strdup_printf ("%f", fabsf (value));
 
2828
        gtk_entry_set_text (GTK_ENTRY (entry), tmp);
 
2829
        g_free (tmp);
 
2830
 
 
2831
        if (value > 0) {
 
2832
                gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
 
2833
        } else {
 
2834
                gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 1);
 
2835
        }
 
2836
}
 
2837
 
 
2838
static void
 
2839
update_coords (ClockData *cd, gboolean valid, gfloat lat, gfloat lon)
 
2840
{
 
2841
        GtkWidget *lat_entry = _clock_get_widget (cd, "edit-location-latitude-entry");
 
2842
        GtkWidget *lon_entry = _clock_get_widget (cd, "edit-location-longitude-entry");
 
2843
        GtkWidget *lat_combo = _clock_get_widget (cd, "edit-location-latitude-combo");
 
2844
        GtkWidget *lon_combo = _clock_get_widget (cd, "edit-location-longitude-combo");
 
2845
 
 
2846
        if (!valid) {
 
2847
                gtk_entry_set_text (GTK_ENTRY (lat_entry), "");
 
2848
                gtk_entry_set_text (GTK_ENTRY (lon_entry), "");
 
2849
                gtk_combo_box_set_active (GTK_COMBO_BOX (lat_combo), -1);
 
2850
                gtk_combo_box_set_active (GTK_COMBO_BOX (lon_combo), -1);
 
2851
 
 
2852
                return;
 
2853
        }
 
2854
 
 
2855
        update_coords_helper (lat, lat_entry, lat_combo);
 
2856
        update_coords_helper (lon, lon_entry, lon_combo);
 
2857
}
 
2858
 
 
2859
static void
 
2860
fill_timezone_combo_from_location (ClockData *cd, ClockLocation *loc)
 
2861
{
 
2862
        if (loc != NULL) {
 
2863
                gweather_timezone_menu_set_tzid (cd->zone_combo, 
 
2864
                                                 clock_location_get_timezone (loc));
 
2865
        } else {
 
2866
                gweather_timezone_menu_set_tzid (cd->zone_combo, NULL);
 
2867
        }
 
2868
}
 
2869
 
 
2870
static void
 
2871
location_update_ok_sensitivity (ClockData *cd)
 
2872
{
 
2873
        GtkWidget *ok_button;
 
2874
        const gchar *timezone;
 
2875
        gchar *name;
 
2876
 
 
2877
        ok_button = _clock_get_widget (cd, "edit-location-ok-button");
 
2878
 
 
2879
        timezone = gweather_timezone_menu_get_tzid (cd->zone_combo);
 
2880
        name = gtk_editable_get_chars (GTK_EDITABLE (cd->location_entry), 0, -1);
 
2881
 
 
2882
        if (timezone && name && name[0] != '\0') {
 
2883
                gtk_widget_set_sensitive (ok_button, TRUE);
 
2884
        } else {
 
2885
                gtk_widget_set_sensitive (ok_button, FALSE);
 
2886
        }
 
2887
 
 
2888
        g_free (name);
 
2889
}
 
2890
 
 
2891
static void
 
2892
location_changed (GObject *object, GParamSpec *param, ClockData *cd)
 
2893
{
 
2894
        GWeatherLocationEntry *entry = GWEATHER_LOCATION_ENTRY (object);
 
2895
        GWeatherLocation *gloc;
 
2896
        GWeatherTimezone *zone;
 
2897
        gboolean latlon_valid;
 
2898
        double latitude = 0.0, longitude = 0.0;
 
2899
 
 
2900
        gloc = gweather_location_entry_get_location (entry);
 
2901
 
 
2902
        latlon_valid = gloc && gweather_location_has_coords (gloc);
 
2903
        if (latlon_valid)
 
2904
                gweather_location_get_coords (gloc, &latitude, &longitude);
 
2905
        update_coords (cd, latlon_valid, latitude, longitude);
 
2906
 
 
2907
        zone = gloc ? gweather_location_get_timezone (gloc) : NULL;
 
2908
        if (zone)
 
2909
                gweather_timezone_menu_set_tzid (cd->zone_combo, gweather_timezone_get_tzid (zone));
 
2910
        else
 
2911
                gweather_timezone_menu_set_tzid (cd->zone_combo, NULL);
 
2912
 
 
2913
        if (gloc)
 
2914
                gweather_location_unref (gloc);
 
2915
}
 
2916
 
 
2917
static void
 
2918
location_name_changed (GObject *object, ClockData *cd)
 
2919
{
 
2920
    location_update_ok_sensitivity (cd);
 
2921
}
 
2922
 
 
2923
static void
 
2924
location_timezone_changed (GObject *object, GParamSpec *param, ClockData *cd)
 
2925
{
 
2926
    location_update_ok_sensitivity (cd);
 
2927
}
 
2928
 
 
2929
static void
 
2930
edit_clear (ClockData *cd)
 
2931
{
 
2932
        GtkWidget *lat_entry = _clock_get_widget (cd, "edit-location-latitude-entry");
 
2933
        GtkWidget *lon_entry = _clock_get_widget (cd, "edit-location-longitude-entry");
 
2934
        GtkWidget *lat_combo = _clock_get_widget (cd, "edit-location-latitude-combo");
 
2935
        GtkWidget *lon_combo = _clock_get_widget (cd, "edit-location-longitude-combo");
 
2936
 
 
2937
        /* clear out the old data */
 
2938
        gweather_location_entry_set_location (cd->location_entry, NULL);
 
2939
        gweather_timezone_menu_set_tzid (cd->zone_combo, NULL);
 
2940
 
 
2941
        gtk_entry_set_text (GTK_ENTRY (lat_entry), "");
 
2942
        gtk_entry_set_text (GTK_ENTRY (lon_entry), "");
 
2943
 
 
2944
        gtk_combo_box_set_active (GTK_COMBO_BOX (lat_combo), -1);
 
2945
        gtk_combo_box_set_active (GTK_COMBO_BOX (lon_combo), -1);
 
2946
}
 
2947
 
 
2948
static void
 
2949
edit_hide (GtkWidget *unused, ClockData *cd)
 
2950
{
 
2951
        GtkWidget *edit_window = _clock_get_widget (cd, "edit-location-window");
 
2952
 
 
2953
        gtk_widget_hide (edit_window);
 
2954
        edit_clear (cd);
 
2955
}
 
2956
 
 
2957
static gboolean
 
2958
edit_delete (GtkWidget *unused, GdkEvent *event, ClockData *cd)
 
2959
{
 
2960
        edit_hide (unused, cd);
 
2961
 
 
2962
        return TRUE;
 
2963
}
 
2964
 
 
2965
static gboolean
 
2966
edit_hide_event (GtkWidget *widget, GdkEvent *event, ClockData *cd)
 
2967
{
 
2968
        edit_hide (widget, cd);
 
2969
 
 
2970
        return TRUE;
 
2971
}
 
2972
 
 
2973
static void
 
2974
prefs_hide (GtkWidget *widget, ClockData *cd)
 
2975
{
 
2976
        GtkWidget *tree;
 
2977
 
 
2978
        edit_hide (widget, cd);
 
2979
 
 
2980
        gtk_widget_hide (cd->prefs_window);
 
2981
 
 
2982
        tree = _clock_get_widget (cd, "cities_list");
 
2983
 
 
2984
        gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree)));
 
2985
 
 
2986
        refresh_click_timeout_time_only (cd);
 
2987
}
 
2988
 
 
2989
static gboolean
 
2990
prefs_hide_event (GtkWidget *widget, GdkEvent *event, ClockData *cd)
 
2991
{
 
2992
        prefs_hide (widget, cd);
 
2993
 
 
2994
        return TRUE;
 
2995
}
 
2996
 
 
2997
static void
 
2998
prefs_help (GtkWidget *widget, ClockData *cd)
 
2999
{
 
3000
        clock_utils_display_help (cd->prefs_window,
 
3001
                                  "clock", "clock-settings");
 
3002
}
 
3003
 
 
3004
static void
 
3005
remove_tree_row (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
 
3006
{
 
3007
        ClockData *cd = data;
 
3008
        ClockLocation *loc = NULL;
 
3009
 
 
3010
        gtk_tree_model_get (model, iter, COL_CITY_LOC, &loc, -1);
 
3011
        cd->locations = g_list_remove (cd->locations, loc);
 
3012
        g_object_unref (loc);
 
3013
 
 
3014
        /* This will update everything related to locations to take into
 
3015
         * account the removed location (via the gconf notification) */
 
3016
        save_cities_store (cd);
 
3017
}
 
3018
 
 
3019
static void
 
3020
run_prefs_locations_remove (GtkButton *button, ClockData *cd)
 
3021
{
 
3022
        GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (cd->prefs_locations));
 
3023
 
 
3024
        gtk_tree_selection_selected_foreach (sel, remove_tree_row, cd);
 
3025
}
 
3026
 
 
3027
static void
 
3028
run_prefs_locations_add (GtkButton *button, ClockData *cd)
 
3029
{
 
3030
        GtkWidget *edit_window = _clock_get_widget (cd, "edit-location-window");
 
3031
 
 
3032
        fill_timezone_combo_from_location (cd, NULL);
 
3033
 
 
3034
        g_object_set_data (G_OBJECT (edit_window), "clock-location", NULL);
 
3035
        gtk_window_set_title (GTK_WINDOW (edit_window), _("Choose Location"));
 
3036
        gtk_window_set_transient_for (GTK_WINDOW (edit_window), GTK_WINDOW (cd->prefs_window));
 
3037
 
 
3038
        if (g_object_get_data (G_OBJECT (edit_window), "delete-handler") == NULL) {
 
3039
                g_object_set_data (G_OBJECT (edit_window), "delete-handler",
 
3040
                                   GINT_TO_POINTER (g_signal_connect (edit_window, "delete_event", G_CALLBACK (edit_delete), cd)));
 
3041
        }
 
3042
 
 
3043
        location_update_ok_sensitivity (cd);
 
3044
 
 
3045
        gtk_widget_grab_focus (GTK_WIDGET (cd->location_entry));
 
3046
        gtk_editable_set_position (GTK_EDITABLE (cd->location_entry), -1);
 
3047
 
 
3048
        gtk_window_present_with_time (GTK_WINDOW (edit_window), gtk_get_current_event_time ());
 
3049
}
 
3050
 
 
3051
static void
 
3052
edit_tree_row (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
 
3053
{
 
3054
        ClockData *cd = data;
 
3055
        ClockLocation *loc;
 
3056
        const char *name;
 
3057
        gchar *tmp;
 
3058
        gfloat lat, lon;
 
3059
 
 
3060
        /* fill the dialog with this location's data, show it */
 
3061
        GtkWidget *edit_window = _clock_get_widget (cd, "edit-location-window");
 
3062
 
 
3063
        GtkWidget *lat_entry = _clock_get_widget (cd, "edit-location-latitude-entry");
 
3064
 
 
3065
        GtkWidget *lon_entry = _clock_get_widget (cd, "edit-location-longitude-entry");
 
3066
 
 
3067
        GtkWidget *lat_combo = _clock_get_widget (cd, "edit-location-latitude-combo");
 
3068
 
 
3069
        GtkWidget *lon_combo = _clock_get_widget (cd, "edit-location-longitude-combo");
 
3070
 
 
3071
        edit_clear (cd);
 
3072
 
 
3073
        gtk_tree_model_get (model, iter, COL_CITY_LOC, &loc, -1);
 
3074
 
 
3075
        gweather_location_entry_set_city (cd->location_entry,
 
3076
                                          clock_location_get_city (loc),
 
3077
                                          clock_location_get_weather_code (loc));
 
3078
        name = clock_location_get_name (loc);
 
3079
        if (name && name[0]) {
 
3080
                gtk_entry_set_text (GTK_ENTRY (cd->location_entry), name);
 
3081
        }
 
3082
 
 
3083
        clock_location_get_coords (loc, &lat, &lon);
 
3084
 
 
3085
        fill_timezone_combo_from_location (cd, loc);
 
3086
 
 
3087
        tmp = g_strdup_printf ("%f", fabsf(lat));
 
3088
        gtk_entry_set_text (GTK_ENTRY (lat_entry), tmp);
 
3089
        g_free (tmp);
 
3090
 
 
3091
        if (lat > 0) {
 
3092
                gtk_combo_box_set_active (GTK_COMBO_BOX (lat_combo), 0);
 
3093
        } else {
 
3094
                gtk_combo_box_set_active (GTK_COMBO_BOX (lat_combo), 1);
 
3095
        }
 
3096
 
 
3097
        tmp = g_strdup_printf ("%f", fabsf(lon));
 
3098
        gtk_entry_set_text (GTK_ENTRY (lon_entry), tmp);
 
3099
        g_free (tmp);
 
3100
 
 
3101
        if (lon > 0) {
 
3102
                gtk_combo_box_set_active (GTK_COMBO_BOX (lon_combo), 0);
 
3103
        } else {
 
3104
                gtk_combo_box_set_active (GTK_COMBO_BOX (lon_combo), 1);
 
3105
        }
 
3106
 
 
3107
        location_update_ok_sensitivity (cd);
 
3108
 
 
3109
        g_object_set_data (G_OBJECT (edit_window), "clock-location", loc);
 
3110
 
 
3111
        gtk_widget_grab_focus (GTK_WIDGET (cd->location_entry));
 
3112
        gtk_editable_set_position (GTK_EDITABLE (cd->location_entry), -1);
 
3113
 
 
3114
        gtk_window_set_title (GTK_WINDOW (edit_window), _("Edit Location"));
 
3115
        gtk_window_present (GTK_WINDOW (edit_window));
 
3116
}
 
3117
 
 
3118
static void
 
3119
run_prefs_locations_edit (GtkButton *unused, ClockData *cd)
 
3120
{
 
3121
        GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (cd->prefs_locations));
 
3122
 
 
3123
        gtk_tree_selection_selected_foreach (sel, edit_tree_row, cd);
 
3124
}
 
3125
 
 
3126
static void
 
3127
set_12hr_format_radio_cb (GtkWidget *widget, ClockData *cd)
 
3128
{
 
3129
        const gchar *val;
 
3130
        ClockFormat format;
 
3131
 
 
3132
        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
 
3133
                format = CLOCK_FORMAT_12;
 
3134
        else
 
3135
                format = CLOCK_FORMAT_24;
 
3136
 
 
3137
        val = gconf_enum_to_string (format_type_enum_map, format);
 
3138
 
 
3139
        panel_applet_gconf_set_string (PANEL_APPLET (cd->applet),
 
3140
                                       KEY_FORMAT, val, NULL);
 
3141
}
 
3142
 
 
3143
static void
 
3144
temperature_combo_changed (GtkComboBox *combo, ClockData *cd)
 
3145
{
 
3146
        int value;
 
3147
        int old_value;
 
3148
        const gchar *str;
 
3149
 
 
3150
        value = gtk_combo_box_get_active (combo) + 1;
 
3151
 
 
3152
        if (cd->use_temperature_default)
 
3153
                old_value = TEMP_UNIT_DEFAULT;
 
3154
        else
 
3155
                old_value = cd->temperature_unit;
 
3156
 
 
3157
        if (value == old_value)
 
3158
                return;
 
3159
 
 
3160
        str = gweather_prefs_temp_enum_to_string (value);
 
3161
 
 
3162
        panel_applet_gconf_set_string (PANEL_APPLET (cd->applet),
 
3163
                                       KEY_TEMPERATURE_UNIT, str, NULL);
 
3164
}
 
3165
 
 
3166
static void
 
3167
speed_combo_changed (GtkComboBox *combo, ClockData *cd)
 
3168
{
 
3169
        int value;
 
3170
        int old_value;
 
3171
        const gchar *str;
 
3172
 
 
3173
        value = gtk_combo_box_get_active (combo) + 1;
 
3174
 
 
3175
        if (cd->use_speed_default)
 
3176
                old_value = SPEED_UNIT_DEFAULT;
 
3177
        else
 
3178
                old_value = cd->speed_unit;
 
3179
 
 
3180
        if (value == old_value)
 
3181
                return;
 
3182
 
 
3183
        str = gweather_prefs_speed_enum_to_string (value);
 
3184
 
 
3185
        panel_applet_gconf_set_string (PANEL_APPLET (cd->applet),
 
3186
                                       KEY_SPEED_UNIT, str, NULL);
 
3187
}
 
3188
 
 
3189
static void
 
3190
fill_prefs_window (ClockData *cd)
 
3191
{
 
3192
        static const int temperatures[] = {
 
3193
                TEMP_UNIT_DEFAULT,
 
3194
                TEMP_UNIT_KELVIN,
 
3195
                TEMP_UNIT_CENTIGRADE,
 
3196
                TEMP_UNIT_FAHRENHEIT,
 
3197
                -1
 
3198
        };
 
3199
 
 
3200
        static const int speeds[] = {
 
3201
                SPEED_UNIT_DEFAULT,
 
3202
                SPEED_UNIT_MS,
 
3203
                SPEED_UNIT_KPH,
 
3204
                SPEED_UNIT_MPH,
 
3205
                SPEED_UNIT_KNOTS,
 
3206
                SPEED_UNIT_BFT,
 
3207
                -1
 
3208
        };
 
3209
 
 
3210
        GtkWidget *radio_12hr;
 
3211
        GtkWidget *radio_24hr;
 
3212
        GtkWidget *widget;
 
3213
        GtkCellRenderer *renderer;
 
3214
        GtkTreeViewColumn *col;
 
3215
        GtkListStore *store;
 
3216
        GtkTreeIter iter;
 
3217
        int i;
 
3218
 
 
3219
        /* Set the 12 hour / 24 hour widget */
 
3220
        radio_12hr = _clock_get_widget (cd, "12hr_radio");
 
3221
        radio_24hr = _clock_get_widget (cd, "24hr_radio");
 
3222
 
 
3223
        if (cd->format == CLOCK_FORMAT_12)
 
3224
                widget = radio_12hr;
 
3225
        else
 
3226
                widget = radio_24hr;
 
3227
 
 
3228
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
 
3229
 
 
3230
        g_signal_connect (radio_12hr, "toggled",
 
3231
                          G_CALLBACK (set_12hr_format_radio_cb), cd);
 
3232
 
 
3233
        /* Set the "Show Date" checkbox */
 
3234
        widget = _clock_get_widget (cd, "date_check");
 
3235
        g_signal_connect (widget, "toggled",
 
3236
                          G_CALLBACK (set_show_date_cb), cd);
 
3237
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), cd->showdate);
 
3238
 
 
3239
        /* Set the "Show Seconds" checkbox */
 
3240
        widget = _clock_get_widget (cd, "seconds_check");
 
3241
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), cd->showseconds);
 
3242
        g_signal_connect (widget, "toggled",
 
3243
                          G_CALLBACK (set_show_seconds_cb), cd);
 
3244
 
 
3245
        /* Set the "Show weather" checkbox */
 
3246
        widget = _clock_get_widget (cd, "weather_check");
 
3247
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), cd->show_weather);
 
3248
        g_signal_connect (widget, "toggled",
 
3249
                          G_CALLBACK (set_show_weather_cb), cd);
 
3250
 
 
3251
        /* Set the "Show temperature" checkbox */
 
3252
        widget = _clock_get_widget (cd, "temperature_check");
 
3253
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), cd->show_temperature);
 
3254
        g_signal_connect (widget, "toggled",
 
3255
                          G_CALLBACK (set_show_temperature_cb), cd);
 
3256
 
 
3257
        /* Fill the Cities list */
 
3258
        widget = _clock_get_widget (cd, "cities_list");
 
3259
 
 
3260
        renderer = gtk_cell_renderer_text_new ();
 
3261
        col = gtk_tree_view_column_new_with_attributes (_("City Name"), renderer, "text", COL_CITY_NAME, NULL);
 
3262
        gtk_tree_view_insert_column (GTK_TREE_VIEW (widget), col, -1);
 
3263
 
 
3264
        renderer = gtk_cell_renderer_text_new ();
 
3265
        col = gtk_tree_view_column_new_with_attributes (_("City Time Zone"), renderer, "text", COL_CITY_TZ, NULL);
 
3266
        gtk_tree_view_insert_column (GTK_TREE_VIEW (widget), col, -1);
 
3267
        
 
3268
        if (cd->cities_store == NULL)
 
3269
                create_cities_store (cd);
 
3270
 
 
3271
        gtk_tree_view_set_model (GTK_TREE_VIEW (widget),
 
3272
                                 GTK_TREE_MODEL (cd->cities_store));
 
3273
 
 
3274
        /* Temperature combo */
 
3275
        widget = _clock_get_widget (cd, "temperature_combo");
 
3276
        store = gtk_list_store_new (1, G_TYPE_STRING);
 
3277
        gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (store));
 
3278
        renderer = gtk_cell_renderer_text_new ();
 
3279
        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), renderer, TRUE);
 
3280
        gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (widget), renderer, "text", 0, NULL);
 
3281
 
 
3282
        for (i = 0; temperatures[i] != -1; i++)
 
3283
                gtk_list_store_insert_with_values (store, &iter, -1,
 
3284
                                                   0, gweather_prefs_get_temp_display_name (temperatures[i]),
 
3285
                                                   -1);
 
3286
 
 
3287
        update_temperature_combo (cd);
 
3288
        g_signal_connect (widget, "changed",
 
3289
                          G_CALLBACK (temperature_combo_changed), cd);
 
3290
 
 
3291
        /* Wind speed combo */
 
3292
        widget = _clock_get_widget (cd, "wind_speed_combo");
 
3293
        store = gtk_list_store_new (1, G_TYPE_STRING);
 
3294
        gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (store));
 
3295
        renderer = gtk_cell_renderer_text_new ();
 
3296
        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), renderer, TRUE);
 
3297
        gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (widget), renderer, "text", 0, NULL);
 
3298
 
 
3299
        for (i = 0; speeds[i] != -1; i++)
 
3300
                gtk_list_store_insert_with_values (store, &iter, -1,
 
3301
                                                   0, gweather_prefs_get_speed_display_name (speeds[i]),
 
3302
                                                   -1);
 
3303
 
 
3304
        update_speed_combo (cd);
 
3305
        g_signal_connect (widget, "changed",
 
3306
                          G_CALLBACK (speed_combo_changed), cd);
 
3307
}
 
3308
 
 
3309
static void
 
3310
ensure_prefs_window_is_created (ClockData *cd)
 
3311
{
 
3312
        GtkWidget *edit_window;
 
3313
        GtkWidget *prefs_close_button;
 
3314
        GtkWidget *prefs_help_button;
 
3315
        GtkWidget *clock_options;
 
3316
        GtkWidget *edit_cancel_button;
 
3317
        GtkWidget *edit_ok_button;
 
3318
        GtkWidget *location_box;
 
3319
        GtkWidget *zone_box;
 
3320
        GtkWidget *location_name_label;
 
3321
        GtkWidget *timezone_label;
 
3322
        GtkTreeSelection *selection;
 
3323
        GWeatherLocation *world;
 
3324
 
 
3325
        if (cd->prefs_window)
 
3326
                return;
 
3327
 
 
3328
        cd->prefs_window = _clock_get_widget (cd, "prefs-window");
 
3329
 
 
3330
        gtk_window_set_icon_name (GTK_WINDOW (cd->prefs_window), CLOCK_ICON);
 
3331
 
 
3332
        prefs_close_button = _clock_get_widget (cd, "prefs-close-button");
 
3333
        prefs_help_button = _clock_get_widget (cd, "prefs-help-button");
 
3334
        clock_options = _clock_get_widget (cd, "clock-options");
 
3335
        cd->prefs_locations = GTK_TREE_VIEW (_clock_get_widget (cd, "cities_list"));
 
3336
        location_name_label = _clock_get_widget (cd, "location-name-label");
 
3337
        timezone_label = _clock_get_widget (cd, "timezone-label");
 
3338
 
 
3339
 
 
3340
        if (!clock_locale_supports_am_pm ())
 
3341
                gtk_widget_hide (clock_options);
 
3342
 
 
3343
        selection = gtk_tree_view_get_selection (cd->prefs_locations);
 
3344
        g_signal_connect (G_OBJECT (selection), "changed",
 
3345
                          G_CALLBACK (prefs_locations_changed), cd);
 
3346
 
 
3347
        g_signal_connect (G_OBJECT (cd->prefs_window), "delete_event",
 
3348
                          G_CALLBACK (prefs_hide_event), cd);
 
3349
 
 
3350
        g_signal_connect (G_OBJECT (prefs_close_button), "clicked",
 
3351
                          G_CALLBACK (prefs_hide), cd);
 
3352
 
 
3353
        g_signal_connect (G_OBJECT (prefs_help_button), "clicked",
 
3354
                          G_CALLBACK (prefs_help), cd);
 
3355
 
 
3356
        cd->prefs_location_remove_button = _clock_get_widget (cd, "prefs-locations-remove-button");
 
3357
 
 
3358
        g_signal_connect (G_OBJECT (cd->prefs_location_remove_button), "clicked",
 
3359
                          G_CALLBACK (run_prefs_locations_remove), cd);
 
3360
 
 
3361
        cd->prefs_location_add_button = _clock_get_widget (cd, "prefs-locations-add-button");
 
3362
 
 
3363
        g_signal_connect (G_OBJECT (cd->prefs_location_add_button), "clicked",
 
3364
                          G_CALLBACK (run_prefs_locations_add), cd);
 
3365
 
 
3366
        cd->prefs_location_edit_button = _clock_get_widget (cd, "prefs-locations-edit-button");
 
3367
 
 
3368
        g_signal_connect (G_OBJECT (cd->prefs_location_edit_button), "clicked",
 
3369
                          G_CALLBACK (run_prefs_locations_edit), cd);
 
3370
 
 
3371
        edit_window = _clock_get_widget (cd, "edit-location-window");
 
3372
 
 
3373
        gtk_window_set_transient_for (GTK_WINDOW (edit_window),
 
3374
                                      GTK_WINDOW (cd->prefs_window));
 
3375
 
 
3376
        g_signal_connect (G_OBJECT (edit_window), "delete_event",
 
3377
                          G_CALLBACK (edit_hide_event), cd);
 
3378
 
 
3379
        edit_cancel_button = _clock_get_widget (cd, "edit-location-cancel-button");
 
3380
 
 
3381
        edit_ok_button = _clock_get_widget (cd, "edit-location-ok-button");
 
3382
 
 
3383
        world = gweather_location_new_world (FALSE);
 
3384
 
 
3385
        location_box = _clock_get_widget (cd, "edit-location-name-box");
 
3386
        cd->location_entry = GWEATHER_LOCATION_ENTRY (gweather_location_entry_new (world));
 
3387
        gtk_widget_show (GTK_WIDGET (cd->location_entry));
 
3388
        gtk_container_add (GTK_CONTAINER (location_box), GTK_WIDGET (cd->location_entry));
 
3389
        gtk_label_set_mnemonic_widget (GTK_LABEL (location_name_label),
 
3390
                                       GTK_WIDGET (cd->location_entry));
 
3391
 
 
3392
        g_signal_connect (G_OBJECT (cd->location_entry), "notify::location",
 
3393
                          G_CALLBACK (location_changed), cd);
 
3394
        g_signal_connect (G_OBJECT (cd->location_entry), "changed",
 
3395
                          G_CALLBACK (location_name_changed), cd);
 
3396
 
 
3397
        zone_box = _clock_get_widget (cd, "edit-location-timezone-box");
 
3398
        cd->zone_combo = GWEATHER_TIMEZONE_MENU (gweather_timezone_menu_new (world));
 
3399
        gtk_widget_show (GTK_WIDGET (cd->zone_combo));
 
3400
        gtk_container_add (GTK_CONTAINER (zone_box), GTK_WIDGET (cd->zone_combo));
 
3401
        gtk_label_set_mnemonic_widget (GTK_LABEL (timezone_label),
 
3402
                                       GTK_WIDGET (cd->zone_combo));
 
3403
 
 
3404
        g_signal_connect (G_OBJECT (cd->zone_combo), "notify::tzid",
 
3405
                          G_CALLBACK (location_timezone_changed), cd);
 
3406
 
 
3407
        gweather_location_unref (world);
 
3408
 
 
3409
        g_signal_connect (G_OBJECT (edit_cancel_button), "clicked",
 
3410
                          G_CALLBACK (edit_hide), cd);
 
3411
 
 
3412
        g_signal_connect (G_OBJECT (edit_ok_button), "clicked",
 
3413
                          G_CALLBACK (run_prefs_edit_save), cd);
 
3414
 
 
3415
        /* Set up the time setting section */
 
3416
 
 
3417
        cd->time_settings_button = _clock_get_widget (cd, "time-settings-button");
 
3418
        g_signal_connect (cd->time_settings_button, "clicked",
 
3419
                          G_CALLBACK (run_time_settings), cd);
 
3420
 
 
3421
        /* fill it with the current preferences */
 
3422
        fill_prefs_window (cd);
 
3423
}
 
3424
 
 
3425
static void
 
3426
display_properties_dialog (ClockData *cd, gboolean start_in_locations_page)
 
3427
{
 
3428
        ensure_prefs_window_is_created (cd);
 
3429
 
 
3430
        if (start_in_locations_page) {
 
3431
                GtkWidget *notebook = _clock_get_widget (cd, "notebook");
 
3432
                gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 1);
 
3433
        }
 
3434
 
 
3435
        update_set_time_button (cd);
 
3436
 
 
3437
        gtk_window_set_screen (GTK_WINDOW (cd->prefs_window),
 
3438
                               gtk_widget_get_screen (cd->applet));
 
3439
        gtk_window_present (GTK_WINDOW (cd->prefs_window));
 
3440
 
 
3441
        refresh_click_timeout_time_only (cd);
 
3442
 
 
3443
        /* FMQ: cd->props was the old preferences window; remove references to it */
 
3444
        /* FMQ: connect to the Help button by hand; look at properties_response_cb() for the help code */
 
3445
#if 0
 
3446
        /* FMQ: check the code below; replace the proper parts */
 
3447
        GtkWidget *hbox;
 
3448
        GtkWidget *vbox;
 
3449
        GtkWidget *combo;
 
3450
        GtkWidget *label;
 
3451
 
 
3452
        gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("24 hour"));
 
3453
        gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("UNIX time"));
 
3454
        gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Internet time"));
 
3455
 
 
3456
        gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
 
3457
        gtk_widget_show (combo);
 
3458
 
 
3459
        cd->custom_hbox = gtk_hbox_new (FALSE, 12);
 
3460
        gtk_box_pack_start (GTK_BOX (vbox), cd->custom_hbox, TRUE, TRUE, 0);
 
3461
 
 
3462
        cd->custom_label = gtk_label_new_with_mnemonic (_("Custom _format:"));
 
3463
        gtk_label_set_use_markup (GTK_LABEL (cd->custom_label), TRUE);
 
3464
        gtk_label_set_justify (GTK_LABEL (cd->custom_label),
 
3465
                               GTK_JUSTIFY_LEFT);
 
3466
        gtk_misc_set_alignment (GTK_MISC (cd->custom_label), 0, 0.5);
 
3467
        gtk_box_pack_start (GTK_BOX (cd->custom_hbox),
 
3468
                            cd->custom_label,
 
3469
                            FALSE, FALSE, 0);
 
3470
 
 
3471
        cd->custom_entry = gtk_entry_new ();
 
3472
        gtk_box_pack_start (GTK_BOX (cd->custom_hbox),
 
3473
                            cd->custom_entry,
 
3474
                            FALSE, FALSE, 0);
 
3475
        gtk_entry_set_text (GTK_ENTRY (cd->custom_entry),
 
3476
                            cd->custom_format);
 
3477
        g_signal_connect (cd->custom_entry, "changed",
 
3478
                          G_CALLBACK (set_custom_format_cb),
 
3479
                          cd);
 
3480
 
 
3481
        g_signal_connect (cd->props, "destroy",
 
3482
                          G_CALLBACK (gtk_widget_destroyed),
 
3483
                          &cd->props);
 
3484
        g_signal_connect (cd->props, "response",
 
3485
                          G_CALLBACK (properties_response_cb),
 
3486
                          cd);
 
3487
 
 
3488
        cd->custom_format_shown = FALSE;
 
3489
        update_properties_for_format (cd, GTK_COMBO_BOX (combo), cd->format);
 
3490
 
 
3491
        /* valid values begin from 1 */
 
3492
        if (cd->can_handle_format_12)
 
3493
                gtk_combo_box_set_active (GTK_COMBO_BOX (combo),
 
3494
                                          cd->format - 1);
 
3495
        else
 
3496
                gtk_combo_box_set_active (GTK_COMBO_BOX (combo),
 
3497
                                          cd->format - 2);
 
3498
 
 
3499
        g_signal_connect (combo, "changed",
 
3500
                          G_CALLBACK (set_format_cb), cd);
 
3501
 
 
3502
        /* Now set up the sensitivity based on gconf key writability */
 
3503
        setup_writability_sensitivity (cd, combo, label, KEY_FORMAT);
 
3504
        setup_writability_sensitivity (cd, cd->custom_entry, cd->custom_label,
 
3505
                                       KEY_CUSTOM_FORMAT);
 
3506
        setup_writability_sensitivity (cd, cd->showseconds_check, NULL, KEY_SHOW_SECONDS);
 
3507
        setup_writability_sensitivity (cd, cd->showdate_check, NULL, KEY_SHOW_DATE);
 
3508
 
 
3509
        gtk_widget_show (cd->props);
 
3510
#endif
 
3511
}
 
3512
 
 
3513
static void
 
3514
verb_display_properties_dialog (GtkAction *action,
 
3515
                                ClockData *cd)
 
3516
{
 
3517
        display_properties_dialog (cd, FALSE);
 
3518
}
 
3519
 
 
3520
static gboolean
 
3521
clock_factory (PanelApplet *applet,
 
3522
               const char  *iid,
 
3523
               gpointer     data)
 
3524
{
 
3525
        gboolean retval = FALSE;
 
3526
 
 
3527
        if (!strcmp (iid, "ClockApplet"))
 
3528
                retval = fill_clock_applet (applet);
 
3529
 
 
3530
        return retval;
 
3531
}
 
3532
 
 
3533
#ifdef CLOCK_INPROCESS
 
3534
PANEL_APPLET_IN_PROCESS_FACTORY ("ClockAppletFactory",
 
3535
                                 PANEL_TYPE_APPLET,
 
3536
                                 clock_factory,
 
3537
                                 NULL)
 
3538
#else
 
3539
PANEL_APPLET_OUT_PROCESS_FACTORY ("ClockAppletFactory",
 
3540
                                  PANEL_TYPE_APPLET,
 
3541
                                  clock_factory,
 
3542
                                  NULL)
 
3543
#endif