1 /*
2  * alarms-list.d -- Alarm list window
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 <time.h>
25 
26 #include "alarm-list-window.h"
27 #include "alarm-settings.h"
28 #include "alarm-actions.h"
29 
30 gboolean
31 alarm_list_window_delete_event (GtkWidget *window, GdkEvent *event, gpointer data);
32 
33 static void
34 alarm_list_window_selection_changed (GtkTreeSelection *, gpointer);
35 
36 static gboolean
37 alarm_list_window_update_timer (gpointer);
38 
39 static gint
40 alarm_list_window_sort_iter_compare (GtkTreeModel *model,
41                                      GtkTreeIter *a, GtkTreeIter *b,
42                                      gpointer data);
43 
44 void
45 alarm_list_window_rows_reordered (GtkTreeModel *model,
46                                   GtkTreePath  *path,
47                                   GtkTreeIter  *iter,
48                                   gpointer      arg3,
49                                   gpointer      data);
50 
51 void
52 alarm_list_window_enable_toggled (GtkCellRendererToggle *cell_renderer,
53                                   gchar *path,
54                                   gpointer data);
55 
56 void
57 alarm_list_window_snooze_menu_activated (GtkMenuItem *item, gpointer data);
58 
59 void
60 alarm_list_window_snooze_menu_custom_activated (GtkMenuItem *menuitem, gpointer data);
61 
62 void
63 alarm_list_window_snooze_menu_update (AlarmListWindow *list_window);
64 
65 static void
66 alarm_list_window_update_row (AlarmListWindow *list_window, GtkTreeIter *iter);
67 
68 /**
69  * Create a new Alarm List Window
70  */
71 AlarmListWindow *
alarm_list_window_new(AlarmApplet * applet)72 alarm_list_window_new (AlarmApplet *applet)
73 {
74 	AlarmListWindow *list_window;
75     GtkBuilder *builder = applet->ui;
76     GtkTreeSelection *selection;
77     GtkTreeSortable *sortable;
78 
79     // Initialize struct
80 	list_window = g_new0 (AlarmListWindow, 1);
81 
82 	list_window->applet = applet;
83 
84     // Widgets
85 	list_window->window = GTK_WINDOW (gtk_builder_get_object (builder, "alarm-list-window"));
86 	list_window->model = GTK_LIST_STORE (gtk_builder_get_object (builder, "alarms-liststore"));
87 	list_window->tree_view = GTK_TREE_VIEW (gtk_builder_get_object (builder, "alarm-list-view"));
88 
89     list_window->new_button = GTK_WIDGET (gtk_builder_get_object (builder, "new-button"));
90     list_window->edit_button = GTK_WIDGET (gtk_builder_get_object (builder, "edit-button"));
91     list_window->delete_button = GTK_WIDGET (gtk_builder_get_object (builder, "delete-button"));
92     list_window->enable_button = GTK_WIDGET (gtk_builder_get_object (builder, "enable-button"));
93     list_window->stop_button = GTK_WIDGET (gtk_builder_get_object (builder, "stop-button"));
94     list_window->snooze_button = GTK_WIDGET (gtk_builder_get_object (builder, "snooze-button"));
95     list_window->snooze_menu = GTK_WIDGET (gtk_builder_get_object (builder, "snooze-menu"));
96 
97     // Set up window accelerator group
98     list_window->accel_group = gtk_accel_group_new ();
99     gtk_window_add_accel_group (list_window->window, list_window->accel_group);
100 
101     // Connect some signals
102     selection = gtk_tree_view_get_selection (list_window->tree_view);
103     g_signal_connect (selection, "changed",
104                       G_CALLBACK (alarm_list_window_selection_changed), applet);
105 
106     // Update view every second for pretty countdowns
107     g_timeout_add (500, (GSourceFunc) alarm_list_window_update_timer, applet);
108 
109     // Set up sorting
110     sortable = GTK_TREE_SORTABLE (list_window->model);
111 
112     gtk_tree_sortable_set_sort_func (sortable, SORTID_TIME_REMAINING,
113         alarm_list_window_sort_iter_compare, GINT_TO_POINTER (SORTID_TIME_REMAINING),
114         NULL);
115 
116     // Set initial sort order
117     gtk_tree_sortable_set_sort_column_id (sortable, SORTID_TIME_REMAINING, GTK_SORT_ASCENDING);
118 
119     // Populate with alarms
120     alarm_list_window_alarms_add (list_window, applet->alarms);
121 
122     // Update snooze menu
123     alarm_list_window_snooze_menu_update (list_window);
124 
125 	return list_window;
126 }
127 
128 /**
129  * Show and present list window
130  */
131 void
alarm_list_window_show(AlarmListWindow * list_window)132 alarm_list_window_show (AlarmListWindow *list_window)
133 {
134     // Let the WM decide the initial position of the window (probably not 0,0)
135     gboolean first_time = !gtk_widget_get_realized (GTK_WIDGET (list_window->window));
136 
137     gtk_window_present_with_time (list_window->window, gtk_get_current_event_time());
138     if (!first_time) {
139         gtk_window_move (list_window->window, list_window->window_pos_x, list_window->window_pos_y);
140     }
141 }
142 
143 /**
144  * Hide list window
145  */
146 void
alarm_list_window_hide(AlarmListWindow * list_window)147 alarm_list_window_hide (AlarmListWindow *list_window)
148 {
149 	gtk_window_get_position (list_window->window, &(list_window->window_pos_x), &(list_window->window_pos_y));
150 	gtk_widget_hide (GTK_WIDGET (list_window->window));
151 }
152 
153 /**
154  * Toggle visibility of list window
155  */
156 void
alarm_list_window_toggle(AlarmListWindow * list_window)157 alarm_list_window_toggle (AlarmListWindow *list_window)
158 {
159 	if (GTK_WIDGET_VISIBLE (list_window->window)) {
160 		alarm_list_window_hide (list_window);
161 	} else {
162 		alarm_list_window_show (list_window);
163 	}
164 }
165 
166 /**
167  * Delete-event handler for list-window
168  */
169 gboolean
alarm_list_window_delete_event(GtkWidget * window,GdkEvent * event,gpointer data)170 alarm_list_window_delete_event (GtkWidget *window, GdkEvent *event, gpointer data)
171 {
172 	AlarmApplet *applet = (AlarmApplet *)data;
173 
174 	gtk_action_activate (GTK_ACTION (applet->action_toggle_list_win));
175 
176 	return TRUE;
177 }
178 
179 //
180 // ALARM LIST MODEL:
181 //
182 
183 /**
184  * Find alarm in the model
185  *
186  * Returns TRUE if found and sets iter to the location
187  * Returns FALSE otherwise
188  */
189 gboolean
alarm_list_window_find_alarm(GtkTreeModel * model,Alarm * alarm,GtkTreeIter * iter)190 alarm_list_window_find_alarm (GtkTreeModel *model,
191                               Alarm *alarm,
192                               GtkTreeIter *iter)
193 {
194     GtkTreeIter it;
195     Alarm *a;
196     gboolean valid;
197 
198     valid = gtk_tree_model_get_iter_first (model, &it);
199 
200     while (valid) {
201         gtk_tree_model_get (model, &it, COLUMN_ALARM, &a, -1);
202 
203         if (a == alarm) {
204             if (iter) {
205                 *iter = it;
206             }
207             return TRUE;
208         }
209 
210         valid = gtk_tree_model_iter_next(model, &it);
211     }
212 
213     return FALSE;
214 }
215 
216 /**
217  * Check whether the list window contains an alarm
218  */
219 gboolean
alarm_list_window_contains(AlarmListWindow * list_window,Alarm * alarm)220 alarm_list_window_contains (AlarmListWindow *list_window, Alarm *alarm)
221 {
222     return alarm_list_window_find_alarm (GTK_TREE_MODEL (list_window->model), alarm, NULL);
223 }
224 
225 /**
226  * Update the row in the list at the position specified by iter
227  */
228 static void
alarm_list_window_update_row(AlarmListWindow * list_window,GtkTreeIter * iter)229 alarm_list_window_update_row (AlarmListWindow *list_window, GtkTreeIter *iter)
230 {
231     GtkTreeModel *model = GTK_TREE_MODEL (list_window->model);
232     Alarm *a;
233 
234     gchar tmp[200];
235     gchar *tmp2;
236     struct tm *tm;
237 
238     const gchar *type_col;
239     const gchar *time_format;
240     GString *time_col;
241     gchar *label_col;
242 
243     // Get the alarm at iter
244     gtk_tree_model_get (GTK_TREE_MODEL (model), iter,
245                         COLUMN_ALARM, &a,
246                         -1);
247 
248     // If alarm is running (active), show remaining time
249     if (a->active) {
250         tm = alarm_get_remain (a);
251     } else {
252         tm = alarm_get_time (a);
253     }
254 
255     if (a->type == ALARM_TYPE_CLOCK) {
256         type_col = ALARM_ICON;
257         time_format = TIME_COL_CLOCK_FORMAT;
258     } else {
259         type_col = TIMER_ICON;
260         time_format = TIME_COL_TIMER_FORMAT;
261     }
262 
263     // Create time column
264     strftime(tmp, sizeof(tmp), time_format, tm);
265 
266     time_col = g_string_new (tmp);
267     if (a->type == ALARM_TYPE_CLOCK && a->repeat != ALARM_REPEAT_NONE) {
268         tmp2 = alarm_repeat_to_pretty (a->repeat);
269         g_string_append_printf (time_col, TIME_COL_REPEAT_FORMAT, tmp2);
270         g_free (tmp2);
271     }
272 
273     // Create label column
274     tmp2 = g_markup_escape_text (a->message, -1);
275     if (a->triggered) {
276         label_col = g_strdup_printf (LABEL_COL_TRIGGERED_FORMAT, tmp2);
277     } else {
278         label_col = g_strdup_printf (LABEL_COL_FORMAT, tmp2);
279     }
280     g_free (tmp2);
281 
282 	gtk_list_store_set (GTK_LIST_STORE (model), iter,
283                         COLUMN_TYPE, type_col,
284                         COLUMN_TIME, time_col->str,
285                         COLUMN_LABEL, label_col,
286                         COLUMN_ACTIVE, a->active,
287                         COLUMN_TRIGGERED, a->triggered,
288                         -1);
289 
290     // Restore icon visibility when an alarm is cleared / snoozed
291     if (!a->triggered) {
292         gtk_list_store_set (GTK_LIST_STORE (model), iter, COLUMN_SHOW_ICON, TRUE, -1);
293     }
294 
295 
296     g_string_free (time_col, TRUE);
297     g_free (label_col);
298 }
299 
300 /**
301  * Add alarm to the list window
302  */
303 void
alarm_list_window_alarm_add(AlarmListWindow * list_window,Alarm * alarm)304 alarm_list_window_alarm_add (AlarmListWindow *list_window, Alarm *alarm)
305 {
306     GtkListStore *store = list_window->model;
307     GtkTreeIter iter;
308 
309     gtk_list_store_append (store, &iter);
310     gtk_list_store_set (store, &iter, COLUMN_ALARM, alarm, -1);
311 
312     alarm_list_window_update_row (list_window, &iter);
313 }
314 
315 /**
316  * Update alarm in the list window
317  */
318 void
alarm_list_window_alarm_update(AlarmListWindow * list_window,Alarm * alarm)319 alarm_list_window_alarm_update (AlarmListWindow *list_window, Alarm *alarm)
320 {
321     GtkTreeIter iter;
322 
323     g_debug ("AlarmListWindow alarm_update: %p (%s)", alarm, alarm->message);
324 
325     if (alarm_list_window_find_alarm (GTK_TREE_MODEL (list_window->model), alarm, &iter)) {
326         alarm_list_window_update_row (list_window, &iter);
327     } else {
328         g_warning ("AlarmListWindow alarm_update: Could not find alarm %p", alarm);
329     }
330 }
331 
332 /**
333  * Remove alarm from the list window
334  */
335 void
alarm_list_window_alarm_remove(AlarmListWindow * list_window,Alarm * alarm)336 alarm_list_window_alarm_remove (AlarmListWindow *list_window, Alarm *alarm)
337 {
338     GtkTreeIter iter;
339 
340     if (alarm_list_window_find_alarm (GTK_TREE_MODEL (list_window->model), alarm, &iter)) {
341         gtk_list_store_remove (list_window->model, &iter);
342     } else {
343         g_warning ("AlarmListWindow alarm_remove: Could not find alarm %p", alarm);
344     }
345 }
346 
347 /**
348  * Add several alarms to the list window
349  */
350 void
alarm_list_window_alarms_add(AlarmListWindow * list_window,GList * alarms)351 alarm_list_window_alarms_add (AlarmListWindow *list_window, GList *alarms)
352 {
353     AlarmApplet *applet = list_window->applet;
354 
355     GList *l = NULL;
356     Alarm *a;
357 
358     for (l = applet->alarms; l; l = l->next) {
359 		a = ALARM (l->data);
360 
361         alarm_list_window_alarm_add (list_window, a);
362     }
363 }
364 
365 /**
366  * Update the alarm view every second
367  */
368 static gboolean
alarm_list_window_update_timer(gpointer data)369 alarm_list_window_update_timer (gpointer data)
370 {
371     AlarmApplet *applet = (AlarmApplet *)data;
372     GtkTreeModel *model = GTK_TREE_MODEL (applet->list_window->model);
373     GtkTreeIter iter;
374     Alarm *a;
375     gboolean show_icon;
376     gboolean valid;
377 
378     valid = gtk_tree_model_get_iter_first (model, &iter);
379 
380     while (valid) {
381         alarm_list_window_update_row (applet->list_window, &iter);
382 
383         gtk_tree_model_get (model, &iter,
384                             COLUMN_ALARM, &a,
385                             COLUMN_SHOW_ICON, &show_icon, -1);
386 
387         // Blink icon on triggered alarms
388         if (a->triggered) {
389             gtk_list_store_set (GTK_LIST_STORE (model), &iter, COLUMN_SHOW_ICON, !show_icon, -1);
390         }
391 
392         valid = gtk_tree_model_iter_next(model, &iter);
393     }
394 
395     // Keep updating
396     return TRUE;
397 }
398 
399 /**
400  * Sort compare function
401  */
402 static gint
alarm_list_window_sort_iter_compare(GtkTreeModel * model,GtkTreeIter * i1,GtkTreeIter * i2,gpointer data)403 alarm_list_window_sort_iter_compare (GtkTreeModel *model,
404                                      GtkTreeIter *i1, GtkTreeIter *i2,
405                                      gpointer data)
406 {
407     gint sortcol = GPOINTER_TO_INT (data);
408     Alarm *a1, *a2;
409     gint ret = 0;
410 
411     // Fetch ze alarms
412     gtk_tree_model_get (model, i1, COLUMN_ALARM, &a1, -1);
413     gtk_tree_model_get (model, i2, COLUMN_ALARM, &a2, -1);
414 
415     switch (sortcol) {
416         case SORTID_TIME_REMAINING:
417         {
418             // Sort by remaining time
419             time_t t1, t2;
420 
421             // Show active alarms first
422             if (a1->active && a2->active) {
423                 t1 = alarm_get_remain_seconds (a1);
424                 t2 = alarm_get_remain_seconds (a2);
425 
426             } else if (a1->active && !a2->active) {
427                 t1 = 0;
428                 t2 = 1;
429             } else if (!a1->active && a2->active) {
430                 t1 = 1;
431                 t2 = 0;
432             } else {
433                 // Both inactive, sort by time
434                 t1 = a1->time;
435                 t2 = a2->time;
436             }
437 
438             ret = t1 - t2;
439         }
440             break;
441         default:
442             g_return_val_if_reached (0);
443     }
444 
445     return ret;
446 }
447 
448 
449 //
450 // TREE VIEW:
451 //
452 
453 /**
454  * Get the selected alarm
455  */
456 Alarm *
alarm_list_window_get_selected_alarm(AlarmListWindow * list_window)457 alarm_list_window_get_selected_alarm (AlarmListWindow *list_window)
458 {
459     GtkTreeModel *model;
460 	GtkTreeSelection *selection;
461 	GtkTreeIter iter;
462 	Alarm *a;
463 
464     g_assert (list_window);
465 
466 	// Fetch selection
467 	selection = gtk_tree_view_get_selection (list_window->tree_view);
468 
469 	if (!gtk_tree_selection_get_selected(selection, &model, &iter)) {
470 		// No alarms selected
471 		//g_debug ("get_selected_alarm: No alarms selected!");
472 		return NULL;
473 	}
474 
475 	gtk_tree_model_get (model, &iter, COLUMN_ALARM, &a, -1);
476 
477 	// gtk_tree_model_get () will increase the reference count
478 	// of the alarms each time it's called. We dereference it
479 	// here so they can be properly freed later with g_object_unref()
480     // Ugh, we use gtk_tree_model_get a lot, is there no other way?
481 	//g_object_unref (a);
482 
483 	return a;
484 }
485 
486 /**
487  * Set the selected alarm
488  */
489 static void
alarm_list_window_select_alarm(AlarmListWindow * list_window,Alarm * alarm)490 alarm_list_window_select_alarm (AlarmListWindow *list_window, Alarm *alarm)
491 {
492     GtkTreeModel *model = GTK_TREE_MODEL (list_window->model);
493     GtkTreeSelection *selection;
494     GtkTreeIter iter;
495 
496     if (!alarm_list_window_find_alarm (model, alarm, &iter)) {
497         g_warning ("AlarmListWindow select_alarm: Alarm %p not found!", alarm);
498         return;
499     }
500 
501     selection = gtk_tree_view_get_selection (list_window->tree_view);
502 
503     gtk_tree_selection_select_iter (selection, &iter);
504 }
505 
506 
507 /**
508  * Selection changed in tree view
509  *
510  * Here we update the associated actions
511  */
512 void
alarm_list_window_selection_changed(GtkTreeSelection * selection,gpointer data)513 alarm_list_window_selection_changed (GtkTreeSelection *selection, gpointer data)
514 {
515     AlarmApplet *applet = (AlarmApplet *)data;
516     AlarmListWindow *list_window = applet->list_window;
517     Alarm *a = list_window->selected_alarm;
518 
519     // If rows have just been reordered, retain the selected row
520     // But only if the reordering was triggered by a click on the toggle cell
521     if (list_window->reordered && list_window->toggled) {
522         list_window->reordered = FALSE;
523         list_window->toggled = FALSE;
524 
525         alarm_list_window_select_alarm (list_window, list_window->selected_alarm);
526         return;
527     }
528 
529     // Reset reordered and toggled flags
530     list_window->reordered = FALSE;
531     list_window->toggled = FALSE;
532 
533     // Update actions
534     alarm_applet_actions_update_sensitive (applet);
535     alarm_action_update_enabled (applet);
536 
537     // Update selected alarm (might be NULL)
538     list_window->selected_alarm = alarm_list_window_get_selected_alarm (list_window);
539 
540     if (list_window->selected_alarm) {
541         // Update snooze button menu
542         if (list_window->selected_alarm->type == ALARM_TYPE_CLOCK) {
543             // We always snooze for 9 mins on alarm clocks
544             gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (list_window->snooze_button), NULL);
545         } else {
546             // Allow custom snooze mins
547             gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (list_window->snooze_button), list_window->snooze_menu);
548         }
549     }
550 
551 
552     g_debug ("AlarmListWindow: selection-changed from %s (%p) to %s (%p)",
553         (a) ? a->message : "<none>", a,
554         (list_window->selected_alarm) ? list_window->selected_alarm->message : "<none>",
555         list_window->selected_alarm);
556 }
557 
558 /**
559  * Toggle cell changed
560  */
561 void
alarm_list_window_enable_toggled(GtkCellRendererToggle * cell_renderer,gchar * path,gpointer data)562 alarm_list_window_enable_toggled (GtkCellRendererToggle *cell_renderer,
563                                   gchar *path,
564                                   gpointer data)
565 {
566     AlarmApplet *applet = (AlarmApplet *)data;
567     AlarmListWindow *list_window = applet->list_window;
568     GtkTreeModel *model = GTK_TREE_MODEL (list_window->model);
569     GtkTreeIter iter;
570     Alarm *a;
571 
572     if (gtk_tree_model_get_iter_from_string (model, &iter, path)) {
573         gtk_tree_model_get (model, &iter, COLUMN_ALARM, &a, -1);
574 
575         g_debug ("AlarmListWindow enable toggled on %p", a);
576 
577         // Reset reordered flag
578         list_window->reordered = FALSE;
579 
580         // Select the toggled alarm
581         alarm_list_window_select_alarm (list_window, a);
582 
583         // Let selection_changed know an alarm was just toggled so
584         // this alarm is re-selected if the rows are reordered
585         list_window->toggled = TRUE;
586 
587         // Activate the enabled action
588         gtk_action_activate (GTK_ACTION (applet->action_enabled));
589     }
590 }
591 
592 /**
593  * Rows reordered callback
594  */
595 void
alarm_list_window_rows_reordered(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer arg3,gpointer data)596 alarm_list_window_rows_reordered (GtkTreeModel *model,
597                                   GtkTreePath  *path,
598                                   GtkTreeIter  *iter,
599                                   gpointer      arg3,
600                                   gpointer      data)
601 {
602     AlarmApplet *applet = (AlarmApplet *)data;
603     AlarmListWindow *list_window = applet->list_window;
604 
605     // Return if list_window is not set. This happens during initialization.
606     if (!list_window)
607         return;
608 
609     // Signal to selection_changed that the rows have been reordered.
610     list_window->reordered = TRUE;
611 }
612 
613 
614 //
615 // TOOLBAR:
616 //
617 
618 /**
619  * Snooze menu item activated
620  */
621 void
alarm_list_window_snooze_menu_activated(GtkMenuItem * menuitem,gpointer data)622 alarm_list_window_snooze_menu_activated (GtkMenuItem *menuitem,
623                                          gpointer          data)
624 {
625     AlarmApplet *applet = (AlarmApplet *)data;
626     gchar **parts;
627     guint i;
628     guint mins;
629 
630 //    g_debug ("AlarmListWindow: snooze-menu activated %s to %d",
631 //        gtk_menu_item_get_label (menuitem), gtk_check_menu_item_get_active (menuitem));
632 
633     if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem))) {
634         // Determine #mins from the name of the menu item (hackish)
635         // Assumes name follows the format {foo}-{mins}
636         parts = g_strsplit (gtk_buildable_get_name (GTK_BUILDABLE (menuitem)), "-", 0);
637         for (i = 0; parts[i] != NULL; i++)
638             // Loop to the last element
639             ;
640 
641         mins = g_strtod (parts[i-1], NULL);
642 
643         g_debug ("AlarmListWindow: snooze-menu activated: Snooze for %d mins!", mins);
644 
645         applet->snooze_mins = mins;
646 
647         gtk_action_activate (applet->action_snooze);
648     }
649 }
650 
651 /**
652  * Snooze menu custom item activated
653  */
654 void
alarm_list_window_snooze_menu_custom_activated(GtkMenuItem * menuitem,gpointer data)655 alarm_list_window_snooze_menu_custom_activated (GtkMenuItem *menuitem,
656                                                 gpointer          data)
657 {
658     AlarmApplet *applet = (AlarmApplet *)data;
659     AlarmListWindow *list_window = applet->list_window;
660     GtkWidget *dialog, *spin;
661     gint response;
662     Alarm *a;
663     guint mins;
664 
665     g_debug ("AlarmListWindow: snooze-menu custom activated");
666 
667     dialog = GTK_WIDGET (gtk_builder_get_object (applet->ui, "snooze-dialog"));
668     spin = GTK_WIDGET (gtk_builder_get_object (applet->ui, "snooze-spin"));
669 
670     // Run dialog, hide for later use
671 	response = gtk_dialog_run (GTK_DIALOG (dialog));
672 	gtk_widget_hide (GTK_WIDGET (dialog));
673 
674 	if (response == GTK_RESPONSE_OK) {
675         mins = (gint) gtk_spin_button_get_value (GTK_SPIN_BUTTON (spin));
676         if ((a = alarm_list_window_get_selected_alarm (list_window))) {
677             g_debug ("AlarmListWindow: Snooze Custom: %s for %d mins", a->message, mins);
678             alarm_snooze (a, mins * 60);
679         }
680     }
681 }
682 
683 /**
684  * Update the snooze menu according to the applet's snooze_mins property
685  */
686 void
alarm_list_window_snooze_menu_update(AlarmListWindow * list_window)687 alarm_list_window_snooze_menu_update (AlarmListWindow *list_window)
688 {
689     AlarmApplet *applet = (AlarmApplet *)list_window->applet;
690     GtkMenuShell *menu = GTK_MENU_SHELL(list_window->snooze_menu);
691     gchar *target_name = g_strdup_printf ("snooze-menu-%d", applet->snooze_mins);
692 
693     const gchar *name;
694     GtkMenuItem *item;
695     GList *l = NULL;
696 
697     g_debug ("AlarmListWindow: menu_update to %d", applet->snooze_mins);
698 
699     block_list (menu->children, alarm_list_window_snooze_menu_activated);
700 
701     for (l = menu->children; l != NULL; l = l->next) {
702         item = GTK_MENU_ITEM (l->data);
703         name = gtk_buildable_get_name (GTK_BUILDABLE (item));
704         if (g_strcmp0 (name, target_name) == 0) {
705             g_object_set (item, "active", TRUE, NULL);
706 
707             g_debug ("AlarmListWindow: menu_update to %s", name);
708         }
709     }
710 
711     unblock_list (menu->children, alarm_list_window_snooze_menu_activated);
712 
713     g_free (target_name);
714 }
715