~ubuntu-branches/ubuntu/wily/alarm-clock-applet/wily

« back to all changes in this revision

Viewing changes to src/alarm.c

  • Committer: Bazaar Package Importer
  • Author(s): Chow Loong Jin
  • Date: 2009-05-30 23:24:27 UTC
  • Revision ID: james.westby@ubuntu.com-20090530232427-88on1j2ily4ajxdz
Tags: upstream-0.2.6
ImportĀ upstreamĀ versionĀ 0.2.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * alarm.c -- Core alarm functionality
 
3
 * 
 
4
 * Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
 
5
 * 
 
6
 * This program is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU General Public License
 
8
 * as published by the Free Software Foundation; either version 2
 
9
 * of the License, or (at your option) any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
19
 * 
 
20
 * Authors:
 
21
 *              Johannes H. Jensen <joh@pseudoberries.com>
 
22
 */
 
23
 
 
24
#include <stdio.h>
 
25
#include <time.h>
 
26
#include <string.h>
 
27
 
 
28
#include "alarm.h"
 
29
 
 
30
G_DEFINE_TYPE (Alarm, alarm, G_TYPE_OBJECT);
 
31
 
 
32
/* Prototypes and constants for property manipulation */
 
33
static void alarm_set_property(GObject *object,
 
34
                               guint prop_id,
 
35
                               const GValue *value,
 
36
                               GParamSpec *pspec);
 
37
 
 
38
static void alarm_get_property(GObject *object,
 
39
                               guint prop_id,
 
40
                               GValue *value,
 
41
                               GParamSpec *pspec);
 
42
 
 
43
static void alarm_constructed (GObject *object);
 
44
 
 
45
static void alarm_dispose (GObject *object);
 
46
 
 
47
static void alarm_gconf_associate_schemas (Alarm *alarm);
 
48
 
 
49
static void alarm_gconf_connect (Alarm *alarm);
 
50
 
 
51
static void alarm_gconf_disconnect (Alarm *alarm);
 
52
 
 
53
static void alarm_gconf_dir_changed (GConfClient *client,
 
54
                                                                         guint cnxn_id,
 
55
                                                                         GConfEntry *entry,
 
56
                                                                         gpointer data);
 
57
 
 
58
static void alarm_timer_start (Alarm *alarm);
 
59
static void alarm_timer_remove (Alarm *alarm);
 
60
static gboolean alarm_timer_is_started (Alarm *alarm);
 
61
 
 
62
static void alarm_player_start (Alarm *alarm);
 
63
static void alarm_player_stop (Alarm *alarm);
 
64
static void alarm_command_run (Alarm *alarm);
 
65
 
 
66
#define ALARM_PRIVATE(o) \
 
67
  (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_ALARM, AlarmPrivate))
 
68
 
 
69
typedef struct _AlarmPrivate AlarmPrivate;
 
70
 
 
71
struct _AlarmPrivate
 
72
{
 
73
        GConfClient *gconf_client;
 
74
        guint gconf_listener;
 
75
        guint timer_id;
 
76
        MediaPlayer *player;
 
77
        guint player_timer_id;
 
78
};
 
79
 
 
80
 
 
81
static GConfEnumStringPair alarm_type_enum_map [] = {
 
82
        { ALARM_TYPE_CLOCK,             "clock" },
 
83
        { ALARM_TYPE_TIMER,             "timer" },
 
84
        { 0, NULL }
 
85
};
 
86
 
 
87
static GConfEnumStringPair alarm_repeat_enum_map [] = {
 
88
        { ALARM_REPEAT_SUN,     "sun" },
 
89
        { ALARM_REPEAT_MON,     "mon" },
 
90
        { ALARM_REPEAT_TUE,     "tue" },
 
91
        { ALARM_REPEAT_WED,     "wed" },
 
92
        { ALARM_REPEAT_THU,     "thu" },
 
93
        { ALARM_REPEAT_FRI,     "fri" },
 
94
        { ALARM_REPEAT_SAT,     "sat" },
 
95
        { 0, NULL }
 
96
};
 
97
 
 
98
static GConfEnumStringPair alarm_notify_type_enum_map [] = {
 
99
        { ALARM_NOTIFY_SOUND,   "sound"  },
 
100
        { ALARM_NOTIFY_COMMAND, "command" },
 
101
        { 0, NULL }
 
102
};
 
103
 
 
104
/* Property indexes */
 
105
static enum {
 
106
        PROP_ALARM_0,
 
107
        PROP_DIR,
 
108
        PROP_ID,
 
109
        PROP_TYPE,
 
110
        PROP_TIME,
 
111
        PROP_TIMESTAMP,
 
112
        PROP_ACTIVE,
 
113
        PROP_MESSAGE,
 
114
        PROP_REPEAT,
 
115
        PROP_SNOOZE,
 
116
        PROP_NOTIFY_TYPE,
 
117
        PROP_SOUND_FILE,
 
118
        PROP_SOUND_LOOP,
 
119
        PROP_COMMAND,
 
120
        PROP_NOTIFY_BUBBLE
 
121
} AlarmProp;
 
122
 
 
123
#define PROP_NAME_DIR                   "gconf-dir"
 
124
#define PROP_NAME_ID                    "id"
 
125
#define PROP_NAME_TYPE                  "type"
 
126
#define PROP_NAME_TIME                  "time"
 
127
#define PROP_NAME_TIMESTAMP             "timestamp"
 
128
#define PROP_NAME_ACTIVE                "active"
 
129
#define PROP_NAME_MESSAGE               "message"
 
130
#define PROP_NAME_REPEAT                "repeat"
 
131
#define PROP_NAME_SNOOZE                "snooze"
 
132
#define PROP_NAME_NOTIFY_TYPE   "notify_type"
 
133
#define PROP_NAME_SOUND_FILE    "sound_file"
 
134
#define PROP_NAME_SOUND_LOOP    "sound_repeat"
 
135
#define PROP_NAME_COMMAND               "command"
 
136
#define PROP_NAME_NOTIFY_BUBBLE "notify_bubble"
 
137
 
 
138
/* Signal indexes */
 
139
static enum
 
140
{
 
141
  SIGNAL_ALARM,
 
142
  SIGNAL_ERROR,
 
143
  SIGNAL_PLAYER,
 
144
  LAST_SIGNAL
 
145
} AlarmSignal;
 
146
 
 
147
/* Signal identifier map */
 
148
static guint alarm_signal[LAST_SIGNAL] = {0, 0, 0};
 
149
 
 
150
/* Prototypes for signal handlers */
 
151
static void alarm_alarm (Alarm *alarm);
 
152
static void alarm_error (Alarm *alarm, GError *err);
 
153
static void alarm_player_changed (Alarm *alarm, MediaPlayerState state);
 
154
 
 
155
/* For debugging purposes only */
 
156
static void
 
157
dump_list (GSList *list)
 
158
{
 
159
        GSList *l;
 
160
        
 
161
        g_print ("[ ");
 
162
        for (l = list; l; l = l->next) {
 
163
                g_print ("%s", (gchar *)l->data);
 
164
                if (l->next)
 
165
                        g_print (", ");
 
166
        }
 
167
        g_print (" ]");
 
168
}
 
169
 
 
170
 
 
171
/* Initialize the Alarm class */
 
172
static void 
 
173
alarm_class_init (AlarmClass *class)
 
