Disconnect the idle sound handler in notes during finalization
[hildon] / hildon / hildon-note.c
1 /*
2  * This file is a part of hildon
3  *
4  * Copyright (C) 2005, 2006 Nokia Corporation, all rights reserved.
5  *
6  * Contact: Rodrigo Novo <rodrigo.novo@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24
25 /**
26  * SECTION:hildon-note
27  * @short_description: A widget to ask confirmation from the user.
28  *
29  * #HildonNote is a convenient way to prompt users for a small amount of
30  * input. A simple note contains an information text and, in case of
31  * confirmation notes, it shows buttons to confirm or cancel. It also can
32  * include a progress bar.
33  *
34  * This widget provides convenient functions to create either
35  * information notes, confirmation notes or cancel notes, which are
36  * useful to show the progress of a requested task allowing the user
37  * to cancel it.
38  *
39  * To create information notes you can use
40  * hildon_note_new_information(). hildon_note_new_confirmation()
41  * creates a note with a text and two buttons to confirm or
42  * cancel. Note that it is possible to create a confirmation note with
43  * customized buttons by using
44  * hildon_note_new_confirmation_add_buttons().
45  *
46  * To create a note with a text, a progress bar and cancel button,
47  * hildon_note_new_cancel_with_progress_bar() can be used.
48  *
49  * <example>
50  * <title>HildonNote example</title>
51  * <programlisting>
52  * <!-- -->
53  * gboolean
54  * show_confirmation_note (GtkWindow *parent)
55  * {
56  *   gint retcode;
57  *   GtkWidget *note;
58  *   note = hildon_note_new_confirmation (parent, "Confirmation message...");
59  * <!-- -->
60  *   retcode = gtk_dialog_run (GTK_DIALOG (note));
61  *   gtk_widget_destroy (note);
62  * <!-- -->
63  *   if (retcode == GTK_RESPONSE_OK) {
64  *        g_debug ("User pressed 'OK' button'");
65  *        return TRUE;
66  *   } else {
67  *        g_debug ("User pressed 'Cancel' button");
68  *        return FALSE;
69  *   }
70  * }
71  * </programlisting>
72  * </example>
73  */
74
75 #ifdef                                          HAVE_CONFIG_H
76 #include                                        <config.h>
77 #endif
78
79 #include                                        <stdio.h>
80 #include                                        <string.h>
81 #include                                        <libintl.h>
82 #include                                        <X11/X.h>
83 #include                                        <X11/Xatom.h>
84 #include                                        <gdk/gdkx.h>
85
86 #undef HILDON_DISABLE_DEPRECATED
87
88 #include                                        "hildon-note.h"
89 #include                                        "hildon-defines.h"
90 #include                                        "hildon-sound.h"
91 #include                                        "hildon-banner.h" 
92 #include                                        "hildon-enum-types.h"
93 #include                                        "hildon-note-private.h"
94
95 #define                                         HILDON_INFORMATION_NOTE_MIN_HEIGHT 140
96
97 #define                                         HILDON_INFORMATION_NOTE_MARGIN 100
98
99 #define                                         CONFIRMATION_SOUND_PATH \
100                                                 "/usr/share/sounds/ui-confirmation_note.wav"
101
102 #define                                         INFORMATION_SOUND_PATH \
103                                                 "/usr/share/sounds/ui-information_note.wav"
104
105 #define                                         _(String) dgettext("hildon-libs", String)
106
107 static void 
108 hildon_note_class_init                          (HildonNoteClass *class);
109
110 static void
111 hildon_note_init                                (HildonNote *dialog);
112
113 static void 
114 hildon_note_rebuild                             (HildonNote *note);
115
116 static void
117 hildon_note_rename                              (HildonNote *note);
118
119 static void
120 hildon_note_finalize                            (GObject *obj_self);
121
122 static void
123 hildon_note_realize                             (GtkWidget *widget);
124
125 static void
126 hildon_note_unrealize                           (GtkWidget *widget);
127
128 static void
129 label_size_request                              (GtkWidget      *label,
130                                                  GtkRequisition *req,
131                                                  GtkWidget      *note);
132
133 static void 
134 hildon_note_set_property                        (GObject *object,
135                                                  guint prop_id,
136                                                  const GValue *value,
137                                                  GParamSpec *pspec);
138
139 static void
140 hildon_note_get_property                        (GObject *object,
141                                                  guint prop_id,
142                                                  GValue *value, 
143                                                  GParamSpec *pspec);
144
145 static void
146 on_show_cb                                      (GtkWidget *widget,
147                                                  gpointer data);
148 static gboolean
149 sound_handling                                  (gpointer data);
150
151 static void
152 unpack_widget                                   (GtkWidget *widget);
153
154 enum 
155 {
156     PROP_0,
157     PROP_HILDON_NOTE_TYPE,
158     PROP_HILDON_NOTE_DESCRIPTION,
159     PROP_HILDON_NOTE_ICON,
160     PROP_HILDON_NOTE_PROGRESSBAR,
161     PROP_HILDON_NOTE_STOCK_ICON
162 };
163
164 static GtkDialogClass*                          parent_class;
165
166 static gboolean
167 event_box_press_event                           (GtkEventBox    *event_box,
168                                                  GdkEventButton *event,
169                                                  GtkDialog      *note)
170 {
171     HildonNotePrivate *priv = HILDON_NOTE_GET_PRIVATE (note);
172
173     if (priv->note_n == HILDON_NOTE_TYPE_INFORMATION ||
174         priv->note_n == HILDON_NOTE_TYPE_INFORMATION_THEME) {
175             gtk_dialog_response (note, GTK_RESPONSE_DELETE_EVENT);
176             return TRUE;
177     } else {
178             return FALSE;
179     }
180 }
181
182 static void
183 hildon_note_set_property                        (GObject *object,
184                                                  guint prop_id,
185                                                  const GValue *value, 
186                                                  GParamSpec * pspec)
187 {
188     HildonNote *note = HILDON_NOTE (object);
189     HildonNotePrivate *priv;
190     GtkWidget *widget;
191
192     priv = HILDON_NOTE_GET_PRIVATE (note);
193     g_assert (priv);
194
195     switch (prop_id) {
196
197         case PROP_HILDON_NOTE_TYPE:
198             priv->note_n = g_value_get_enum (value);
199             hildon_note_rename (note);
200             hildon_note_rebuild (note);
201             break;
202
203         case PROP_HILDON_NOTE_DESCRIPTION:
204             if (priv->original_description) 
205                     g_free (priv->original_description);
206             priv->original_description = g_value_dup_string (value);
207
208             gtk_label_set_text (GTK_LABEL (priv->label), priv->original_description);
209             /* FIXME Is the "original_description" used anywhere? */
210             
211             break;
212
213         case PROP_HILDON_NOTE_ICON:
214             if (priv->icon) {
215               g_free (priv->icon);
216             }
217             priv->icon = g_value_dup_string (value);
218             break;
219
220         case PROP_HILDON_NOTE_STOCK_ICON:
221             if (priv->stock_icon) {
222               g_free (priv->stock_icon);
223             }
224             priv->stock_icon = g_value_dup_string (value);
225             break;
226
227         case PROP_HILDON_NOTE_PROGRESSBAR:
228             widget = g_value_get_object (value);
229             if (widget != priv->progressbar)
230             {
231                 if (priv->progressbar)
232                     g_object_unref (priv->progressbar);
233
234                 priv->progressbar = widget;
235
236                 if (widget)
237                 {
238                     g_object_ref (widget);
239                     gtk_object_sink (GTK_OBJECT (widget));
240                 }
241
242                 hildon_note_rebuild (note);
243             }
244             break;
245
246         default:
247             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
248             break;
249     }
250 }
251
252 static void
253 hildon_note_get_property                        (GObject *object,
254                                                  guint prop_id, 
255                                                  GValue *value, 
256                                                  GParamSpec *pspec)
257 {
258     HildonNote *note = HILDON_NOTE (object);
259     HildonNotePrivate *priv;
260
261     priv = HILDON_NOTE_GET_PRIVATE (note);
262
263     switch (prop_id) {
264
265         case PROP_HILDON_NOTE_TYPE:
266             g_value_set_enum (value, priv->note_n);
267             break;
268
269         case PROP_HILDON_NOTE_DESCRIPTION:
270             g_value_set_string (value, priv->original_description);
271             break;
272
273         case PROP_HILDON_NOTE_ICON:
274             g_value_set_string (value, priv->icon);
275             break;
276
277         case PROP_HILDON_NOTE_STOCK_ICON:
278             g_value_set_string (value, priv->stock_icon);
279             break;
280
281         case PROP_HILDON_NOTE_PROGRESSBAR:
282             g_value_set_object (value, priv->progressbar);
283             break;
284
285         default:
286             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
287             break;
288     }
289 }
290
291 /**
292  * hildon_note_get_type:
293  *
294  * Returns GType for HildonNote.
295  *
296  * Returns: HildonNote type
297  */
298 GType G_GNUC_CONST
299 hildon_note_get_type                            (void)
300 {
301     static GType dialog_type = 0;
302
303     if (! dialog_type) {
304         static const GTypeInfo dialog_info = {
305             sizeof(HildonNoteClass),
306             NULL,       /* base_init */
307             NULL,       /* base_finalize */
308             (GClassInitFunc) hildon_note_class_init,
309             NULL,       /* class_finalize */
310             NULL,       /* class_data */
311             sizeof(HildonNote),
312             0,  /* n_preallocs */
313             (GInstanceInitFunc) hildon_note_init
314         };
315         dialog_type = g_type_register_static (GTK_TYPE_DIALOG,
316                 "HildonNote",
317                 &dialog_info, 0);
318     }
319     return dialog_type;
320 }
321
322 static void 
323 hildon_note_class_init                          (HildonNoteClass *class)
324 {
325     GObjectClass *object_class = G_OBJECT_CLASS (class);
326     GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
327
328     /* set the global parent_class */
329     parent_class = g_type_class_peek_parent (class);
330
331     g_type_class_add_private (class, sizeof (HildonNotePrivate));
332
333     object_class->finalize      = hildon_note_finalize;
334     object_class->set_property  = hildon_note_set_property;
335     object_class->get_property  = hildon_note_get_property;
336     widget_class->realize       = hildon_note_realize;
337     widget_class->unrealize     = hildon_note_unrealize;
338
339     g_object_class_install_property (object_class,
340             PROP_HILDON_NOTE_TYPE,
341             g_param_spec_enum ("note-type",
342                 "note type",
343                 "The type of the note dialog",
344                 hildon_note_type_get_type (),
345                 HILDON_NOTE_TYPE_CONFIRMATION,
346                 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
347
348     /**
349      * HildonNote:description:
350      *
351      * Description for the note.
352      */
353     g_object_class_install_property (object_class,
354             PROP_HILDON_NOTE_DESCRIPTION,
355             g_param_spec_string ("description",
356                 "note description",
357                 "The text that appears in the note dialog",
358                 "",
359                 G_PARAM_READWRITE));
360
361     /**
362      * HildonNote:icon:
363      *
364      * Icon for the note.
365      *
366      * Deprecated: Since 2.2
367      */
368     g_object_class_install_property (object_class,
369             PROP_HILDON_NOTE_ICON,
370             g_param_spec_string ("icon",
371                 "note icon",
372                 "The name of the icon that appears in the note dialog",
373                 "",
374                 G_PARAM_READWRITE));
375
376     /**
377      * HildonNote:stock-icon:
378      *
379      * Stock icon name for the note.
380      *
381      * Deprecated: Since 2.2
382      */
383     g_object_class_install_property (object_class,
384             PROP_HILDON_NOTE_STOCK_ICON,
385             g_param_spec_string ("stock-icon",
386                 "Stock note icon",
387                 "The stock name of the icon that appears in the note dialog",
388                 "",
389                 G_PARAM_READWRITE));
390
391     /**
392      * HildonNote:progressbar:
393      *
394      * Progressbar for the note (if any).
395      */
396     g_object_class_install_property (object_class,
397             PROP_HILDON_NOTE_PROGRESSBAR,
398             g_param_spec_object ("progressbar",
399                 "Progressbar widget",
400                 "The progressbar that appears in the note dialog",
401                 GTK_TYPE_PROGRESS_BAR,
402                 G_PARAM_READWRITE));
403 }
404
405 static void 
406 hildon_note_init                                (HildonNote *dialog)
407 {
408     HildonNotePrivate *priv = HILDON_NOTE_GET_PRIVATE (dialog);
409     g_assert (priv);
410
411     priv->label = gtk_label_new (NULL);
412     gtk_label_set_line_wrap (GTK_LABEL (priv->label), TRUE);
413     gtk_label_set_justify (GTK_LABEL (priv->label), GTK_JUSTIFY_LEFT);
414
415     priv->event_box = gtk_event_box_new ();
416     priv->icon = NULL;
417     priv->stock_icon = NULL;
418     priv->idle_handler = 0;
419
420     gtk_event_box_set_visible_window (GTK_EVENT_BOX (priv->event_box), FALSE);
421     gtk_event_box_set_above_child (GTK_EVENT_BOX (priv->event_box), TRUE);
422     g_signal_connect (priv->event_box, "button-press-event",
423                       G_CALLBACK (event_box_press_event), dialog);
424
425     /* Because ESD is synchronous, we wish to play sound after the
426        note is already on screen to avoid blocking its appearance */
427     g_signal_connect (GTK_WIDGET (dialog), "show",
428                       G_CALLBACK (on_show_cb), NULL);
429
430     /* Acquire real references to our internal children, since
431        they are not nessecarily packed into container in each
432        layout */
433     g_object_ref_sink (priv->event_box);
434     g_object_ref_sink (priv->label);
435
436     gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
437     gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
438
439     /* We use special hint to turn the note into information notification. */
440     gtk_window_set_type_hint (GTK_WINDOW (dialog), GDK_WINDOW_TYPE_HINT_NOTIFICATION);
441 }
442
443
444 static void 
445 hildon_note_finalize                            (GObject *obj_self)
446 {
447     HildonNotePrivate *priv = HILDON_NOTE_GET_PRIVATE (obj_self);
448     g_assert (priv);
449
450     /* FIXME Some of this stuff should be moved to dispose */
451
452     /* Free internal data */
453     if (priv->event_box)
454         g_object_unref (priv->event_box);
455
456     if (priv->label)
457         g_object_unref (priv->label);
458
459     if (priv->icon) {
460         g_free (priv->icon);
461         priv->icon = NULL;
462     }
463     if (priv->stock_icon) {
464         g_free (priv->stock_icon);
465         priv->stock_icon = NULL;
466     }
467     if (priv->idle_handler) {
468         g_source_remove (priv->idle_handler);
469         priv->idle_handler = 0;
470     }
471
472     if (priv->progressbar)
473         g_object_unref (priv->progressbar);
474
475     if (priv->original_description)
476         g_free (priv->original_description);
477
478     G_OBJECT_CLASS (parent_class)->finalize (obj_self);
479 }
480
481 static void
482 label_size_request                              (GtkWidget      *label,
483                                                  GtkRequisition *req,
484                                                  GtkWidget      *note)
485 {
486     gint note_height = MAX (HILDON_INFORMATION_NOTE_MIN_HEIGHT, req->height);
487     g_object_set (note, "height-request", note_height, NULL);
488 }
489
490 static void
491 resize_button (GtkWidget *button, gpointer *data)
492 {
493     gint width = GPOINTER_TO_INT (data);
494     g_object_set (button, "width-request", width, NULL);
495 }
496
497 static void
498 hildon_note_orientation_update (HildonNote *note, GdkScreen *screen)
499 {
500     GtkDialog *dialog = GTK_DIALOG (note);
501     HildonNotePrivate* priv = HILDON_NOTE_GET_PRIVATE (note);
502     GtkWidget *parent;
503     gint button_width, padding;
504     gboolean portrait = gdk_screen_get_width (screen) < gdk_screen_get_height (screen);
505
506     g_object_ref (dialog->action_area);
507     unpack_widget (dialog->action_area);
508
509     if (portrait) {
510         parent = dialog->vbox;
511         button_width = gdk_screen_get_width (screen) - HILDON_MARGIN_DOUBLE * 2;
512         padding = HILDON_MARGIN_DOUBLE;
513     } else {
514         parent = gtk_widget_get_parent (dialog->vbox);
515         button_width = priv->button_width;
516         padding = 0;
517     }
518
519     gtk_box_pack_end (GTK_BOX (parent), dialog->action_area,
520                       portrait, TRUE, 0);
521     gtk_box_reorder_child (GTK_BOX (parent), dialog->action_area, 0);
522     gtk_container_foreach (GTK_CONTAINER (dialog->action_area),
523                            (GtkCallback) resize_button,
524                            GINT_TO_POINTER (button_width));
525     g_object_unref (dialog->action_area);
526     gtk_container_child_set (GTK_CONTAINER (priv->box), priv->label,
527                              "padding", padding, NULL);
528 }
529
530 static void
531 screen_size_changed                            (GdkScreen *screen,
532                                                 GtkWidget *note)
533 {
534     HildonNotePrivate *priv = HILDON_NOTE_GET_PRIVATE (note);
535     gint screen_width = gdk_screen_get_width (screen);
536     gint text_width = screen_width - HILDON_INFORMATION_NOTE_MARGIN * 2;
537
538     if (priv->note_n == HILDON_NOTE_TYPE_INFORMATION ||
539         priv->note_n == HILDON_NOTE_TYPE_INFORMATION_THEME) {
540         g_object_set (note, "width-request", screen_width, NULL);
541         g_object_set (priv->label, "width-request", text_width, NULL);
542
543         return;
544     } else if (priv->note_n == HILDON_NOTE_TYPE_CONFIRMATION) {
545         hildon_note_orientation_update (HILDON_NOTE (note), screen);
546     }
547 }
548
549 static void
550 hildon_note_realize                             (GtkWidget *widget)
551 {
552     GdkDisplay *display;
553     gboolean is_info_note = FALSE;
554     Atom atom;
555     const gchar *notification_type;
556     HildonNotePrivate *priv = HILDON_NOTE_GET_PRIVATE (widget);
557     g_assert (priv);
558
559     /* Make widget->window accessible */
560     GTK_WIDGET_CLASS (parent_class)->realize (widget);
561
562     /* Border only, no titlebar */
563     gdk_window_set_decorations (widget->window, GDK_DECOR_BORDER);
564
565     /* Set the _HILDON_NOTIFICATION_TYPE property so Matchbox places the window correctly */
566     display = gdk_drawable_get_display (widget->window);
567     atom = gdk_x11_get_xatom_by_name_for_display (display, "_HILDON_NOTIFICATION_TYPE");
568
569     if (priv->note_n == HILDON_NOTE_TYPE_INFORMATION ||
570         priv->note_n == HILDON_NOTE_TYPE_INFORMATION_THEME) {
571         notification_type = "_HILDON_NOTIFICATION_TYPE_INFO";
572         is_info_note = TRUE;
573     } else {
574         notification_type = "_HILDON_NOTIFICATION_TYPE_CONFIRMATION";
575     }
576
577     XChangeProperty (GDK_WINDOW_XDISPLAY (widget->window), GDK_WINDOW_XID (widget->window),
578                      atom, XA_STRING, 8, PropModeReplace, (guchar *) notification_type,
579                      strlen (notification_type));
580
581     if (is_info_note) {
582         g_signal_connect (priv->label, "size-request", G_CALLBACK (label_size_request), widget);
583     }
584
585     GdkScreen *screen = gtk_widget_get_screen (widget);
586     g_signal_connect (screen, "size-changed", G_CALLBACK (screen_size_changed), widget);
587     screen_size_changed (screen, widget);
588 }
589
590 static void
591 hildon_note_unrealize                           (GtkWidget *widget)
592 {
593     HildonNotePrivate *priv = HILDON_NOTE_GET_PRIVATE (widget);
594     GdkScreen *screen = gtk_widget_get_screen (widget);
595
596     g_signal_handlers_disconnect_by_func (screen, G_CALLBACK (screen_size_changed), widget);
597     g_signal_handlers_disconnect_by_func (priv->label, G_CALLBACK (label_size_request), widget);
598
599     GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
600 }
601
602
603 /* Helper function for removing a widget from it's container.
604    we own a separate reference to each object we try to unpack,
605    so extra referencing is not needed. */
606 static void 
607 unpack_widget                                   (GtkWidget *widget)
608 {
609     g_assert (widget == NULL || GTK_IS_WIDGET (widget));
610
611     if (widget && widget->parent)
612         gtk_container_remove (GTK_CONTAINER (widget->parent), widget);
613 }
614
615 /*
616   Name the widget and text label based on the note type. This is used
617   by the theme to give proper backgrounds depending on the note type.
618 */
619 static void
620 hildon_note_rename                              (HildonNote *note)
621 {
622   GEnumValue *value;
623   GEnumClass *enum_class;
624   gchar *name;
625
626   HildonNotePrivate *priv = HILDON_NOTE_GET_PRIVATE (note);
627
628   enum_class = g_type_class_ref (HILDON_TYPE_NOTE_TYPE);
629   value = g_enum_get_value (enum_class, priv->note_n);
630
631   name = g_strconcat ("HildonNote-", value->value_nick, NULL);
632   gtk_widget_set_name (GTK_WIDGET (note), name);
633   g_free (name);
634
635   name = g_strconcat ("HildonNoteLabel-", value->value_nick, NULL);
636   gtk_widget_set_name (priv->label, name);
637   g_free (name);
638
639   g_type_class_unref (enum_class);
640 }
641
642 static void
643 hildon_note_rebuild                             (HildonNote *note)
644 {
645     GtkDialog *dialog;
646     HildonNotePrivate *priv;
647     gboolean is_info_note = FALSE;
648
649     g_assert (HILDON_IS_NOTE (note));
650
651     priv = HILDON_NOTE_GET_PRIVATE (note);
652     g_assert (priv);
653
654     dialog = GTK_DIALOG (note);
655
656     /* Reuse exiting content widgets for new layout */
657     unpack_widget (priv->label);
658     unpack_widget (priv->progressbar);
659     unpack_widget (priv->event_box);
660
661     /* Destroy old layout and buttons */
662     if (priv->box) {
663         gtk_widget_destroy (priv->box);
664         priv->box = NULL;
665     }
666     if (priv->okButton) {
667         gtk_widget_destroy (priv->okButton);
668         priv->okButton = NULL;
669     }
670     if (priv->cancelButton) {
671         gtk_widget_destroy (priv->cancelButton);
672         priv->cancelButton = NULL;
673     }
674
675     /* Add needed buttons and images for each note type */
676     switch (priv->note_n)
677     {
678         case HILDON_NOTE_TYPE_CONFIRMATION:
679             priv->okButton = gtk_dialog_add_button (dialog,
680                     _("wdgt_bd_yes"), GTK_RESPONSE_OK);
681             priv->cancelButton = gtk_dialog_add_button (dialog,
682                     _("wdgt_bd_no"), GTK_RESPONSE_CANCEL);
683             gtk_widget_show (priv->cancelButton);
684             g_object_get (priv->okButton, "width-request",
685                           &priv->button_width, NULL);
686             gtk_widget_set_no_show_all (priv->cancelButton, FALSE);
687             break;
688
689         case HILDON_NOTE_TYPE_PROGRESSBAR:
690             priv->cancelButton = gtk_dialog_add_button (dialog,
691                     _("wdgt_bd_stop"), GTK_RESPONSE_CANCEL);
692             gtk_widget_show (priv->cancelButton);
693             gtk_widget_set_no_show_all (priv->cancelButton, FALSE);
694             break;
695
696         case HILDON_NOTE_TYPE_INFORMATION_THEME:
697         case HILDON_NOTE_TYPE_INFORMATION:
698             is_info_note = TRUE;
699             break;
700
701         case HILDON_NOTE_TYPE_CONFIRMATION_BUTTON:
702         default:
703             break;
704     }
705
706     /* Don't display the action area if this is just an information
707      * note. This prevents text from being slightly aligned to the
708      * left
709      */
710     if (is_info_note) {
711         gtk_widget_hide (dialog->action_area);
712     } else {
713         gtk_widget_show (dialog->action_area);
714     }
715     gtk_widget_set_no_show_all (dialog->action_area, is_info_note);
716
717     /* Pack label vertically. Spacing is only necessary for the progressbar note. */
718     priv->box = gtk_vbox_new (FALSE, priv->progressbar ? HILDON_MARGIN_DOUBLE : 0);
719     gtk_container_add (GTK_CONTAINER (priv->event_box), priv->box);
720     gtk_box_pack_start (GTK_BOX (priv->box), priv->label, TRUE, TRUE, 0);
721
722     if (priv->progressbar)
723         gtk_box_pack_start (GTK_BOX (priv->box), priv->progressbar, FALSE, FALSE, 0);
724
725     gtk_container_add (GTK_CONTAINER (dialog->vbox), priv->event_box);
726
727     gtk_widget_show_all (priv->event_box);
728 }
729
730 /**
731  * hildon_note_new_confirmation_add_buttons:
732  * @parent: the parent window. The X window ID of the parent window
733  *   has to be the same as the X window ID of the application. This is
734  *   important so that the window manager could handle the windows
735  *   correctly.
736  *   In GTK the X window ID can be checked using
737  *   GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
738  * @description: the message to confirm
739  * @Varargs: arguments pairs for new buttons(label and return value). 
740  *   Terminate the list with %NULL value.
741  * 
742  * Create a new confirmation note with custom buttons. Confirmation
743  * note has a text and any number of buttons. It's important to note
744  * that even though the name of the function might suggest, the
745  * default ok/cancel buttons are not appended but you have to provide
746  * all of the buttons.
747  *
748  * FIXME: This doc seems to be wrong, the two buttons aren't added so
749  * it would only contain the "additional" buttons? However, changing
750  * this would break those applications that rely on current behaviour.
751  *
752  * Returns: A #GtkWidget pointer of the note
753  */
754 GtkWidget*
755 hildon_note_new_confirmation_add_buttons        (GtkWindow *parent,
756                                                  const gchar *description,
757                                                  ...)
758 {
759     va_list args;
760     char *message;
761     int value;
762     GtkWidget *button;
763
764     g_return_val_if_fail (description != NULL, NULL);
765
766     GtkWidget *conf_note =
767         g_object_new (HILDON_TYPE_NOTE,
768                 "note-type", HILDON_NOTE_TYPE_CONFIRMATION_BUTTON,
769                 "description", description,
770                 NULL);
771
772     if (parent != NULL)
773         gtk_window_set_transient_for (GTK_WINDOW (conf_note), parent);
774
775     /* Add the buttons from varargs */
776     va_start(args, description);
777
778     while (TRUE) {
779         message = va_arg (args, char *);
780
781         if (! message) {
782             break;
783         }
784         value = va_arg (args, int);
785
786         button = gtk_dialog_add_button (GTK_DIALOG (conf_note), message, value);
787         /* maemo-gtk is going to set the "no-show-all" property all
788            cancel/close-like buttons to TRUE, so that they are not shown. On
789            the other hand, this confirmation note with custom buttons should
790            not obey this rule, so we need to make sure they are shown. */
791         gtk_widget_show (button);
792         gtk_widget_set_no_show_all (button, FALSE);
793     }
794
795     va_end (args);
796
797     return conf_note;
798 }
799
800
801 /**
802  * hildon_note_new_confirmation:
803  * @parent: the parent window. The X window ID of the parent window
804  *   has to be the same as the X window ID of the application. This is
805  *   important so that the window manager could handle the windows
806  *   correctly. In GTK the X window ID can be checked using
807  *   GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
808  * @description: the message to confirm
809  *
810  * Create a new confirmation note. Confirmation note has a text (description)
811  * that you specify and two buttons.
812  *
813  * Returns: a #GtkWidget pointer of the note
814  */
815 GtkWidget*
816 hildon_note_new_confirmation                    (GtkWindow *parent,
817                                                  const gchar *description)
818 {
819     GtkWidget *dialog = NULL;
820
821     g_return_val_if_fail (description != NULL, NULL);
822
823     dialog = g_object_new (HILDON_TYPE_NOTE,
824             "note-type",
825             HILDON_NOTE_TYPE_CONFIRMATION,
826             "description", description, NULL);
827
828     if (parent != NULL)
829         gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
830
831     return dialog;
832 }
833
834 /**
835  * hildon_note_new_confirmation_with_icon_name:
836  * @parent: the parent window. The X window ID of the parent window
837  *   has to be the same as the X window ID of the application. This is
838  *   important so that the window manager could handle the windows
839  *   correctly. In GTK the X window ID can be checked using
840  *   GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
841  * @description: the message to confirm
842  * @icon_name: icon to be displayed. If NULL, default icon is used.
843  * 
844  * Create a new confirmation note. Confirmation note has a text (description) 
845  * that you specify and two buttons.
846  *
847  * Deprecated: Since 2.2, icons are not shown in confirmation notes. Icons set
848  * with this function will be ignored. Use hildon_note_new_confirmation() instead.
849  *
850  * Returns: a #GtkWidget pointer of the note
851  */
852 GtkWidget*
853 hildon_note_new_confirmation_with_icon_name     (GtkWindow *parent,
854                                                  const gchar *description,
855                                                  const gchar *icon_name)
856 {
857     GtkWidget *dialog;
858
859     dialog = hildon_note_new_confirmation (parent, description);
860     g_object_set (dialog, "icon", icon_name, NULL);
861
862     return dialog;
863 }
864
865 /**
866  * hildon_note_new_information:
867  * @parent: the parent window. The X window ID of the parent window
868  *   has to be the same as the X window ID of the application. This is
869  *   important so that the window manager could handle the windows
870  *   correctly. In GTK the X window ID can be checked using
871  *   GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
872  * @description: the message to confirm
873  * 
874  * Create a new information note. Information note has a text (description)
875  * that you specify and an OK button.
876  * 
877  * Returns: a #GtkWidget pointer of the note
878  */
879 GtkWidget*
880 hildon_note_new_information                     (GtkWindow *parent,
881                                                  const gchar *description)
882 {
883     GtkWidget *dialog = NULL;
884
885     g_return_val_if_fail (description != NULL, NULL);
886
887     dialog = g_object_new (HILDON_TYPE_NOTE,
888             "note-type",
889             HILDON_NOTE_TYPE_INFORMATION_THEME,
890             "description", description, NULL);
891
892     if (parent != NULL)
893         gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
894
895     return dialog;
896 }
897
898 /**
899  * hildon_note_new_information_with_icon_name:
900  * @parent: the parent window. The X window ID of the parent window
901  *   has to be the same as the X window ID of the application. This is
902  *   important so that the window manager could handle the windows
903  *   correctly. In GTK the X window ID can be checked using
904  *   GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
905  * @description: the message to confirm
906  * @icon_name: icon to be displayed. If NULL, default icon is used.
907  * 
908  * Create a new information note. Information note has text(description) 
909  * that you specify, an OK button and an icon.
910  * 
911  * Deprecated: Since 2.2, icons are not shown in confirmation notes. Icons set
912  * with this function will be ignored. Use hildon_note_new_information() instead.
913  *
914  * Returns: a #GtkWidget pointer of the note
915  */
916 GtkWidget*
917 hildon_note_new_information_with_icon_name      (GtkWindow * parent,
918                                                  const gchar *description,
919                                                  const gchar *icon_name)
920 {
921     GtkWidget *dialog;
922
923     dialog = hildon_note_new_information (parent, description);
924     g_object_set (dialog, "icon", icon_name, NULL);
925
926     return dialog;
927 }
928
929 /* FIXME This documentation string LIES! */
930
931 /**
932  * hildon_note_new_cancel_with_progress_bar:
933  * @parent: the parent window. The X window ID of the parent window
934  *   has to be the same as the X window ID of the application. This is
935  *   important so that the window manager could handle the windows
936  *   correctly. In GTK the X window ID can be checked using
937  *   GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
938  * @description: the action to cancel
939  * @progressbar: a pointer to #GtkProgressBar to be filled with the
940  *   progressbar assigned to this note. Use this to set the fraction of
941  *   progressbar done. This parameter can be %NULL as well, in which
942  *   case plain text cancel note appears.
943  *
944  * Create a new cancel note with a progress bar. Cancel note has 
945  * text(description) that you specify, a Cancel button and a progress bar.
946  *
947  * Returns: a #GtkDialog. Use this to get rid of this note when you
948  *   no longer need it.
949  */
950 GtkWidget*
951 hildon_note_new_cancel_with_progress_bar        (GtkWindow *parent,
952                                                  const gchar *description,
953                                                  GtkProgressBar *progressbar)
954 {
955     GtkWidget *dialog = NULL;
956
957     g_return_val_if_fail (description != NULL, NULL);
958
959     dialog = g_object_new (HILDON_TYPE_NOTE,
960             "note-type",
961             HILDON_NOTE_TYPE_PROGRESSBAR,
962             "description", description,
963             "progressbar",
964             progressbar, NULL);
965
966     if (parent != NULL)
967         gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
968
969     return dialog;
970 }
971
972
973 /**
974  * hildon_note_set_button_text:
975  * @note: a #HildonNote
976  * @text: sets the button text and if there is two buttons in dialog, 
977  *   the button texts will be &lt;text&gt;, "Cancel".  
978  *
979  * Sets the button text to be used by the hildon_note widget.
980  */
981 void 
982 hildon_note_set_button_text                     (HildonNote *note, 
983                                                  const gchar *text)
984 {
985     HildonNotePrivate *priv;
986
987     g_return_if_fail (HILDON_IS_NOTE (note));
988
989     priv = HILDON_NOTE_GET_PRIVATE (HILDON_NOTE (note));
990     g_assert (priv);
991
992     if (priv->okButton) {
993         gtk_button_set_label (GTK_BUTTON (priv->okButton), text);
994         gtk_button_set_label (GTK_BUTTON (priv->cancelButton),
995                 _("wdgt_bd_no"));
996     } else {
997         gtk_button_set_label (GTK_BUTTON (priv->cancelButton), text);
998     }
999 }
1000
1001 /**
1002  * hildon_note_set_button_texts:
1003  * @note: a #HildonNote
1004  * @text_ok: the new text of the default OK button
1005  * @text_cancel: the new text of the default cancel button 
1006  *
1007  * Sets the button texts to be used by this hildon_note widget.
1008  */
1009 void 
1010 hildon_note_set_button_texts                    (HildonNote *note,
1011                                                  const gchar *text_ok,
1012                                                  const gchar *text_cancel)
1013 {
1014     HildonNotePrivate *priv;
1015
1016     g_return_if_fail (HILDON_IS_NOTE (note));
1017
1018     priv = HILDON_NOTE_GET_PRIVATE (HILDON_NOTE (note));
1019     g_assert (priv);
1020
1021     if (priv->okButton) {
1022         gtk_button_set_label (GTK_BUTTON (priv->okButton), text_ok);
1023         gtk_button_set_label (GTK_BUTTON (priv->cancelButton), text_cancel);
1024     } else {
1025         gtk_button_set_label (GTK_BUTTON (priv->cancelButton), text_cancel);
1026     }
1027 }
1028
1029 static void
1030 on_show_cb                                      (GtkWidget *widget,
1031                                                  gpointer data)
1032 {
1033     HildonNotePrivate *priv;
1034
1035     priv = HILDON_NOTE_GET_PRIVATE (widget);
1036     priv->idle_handler = g_idle_add (sound_handling, widget);
1037 }
1038
1039 /* We play a system sound when the note comes visible */
1040 static gboolean
1041 sound_handling                                  (gpointer data)
1042 {
1043     HildonNotePrivate *priv = HILDON_NOTE_GET_PRIVATE (data);
1044     g_assert (priv);
1045
1046     switch (priv->note_n)
1047     {
1048         case HILDON_NOTE_TYPE_INFORMATION:
1049         case HILDON_NOTE_TYPE_INFORMATION_THEME:
1050             hildon_play_system_sound (INFORMATION_SOUND_PATH);
1051             break;
1052
1053         case HILDON_NOTE_TYPE_CONFIRMATION:
1054         case HILDON_NOTE_TYPE_CONFIRMATION_BUTTON:
1055             hildon_play_system_sound (CONFIRMATION_SOUND_PATH);
1056             break;
1057
1058         default:
1059             break;
1060     };
1061
1062     priv->idle_handler = 0;
1063
1064     return FALSE;
1065 }