2
* ui.c - Alarm Clock applet UI routines
4
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
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.
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.
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.
21
* Johannes H. Jensen <joh@pseudoberries.com>
27
#include <libnotify/notify.h>
30
#include "alarm-applet.h"
32
#include "alarms-list.h"
42
display_error_dialog (const gchar *message, const gchar *secondary_text, GtkWindow *parent)
46
dialog = gtk_message_dialog_new (parent,
47
GTK_DIALOG_DESTROY_WITH_PARENT,
48
GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
51
if (secondary_text != NULL) {
52
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
56
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
57
gtk_dialog_run (GTK_DIALOG (dialog));
58
gtk_widget_destroy (dialog);
62
// TODO: Should display any triggered alarms / etc.
64
alarm_applet_label_update (AlarmApplet *applet)
68
guint hour, min, sec, now;
71
if (!applet->upcoming_alarm) {
73
g_object_set (applet->label, "label", ALARM_DEF_LABEL, NULL);
77
a = applet->upcoming_alarm;
79
if (applet->label_type == LABEL_TYPE_REMAIN) {
81
tm = alarm_get_remain (a);
84
tm = alarm_get_time (a);
87
tmp = g_strdup_printf(_("%02d:%02d:%02d"), tm->tm_hour, tm->tm_min, tm->tm_sec);
89
g_object_set(applet->label, "label", tmp, NULL);
93
// TODO: Refactor for more fancy tooltip with alarm summary.
95
alarm_applet_update_tooltip (AlarmApplet *applet)
97
struct tm *time, *remain;
103
tip = g_string_new ("");
105
// Find all active alarms
106
for (l = applet->alarms; l; l = l->next) {
109
if (!a->active) continue;
113
time = alarm_get_time (a);
114
remain = alarm_get_remain (a);
116
g_string_append_printf (tip, _("\n(%c) <b>%s</b> @%02d:%02d:%02d (-%02d:%02d:%02d)"), (a->type == ALARM_TYPE_TIMER) ? 'T' : 'A', a->message,
117
time->tm_hour, time->tm_min, time->tm_sec, remain->tm_hour, remain->tm_min, remain->tm_sec);
121
tip = g_string_prepend (tip, _("Active alarms:"));
123
tip = g_string_append (tip, _("No active alarms"));
126
tip = g_string_append (tip, _("\n\nClick to snooze alarms"));
127
tip = g_string_append (tip, _("\nDouble click to edit alarms"));
129
gtk_widget_set_tooltip_markup (GTK_WIDGET (applet->parent), tip->str);
131
g_string_free (tip, TRUE);
135
is_separator (GtkTreeModel *model, GtkTreeIter *iter, gpointer sep_index)
140
path = gtk_tree_model_get_path (model, iter);
141
result = gtk_tree_path_get_indices (path)[0] == GPOINTER_TO_INT (sep_index);
142
gtk_tree_path_free (path);
148
* Shamelessly stolen from gnome-da-capplet.c
151
fill_combo_box (GtkComboBox *combo_box, GList *list, const gchar *custom_label)
155
GtkCellRenderer *renderer;
157
GdkPixbuf *pixbuf = NULL;
159
AlarmListEntry *entry;
161
g_debug ("fill_combo_box... %d", g_list_length (list));
163
// if (theme == NULL) {
164
theme = gtk_icon_theme_get_default ();
167
gtk_combo_box_set_row_separator_func (combo_box, is_separator,
168
GINT_TO_POINTER (g_list_length (list)), NULL);
170
model = GTK_TREE_MODEL (gtk_list_store_new (2, GDK_TYPE_PIXBUF, G_TYPE_STRING));
171
gtk_combo_box_set_model (combo_box, model);
173
gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo_box));
175
renderer = gtk_cell_renderer_pixbuf_new ();
177
/* not all cells have a pixbuf, this prevents the combo box to shrink */
178
gtk_cell_renderer_set_fixed_size (renderer, -1, 22);
179
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, FALSE);
180
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer,
181
"pixbuf", PIXBUF_COL,
184
renderer = gtk_cell_renderer_text_new ();
185
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE);
186
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer,
190
for (l = list; l != NULL; l = g_list_next (l)) {
191
entry = (AlarmListEntry *) l->data;
193
pixbuf = gtk_icon_theme_load_icon (theme, entry->icon, 22, 0, NULL);
195
gtk_list_store_append (GTK_LIST_STORE (model), &iter);
196
gtk_list_store_set (GTK_LIST_STORE (model), &iter,
198
TEXT_COL, entry->name,
202
g_object_unref (pixbuf);
205
gtk_list_store_append (GTK_LIST_STORE (model), &iter);
206
gtk_list_store_set (GTK_LIST_STORE (model), &iter, -1);
207
gtk_list_store_append (GTK_LIST_STORE (model), &iter);
208
gtk_list_store_set (GTK_LIST_STORE (model), &iter,
210
TEXT_COL, custom_label,
216
button_cb (GtkWidget *widget,
217
GdkEventButton *event,
220
AlarmApplet *applet = (AlarmApplet *)data;
222
g_debug("BUTTON: %d", event->button);
224
/* React only to left mouse button */
225
if (event->button == 2 || event->button == 3) {
229
if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) {
230
/* Double click: Open list alarms */
231
list_alarms_dialog_display (applet);
233
alarm_applet_snooze_alarms (applet);
236
/* Show edit alarms dialog */
237
//display_list_alarms_dialog (applet);
242
/* Taken from the GeyesApplet */
244
applet_back_change (PanelApplet *a,
245
PanelAppletBackgroundType type,
250
/* taken from the TrashApplet */
251
GtkRcStyle *rc_style;
255
gtk_widget_set_style (GTK_WIDGET (applet->parent), NULL);
256
rc_style = gtk_rc_style_new ();
257
gtk_widget_modify_style (GTK_WIDGET (applet->parent), rc_style);
258
gtk_rc_style_unref (rc_style);
261
case PANEL_COLOR_BACKGROUND:
262
gtk_widget_modify_bg (GTK_WIDGET (applet->parent),
263
GTK_STATE_NORMAL, color);
266
case PANEL_PIXMAP_BACKGROUND:
267
style = gtk_style_copy (GTK_WIDGET (
268
applet->parent)->style);
269
if (style->bg_pixmap[GTK_STATE_NORMAL])
271
(style->bg_pixmap[GTK_STATE_NORMAL]);
272
style->bg_pixmap[GTK_STATE_NORMAL] = g_object_ref
274
gtk_widget_set_style (GTK_WIDGET (applet->parent),
276
g_object_unref (style);
279
case PANEL_NO_BACKGROUND:
286
/* Taken from gnome-panel/button-widget.c */
288
alarm_applet_icon_update (AlarmApplet *applet)
290
static const gchar *prev_icon = ALARM_ICON;
295
const gchar *icon_name = ALARM_ICON;
297
if (applet->upcoming_alarm && applet->upcoming_alarm->type == ALARM_TYPE_TIMER) {
298
icon_name = TIMER_ICON;
301
w = GTK_WIDGET (applet->parent);
303
if (panel_applet_get_orient (applet->parent) == PANEL_APPLET_ORIENT_UP ||
304
panel_applet_get_orient (applet->parent) == PANEL_APPLET_ORIENT_DOWN)
305
size = w->allocation.height;
307
size = w->allocation.width;
322
// Reload icon only if the size is different.}
323
icon = gtk_image_get_pixbuf (GTK_IMAGE (applet->icon));
326
if (IS_HORIZONTAL (applet->parent))
327
pbsize = gdk_pixbuf_get_height (icon);
329
pbsize = gdk_pixbuf_get_width (icon);
331
if (prev_icon == icon_name && pbsize == size) {
333
//g_debug ("load_icon: Existing size the same.");
338
g_debug ("Resizing icon to %dx%d...", size, size);
340
icon = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
346
g_critical ("Icon not found.");
350
g_object_set (applet->icon, "pixbuf", icon, NULL);
353
g_object_unref (icon);
355
prev_icon = icon_name;
359
change_size_cb (GtkWidget *widget,
360
GtkAllocation *alloc,
363
alarm_applet_icon_update (applet);
369
update_orient (AlarmApplet *applet)
378
if (IS_HORIZONTAL (applet->parent) && ORIENT_IS_HORIZONTAL (applet->orient)) {
379
// Nothing to do, both old and new orientation is horizontal.
383
/* Do we need to repack? */
384
if (IS_HORIZONTAL (applet->parent) != ORIENT_IS_HORIZONTAL (applet->orient)) {
385
g_debug ("update_orient: REPACK");
388
if (IS_HORIZONTAL (applet->parent))
389
box = gtk_hbox_new(FALSE, 6);
391
box = gtk_vbox_new(FALSE, 6);
394
g_object_ref (applet->icon);
395
g_object_ref (applet->label);
398
gtk_container_remove (GTK_CONTAINER (applet->box), applet->icon);
399
gtk_container_remove (GTK_CONTAINER (applet->box), applet->label);
400
gtk_container_remove (GTK_CONTAINER (applet->parent), applet->box);
403
gtk_box_pack_start_defaults(GTK_BOX (box), applet->icon);
404
gtk_box_pack_start_defaults(GTK_BOX (box), applet->label);
408
/* Add to container and show */
409
gtk_container_add (GTK_CONTAINER (applet->parent), box);
410
gtk_widget_show_all (GTK_WIDGET (applet->parent));
413
switch (panel_applet_get_orient (applet->parent)) {
414
case PANEL_APPLET_ORIENT_LEFT:
417
case PANEL_APPLET_ORIENT_RIGHT:
426
angle = gtk_label_get_angle (GTK_LABEL (applet->label));
427
if (angle != new_angle) {
429
gtk_label_set_angle (GTK_LABEL (applet->label), new_angle);
434
orient_change_cb (PanelApplet *a,
435
PanelAppletOrient orient,
438
g_debug ("applet_orient_change");
440
update_orient (applet);
442
// Store new orientation
443
applet->orient = panel_applet_get_orient (applet->parent);
448
unrealize_cb (GtkWidget *object, AlarmApplet *applet)
450
alarm_applet_destroy (applet);
453
#ifdef HAVE_LIBNOTIFY
455
alarm_applet_notification_action_cb (NotifyNotification *notify,
459
Alarm *alarm = ALARM (data);
461
g_debug ("NOTIFY ACTION: %s", action);
463
if (strcmp (action, "clear") == 0) {
464
g_debug ("NOTIFY CLEAR #%d", alarm->id);
468
g_debug ("NOTIFY SNOOZE #%d", alarm->id);
469
alarm_snooze (alarm);
474
/* Taken from the battery applet */
476
alarm_applet_notification_display (AlarmApplet *applet, Alarm *alarm)
478
#ifdef HAVE_LIBNOTIFY
479
GError *error = NULL;
482
const gchar *message;
483
const gchar *icon = (alarm->type == ALARM_TYPE_CLOCK) ? ALARM_ICON : TIMER_ICON;
485
if (!notify_is_initted () && !notify_init (_("Alarm Applet")))
488
message = alarm->message;
490
applet->notify = notify_notification_new (_("Alarm!"), message, icon, GTK_WIDGET (applet->icon));
492
notify_notification_set_timeout (applet->notify, NOTIFY_EXPIRES_NEVER);
493
notify_notification_add_action (applet->notify, "clear", "Clear", alarm_applet_notification_action_cb, alarm, NULL);
496
notify_notification_add_action (applet->notify, "snooze", "Snooze", alarm_applet_notification_action_cb, alarm, NULL);
499
result = notify_notification_show (applet->notify, &error);
503
g_warning (error->message);
504
g_error_free (error);
514
alarm_applet_notification_close (AlarmApplet *applet)
516
#ifdef HAVE_LIBNOTIFY
518
GError *error = NULL;
520
result = notify_notification_close (applet->notify, &error);
524
g_warning (error->message);
525
g_error_free (error);
528
g_object_unref (applet->notify);
529
applet->notify = NULL;
537
alarm_applet_ui_update (AlarmApplet *applet)
539
if (applet->show_label) {
540
alarm_applet_label_update (applet);
543
alarm_applet_update_tooltip (applet);
549
alarm_applet_ui_init (AlarmApplet *applet)
554
/* Set up PanelApplet signals */
555
g_signal_connect (G_OBJECT(applet->parent), "button-press-event",
556
G_CALLBACK(button_cb), applet);
558
g_signal_connect (G_OBJECT(applet->parent), "unrealize",
559
G_CALLBACK(unrealize_cb), applet);
561
g_signal_connect (G_OBJECT(applet->parent), "change-background",
562
G_CALLBACK (applet_back_change), applet);
564
g_signal_connect (G_OBJECT(applet->parent), "change-orient",
565
G_CALLBACK (orient_change_cb), applet);
567
g_signal_connect (G_OBJECT(applet->parent), "size-allocate",
568
G_CALLBACK (change_size_cb), applet);
570
/* Set up container box */
571
if (IS_HORIZONTAL (applet->parent))
572
applet->box = gtk_hbox_new(FALSE, 6);
574
applet->box = gtk_vbox_new(FALSE, 6);
576
/* Store orientation for future reference */
577
applet->orient = panel_applet_get_orient (applet->parent);
579
/* Set up icon and label */
580
applet->icon = gtk_image_new ();
581
alarm_applet_icon_update (applet);
583
applet->label = g_object_new(GTK_TYPE_LABEL,
584
"label", ALARM_DEF_LABEL,
586
"visible", applet->show_label,
587
"no-show-all", TRUE, /* So gtk_widget_show_all() won't set visible to TRUE */
590
/* Set up UI updater */
591
alarm_applet_ui_update (applet);
592
applet->timer_id = g_timeout_add_seconds (1, (GSourceFunc)alarm_applet_ui_update, applet);
595
gtk_box_pack_start_defaults(GTK_BOX (applet->box), applet->icon);
596
gtk_box_pack_start_defaults(GTK_BOX (applet->box), applet->label);
598
/* Update orientation */
599
update_orient (applet);
601
/* Add to container and show */
602
gtk_container_add (GTK_CONTAINER (applet->parent), applet->box);
603
gtk_widget_show_all (GTK_WIDGET (applet->parent));
605
alarm_applet_update_tooltip (applet);
613
menu_snooze_alarm_cb (BonoboUIComponent *component,
617
g_debug("menu_snooze_alarm");
619
alarm_applet_snooze_alarms (applet);
623
menu_clear_alarm_cb (BonoboUIComponent *component,
627
g_debug("menu_clear_alarm");
629
alarm_applet_clear_alarms (applet);
633
menu_list_alarms_cb (BonoboUIComponent *component,
637
AlarmApplet *applet = (AlarmApplet *)data;
638
list_alarms_dialog_display (applet);
642
menu_preferences_cb (BonoboUIComponent *component,
646
/* Construct the preferences dialog and show it here */
647
g_debug("preferences_dialog");
649
preferences_dialog_display (applet);
653
menu_about_cb (BonoboUIComponent *component,
657
/* Construct the about dialog and show it here */
658
g_debug("about_dialog");
660
static const gchar *const authors[] = {
661
"Johannes H. Jensen <joh@pseudoberries.com>",
664
static const gchar *const documenters[] = {
665
"Johannes H. Jensen <joh@pseudoberries.com>",
668
static const gchar *const artists[] = {
669
"Lasse Gulvåg Sætre <lassegs@gmail.com>",
673
gtk_show_about_dialog (NULL,
674
"program-name", ALARM_NAME,
675
"title", _("About " ALARM_NAME),
677
"copyright", "\xC2\xA9 2007 Johannes H. Jensen",
678
"website", "http://alarm-clock.pseudoberries.com/",
680
"documenters", documenters,
682
"logo-icon-name",ALARM_ICON,
690
alarm_applet_menu_init (AlarmApplet *applet)
692
GtkIconInfo *info = gtk_icon_theme_lookup_icon (gtk_icon_theme_get_default(), SNOOZE_ICON, 16, 0);
694
g_debug ("ICON: %s", gtk_icon_info_get_filename (info));
696
static const gchar *menu_xml =
697
"<popup name=\"button3\">\n"
698
" <menuitem name=\"Snooze Item\" "
699
" verb=\"SnoozeAlarm\" "
700
" _label=\"_Snooze alarms\" "
701
" pixtype=\"filename\" "
702
" pixname=\"%s\"/>\n"
703
" <menuitem name=\"Clear Item\" "
704
" verb=\"ClearAlarm\" "
705
" _label=\"_Clear alarms\" "
706
" pixtype=\"stock\" "
707
" pixname=\"gtk-clear\"/>\n"
709
" <menuitem name=\"List Alarms\" "
710
" verb=\"ListAlarms\" "
711
" _label=\"_Edit Alarms\" "
712
" pixtype=\"stock\" "
713
" pixname=\"gtk-edit\"/>\n"
714
" <menuitem name=\"Preferences Item\" "
715
" verb=\"Preferences\" "
716
" _label=\"_Preferences...\"\n"
717
" pixtype=\"stock\" "
718
" pixname=\"gtk-properties\"/>\n"
719
" <menuitem name=\"About Item\" "
721
" _label=\"_About...\"\n"
722
" pixtype=\"stock\" "
723
" pixname=\"gtk-about\"/>\n"
726
static const BonoboUIVerb menu_verbs [] = {
727
BONOBO_UI_VERB ("SnoozeAlarm", menu_snooze_alarm_cb),
728
BONOBO_UI_VERB ("ClearAlarm", menu_clear_alarm_cb),
729
BONOBO_UI_VERB ("ListAlarms", menu_list_alarms_cb),
730
BONOBO_UI_VERB ("Preferences", menu_preferences_cb),
731
BONOBO_UI_VERB ("About", menu_about_cb),
735
gchar *xml = g_strdup_printf (menu_xml, gtk_icon_info_get_filename (info));
737
panel_applet_setup_menu (PANEL_APPLET (applet->parent),
743
gtk_icon_info_free (info);
749
* An error callback for MediaPlayers
752
media_player_error_cb (MediaPlayer *player, GError *err, GtkWindow *parent)
756
uri = media_player_get_uri (player);
757
tmp = g_strdup_printf (_("%s: %s"), uri, err->message);
759
g_critical (_("Could not play '%s': %s"), uri, err->message);
760
display_error_dialog (_("Could not play"), tmp, parent);