174
{
 
175
        GParamSpec *dir_param;
 
176
        GParamSpec *id_param;
 
177
        GParamSpec *type_param;
 
178
        GParamSpec *time_param;
 
179
        GParamSpec *timestamp_param;
 
180
        GParamSpec *active_param;
 
181
        GParamSpec *message_param;
 
182
        GParamSpec *repeat_param;
 
183
        GParamSpec *snooze_param;
 
184
        GParamSpec *notify_type_param;
 
185
        GParamSpec *sound_file_param;
 
186
        GParamSpec *sound_loop_param;
 
187
        GParamSpec *command_param;
 
188
        GParamSpec *notify_bubble_param;
 
189
        
 
190
        GObjectClass *g_object_class;
 
191
 
 
192
        /* get handle to base object */
 
193
        g_object_class = G_OBJECT_CLASS (class);
 
194
 
 
195
        /* << miscellaneous initialization >> */
 
196
 
 
197
        /* create GParamSpec descriptions for properties */
 
198
        dir_param = g_param_spec_string (PROP_NAME_DIR,
 
199
                                                                         "GConf dir",
 
200
                                                                         "GConf base directory",
 
201
                                                                         NULL,
 
202
                                                                         G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
 
203
        
 
204
        id_param = g_param_spec_uint (PROP_NAME_ID,
 
205
                                                                  "alarm id",
 
206
                                                                  "id of the alarm",
 
207
                                                                  0,            /* min */
 
208
                                                                  UINT_MAX,     /* max */
 
209
                                                                  0,            /* default */
 
210
                                                                  G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
 
211
        
 
212
        type_param = g_param_spec_uint (PROP_NAME_TYPE,
 
213
                                                                        "alarm type",
 
214
                                                                        "type of the alarm",
 
215
                                                                        ALARM_TYPE_CLOCK,
 
216
                                                                        ALARM_TYPE_TIMER,
 
217
                                                                        ALARM_DEFAULT_TYPE,
 
218
                                                                        G_PARAM_READWRITE);
 
219
        
 
220
        
 
221
        time_param = g_param_spec_uint (PROP_NAME_TIME,
 
222
                                                                         "alarm time",
 
223
                                                                         "time when the alarm should trigger",
 
224
                                                                         0,                                             /* min */
 
225
                                                                         UINT_MAX,                              /* max */
 
226
                                                                         ALARM_DEFAULT_TIME,    /* default */
 
227
                                                                         G_PARAM_READWRITE);
 
228
        
 
229
        timestamp_param = g_param_spec_uint (PROP_NAME_TIMESTAMP,
 
230
                                                                                 "alarm timestamp",
 
231
                                                                                 "UNIX timestamp when the alarm should trigger",
 
232
                                                                                 0,                                             /* min */
 
233
                                                                                 UINT_MAX,                              /* max */
 
234
                                                                                 ALARM_DEFAULT_TIME,    /* default */
 
235
                                                                                 G_PARAM_READWRITE);
 
236
        
 
237
        active_param = g_param_spec_boolean (PROP_NAME_ACTIVE, 
 
238
                                                                                 "active alarm",
 
239
                                                                                 "whether the alarm is on or not",
 
240
                                                                                 ALARM_DEFAULT_ACTIVE,
 
241
                                                                                 G_PARAM_READWRITE);
 
242
 
 
243
        message_param = g_param_spec_string (PROP_NAME_MESSAGE,
 
244
                                                                                 "alarm message",
 
245
                                                                                 "message which describes this alarm",
 
246
                                                                                 ALARM_DEFAULT_MESSAGE,
 
247
                                                                                 G_PARAM_READWRITE);
 
248
        
 
249
        repeat_param = g_param_spec_uint (PROP_NAME_REPEAT,
 
250
                                                                          "repeat",
 
251
                                                                          "repeat the alarm",
 
252
                                                                          ALARM_REPEAT_NONE,    /* min */
 
253
                                                                          ALARM_REPEAT_ALL,             /* max */
 
254
                                                                          ALARM_DEFAULT_REPEAT, /* default */
 
255
                                                                          G_PARAM_READWRITE);
 
256
        
 
257
        snooze_param = g_param_spec_uint (PROP_NAME_SNOOZE,
 
258
                                                                          "snooze",
 
259
                                                                          "enable snoozing of the alarm",
 
260
                                                                          0,                                    /* min */
 
261
                                                                          UINT_MAX,                             /* max */
 
262
                                                                          ALARM_DEFAULT_SNOOZE, /* default */
 
263
                                                                          G_PARAM_READWRITE);
 
264
        
 
265
        notify_type_param = g_param_spec_uint (PROP_NAME_NOTIFY_TYPE,
 
266
                                                                                "notification type",
 
267
                                                                                "what kind of notification should be used",
 
268
                                                                                ALARM_NOTIFY_SOUND,
 
269
                                                                                ALARM_NOTIFY_COMMAND,
 
270
                                                                                ALARM_DEFAULT_NOTIFY_TYPE,
 
271
                                                                                G_PARAM_READWRITE);
 
272
        
 
273
        sound_file_param = g_param_spec_string (PROP_NAME_SOUND_FILE,
 
274
                                                                                 "sound file",
 
275
                                                                                 "sound file to play",
 
276
                                                                                 ALARM_DEFAULT_SOUND_FILE,
 
277
                                                                                 G_PARAM_READWRITE);
 
278
        
 
279
        sound_loop_param = g_param_spec_boolean (PROP_NAME_SOUND_LOOP,
 
280
                                                                                         "sound loop",
 
281
                                                                                         "whether the sound should be looped",
 
282
                                                                                         ALARM_DEFAULT_SOUND_LOOP,
 
283
                                                                                         G_PARAM_READWRITE);
 
284
        
 
285
        command_param = g_param_spec_string (PROP_NAME_COMMAND,
 
286
                                                                                 "command",
 
287
                                                                                 "command to run",
 
288
                                                                                 ALARM_DEFAULT_COMMAND,
 
289
                                                                                 G_PARAM_READWRITE);
 
290
        
 
291
        notify_bubble_param = g_param_spec_boolean (PROP_NAME_NOTIFY_BUBBLE, 
 
292
                                                                                                "notification bubble",
 
293
                                                                                                "whether the alarm should display a notification bubble when triggered",
 
294
                                                                                                ALARM_DEFAULT_NOTIFY_BUBBLE,
 
295
                                                                                                G_PARAM_READWRITE);
 
296
        
 
297
        
 
298
        /* override base object methods */
 
299
        g_object_class->set_property = alarm_set_property;
 
300
        g_object_class->get_property = alarm_get_property;
 
301
        g_object_class->constructed      = alarm_constructed;
 
302
        g_object_class->dispose          = alarm_dispose;
 
303
 
 
304
        /* install properties */
 
305
        g_object_class_install_property (g_object_class, PROP_DIR, dir_param);
 
306
        g_object_class_install_property (g_object_class, PROP_ID, id_param);
 
307
        g_object_class_install_property (g_object_class, PROP_TYPE, type_param);
 
308
        g_object_class_install_property (g_object_class, PROP_TIME, time_param);
 
309
        g_object_class_install_property (g_object_class, PROP_TIMESTAMP, timestamp_param);
 
310
        g_object_class_install_property (g_object_class, PROP_ACTIVE, active_param);
 
311
        g_object_class_install_property (g_object_class, PROP_MESSAGE, message_param);
 
312
        g_object_class_install_property (g_object_class, PROP_REPEAT, repeat_param);
 
313
        g_object_class_install_property (g_object_class, PROP_SNOOZE, snooze_param);
 
314
        g_object_class_install_property (g_object_class, PROP_NOTIFY_TYPE, notify_type_param);
 
315
        g_object_class_install_property (g_object_class, PROP_SOUND_FILE, sound_file_param);
 
316
        g_object_class_install_property (g_object_class, PROP_SOUND_LOOP, sound_loop_param);
 
317
        g_object_class_install_property (g_object_class, PROP_COMMAND, command_param);
 
318
        g_object_class_install_property (g_object_class, PROP_NOTIFY_BUBBLE, notify_bubble_param);
 
319
        
 
320
        g_type_class_add_private (class, sizeof (AlarmPrivate));
 
321
        
 
322
        /* set signal handlers */
 
323
        class->alarm = alarm_alarm;
 
324
        class->error = alarm_error;
 
325
        class->player_changed = alarm_player_changed;
 
326
 
 
327
        /* install signals and default handlers */
 
328
        alarm_signal[SIGNAL_ALARM] = g_signal_new ("alarm",             /* name */
 
329
                                                                                           TYPE_ALARM,  /* class type identifier */
 
330
                                                                                           G_SIGNAL_RUN_LAST, /* options */
 
331
                                                                                           G_STRUCT_OFFSET (AlarmClass, alarm), /* handler offset */
 
332
                                                                                           NULL, /* accumulator function */
 
333
                                                                                           NULL, /* accumulator data */
 
334
                                                                                           g_cclosure_marshal_VOID__VOID, /* marshaller */
 
335
                                                                                           G_TYPE_NONE, /* type of return value */
 
336
                                                                                           0);
 
337
        
 
338
        alarm_signal[SIGNAL_ERROR] = g_signal_new ("error",
 
339
                                                                                           TYPE_ALARM,
 
340
                                                                                           G_SIGNAL_RUN_LAST,
 
341
                                                                                           G_STRUCT_OFFSET (AlarmClass, error),
 
342
                                                                                           NULL,
 
343
                                                                                           NULL,
 
344
                                                                                           g_cclosure_marshal_VOID__POINTER,
 
345
                                                                                           G_TYPE_NONE,
 
346
                                                                                           1,
 
347
                                                                                           G_TYPE_POINTER);
 
348
        
 
349
        alarm_signal[SIGNAL_PLAYER] = g_signal_new ("player_changed",           /* name */
 
350
                                                                                                TYPE_ALARM,     /* class type identifier */
 
351
                                                                                                G_SIGNAL_RUN_LAST, /* options */
 
352
                                                                                                G_STRUCT_OFFSET (AlarmClass, player_changed), /* handler offset */
 
353
                                                                                                NULL, /* accumulator function */
 
354
                                                                                                NULL, /* accumulator data */
 
355
                                                                                                g_cclosure_marshal_VOID__UINT, /* marshaller */
 
356
                                                                                                G_TYPE_NONE, /* type of return value */
 
357
                                                                                                1,
 
358
                                                                                                G_TYPE_UINT);
 
359
}
 
360
 
 
361
/*
 
362
 * Utility function for extracting the strings out of a GConfValue of type
 
363
 * GCONF_VALUE_LIST and placing them in a plan GSList of strings.
 
364
 * 
 
365
 * Note: You should free the GSList returned but NOT the string contents.
 
366
 */
 
367
static GSList *
 
368
alarm_gconf_extract_list_string (GConfValue *val)
 
369
{
 
370
        GSList *list, *new_list, *l;
 
371
        
 
372
        g_assert (GCONF_VALUE_STRING == gconf_value_get_list_type (val));
 
373
        
 
374
        /* Fetch GSList of GConfValues. Extract them and put into a plain list of strings.
 
375
         * Note that the returned string from gconf_value_get_string() is owned by the GConfValue
 
376
         * and should thus NOT be freed.
 
377
         */
 
378
        list = gconf_value_get_list (val);
 
379
        new_list = NULL;
 
380
        for (l = list; l; l = l->next) {
 
381
                new_list = g_slist_append (new_list, (gpointer) gconf_value_get_string ((GConfValue *)l->data));
 
382
        }
 
383
        
 
384
        return new_list;
 
385
}
 
386
 
 
387
static void
 
388
alarm_gconf_load (Alarm *alarm)
 
389
{
 
390
        AlarmPrivate *priv      = ALARM_PRIVATE (alarm);
 
391
        GConfClient *client = priv->gconf_client;
 
392
        GConfValue *val;
 
393
        gchar *key, *tmp;
 
394
        GSList *list;
 
395
        guint i;
 
396
        
 
397
        /*
 
398
         * TYPE
 
399
         */
 
400
        key = alarm_gconf_get_full_key (alarm, PROP_NAME_TYPE);
 
401
        tmp = gconf_client_get_string (client, key, NULL);
 
402
        g_free (key);
 
403
        
 
404
        i = alarm_type_from_string (tmp);
 
405
        
 
406
        if (i > 0) {
 
407
                alarm->type = i;
 
408
        } else {
 
409
                // Not found in GConf, fall back to defaults
 
410
                alarm->type = ALARM_DEFAULT_TYPE;
 
411
                g_object_set (alarm, PROP_NAME_TYPE, ALARM_DEFAULT_TYPE, NULL);
 
412
        }
 
413
        
 
414
        if (tmp)
 
415
                g_free (tmp);
 
416
        
 
417
        /*
 
418
         * TIME
 
419
         */
 
420
        key = alarm_gconf_get_full_key (alarm, PROP_NAME_TIME);
 
421
        val = gconf_client_get (client, key, NULL);
 
422
        g_free (key);
 
423
        
 
424
        if (val) {
 
425
                alarm->time = (time_t)gconf_value_get_int (val);
 
426
                gconf_value_free (val);
 
427
        } else {
 
428
                // Not found in GConf, fall back to defaults
 
429
                g_object_set (alarm, PROP_NAME_TIME, ALARM_DEFAULT_TIME, NULL);
 
430
        }
 
431
        
 
432
        /*
 
433
         * TIMESTAMP
 
434
         */
 
435
        key = alarm_gconf_get_full_key (alarm, PROP_NAME_TIMESTAMP);
 
436
        val = gconf_client_get (client, key, NULL);
 
437
        g_free (key);
 
438
        
 
439
        if (val) {
 
440
                alarm->timestamp = (time_t)gconf_value_get_int (val);
 
441
                gconf_value_free (val);
 
442
        } else {
 
443
                // Not found in GConf, fall back to defaults
 
444
                g_object_set (alarm, PROP_NAME_TIMESTAMP, ALARM_DEFAULT_TIMESTAMP, NULL);
 
445
        }
 
446
        
 
447
        /*
 
448
         * ACTIVE
 
449
         */
 
450
        key = alarm_gconf_get_full_key (alarm, PROP_NAME_ACTIVE);
 
451
        val = gconf_client_get (client, key, NULL);
 
452
        g_free (key);
 
453
        
 
454
        if (val) {
 
455
                // We g_object_set here so the timer will be started for
 
456
                // active alarms
 
457
                g_object_set (alarm, "active", gconf_value_get_bool (val), NULL);
 
458
                gconf_value_free (val);
 
459
        } else {
 
460
                // Not found in GConf, fall back to defaults
 
461
                g_object_set (alarm, PROP_NAME_ACTIVE, ALARM_DEFAULT_ACTIVE, NULL);
 
462
        }
 
463
        
 
464
        /*
 
465
         * MESSAGE
 
466
         */
 
467
        key = alarm_gconf_get_full_key (alarm, PROP_NAME_MESSAGE);
 
468
        tmp = gconf_client_get_string (client, key, NULL);
 
469
        g_free (key);
 
470
        
 
471
        if (tmp) {
 
472
                alarm->message = tmp;
 
473
        } else {
 
474
                // Not found in GConf, fall back to defaults
 
475
                g_object_set (alarm, PROP_NAME_MESSAGE, ALARM_DEFAULT_MESSAGE, NULL);
 
476
        }
 
477
        
 
478
        /*
 
479
         * REPEAT
 
480
         */
 
481
        key = alarm_gconf_get_full_key (alarm, PROP_NAME_REPEAT);
 
482
        val = gconf_client_get (client, key, NULL);
 
483
        g_free (key);
 
484
        
 
485
        if (val) {
 
486
                list = alarm_gconf_extract_list_string (val);
 
487
                
 
488
                alarm->repeat = alarm_repeat_from_list (list);
 
489
                
 
490
                g_slist_free (list);
 
491
                gconf_value_free (val);
 
492
        } else {
 
493
                // Not found in GConf, fall back to defaults
 
494
                g_object_set (alarm, PROP_NAME_REPEAT, ALARM_DEFAULT_REPEAT, NULL);
 
495
        }
 
496
        
 
497
        /*
 
498
         * SNOOZE
 
499
         */
 
500
        key = alarm_gconf_get_full_key (alarm, PROP_NAME_SNOOZE);
 
501
        val = gconf_client_get (client, key, NULL);
 
502
        g_free (key);
 
503
        
 
504
        if (val) {
 
505
                alarm->snooze = gconf_value_get_int (val);
 
506
                gconf_value_free (val);
 
507
        } else {
 
508
                // Not found in GConf, fall back to defaults
 
509
                g_object_set (alarm, PROP_NAME_SNOOZE, ALARM_DEFAULT_SNOOZE, NULL);
 
510
        }
 
511
        
 
512
        /*
 
513
         * NOTIFY TYPE
 
514
         */
 
515
        key = alarm_gconf_get_full_key (alarm, PROP_NAME_NOTIFY_TYPE);
 
516
        tmp = gconf_client_get_string (client, key, NULL);
 
517
        g_free (key);
 
518
        
 
519
        i = alarm_notify_type_from_string (tmp);
 
520
        
 
521
        if (i > 0) {
 
522
                alarm->notify_type = i;
 
523
        } else {
 
524
                // Not found in GConf, fall back to defaults
 
525
                g_object_set (alarm, PROP_NAME_NOTIFY_TYPE, ALARM_DEFAULT_NOTIFY_TYPE, NULL);
 
526
        }
 
527
        
 
528
        if (tmp)
 
529
                g_free (tmp);
 
530
        
 
531
        /*
 
532
         * SOUND FILE
 
533
         */
 
534
        key = alarm_gconf_get_full_key (alarm, PROP_NAME_SOUND_FILE);
 
535
        tmp = gconf_client_get_string (client, key, NULL);
 
536
        g_free (key);
 
537
        
 
538
        if (tmp) {
 
539
                alarm->sound_file = tmp;
 
540
        } else {
 
541
                // Not found in GConf, fall back to defaults
 
542
                g_object_set (alarm, PROP_NAME_SOUND_FILE, ALARM_DEFAULT_SOUND_FILE, NULL);
 
543
        }
 
544
        
 
545
        /*
 
546
         * SOUND LOOP
 
547
         */
 
548
        key = alarm_gconf_get_full_key (alarm, PROP_NAME_SOUND_LOOP);
 
549
        val = gconf_client_get (client, key, NULL);
 
550
        g_free (key);
 
551
        
 
552
        if (val) {
 
553
                alarm->sound_loop = gconf_value_get_bool (val);
 
554
                gconf_value_free (val);
 
555
        } else {
 
556
                // Not found in GConf, fall back to defaults
 
557
                g_object_set (alarm, PROP_NAME_SOUND_LOOP, ALARM_DEFAULT_SOUND_LOOP, NULL);
 
558
        }
 
559
 
 
560
 
 
561
        /*
 
562
         * COMMAND
 
563
         */
 
564
        key = alarm_gconf_get_full_key (alarm, PROP_NAME_COMMAND);
 
565
        tmp = gconf_client_get_string (client, key, NULL);
 
566
        g_free (key);
 
567
        
 
568
        if (tmp) {
 
569
                alarm->command = tmp;
 
570
        } else {
 
571
                // Not found in GConf, fall back to defaults
 
572
                g_object_set (alarm, PROP_NAME_COMMAND, ALARM_DEFAULT_COMMAND, NULL);
 
573
        }
 
574
        
 
575
        
 
576
        /*
 
577
         * NOTIFY_BUBBLE
 
578
         */
 
579
        key = alarm_gconf_get_full_key (alarm, PROP_NAME_NOTIFY_BUBBLE);
 
580
        val = gconf_client_get (client, key, NULL);
 
581
        g_free (key);
 
582
 
 
583
        if (val) {
 
584
                alarm->notify_bubble = gconf_value_get_bool (val);
 
585
                gconf_value_free (val);
 
586
        } else {
 
587
                // Not found in GConf, fall back to defaults
 
588
                g_object_set (alarm, PROP_NAME_NOTIFY_BUBBLE, ALARM_DEFAULT_NOTIFY_BUBBLE, NULL);
 
589
        }
 
590
}
 
591
 
 
592
static void
 
593
alarm_init (Alarm *self)
 
594
{
 
595
        AlarmPrivate *priv = ALARM_PRIVATE (self);
 
596
        
 
597
        self->gconf_dir = NULL;
 
598
        self->id = -1;
 
599
        
 
600
        priv->gconf_listener = 0;
 
601
        priv->gconf_client = gconf_client_get_default ();
 
602
}
 
603
 
 
604
static void
 
605
alarm_constructed (GObject *object)
 
606
{
 
607
        Alarm *alarm = ALARM (object);
 
608
        
 
609
        // Load gconf settings
 
610
        alarm_gconf_load (alarm);
 
611
        
 
612
        // Connect gconf listener
 
613
        //alarm_gconf_connect (alarm);
 
614
}
 
615
 
 
616
/* set an Alarm property */
 
617
static void 
 
618
alarm_set_property (GObject *object, 
 
619
                                        guint prop_id,
 
620
                                        const GValue *value,
 
621
                                        GParamSpec *pspec) 
 
622
{
 
623
        Alarm *alarm;
 
624
        AlarmPrivate *priv = ALARM_PRIVATE (object);
 
625
        
 
626
        GConfClient *client;
 
627
        GError          *err = NULL;
 
628
        
 
629
        const gchar     *str;
 
630
        guint            d, old;
 
631
        AlarmType        type, new_type;
 
632
        gboolean         bool;
 
633
        GSList          *list;
 
634
        
 
635
        gchar *key, *tmp;
 
636
 
 
637
        alarm = ALARM (object);
 
638
        client = priv->gconf_client;
 
639
        
 
640
        g_debug ("set_property %s", pspec->name);
 
641
        
 
642
        switch (prop_id) {
 
643
        case PROP_DIR:
 
644
                str = g_value_get_string (value);
 
645
                
 
646
                /* Validate */
 
647
                if (!str) {
 
648
                        g_critical ("Invalid gconf-dir value: \"%s\": NULL", str);
 
649
                        return;
 
650
                }
 
651
                
 
652
                if (!gconf_valid_key (str, &tmp)) {
 
653
                        g_critical ("Invalid gconf-dir value: \"%s\": %s", str, tmp);
 
654
                        g_free (tmp);
 
655
                        return;
 
656
                }
 
657
                
 
658
                if (!alarm->gconf_dir || strcmp (str, alarm->gconf_dir) != 0) {
 
659
                        // Changed, remove old gconf listeners
 
660
                        alarm_gconf_disconnect (alarm);
 
661
                        
 
662
                        if (alarm->gconf_dir != NULL)
 
663
                                g_free (alarm->gconf_dir);
 
664
                        alarm->gconf_dir = g_strdup (str);
 
665
                        
 
666
                        // Associate schemas
 
667
                        alarm_gconf_associate_schemas (alarm);
 
668
                        
 
669
                        alarm_gconf_connect (alarm);
 
670
                }
 
671
                break;
 
672
        case PROP_ID:
 
673
                d = g_value_get_uint (value);
 
674
                
 
675
                if (d != alarm->id) {
 
676
                        alarm_gconf_disconnect (alarm);
 
677
                        alarm->id = d;
 
678
                        
 
679
                        alarm_gconf_associate_schemas (alarm);
 
680
                        
 
681
                        alarm_gconf_load (alarm);
 
682
                        alarm_gconf_connect (alarm);
 
683
                }
 
684
                break;
 
685
        case PROP_TYPE:
 
686
                alarm->type = g_value_get_uint (value);
 
687
                
 
688
                // If we changed from CLOCK to TIMER we need to update the time
 
689
                if (alarm->type == ALARM_TYPE_TIMER && alarm->active) {
 
690
                        alarm_update_timestamp (alarm);
 
691
                }
 
692
                
 
693
                key = alarm_gconf_get_full_key (alarm, PROP_NAME_TYPE);
 
694
                
 
695
                if (!gconf_client_set_string (client, key, 
 
696
                                                                          alarm_type_to_string (alarm->type), 
 
697
                                                                          &err)) {
 
698
                        
 
699
                        g_critical ("Could not set %s (gconf): %s", 
 
700
                                                key, err->message);
 
701
                        
 
702
                        g_error_free (err);
 
703
                }
 
704
                
 
705
                g_free (key);
 
706
                break;
 
707
        case PROP_TIME:
 
708
                alarm->time = g_value_get_uint (value);
 
709
                
 
710
                if (alarm->active) {
 
711
                        // Update timestamp
 
712
                        alarm_update_timestamp (alarm);
 
713
                }
 
714
                
 
715
                key = alarm_gconf_get_full_key (alarm, PROP_NAME_TIME);
 
716
                
 
717
                if (!gconf_client_set_int (client, key, alarm->time, &err)) {
 
718
                        
 
719
                        g_critical ("Could not set %s (gconf): %s", 
 
720
                                                key, err->message);
 
721
                        
 
722
                        g_error_free (err);
 
723
                }
 
724
                
 
725
                g_free (key);
 
726
                break;
 
727
        case PROP_TIMESTAMP:
 
728
                alarm->timestamp = g_value_get_uint (value);
 
729
                
 
730
                key = alarm_gconf_get_full_key (alarm, PROP_NAME_TIMESTAMP);
 
731
                
 
732
                if (!gconf_client_set_int (client, key, alarm->timestamp, &err)) {
 
733
                        
 
734
                        g_critical ("Could not set %s (gconf): %s", 
 
735
                                                key, err->message);
 
736
                        
 
737
                        g_error_free (err);
 
738
                }
 
739
                
 
740
                g_free (key);
 
741
                break;
 
742
        case PROP_ACTIVE:
 
743
                bool = alarm->active;
 
744
                alarm->active = g_value_get_boolean (value);
 
745
                
 
746
                //g_debug ("[%p] #%d ACTIVE: old=%d new=%d", alarm, alarm->id, bool, alarm->active);
 
747
                if (alarm->active && !alarm_timer_is_started(alarm)) {
 
748
                        // Start timer
 
749
                        alarm_timer_start (alarm);
 
750
                }
 
751
                else if (!alarm->active && alarm_timer_is_started(alarm)) {
 
752
                        // Stop timer
 
753
                        alarm_timer_remove (alarm);
 
754
                }
 
755
                
 
756
                
 
757
                key = alarm_gconf_get_full_key (alarm, PROP_NAME_ACTIVE);
 
758
                
 
759
                if (!gconf_client_set_bool (client, key, alarm->active, &err)) {
 
760
                        
 
761
                        g_critical ("Could not set %s (gconf): %s", 
 
762
                                                key, err->message);
 
763
                        
 
764
                        g_error_free (err);
 
765
                }
 
766
                
 
767
                g_free (key);
 
768
                break;
 
769
        case PROP_MESSAGE:
 
770
                if (alarm->message)
 
771
                        g_free (alarm->message);
 
772
                
 
773
                alarm->message = g_strdup (g_value_get_string (value));
 
774
                
 
775
                key = alarm_gconf_get_full_key (alarm, PROP_NAME_MESSAGE);
 
776
                
 
777
                if (!gconf_client_set_string (client, key, 
 
778
                                                                          alarm->message, 
 
779
                                                                          &err)) {
 
780
                        
 
781
                        g_critical ("Could not set %s (gconf): %s", 
 
782
                                                key, err->message);
 
783
                        
 
784
                        g_error_free (err);
 
785
                }
 
786
                
 
787
                g_free (key);
 
788
                
 
789
                break;
 
790
        case PROP_REPEAT:
 
791
                alarm->repeat = g_value_get_uint (value);
 
792
                
 
793
                if (alarm->active) {
 
794
                        alarm_update_timestamp (alarm);
 
795
                }
 
796
                
 
797
                key = alarm_gconf_get_full_key (alarm, PROP_NAME_REPEAT);
 
798
                list = alarm_repeat_to_list (alarm->repeat);
 
799
                
 
800
                if (!gconf_client_set_list(client, key, 
 
801
                                                                   GCONF_VALUE_STRING, list, 
 
802
                                                                   &err)) {
 
803
                        
 
804
                        g_critical ("Could not set %s (gconf): %s", 
 
805
                                                key, err->message);
 
806
                        
 
807
                        g_error_free (err);
 
808
                }
 
809
                
 
810
                g_slist_free (list);
 
811
                g_free (key);
 
812
                
 
813
                break;
 
814
        case PROP_SNOOZE:
 
815
                alarm->snooze = g_value_get_uint (value);
 
816
                
 
817
                key = alarm_gconf_get_full_key (alarm, PROP_NAME_SNOOZE);
 
818
                
 
819
                if (!gconf_client_set_int (client, key, alarm->snooze, &err)) {
 
820
                        
 
821
                        g_critical ("Could not set %s (gconf): %s", 
 
822
                                                key, err->message);
 
823
                        
 
824
                        g_error_free (err);
 
825
                }
 
826
                
 
827
                g_free (key);
 
828
                break;
 
829
        case PROP_NOTIFY_TYPE:
 
830
                alarm->notify_type = g_value_get_uint (value);
 
831
                
 
832
                key = alarm_gconf_get_full_key (alarm, PROP_NAME_NOTIFY_TYPE);
 
833
                
 
834
                if (!gconf_client_set_string (client, key, 
 
835
                                                                          alarm_notify_type_to_string (alarm->notify_type), 
 
836
                                                                          &err)) {
 
837
                        
 
838
                        g_critical ("Could not set %s (gconf): %s", 
 
839
                                                key, err->message);
 
840
                        
 
841
                        g_error_free (err);
 
842
                }
 
843
                
 
844
                g_free (key);
 
845
                
 
846
                break;
 
847
        case PROP_SOUND_FILE:
 
848
                alarm->sound_file = g_strdup (g_value_get_string (value));
 
849
                
 
850
                key = alarm_gconf_get_full_key (alarm, PROP_NAME_SOUND_FILE);
 
851
                
 
852
                if (!gconf_client_set_string (client, key, 
 
853
                                                                          alarm->sound_file, 
 
854
                                                                          &err)) {
 
855
                        
 
856
                        g_critical ("Could not set %s (gconf): %s", 
 
857
                                                key, err->message);
 
858
                        
 
859
                        g_error_free (err);
 
860
                }
 
861
                
 
862
                g_free (key);
 
863
                
 
864
                break;
 
865
        case PROP_SOUND_LOOP:
 
866
                alarm->sound_loop = g_value_get_boolean (value);
 
867
                
 
868
                key = alarm_gconf_get_full_key (alarm, PROP_NAME_SOUND_LOOP);
 
869
                
 
870
                if (!gconf_client_set_bool (client, key, alarm->sound_loop, &err)) {
 
871
                        
 
872
                        g_critical ("Could not set %s (gconf): %s", 
 
873
                                                key, err->message);
 
874
                        
 
875
                        g_error_free (err);
 
876
                }
 
877
                
 
878
                g_free (key);
 
879
                break;
 
880
        case PROP_COMMAND:
 
881
                alarm->command = g_strdup (g_value_get_string (value));
 
882
                
 
883
                key = alarm_gconf_get_full_key (alarm, PROP_NAME_COMMAND);
 
884
                
 
885
                if (!gconf_client_set_string (client, key, 
 
886
                                                                          alarm->command, 
 
887
                                                                          &err)) {
 
888
                        
 
889
                        g_critical ("Could not set %s (gconf): %s", 
 
890
                                                key, err->message);
 
891
                        
 
892
                        g_error_free (err);
 
893
                }
 
894
                
 
895
                g_free (key);
 
896
                
 
897
                break;
 
898
        case PROP_NOTIFY_BUBBLE:
 
899
                bool = alarm->notify_bubble;
 
900
                alarm->notify_bubble = g_value_get_boolean (value);
 
901
                
 
902
                key = alarm_gconf_get_full_key (alarm, PROP_NAME_NOTIFY_BUBBLE);
 
903
                
 
904
                if (!gconf_client_set_bool (client, key, alarm->notify_bubble, &err)) {
 
905
                        
 
906
                        g_critical ("Could not set %s (gconf): %s", 
 
907
                                                key, err->message);
 
908
                        
 
909
                        g_error_free (err);
 
910
                }
 
911
                
 
912
                g_free (key);
 
913
                break;
 
914
        default:
 
915
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
916
                break;
 
917
        }
 
918
}
 
919
 
 
920
/* retrive an Alarm property */
 
921
static void 
 
922
alarm_get_property (GObject *object, 
 
923
                                        guint prop_id, 
 
924
                                        GValue *value,
 
925
                                        GParamSpec *pspec) 
 
926
{
 
927
        Alarm *alarm = ALARM (object);
 
928
        
 
929
        switch (prop_id) {
 
930
        case PROP_DIR:
 
931
                g_value_set_string (value, alarm->gconf_dir);
 
932
                break;
 
933
        case PROP_ID:
 
934
                g_value_set_uint (value, alarm->id);
 
935
                break;
 
936
        case PROP_TYPE:
 
937
                g_value_set_uint (value, alarm->type);
 
938
                break;
 
939
        case PROP_TIME:
 
940
                g_value_set_uint (value, alarm->time);
 
941
                break;
 
942
        case PROP_TIMESTAMP:
 
943
                g_value_set_uint (value, alarm->timestamp);
 
944
                break;
 
945
        case PROP_ACTIVE:
 
946
                g_value_set_boolean (value, alarm->active);
 
947
                break;
 
948
        case PROP_MESSAGE:
 
949
                g_value_set_string (value, alarm->message);
 
950
                break;
 
951
        case PROP_REPEAT:
 
952
                g_value_set_uint (value, alarm->repeat);
 
953
                break;
 
954
        case PROP_SNOOZE:
 
955
                g_value_set_uint (value, alarm->snooze);
 
956
                break;
 
957
        case PROP_NOTIFY_TYPE:
 
958
                g_value_set_uint (value, alarm->notify_type);
 
959
                break;
 
960
        case PROP_SOUND_FILE:
 
961
                g_value_set_string (value, alarm->sound_file);
 
962
                break;
 
963
        case PROP_SOUND_LOOP:
 
964
                g_value_set_boolean (value, alarm->sound_loop);
 
965
                break;
 
966
        case PROP_COMMAND:
 
967
                g_value_set_string (value, alarm->command);
 
968
                break;
 
969
        case PROP_NOTIFY_BUBBLE:
 
970
                g_value_set_boolean (value, alarm->notify_bubble);
 
971
                break;
 
972
        default:
 
973
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
974
                break;
 
975
        }
 
976
}
 
977
 
 
978
/*
 
979
 * ERROR signal {{
 
980
 */
 
981
GQuark
 
982
alarm_error_quark (void)
 
983
{
 
984
        return g_quark_from_static_string ("alarm-error-quark");
 
985
}
 
986
 
 
987
static void
 
988
alarm_error (Alarm *alarm, GError *err)
 
989
{
 
990
        g_debug ("[%p] #%d: alarm_error: #%d: %s", alarm, alarm->id, err->code, err->message);
 
991
}
 
992
 
 
993
void
 
994
alarm_error_trigger (Alarm *alarm, AlarmErrorCode code, const gchar *msg)
 
995
{
 
996
        GError *err = g_error_new (ALARM_ERROR, code, "%s", msg);
 
997
        
 
998
        g_signal_emit (alarm, alarm_signal[SIGNAL_ERROR], 0, err, NULL);
 
999
}
 
1000
 
 
1001
/*
 
1002
 * }} ERROR signal
 
1003
 */
 
1004
 
 
1005
static void
 
1006
alarm_player_changed (Alarm *alarm, MediaPlayerState state)
 
1007
{
 
1008
        g_debug ("alarm_player_changed (%p, %d)", alarm, state);
 
1009
}
 
1010
 
 
1011
 
 
1012
/*
 
1013
 * ALARM signal {{
 
1014
 */
 
1015
 
 
1016
static void 
 
1017
alarm_alarm (Alarm *alarm)
 
1018
{
 
1019
        g_debug ("[%p] #%d: alarm_alarm", alarm, alarm->id);
 
1020
}
 
1021
 
 
1022
void
 
1023
alarm_trigger (Alarm *alarm)
 
1024
{
 
1025
        g_signal_emit (alarm, alarm_signal[SIGNAL_ALARM], 0, NULL);
 
1026
        
 
1027
        /*
 
1028
         * Do we want to repeat this alarm?
 
1029
         */
 
1030
        if (alarm_should_repeat (alarm)) {
 
1031
                g_debug ("alarm_trigger REPEATING");
 
1032
                alarm_update_timestamp_full (alarm, FALSE);
 
1033
        } else {
 
1034
                alarm_disable (alarm);
 
1035
        }
 
1036
        
 
1037
        switch (alarm->notify_type) {
 
1038
        case ALARM_NOTIFY_SOUND:
 
1039
                // Start sound playback
 
1040
                g_debug("[%p] #%d Start player", alarm, alarm->id);
 
1041
                alarm_player_start (alarm);
 
1042
                break;
 
1043
        case ALARM_NOTIFY_COMMAND:
 
1044
                // Start app
 
1045
                g_debug("[%p] #%d Start command", alarm, alarm->id);
 
1046
                alarm_command_run (alarm);
 
1047
                break;
 
1048
        default:
 
1049
                g_debug ("NOTIFICATION TYPE %d Not yet implemented.", alarm->notify_type);
 
1050
        }
 
1051
}
 
1052
 
 
1053
/*
 
1054
 * Convenience functions for enabling/disabling the alarm.
 
1055
 * 
 
1056
 * Will update timestamp if needed.
 
1057
 */
 
1058
void
 
1059
alarm_set_enabled (Alarm *alarm, gboolean enabled)
 
1060
{
 
1061
        if (enabled) {
 
1062
                alarm_update_timestamp (alarm);
 
1063
        }
 
1064
        
 
1065
        g_object_set (alarm, "active", enabled, NULL);
 
1066
}
 
1067
 
 
1068
void
 
1069
alarm_enable (Alarm *alarm)
 
1070
{
 
1071
        alarm_set_enabled (alarm, TRUE);
 
1072
}
 
1073
 
 
1074
void
 
1075
alarm_disable (Alarm *alarm)
 
1076
{
 
1077
        alarm_set_enabled (alarm, FALSE);
 
1078
}
 
1079
 
 
1080
/*
 
1081
 * Delete alarm. This will remove all configuration
 
1082
 * associated with this alarm.
 
1083
 */
 
1084
void
 
1085
alarm_delete (Alarm *alarm)
 
1086
{
 
1087
        AlarmPrivate *priv = ALARM_PRIVATE (alarm);
 
1088
        GConfClient *client = priv->gconf_client;
 
1089
        gchar *key;
 
1090
        
 
1091
        // Disconnect gconf listeners
 
1092
        alarm_gconf_disconnect (alarm);
 
1093
        
 
1094
        // Remove configuration
 
1095
        key = alarm_gconf_get_dir (alarm);
 
1096
        g_debug ("alarm_delete: recursive unset on %s", key);
 
1097
        gconf_client_recursive_unset (client, key, GCONF_UNSET_INCLUDING_SCHEMA_NAMES, NULL);
 
1098
        gconf_client_suggest_sync (client, NULL);
 
1099
        g_free (key);
 
1100
}
 
1101
 
 
1102
/*
 
1103
 * Snooze the alarm.
 
1104
 */
 
1105
void
 
1106
alarm_snooze (Alarm *alarm)
 
1107
{
 
1108
        // SNOOZE
 
1109
        if (alarm->snooze == 0) {
 
1110
                alarm_clear (alarm);
 
1111
                return;
 
1112
        }
 
1113
        
 
1114
        if (!alarm_is_playing (alarm)) return;
 
1115
        
 
1116
        g_debug ("alarm_snooze SNOOZING FOR %d minutes", alarm->snooze);
 
1117
        
 
1118
        time_t now = time (NULL);
 
1119
        
 
1120
        g_object_set (alarm, 
 
1121
                                  "timestamp", now + alarm->snooze * 60,
 
1122
                                  "active", TRUE,
 
1123
                                  NULL);
 
1124
        
 
1125
        alarm_clear (alarm);
 
1126
}
 
1127
 
 
1128
/*
 
1129
 * Clear the alarm. This will stop any running players.
 
1130
 */
 
1131
void
 
1132
alarm_clear (Alarm *alarm)
 
1133
{
 
1134
        alarm_player_stop (alarm);
 
1135
}
 
1136
 
 
1137
/*
 
1138
 * Is the alarm playing?
 
1139
 */
 
1140
gboolean
 
1141
alarm_is_playing (Alarm *a)
 
1142
{
 
1143
        AlarmPrivate *priv = ALARM_PRIVATE (a);
 
1144
        
 
1145
        return priv->player && priv->player->state == MEDIA_PLAYER_PLAYING;
 
1146
}
 
1147
 
 
1148
 
 
1149
 
 
1150
static gboolean
 
1151
alarm_timer_update (Alarm *alarm)
 
1152
{
 
1153
        time_t now;
 
1154
        
 
1155
        time (&now);
 
1156
        
 
1157
        if (now >= alarm->timestamp) {
 
1158
                alarm_trigger (alarm);
 
1159
                
 
1160
                // Remove callback only if we don't intend to repeat the alarm
 
1161
                return alarm_should_repeat (alarm);
 
1162
        } else if (alarm->timestamp - now <= 10) {
 
1163
                g_debug ("[%p] #%d %2d...", alarm, alarm->id, (int)(alarm->timestamp - now));
 
1164
        }
 
1165
        
 
1166
        // Keep callback
 
1167
        return TRUE;
 
1168
}
 
1169
 
 
1170
static void
 
1171
alarm_timer_start (Alarm *alarm)
 
1172
{
 
1173
        AlarmPrivate *priv = ALARM_PRIVATE(alarm);
 
1174
        
 
1175
        g_debug ("[%p] #%d timer_start", alarm, alarm->id);
 
1176
        
 
1177
        // Remove old timer, if any
 
1178
        alarm_timer_remove (alarm);
 
1179
        
 
1180
        // Keep us updated every 1 second
 
1181
        priv->timer_id = g_timeout_add_seconds (1, (GSourceFunc) alarm_timer_update, alarm);
 
1182
}
 
1183
 
 
1184
static gboolean
 
1185
alarm_timer_is_started (Alarm *alarm)
 
1186
{
 
1187
        AlarmPrivate *priv = ALARM_PRIVATE(alarm);
 
1188
                
 
1189
        return priv->timer_id > 0;
 
1190
}
 
1191
 
 
1192
static void
 
1193
alarm_timer_remove (Alarm *alarm)
 
1194
{
 
1195
        AlarmPrivate *priv = ALARM_PRIVATE(alarm);
 
1196
        
 
1197
        if (alarm_timer_is_started(alarm)) {
 
1198
                g_debug ("#%d timer_remove (%p)", alarm->id, alarm);
 
1199
                
 
1200
                g_source_remove (priv->timer_id);
 
1201
                
 
1202
                priv->timer_id = 0;
 
1203
        }
 
1204
}
 
1205
 
 
1206
 
 
1207
/*
 
1208
 * }} ALARM signal
 
1209
 */
 
1210
 
 
1211
/*
 
1212
 * Taken from panel-applet.c
 
1213
 */
 
1214
static void
 
1215
alarm_gconf_associate_schemas (Alarm *alarm)
 
1216
{
 
1217
        AlarmPrivate *priv  = ALARM_PRIVATE (alarm);
 
1218
        GConfClient *client = priv->gconf_client;
 
1219
        GSList *list, *l;
 
1220
        GError *error = NULL;
 
1221
        
 
1222
        if (alarm->id < 0)
 
1223
                return;
 
1224
 
 
1225
        list = gconf_client_all_entries (client, ALARM_GCONF_SCHEMA_DIR, &error);
 
1226
 
 
1227
        g_return_if_fail (error == NULL);
 
1228
 
 
1229
        for (l = list; l; l = l->next) {
 
1230
                GConfEntry *entry = l->data;
 
1231
                gchar      *key;
 
1232
                gchar      *tmp;
 
1233
                
 
1234
                tmp = g_path_get_basename (gconf_entry_get_key (entry));
 
1235
                
 
1236
                if (strchr (tmp, '-'))
 
1237
                        g_warning ("Applet key '%s' contains a hyphen. Please "
 
1238
                                           "use underscores in gconf keys\n", tmp);
 
1239
                
 
1240
                key = alarm_gconf_get_full_key (alarm, tmp);
 
1241
 
 
1242
                g_free (tmp);
 
1243
                
 
1244
                gconf_engine_associate_schema (
 
1245
                                client->engine, key, gconf_entry_get_key (entry), &error);
 
1246
 
 
1247
                g_free (key);
 
1248
 
 
1249
                gconf_entry_free (entry);
 
1250
 
 
1251
                if (error) {
 
1252
                        g_slist_free (list);
 
1253
                        return;
 
1254
                }
 
1255
        }
 
1256
 
 
1257
        g_slist_free (list);
 
1258
}
 
1259
 
 
1260
static void
 
1261
alarm_gconf_connect (Alarm *alarm)
 
1262
{
 
1263
        AlarmPrivate *priv = ALARM_PRIVATE (alarm);
 
1264
        gchar *dir;
 
1265
        GError *err = NULL;
 
1266
        
 
1267
//      g_debug ("gconf_connect (%p) ? %d", alarm, IS_ALARM ((gpointer)alarm));
 
1268
        
 
1269
        if (alarm->id < 0)
 
1270
                return;
 
1271
        
 
1272
        dir = alarm_gconf_get_dir (alarm);
 
1273
        
 
1274
//      g_debug ("alarm_gconf_connect (%p) to dir %s", alarm, dir);
 
1275
        
 
1276
        gconf_client_add_dir (priv->gconf_client, dir, 
 
1277
                                                  GCONF_CLIENT_PRELOAD_ONELEVEL, &err);
 
1278
        
 
1279
        if (err) {
 
1280
                g_warning ("alarm_gconf_connect (%p): gconf_client_add_dir (%s) failed: %s", alarm, dir, err->message);
 
1281
                g_error_free (err);
 
1282
                err = NULL;
 
1283
        }
 
1284
        
 
1285
        priv->gconf_listener = 
 
1286
                gconf_client_notify_add (
 
1287
                        priv->gconf_client, dir,
 
1288
                        (GConfClientNotifyFunc) alarm_gconf_dir_changed,
 
1289
                        alarm, NULL, &err);
 
1290
        
 
1291
        if (err) {
 
1292
                g_warning ("alarm_gconf_connect (%p): gconf_client_notify_add (%s) failed: %s", alarm, dir, err->message);
 
1293
                g_error_free (err);
 
1294
                err = NULL;
 
1295
        }
 
1296
        
 
1297
//      g_debug ("alarm_gconf_connect: Added listener %d to alarm #%d %p", priv->gconf_listener, alarm->id, alarm);
 
1298
        
 
1299
        g_free (dir);
 
1300
}
 
1301
 
 
1302
static void
 
1303
alarm_gconf_disconnect (Alarm *alarm)
 
1304
{
 
1305
        AlarmPrivate *priv = ALARM_PRIVATE (alarm);
 
1306
        gchar *dir;
 
1307
        
 
1308
        if (priv->gconf_listener) {
 
1309
                //g_debug ("alarm_gconf_disconnect: Removing listener %d from alarm #%d %p", priv->gconf_listener, alarm->id, alarm);
 
1310
                gconf_client_notify_remove (priv->gconf_client, priv->gconf_listener);
 
1311
                priv->gconf_listener = 0;
 
1312
                
 
1313
                dir = alarm_gconf_get_dir (alarm);
 
1314
                gconf_client_remove_dir (priv->gconf_client, dir, NULL);
 
1315
                g_free (dir);
 
1316
        }
 
1317
}
 
1318
 
 
1319
/*
 
1320
 * Updates the local copy with the new value if it has changed.
 
1321
 */
 
1322
static void 
 
1323
alarm_gconf_dir_changed (GConfClient *client,
 
1324
                                                 guint cnxn_id,
 
1325
                                                 GConfEntry *entry,
 
1326
                                                 gpointer data)
 
1327
{
 
1328
        Alarm *alarm = ALARM (data);
 
1329
        GParamSpec *param;
 
1330
        gchar *name;
 
1331
        
 
1332
        guint i;
 
1333
        gboolean b;
 
1334
        const gchar *str;
 
1335
        GSList *list;
 
1336
        
 
1337
        name = g_path_get_basename (entry->key);
 
1338
        param = g_object_class_find_property (G_OBJECT_GET_CLASS (alarm), name);
 
1339
        
 
1340
        if (!param) {
 
1341
                g_free (name);
 
1342
                return;
 
1343
        }
 
1344
        
 
1345
        g_debug ("alarm_gconf changed #%d %p: %s", alarm->id, alarm, name);
 
1346
        
 
1347
        switch (param->param_id) {
 
1348
        case PROP_TYPE:
 
1349
                str = gconf_value_get_string (entry->value);
 
1350
                i = alarm_type_from_string (str);
 
1351
                if (i > 0 && i != alarm->type)
 
1352
                        g_object_set (alarm, name, i, NULL);
 
1353
                break;
 
1354
        case PROP_TIME:
 
1355
                i = gconf_value_get_int (entry->value);
 
1356
                if (i != alarm->time)
 
1357
                        g_object_set (alarm, name, i, NULL);
 
1358
                break;
 
1359
        case PROP_TIMESTAMP:
 
1360
                i = gconf_value_get_int (entry->value);
 
1361
                if (i != alarm->timestamp)
 
1362
                        g_object_set (alarm, name, i, NULL);
 
1363
                break;
 
1364
        case PROP_ACTIVE:
 
1365
                b = gconf_value_get_bool (entry->value);
 
1366
                if (b != alarm->active) {
 
1367
                        g_debug ("[%p] #%d GCONF-ACTIVE changed from %d to %d", alarm, alarm->id, alarm->active, b);
 
1368
                        g_object_set (alarm, name, b, NULL);
 
1369
                }
 
1370
                break;
 
1371
        case PROP_MESSAGE:
 
1372
                str = gconf_value_get_string (entry->value);
 
1373
                if (strcmp (str, alarm->message) != 0)
 
1374
                        g_object_set (alarm, name, str, NULL);
 
1375
                break;
 
1376
        case PROP_REPEAT:
 
1377
                list = alarm_gconf_extract_list_string (entry->value);
 
1378
                
 
1379
                i = alarm_repeat_from_list (list);
 
1380
                if (i != alarm->repeat)
 
1381
                        g_object_set (alarm, name, i, NULL);
 
1382
                
 
1383
                g_slist_free (list);
 
1384
                break;
 
1385
        case PROP_SNOOZE:
 
1386
                i = gconf_value_get_int (entry->value);
 
1387
                if (i != alarm->snooze)
 
1388
                        g_object_set (alarm, name, i, NULL);
 
1389
                break;
 
1390
        case PROP_NOTIFY_TYPE:
 
1391
                str = gconf_value_get_string (entry->value);
 
1392
                i = alarm_notify_type_from_string (str);
 
1393
                if (i > 0 && i != alarm->notify_type)
 
1394
                        g_object_set (alarm, name, i, NULL);
 
1395
                break;
 
1396
        case PROP_SOUND_FILE:
 
1397
                str = gconf_value_get_string (entry->value);
 
1398
                if (strcmp (str, alarm->sound_file) != 0)
 
1399
                        g_object_set (alarm, name, str, NULL);
 
1400
                break;
 
1401
        case PROP_SOUND_LOOP:
 
1402
                b = gconf_value_get_bool (entry->value);
 
1403
                if (b != alarm->sound_loop)
 
1404
                        g_object_set (alarm, name, b, NULL);
 
1405
                break;
 
1406
        case PROP_COMMAND:
 
1407
                str = gconf_value_get_string (entry->value);
 
1408
                if (strcmp (str, alarm->command) != 0)
 
1409
                        g_object_set (alarm, name, str, NULL);
 
1410
                break;
 
1411
        case PROP_NOTIFY_BUBBLE:
 
1412
                b = gconf_value_get_bool (entry->value);
 
1413
                if (b != alarm->notify_bubble)
 
1414
                        g_object_set (alarm, name, b, NULL);
 
1415
                break;
 
1416
        default:
 
1417
                g_warning ("Valid property ID %d not handled!", param->param_id);
 
1418
                break;
 
1419
        }
 
1420
        
 
1421
        g_free (name);
 
1422
}
 
1423
 
 
1424
static void
 
1425
alarm_dispose (GObject *object)
 
1426
{
 
1427
        Alarm *alarm = ALARM (object);
 
1428
        AlarmPrivate *priv = ALARM_PRIVATE (object);
 
1429
        GObjectClass *parent = (GObjectClass *)alarm_parent_class;
 
1430
        
 
1431
        g_debug ("alarm_dispose (%p)", alarm);
 
1432
        
 
1433
        if (parent->dispose)
 
1434
                parent->dispose (object);
 
1435
        
 
1436
        alarm_gconf_disconnect (alarm);
 
1437
        alarm_timer_remove(alarm);
 
1438
        alarm_clear (alarm);
 
1439
}
 
1440
 
 
1441
/*
 
1442
 * Convenience function for creating a new alarm instance.
 
1443
 * Passing -1 as the id will generate a new ID with alarm_gen_id
 
1444
 */
 
1445
Alarm *
 
1446
alarm_new (const gchar *gconf_dir, gint id)
 
1447
{
 
1448
        Alarm *alarm;
 
1449
        
 
1450
        if (id < 0) {
 
1451
                id = alarm_gen_id_dir (gconf_dir);
 
1452
        }
 
1453
        
 
1454
        alarm = g_object_new (TYPE_ALARM,
 
1455
                                                  "gconf-dir", gconf_dir,
 
1456
                                                  "id", id,
 
1457
                                                  NULL);
 
1458
        
 
1459
        return alarm;
 
1460
}
 
1461
 
 
1462
guint
 
1463
alarm_gen_id_dir (const gchar *gconf_dir)
 
1464
{
 
1465
        GConfClient *client;
 
1466
        gchar *key = NULL;
 
1467
        gint id;
 
1468
        
 
1469
        client = gconf_client_get_default ();
 
1470
        
 
1471
        id = 0;
 
1472
        do {
 
1473
                if (key)
 
1474
                        g_free (key);
 
1475
                
 
1476
                key = g_strdup_printf("%s/" ALARM_GCONF_DIR_PREFIX "%d", gconf_dir, id);
 
1477
                id++;
 
1478
                
 
1479
        } while (gconf_client_dir_exists (client, key, NULL));
 
1480
        
 
1481
        g_free (key);
 
1482
        
 
1483
        return (guint)(id-1);
 
1484
}
 
1485
 
 
1486
/*
 
1487
 * Will try to find the first available ID in gconf_dir
 
1488
 */
 
1489
guint
 
1490
alarm_gen_id (Alarm *alarm)
 
1491
{
 
1492
        return alarm_gen_id_dir (alarm->gconf_dir);
 
1493
}
 
1494
 
 
1495
const gchar *alarm_type_to_string (AlarmType type)
 
1496
{
 
1497
        return gconf_enum_to_string (alarm_type_enum_map, type);
 
1498
}
 
1499
 
 
1500
AlarmType alarm_type_from_string (const gchar *type)
 
1501
{
 
1502
        AlarmType ret = ALARM_TYPE_INVALID;
 
1503
        
 
1504
        if (!type)
 
1505
                return ret;
 
1506
        
 
1507
        gconf_string_to_enum (alarm_type_enum_map, type, (gint *)&ret);
 
1508
        
 
1509
        return ret;
 
1510
}
 
1511
 
 
1512
const gchar *alarm_notify_type_to_string (AlarmNotifyType type)
 
1513
{
 
1514
        return gconf_enum_to_string (alarm_notify_type_enum_map, type);
 
1515
}
 
1516
 
 
1517
AlarmNotifyType alarm_notify_type_from_string (const gchar *type)
 
1518
{
 
1519
        AlarmNotifyType ret = ALARM_NOTIFY_INVALID;
 
1520
        
 
1521
        if (!type)
 
1522
                return ret;
 
1523
        
 
1524
        gconf_string_to_enum (alarm_notify_type_enum_map, type, (gint *)&ret);
 
1525
        
 
1526
        return ret;
 
1527
}
 
1528
 
 
1529
gchar *
 
1530
alarm_gconf_get_dir (Alarm *alarm)
 
1531
{
 
1532
        gchar *key;
 
1533
        
 
1534
        g_return_val_if_fail (IS_ALARM (alarm), NULL);
 
1535
        
 
1536
        key = g_strdup_printf ("%s/" ALARM_GCONF_DIR_PREFIX "%d", alarm->gconf_dir, alarm->id);
 
1537
        
 
1538
        return key;
 
1539
}
 
1540
 
 
1541
gchar *
 
1542
alarm_gconf_get_full_key (Alarm *alarm, const gchar *key)
 
1543
{
 
1544
        gchar *full_key;
 
1545
        
 
1546
        g_return_val_if_fail (IS_ALARM (alarm), NULL);
 
1547
 
 
1548
        if (!key)
 
1549
                return NULL;
 
1550
        
 
1551
        full_key = g_strdup_printf ("%s/" ALARM_GCONF_DIR_PREFIX "%d/%s", alarm->gconf_dir, alarm->id, key);
 
1552
 
 
1553
        return full_key;
 
1554
}
 
1555
 
 
1556
typedef struct {
 
1557
        GObject *object;
 
1558
        const gchar *name;
 
1559
        gulong handler_id;
 
1560
} AlarmBindArg;
 
1561
 
 
1562
static AlarmBindArg *
 
1563
alarm_bind_arg_new (GObject *object, const gchar *name, gulong handler_id)
 
1564
{
 
1565
        AlarmBindArg *arg;
 
1566
        
 
1567
        arg = g_new (AlarmBindArg, 1);
 
1568
        arg->object = object;
 
1569
        arg->name = name;
 
1570
        arg->handler_id = handler_id;
 
1571
        
 
1572
        return arg;
 
1573
}
 
1574
 
 
1575
static void
 
1576
alarm_bind_arg_free (AlarmBindArg *arg)
 
1577
{
 
1578
        if (!arg)
 
1579
                return;
 
1580
        
 
1581
        g_free ((gpointer)arg);
 
1582
}
 
1583
 
 
1584
static void
 
1585
alarm_bind_update (GObject *object,
 
1586
                                   GParamSpec *pspec,
 
1587
                                   gpointer data)
 
1588
{
 
1589
        //Alarm *alarm;
 
1590
        AlarmBindArg *arg = (AlarmBindArg *)data;
 
1591
        gpointer d;
 
1592
        
 
1593
        /*
 
1594
         * Determine which argument is the alarm
 
1595
         */
 
1596
        /*if (IS_ALARM (object)) {
 
1597
                 alarm = ALARM (object);
 
1598
        } else {
 
1599
                alarm = ALARM (arg->object);
 
1600
        }
 
1601
        
 
1602
        g_debug ("alarm_bind_update #%d(%p) [%s] -> %p [%s]", alarm->id, alarm, pspec->name, arg->object, arg->name);
 
1603
        */
 
1604
        g_object_get (object, pspec->name, &d, NULL);
 
1605
        
 
1606
        // Block other signal handler
 
1607
        g_signal_handlers_block_matched(arg->object, 
 
1608
                                                                        G_SIGNAL_MATCH_FUNC,
 
1609
                                                                        0, 0, NULL, alarm_bind_update, NULL);
 
1610
        
 
1611
        g_object_set (arg->object, arg->name, d, NULL);
 
1612
        
 
1613
        g_signal_handlers_unblock_matched(arg->object, 
 
1614
                                                                          G_SIGNAL_MATCH_FUNC,
 
1615
                                                                          0, 0, NULL, alarm_bind_update, NULL);
 
1616
}
 
1617
 
 
1618
/*
 
1619
 * We would like to disconnect any signal handlers from the alarm
 
1620
 * when the destination object is finalized. And vice versa.
 
1621
 */
 
1622
static void
 
1623
alarm_bind_weak_notify (gpointer data, GObject *where_the_object_was)
 
1624
{
 
1625
        AlarmBindArg *arg = (AlarmBindArg *)data;
 
1626
        
 
1627
        g_assert (arg);
 
1628
        g_assert (arg->object);
 
1629
        g_assert (arg->handler_id);
 
1630
        
 
1631
        if (G_IS_OBJECT (arg->object)) {
 
1632
                if (g_signal_handler_is_connected (arg->object, arg->handler_id)) {
 
1633
                        g_signal_handler_disconnect (arg->object, arg->handler_id);
 
1634
                }
 
1635
        }
 
1636
        
 
1637
        alarm_bind_arg_free (arg);
 
1638
}
 
1639
 
 
1640
/*
 
1641
 * Binds both ways.
 
1642
 */
 
1643
void
 
1644
alarm_bind (Alarm *alarm, 
 
1645
                        const gchar *prop, 
 
1646
                        GObject *dest, 
 
1647
                        const gchar *dest_prop)
 
1648
{
 
1649
        AlarmBindArg *arg, *obj_arg;
 
1650
        GParamSpec *param;
 
1651
        gchar *tmp;
 
1652
        gulong handler, obj_handler;
 
1653
        
 
1654
        param = g_object_class_find_property (G_OBJECT_GET_CLASS(alarm), prop);
 
1655
        g_assert (param);
 
1656
        param = g_object_class_find_property (G_OBJECT_GET_CLASS(dest), dest_prop);
 
1657
        g_assert (param);
 
1658
        
 
1659
//      g_debug ("Bind from %p [%s] -> %p [%s]", alarm, prop, dest, dest_prop);
 
1660
        
 
1661
        // Alarm -> Object
 
1662
        tmp = g_strdup_printf("notify::%s", prop);
 
1663
        arg = alarm_bind_arg_new (dest, dest_prop, 0);
 
1664
        handler = g_signal_connect (alarm, tmp, G_CALLBACK (alarm_bind_update), arg);
 
1665
        g_free(tmp);
 
1666
        
 
1667
        // Object -> Alarm
 
1668
        tmp = g_strdup_printf ("notify::%s", dest_prop);
 
1669
        obj_arg = alarm_bind_arg_new (G_OBJECT (alarm), prop, handler);
 
1670
        obj_handler = g_signal_connect (dest, tmp, G_CALLBACK (alarm_bind_update), obj_arg);
 
1671
        g_free(tmp);
 
1672
        
 
1673
        arg->handler_id = obj_handler;
 
1674
        
 
1675
        // Disconnect Object when Alarm is finalized (freed)
 
1676
        g_object_weak_ref (G_OBJECT (alarm), alarm_bind_weak_notify, arg);
 
1677
        
 
1678
        // Disconnect Alarm when Object is finalized (freed)
 
1679
        g_object_weak_ref (dest, alarm_bind_weak_notify, obj_arg);
 
1680
}
 
1681
 
 
1682
static gint
 
1683
alarm_list_item_compare (gconstpointer a, gconstpointer b)
 
1684
{
 
1685
        Alarm *a1 = ALARM (a);
 
1686
        Alarm *a2 = ALARM (b);
 
1687
        
 
1688
        return a1->id - a2->id;
 
1689
}
 
1690
 
 
1691
/*
 
1692
 * Check if a gconf directory is a valid alarm dir.
 
1693
 * 
 
1694
 * Returns >= 0 for valid alarm directory, -1 otherwise.
 
1695
 */
 
1696
gint
 
1697
alarm_gconf_dir_get_id (const gchar *dir)
 
1698
{
 
1699
        gint id;
 
1700
        gchar *d;
 
1701
        
 
1702
        d = g_path_get_basename (dir);
 
1703
        
 
1704
        if (sscanf (d, ALARM_GCONF_DIR_PREFIX "%d", &id) <= 0 || id < 0) {
 
1705
                // INVALID
 
1706
                id = -1;
 
1707
        }
 
1708
        
 
1709
        g_free (d);
 
1710
        
 
1711
        return id;
 
1712
}
 
1713
 
 
1714
/*
 
1715
 * Get list of alarms in gconf_dir
 
1716
 */
 
1717
GList *
 
1718
alarm_get_list (const gchar *gconf_dir)
 
1719
{
 
1720
        GConfClient *client;
 
1721
        GSList *dirs = NULL;
 
1722
        GSList *l = NULL;
 
1723
        gchar *tmp, *dir;
 
1724
        
 
1725
        GList *ret = NULL;
 
1726
        Alarm *alarm;
 
1727
        gint id;
 
1728
        
 
1729
        client = gconf_client_get_default ();
 
1730
        dirs = gconf_client_all_dirs (client, gconf_dir, NULL);
 
1731
        
 
1732
        if (!dirs)
 
1733
                return NULL;
 
1734
        
 
1735
        for (l = dirs; l; l = l->next) {
 
1736
                tmp = (gchar *)l->data;
 
1737
                
 
1738
                id = alarm_gconf_dir_get_id (tmp);
 
1739
                if (id >= 0) {
 
1740
                        g_debug ("alarm_get_list: found VALID %s #%d", tmp, id);
 
1741
                        
 
1742
                        alarm = alarm_new (gconf_dir, id);
 
1743
                        g_debug ("\tref = %d", G_OBJECT (alarm)->ref_count);
 
1744
                        ret = g_list_insert_sorted (ret, alarm, alarm_list_item_compare);
 
1745
                        g_debug ("\tappend ref = %d", G_OBJECT (alarm)->ref_count);
 
1746
                }
 
1747
                
 
1748
                g_free (tmp);
 
1749
        }
 
1750
        
 
1751
        g_slist_free (dirs);
 
1752
        
 
1753
        return ret;
 
1754
}
 
1755
 
 
1756
/*
 
1757
 * Connect a signal callback to all alarms in list.
 
1758
 */
 
1759
void
 
1760
alarm_signal_connect_list (GList *instances,
 
1761
                                                   const gchar *detailed_signal,
 
1762
                                                   GCallback c_handler,
 
1763
                                                   gpointer data)
 
1764
{
 
1765
        GList *l;
 
1766
        Alarm *a;
 
1767
        g_debug ("alarm_signal_connect_list");
 
1768
        for (l = instances; l != NULL; l = l->next) {
 
1769
                a = ALARM (l->data);
 
1770
                
 
1771
                g_debug (" - connecting #%d: %s...", a->id, detailed_signal);
 
1772
                
 
1773
                gboolean ret = g_signal_connect (a, detailed_signal, c_handler, data);
 
1774
                g_debug (" = %d", ret);
 
1775
        }
 
1776
}
 
1777
 
 
1778
 
 
1779
/**
 
1780
 * Player error
 
1781
 */
 
1782
static void
 
1783
alarm_player_error_cb (MediaPlayer *player, GError *err, gpointer data)
 
1784
{
 
1785
        Alarm *alarm = ALARM (data);
 
1786
        gchar *uri;
 
1787
        gchar *msg;
 
1788
        
 
1789
        uri = media_player_get_uri (player);
 
1790
        msg = g_strdup_printf ("Could not play '%s': %s", uri, err->message);
 
1791
        
 
1792
        g_critical (msg);
 
1793
        
 
1794
        /* Emit error signal */
 
1795
        alarm_error_trigger (alarm, ALARM_ERROR_PLAY, msg);
 
1796
        
 
1797
        g_free (uri);
 
1798
        g_free (msg);
 
1799
}
 
1800
 
 
1801
static void
 
1802
alarm_player_state_cb (MediaPlayer *player, MediaPlayerState state, gpointer data)
 
1803
{
 
1804
        static MediaPlayerState prev_state = MEDIA_PLAYER_INVALID;
 
1805
        
 
1806
        Alarm *alarm       = ALARM (data);
 
1807
        AlarmPrivate *priv = ALARM_PRIVATE (alarm);
 
1808
        
 
1809
        if (state != prev_state) {
 
1810
                // Emit player_changed signal
 
1811
                g_signal_emit (alarm, alarm_signal[SIGNAL_PLAYER], 0, state, NULL);
 
1812
        }
 
1813
        
 
1814
        if (state == MEDIA_PLAYER_STOPPED) {
 
1815
                g_debug ("[%p] #%d Freeing media player %p", alarm, alarm->id, player);
 
1816
                
 
1817
                media_player_free (player);
 
1818
                
 
1819
                priv->player = NULL;
 
1820
        }
 
1821
}
 
1822
 
 
1823
static gboolean
 
1824
alarm_player_timeout (gpointer data)
 
1825
{
 
1826
        Alarm *alarm = ALARM (data);
 
1827
        
 
1828
        g_debug ("[%p] #%d player_timeout", alarm, alarm->id);
 
1829
        
 
1830
        alarm_player_stop (alarm);
 
1831
        
 
1832
        return FALSE;
 
1833
}
 
1834
 
 
1835
 
 
1836
/**
 
1837
 * Play sound via gstreamer
 
1838
 */
 
1839
static void
 
1840
alarm_player_start (Alarm *alarm)
 
1841
{
 
1842
        AlarmPrivate *priv = ALARM_PRIVATE (alarm);
 
1843
        
 
1844
        if (priv->player == NULL) {
 
1845
                priv->player = media_player_new (alarm->sound_file,
 
1846
                                                                                 alarm->sound_loop,
 
1847
                                                                                 alarm_player_state_cb, alarm,
 
1848
                                                                                 alarm_player_error_cb, alarm);
 
1849
        } else {
 
1850
                media_player_set_uri (priv->player, alarm->sound_file);
 
1851
        }
 
1852
        
 
1853
        media_player_start (priv->player);
 
1854
        
 
1855
        g_debug ("[%p] #%d player_start...", alarm, alarm->id);
 
1856
        
 
1857
        /*
 
1858
         * Add stop timeout
 
1859
         */
 
1860
        priv->player_timer_id = g_timeout_add_seconds(ALARM_SOUND_TIMEOUT, alarm_player_timeout, alarm);
 
1861
}
 
1862
 
 
1863
/**
 
1864
 * Stop player
 
1865
 */
 
1866
static void
 
1867
alarm_player_stop (Alarm *alarm)
 
1868
{
 
1869
        AlarmPrivate *priv = ALARM_PRIVATE (alarm);
 
1870
        
 
1871
        if (priv->player != NULL) {
 
1872
                media_player_stop (priv->player);
 
1873
                
 
1874
                if (priv->player_timer_id > 0) {
 
1875
                        g_source_remove (priv->player_timer_id);
 
1876
                        priv->player_timer_id = 0;
 
1877
                }
 
1878
        }
 
1879
}
 
1880
 
 
1881
/*
 
1882
 * Run Command
 
1883
 */
 
1884
static void
 
1885
alarm_command_run (Alarm *alarm)
 
1886
{
 
1887
        GError *err = NULL;
 
1888
        gchar *msg;
 
1889
        
 
1890
        if (!g_spawn_command_line_async (alarm->command, &err)) {
 
1891
                
 
1892
                msg = g_strdup_printf ("Could not launch `%s': %s", alarm->command, err->message);
 
1893
                
 
1894
                g_critical (msg);
 
1895
                
 
1896
                /* Emit error signal */
 
1897
                alarm_error_trigger (alarm, ALARM_ERROR_COMMAND, msg);
 
1898
                
 
1899
                g_free (msg);
 
1900
                g_error_free (err);
 
1901
        }
 
1902
}
 
1903
 
 
1904
 
 
1905
 
 
1906
 
 
1907
 
 
1908
 
 
1909
/*
 
1910
 * Set time according to hour, min, sec
 
1911
 */
 
1912
void
 
1913
alarm_set_time (Alarm *alarm, guint hour, guint minute, guint second)
 
1914
{
 
1915
        g_debug ("alarm_set_time (%d:%d:%d)", hour, minute, second);
 
1916
        
 
1917
        g_object_set (alarm, "time", second + minute * 60 + hour * 60 * 60, NULL);
 
1918
}
 
1919
 
 
1920
/*
 
1921
 * Calculates the distance from wday1 to wday2
 
1922
 */
 
1923
gint
 
1924
alarm_wday_distance (gint wday1, gint wday2)
 
1925
{
 
1926
        gint d;
 
1927
        
 
1928
        d = wday2 - wday1;
 
1929
        if (d < 0)
 
1930
                d += 7;
 
1931
        
 
1932
        return d;
 
1933
}
 
1934
 
 
1935
static gboolean
 
1936
alarm_time_is_future (struct tm *tm, guint hour, guint minute, guint second)
 
1937
{
 
1938
        return (hour > tm->tm_hour ||
 
1939
                        (hour == tm->tm_hour && minute > tm->tm_min) ||
 
1940
                        (hour == tm->tm_hour && minute == tm->tm_min && second > tm->tm_sec));
 
1941
}
 
1942
 
 
1943
 
 
1944
/*
 
1945
 * Set time according to hour, min, sec and alarm->repeat
 
1946
 */
 
1947
static void
 
1948
alarm_set_timestamp (Alarm *alarm, guint hour, guint minute, guint second, gboolean include_today)
 
1949
{
 
1950
        time_t now, new;
 
1951
        gint i, d, wday;
 
1952
        AlarmRepeat rep;
 
1953
        struct tm *tm;
 
1954
        
 
1955
        g_debug ("alarm_set_time_full (%d, %d, %d, %d)", hour, minute, second, include_today);
 
1956
        
 
1957
        time (&now);
 
1958
        tm = localtime (&now);
 
1959
        
 
1960
        //i = (today == 6) ? 0 : today + 1;
 
1961
        //today--;
 
1962
        
 
1963
        if (alarm->repeat == ALARM_REPEAT_NONE) {
 
1964
                // Check if the alarm is for tomorrow
 
1965
                if (!alarm_time_is_future (tm, hour, minute, second)) {
 
1966
                        
 
1967
                        //if (wday < 0) {
 
1968
                                g_debug("alarm_set_time_full: Alarm is for tomorrow.");
 
1969
                                tm->tm_mday++;
 
1970
                        /*} else {
 
1971
                                // wday == tm->tm_wday
 
1972
                                g_debug("alarm_set_time_full: Alarm is in 1 week.");
 
1973
                                tm->tm_mday += 7;
 
1974
                        }*/
 
1975
                }
 
1976
        } else {
 
1977
                // REPEAT SET: Find the closest repeat day
 
1978
                wday = -1;
 
1979
                
 
1980
                i = tm->tm_wday;
 
1981
                if (!include_today)
 
1982
                        i++;
 
1983
                
 
1984
                // Try finding a day in this week
 
1985
                for (; i < 7; i++) {
 
1986
                        rep = 1 << i;
 
1987
                        if (alarm->repeat & rep) {
 
1988
                                if (i == tm->tm_wday && !alarm_time_is_future (tm, hour, minute, second)) continue;
 
1989
                                
 
1990
                                // FOUND!
 
1991
                                //g_debug ("\tMATCH");
 
1992
                                wday = i;
 
1993
                                break;
 
1994
                        }
 
1995
                }
 
1996
                
 
1997
                // If we haven't found a day in the current week, check next week
 
1998
                if (wday == -1) {
 
1999
                        for (i = 0; i <= tm->tm_wday; i++) {
 
2000
                                rep = 1 << i;
 
2001
                                if (alarm->repeat & rep/* && alarm_time_is_future (tm, hour, minute, second)*/) {
 
2002
                                        // FOUND!
 
2003
                                        //g_debug ("\tMATCH");
 
2004
                                        wday = i;
 
2005
                                        break;
 
2006
                                }
 
2007
                        }
 
2008
                }
 
2009
                
 
2010
                g_debug ("Closest WDAY = %d", wday);
 
2011
                
 
2012
                if (wday == tm->tm_wday && (!include_today || !alarm_time_is_future (tm, hour, minute, second)))
 
2013
                        wday = 7;
 
2014
                
 
2015
                
 
2016
                // Calculate distance from now to wday
 
2017
                if (wday == 7) {
 
2018
                        g_debug("alarm_set_time_full: Alarm is in (forced) 1 week.");
 
2019
                        d = 7;
 
2020
                } else {
 
2021
                        g_debug ("d = tm->tm_wday(%d) - wday(%d)", tm->tm_wday, wday);
 
2022
                        d = alarm_wday_distance (tm->tm_wday, wday);
 
2023
                }
 
2024
                
 
2025
                g_debug ("alarm_set_time_full: Alarm is in %d days.", d);
 
2026
                
 
2027
                tm->tm_mday += d;
 
2028
        }
 
2029
        
 
2030
        tm->tm_hour = hour;
 
2031
        tm->tm_min  = minute;
 
2032
        tm->tm_sec  = second;
 
2033
        
 
2034
        // DEBUG:
 
2035
        char tmp[512];
 
2036
        strftime (tmp, sizeof (tmp), "%c", tm);
 
2037
        g_debug ("alarm_set_time_full: Alarm will trigger at %s", tmp);
 
2038
        
 
2039
        new = mktime (tm);
 
2040
        g_debug ("alarm_set_time_full: Setting to %d", new);
 
2041
        g_object_set (alarm, "timestamp", new, NULL);
 
2042
}
 
2043
 
 
2044
/*
 
2045
 * Update the alarm timestamp to point to the nearest future
 
2046
 * hour/min/sec according to the time value.
 
2047
 */
 
2048
void
 
2049
alarm_update_timestamp_full (Alarm *alarm, gboolean include_today)
 
2050
{
 
2051
        if (alarm->type == ALARM_TYPE_CLOCK) {
 
2052
                struct tm *tm = alarm_get_time (alarm);
 
2053
                g_debug ("update_timestamp_full: %d:%d:%d", tm->tm_hour, tm->tm_min, tm->tm_sec);
 
2054
                alarm_set_timestamp (alarm, tm->tm_hour, tm->tm_min, tm->tm_sec, include_today);
 
2055
        } else {
 
2056
                /* ALARM_TYPE_TIMER */
 
2057
                g_object_set (alarm, "timestamp", time(NULL) + alarm->time, NULL);
 
2058
        }
 
2059
}
 
2060
 
 
2061
/*
 
2062
 * Update the alarm timestamp to point to the nearest future
 
2063
 * hour/min/sec according to the time value.
 
2064
 * 
 
2065
 * Equivalent to alarm_update_timestamp_full (alarm, TRUE)
 
2066
 */
 
2067
void
 
2068
alarm_update_timestamp (Alarm *alarm)
 
2069
{
 
2070
        alarm_update_timestamp_full (alarm, TRUE);
 
2071
}
 
2072
 
 
2073
/*
 
2074
 * Get the alarm time.
 
2075
 */
 
2076
struct tm *
 
2077
alarm_get_time (Alarm *alarm)
 
2078
{
 
2079
        return gmtime (&(alarm->time));
 
2080
}
 
2081
 
 
2082
/*
 
2083
 * Get the remaining alarm time.
 
2084
 */
 
2085
static struct tm tm;
 
2086
 
 
2087
struct tm *
 
2088
alarm_get_remain (Alarm *alarm)
 
2089
{
 
2090
        time_t now;
 
2091
        //struct tm tm;
 
2092
        
 
2093
        now = time (NULL);
 
2094
        tm.tm_sec = alarm->timestamp - now;
 
2095
        
 
2096
        tm.tm_min = tm.tm_sec / 60;
 
2097
        tm.tm_sec -= tm.tm_min * 60;
 
2098
 
 
2099
        tm.tm_hour = tm.tm_min / 60;
 
2100
        tm.tm_min -= tm.tm_hour * 60;
 
2101
        
 
2102
        return &tm;
 
2103
}
 
2104
 
 
2105
/*
 
2106
 * AlarmRepeat utilities {{
 
2107
 */
 
2108
 
 
2109
const gchar *
 
2110
alarm_repeat_to_string (AlarmRepeat repeat)
 
2111
{
 
2112
        return gconf_enum_to_string (alarm_repeat_enum_map, repeat);
 
2113
}
 
2114
 
 
2115
AlarmRepeat
 
2116
alarm_repeat_from_string (const gchar *str)
 
2117
{
 
2118
        AlarmRepeat ret = ALARM_REPEAT_NONE;
 
2119
        
 
2120
        if (!str)
 
2121
                return ret;
 
2122
        
 
2123
        gconf_string_to_enum (alarm_repeat_enum_map, str, (gint *)&ret);
 
2124
        
 
2125
        return ret;
 
2126
}
 
2127
 
 
2128
AlarmRepeat
 
2129
alarm_repeat_from_list (GSList *list)
 
2130
{
 
2131
        GSList *l;
 
2132
        AlarmRepeat repeat = ALARM_REPEAT_NONE;
 
2133
        
 
2134
        for (l = list; l; l = l->next) {
 
2135
                repeat |= alarm_repeat_from_string ((gchar *)l->data);
 
2136
        }
 
2137
        
 
2138
        return repeat;
 
2139
}
 
2140
 
 
2141
GSList *
 
2142
alarm_repeat_to_list (AlarmRepeat repeat)
 
2143
{
 
2144
        GSList *list = NULL;
 
2145
        AlarmRepeat r;
 
2146
        gint i;
 
2147
        
 
2148
        for (r = ALARM_REPEAT_SUN, i = 0; r <= ALARM_REPEAT_SAT; r = 1 << ++i) {
 
2149
                if (repeat & r)
 
2150
                        list = g_slist_append (list, (gpointer) alarm_repeat_to_string (r));
 
2151
        }
 
2152
        
 
2153
        return list;
 
2154
}
 
2155
 
 
2156
gboolean
 
2157
alarm_should_repeat (Alarm *alarm)
 
2158
{
 
2159
        return alarm->type == ALARM_TYPE_CLOCK && alarm->repeat != ALARM_REPEAT_NONE;
 
2160
}
 
2161
 
 
2162
/*
 
2163
 * }} AlarmRepeat utilities
 
2164
 */