2008-07-29 Claudio Saavedra <csaavedra@igalia.com>
[hildon] / src / 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: Michael Dominic Kostrzewa <michael.kostrzewa@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  * Notes are used to for confirmation (OK/Cancel/etc.) from the user.
30  * A simple note contains an information text. Additional features
31  * such as progress bars or animation can also be included.
32  * 
33  * <example>
34  * <title>HildonNote example</title>
35  * <programlisting>
36  * <!-- -->
37  * hildon_note_new_confirmation (window, "Confirmation message...");
38  * <!-- -->
39  * i = gtk_dialog_run (GTK_DIALOG (note));
40  * gtk_widget_destroy (GTK_WIDGET (note));
41  * <!-- -->
42  * if (i == GTK_RESPONSE_OK)
43  *      gtk_infoprint (window, "User pressed 'OK' button'");
44  * else
45  *      gtk_infoprint (window, "User pressed 'Cancel' button" );
46  * </programlisting>
47  * </example>
48  */
49
50 #ifdef                                          HAVE_CONFIG_H
51 #include                                        <config.h>
52 #endif
53
54 #include                                        "hildon-note.h"
55 #include                                        <gtk/gtklabel.h>
56 #include                                        <gtk/gtkimage.h>
57 #include                                        <gtk/gtkhbox.h>
58 #include                                        <gtk/gtkalignment.h>
59 #include                                        <gtk/gtkvbox.h>
60 #include                                        <gtk/gtkbutton.h>
61 #include                                        <libintl.h>
62 #include                                        "hildon-defines.h"
63 #include                                        "hildon-sound.h"
64 #include                                        "hildon-banner.h" 
65 #include                                        "hildon-enum-types.h"
66 #include                                        <stdio.h>
67 #include                                        <string.h>
68 #include                                        <X11/X.h>
69 #include                                        <X11/Xatom.h>
70 #include                                        "hildon-note-private.h"
71
72 #define                                         CONFIRMATION_SOUND_PATH \
73                                                 "/usr/share/sounds/ui-confirmation_note.wav"
74
75 #define                                         INFORMATION_SOUND_PATH \
76                                                 "/usr/share/sounds/ui-information_note.wav"
77
78 #define                                         HILDON_NOTE_CONFIRMATION_ICON \
79                                                 "qgn_note_confirm"
80
81 #define                                         HILDON_NOTE_INFORMATION_ICON \
82                                                 "qgn_note_info"
83
84 #define                                         _(String) dgettext("hildon-libs", String)
85
86 static void 
87 hildon_note_class_init                          (HildonNoteClass *class);
88
89 static void
90 hildon_note_init                                (HildonNote *dialog);
91
92 static void 
93 hildon_note_rebuild                             (HildonNote *note);
94
95 static void
96 hildon_note_finalize                            (GObject *obj_self);
97
98 static gboolean
99 hildon_note_button_release                      (GtkWidget *widget,
100                                                  GdkEventButton *event);
101
102 static void
103 hildon_note_map                                 (GtkWidget *widget);
104
105 static void
106 hildon_note_unmap                               (GtkWidget *widget);
107
108 static void
109 hildon_note_realize                             (GtkWidget *widget);
110
111 static void 
112 hildon_note_set_property                        (GObject *object,
113                                                  guint prop_id,
114                                                  const GValue *value,
115                                                  GParamSpec *pspec);
116
117 static void
118 hildon_note_get_property                        (GObject *object,
119                                                  guint prop_id,
120                                                  GValue *value, 
121                                                  GParamSpec *pspec);
122
123 static gboolean
124 sound_handling                                  (GtkWidget *widget, 
125                                                  GdkEventExpose *event, 
126                                                  gpointer data);
127
128 enum 
129 {
130     PROP_0,
131     PROP_HILDON_NOTE_TYPE,
132     PROP_HILDON_NOTE_DESCRIPTION,
133     PROP_HILDON_NOTE_ICON,
134     PROP_HILDON_NOTE_PROGRESSBAR,
135     PROP_HILDON_NOTE_STOCK_ICON
136 };
137
138 static GtkDialogClass*                          parent_class;
139
140 static GdkWindow *
141 grab_transfer_window_get                        (GtkWidget *widget)
142 {
143     GdkWindow *window;
144     GdkWindowAttr attributes;
145     gint attributes_mask;
146
147     attributes.x = 0;
148     attributes.y = 0;
149     attributes.width = 10;
150     attributes.height = 10;
151     attributes.window_type = GDK_WINDOW_TEMP;
152     attributes.wclass = GDK_INPUT_ONLY;
153     attributes.override_redirect = TRUE;
154     attributes.event_mask = 0;
155
156     attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR;
157
158     window = gdk_window_new (gtk_widget_get_root_window (widget),
159                              &attributes, attributes_mask);
160     gdk_window_set_user_data (window, widget);
161
162     gdk_window_show (window);
163
164     return window;
165 }
166
167 static void
168 hildon_note_set_property                        (GObject *object,
169                                                  guint prop_id,
170                                                  const GValue *value, 
171                                                  GParamSpec * pspec)
172 {
173     HildonNote *note = HILDON_NOTE (object);
174     HildonNotePrivate *priv;
175     GtkWidget *widget;
176
177     priv = HILDON_NOTE_GET_PRIVATE (note);
178     g_assert (priv);
179
180     switch (prop_id) {
181
182         case PROP_HILDON_NOTE_TYPE:
183             priv->note_n = g_value_get_enum (value);
184             hildon_note_rebuild (note);
185             break;
186
187         case PROP_HILDON_NOTE_DESCRIPTION:
188             if (priv->original_description) 
189                     g_free (priv->original_description);
190             priv->original_description = g_value_dup_string (value);
191
192             gtk_label_set_text (GTK_LABEL (priv->label), priv->original_description);
193             /* FIXME Is the "original_description" used anywhere? */
194             
195             break;
196
197         case PROP_HILDON_NOTE_ICON:
198             gtk_image_set_from_icon_name (GTK_IMAGE (priv->icon), 
199                     g_value_get_string(value), HILDON_ICON_SIZE_BIG_NOTE);
200             break;
201
202         case PROP_HILDON_NOTE_STOCK_ICON:
203             gtk_image_set_from_stock (GTK_IMAGE (priv->icon), 
204                     g_value_get_string (value), HILDON_ICON_SIZE_BIG_NOTE);
205             break;
206
207         case PROP_HILDON_NOTE_PROGRESSBAR:
208             widget = g_value_get_object (value);
209             if (widget != priv->progressbar)
210             {
211                 if (priv->progressbar)
212                     g_object_unref (priv->progressbar);
213
214                 priv->progressbar = widget;
215
216                 if (widget)
217                 {
218                     g_object_ref (widget);
219                     gtk_object_sink (GTK_OBJECT (widget));
220                 }
221
222                 hildon_note_rebuild (note);
223             }
224             break;
225
226         default:
227             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
228             break;
229     }
230 }
231
232 static void
233 hildon_note_get_property                        (GObject *object,
234                                                  guint prop_id, 
235                                                  GValue *value, 
236                                                  GParamSpec *pspec)
237 {
238     HildonNote *note = HILDON_NOTE (object);
239     HildonNotePrivate *priv;
240
241     priv = HILDON_NOTE_GET_PRIVATE (note);
242
243     switch (prop_id) {
244
245         case PROP_HILDON_NOTE_TYPE:
246             g_value_set_enum (value, priv->note_n);
247             break;
248
249         case PROP_HILDON_NOTE_DESCRIPTION:
250             g_value_set_string (value, priv->original_description);
251             break;
252
253         case PROP_HILDON_NOTE_ICON:
254             g_object_get_property (G_OBJECT (priv->icon), "icon-name", value);
255             break;
256
257         case PROP_HILDON_NOTE_STOCK_ICON:
258             g_object_get_property (G_OBJECT (priv->icon), "stock", value);
259             break;
260
261         case PROP_HILDON_NOTE_PROGRESSBAR:
262             g_value_set_object (value, priv->progressbar);
263             break;
264
265         default:
266             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
267             break;
268     }
269 }
270
271 /**
272  * hildon_note_get_type:
273  *
274  * Returns GType for HildonNote.
275  *
276  * Returns: HildonNote type
277  */
278 GType G_GNUC_CONST
279 hildon_note_get_type                            (void)
280 {
281     static GType dialog_type = 0;
282
283     if (! dialog_type) {
284         static const GTypeInfo dialog_info = {
285             sizeof(HildonNoteClass),
286             NULL,       /* base_init */
287             NULL,       /* base_finalize */
288             (GClassInitFunc) hildon_note_class_init,
289             NULL,       /* class_finalize */
290             NULL,       /* class_data */
291             sizeof(HildonNote),
292             0,  /* n_preallocs */
293             (GInstanceInitFunc) hildon_note_init
294         };
295         dialog_type = g_type_register_static (GTK_TYPE_DIALOG,
296                 "HildonNote",
297                 &dialog_info, 0);
298     }
299     return dialog_type;
300 }
301
302 static void 
303 hildon_note_class_init                          (HildonNoteClass *class)
304 {
305     GObjectClass *object_class = G_OBJECT_CLASS (class);
306     GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
307
308     /* set the global parent_class */
309     parent_class = g_type_class_peek_parent (class);
310
311     g_type_class_add_private (class, sizeof (HildonNotePrivate));
312
313     object_class->finalize      = hildon_note_finalize;
314     object_class->set_property  = hildon_note_set_property;
315     object_class->get_property  = hildon_note_get_property;
316     widget_class->button_release_event = hildon_note_button_release;
317     widget_class->map           = hildon_note_map;
318     widget_class->unmap         = hildon_note_unmap;
319     widget_class->realize       = hildon_note_realize;
320
321     g_object_class_install_property (object_class,
322             PROP_HILDON_NOTE_TYPE,
323             g_param_spec_enum ("note-type",
324                 "note type",
325                 "The type of the note dialog",
326                 hildon_note_type_get_type (),
327                 HILDON_NOTE_TYPE_CONFIRMATION,
328                 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
329
330     /**
331      * HildonNote:description:
332      *
333      * Description for the note.
334      */
335     g_object_class_install_property (object_class,
336             PROP_HILDON_NOTE_DESCRIPTION,
337             g_param_spec_string ("description",
338                 "note description",
339                 "The text that appears in the note dialog",
340                 "",
341                 G_PARAM_READWRITE));
342
343     /**
344      * HildonNote:icon:
345      *
346      * Icon for the note.
347      */
348     g_object_class_install_property (object_class,
349             PROP_HILDON_NOTE_ICON,
350             g_param_spec_string ("icon",
351                 "note icon",
352                 "The name of the icon that appears in the note dialog",
353                 "",
354                 G_PARAM_READWRITE));
355
356     /**
357      * HildonNote:stock-icon:
358      *
359      * Stock icon name for the note.
360      */
361     g_object_class_install_property (object_class,
362             PROP_HILDON_NOTE_STOCK_ICON,
363             g_param_spec_string ("stock-icon",
364                 "Stock note icon",
365                 "The stock name of the icon that appears in the note dialog",
366                 "",
367                 G_PARAM_READWRITE));
368
369     /**
370      * HildonNote:progressbar:
371      *
372      * Progressbar for the note (if any).
373      */
374     g_object_class_install_property (object_class,
375             PROP_HILDON_NOTE_PROGRESSBAR,
376             g_param_spec_object ("progressbar",
377                 "Progressbar widget",
378                 "The progressbar that appears in the note dialog",
379                 GTK_TYPE_PROGRESS_BAR,
380                 G_PARAM_READWRITE));
381 }
382
383 static void 
384 hildon_note_init                                (HildonNote *dialog)
385 {
386     HildonNotePrivate *priv = HILDON_NOTE_GET_PRIVATE (dialog);
387     g_assert (priv);
388
389     priv->label = gtk_label_new (NULL);
390     gtk_label_set_line_wrap (GTK_LABEL (priv->label), TRUE);
391     
392     priv->icon  = gtk_image_new ();
393     priv->close_if_pressed_outside = FALSE;
394     priv->transfer_window = NULL;
395
396     /* Acquire real references to our internal children, since
397        they are not nessecarily packed into container in each
398        layout */
399     g_object_ref_sink (priv->label);
400     g_object_ref_sink (priv->icon);
401
402     gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
403     gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
404 }
405
406
407 static void 
408 hildon_note_finalize                            (GObject *obj_self)
409 {
410     HildonNotePrivate *priv = HILDON_NOTE_GET_PRIVATE (obj_self);
411     g_assert (priv);
412
413     /* FIXME Some of this stuff should be moved to dispose */
414
415     /* Free internal data */
416     if (priv->label)
417         g_object_unref (priv->label);
418
419     if (priv->icon)
420         g_object_unref (priv->icon);
421
422     if (priv->progressbar)
423         g_object_unref (priv->progressbar);
424
425     if (priv->original_description)
426         g_free (priv->original_description);
427
428     G_OBJECT_CLASS (parent_class)->finalize (obj_self);
429 }
430
431
432 static gboolean
433 hildon_note_button_release                      (GtkWidget *widget,
434                                                  GdkEventButton *event)
435 {
436     int x, y;
437     gboolean info_note, released_outside;
438     HildonNotePrivate *priv = HILDON_NOTE_GET_PRIVATE (widget);
439
440     gdk_window_get_position (widget->window, &x, &y);
441
442     /* Whether the button has been released outside the widget */
443     released_outside = (event->x_root < x || event->x_root > x + widget->allocation.width ||
444                         event->y_root < y || event->y_root > y + widget->allocation.height);
445
446     /* Information notes are also closed by tapping on them */
447     info_note = (priv->note_n == HILDON_NOTE_TYPE_INFORMATION ||
448                  priv->note_n == HILDON_NOTE_TYPE_INFORMATION_THEME);
449
450     if (info_note || (released_outside && priv->close_if_pressed_outside)) {
451         gtk_dialog_response (GTK_DIALOG (widget), GTK_RESPONSE_CANCEL);
452     }
453
454     if (GTK_WIDGET_CLASS (parent_class)->button_release_event) {
455         return GTK_WIDGET_CLASS (parent_class)->button_release_event (widget, event);
456     } else {
457         return FALSE;
458     }
459 }
460
461 static void
462 hildon_note_map                                 (GtkWidget *widget)
463 {
464     HildonNotePrivate *priv = HILDON_NOTE_GET_PRIVATE (widget);
465     g_assert (priv);
466
467     /* Map the window */
468     GTK_WIDGET_CLASS (parent_class)->map (widget);
469
470     if (priv->transfer_window == NULL && priv->close_if_pressed_outside) {
471         gboolean has_grab = FALSE;
472
473         priv->transfer_window = grab_transfer_window_get (widget);
474
475         if (gdk_pointer_grab (priv->transfer_window, TRUE,
476                               GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
477                               GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
478                               GDK_POINTER_MOTION_MASK, NULL, NULL,
479                               GDK_CURRENT_TIME) == GDK_GRAB_SUCCESS) {
480             if (gdk_keyboard_grab (priv->transfer_window, TRUE,
481                                    GDK_CURRENT_TIME) == GDK_GRAB_SUCCESS) {
482                 has_grab = TRUE;
483             } else {
484                 gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
485                                             GDK_CURRENT_TIME);
486             }
487         }
488
489         if (has_grab) {
490             gtk_grab_add (widget);
491         } else {
492             gdk_window_destroy (priv->transfer_window);
493             priv->transfer_window = NULL;
494         }
495     }
496 }
497
498 static void
499 hildon_note_unmap                               (GtkWidget *widget)
500 {
501     HildonNotePrivate *priv = HILDON_NOTE_GET_PRIVATE (widget);
502     g_assert (priv);
503
504     if (priv->transfer_window != NULL) {
505         /* Remove the grab */
506         gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
507                                     GDK_CURRENT_TIME);
508         gtk_grab_remove (widget);
509
510         /* Destroy the transfer window */
511         gdk_window_destroy (priv->transfer_window);
512         priv->transfer_window = NULL;
513     }
514 }
515
516 static void
517 hildon_note_realize                             (GtkWidget *widget)
518 {
519     GdkDisplay *display;
520     Atom atom;
521     const gchar *notification_type;
522     HildonNotePrivate *priv = HILDON_NOTE_GET_PRIVATE (widget);
523     g_assert (priv);
524
525     /* Make widget->window accessible */
526     GTK_WIDGET_CLASS (parent_class)->realize (widget);
527
528     /* Border only, no titlebar */
529     gdk_window_set_decorations (widget->window, GDK_DECOR_BORDER);
530
531     /* Because ESD is synchronous, we wish to play sound after the
532        note is already on screen to avoid blocking its appearance */
533     if (priv->sound_signal_handler == 0)
534         priv->sound_signal_handler = g_signal_connect_after(widget, 
535                 "expose-event", G_CALLBACK (sound_handling), NULL);
536
537     /* We use special hint to turn the note into information notification. */
538     gdk_window_set_type_hint (widget->window, GDK_WINDOW_TYPE_HINT_NOTIFICATION);
539
540     /* Set the _HILDON_NOTIFICATION_TYPE property so Matchbox places the window correctly */
541     display = gdk_drawable_get_display (widget->window);
542     atom = gdk_x11_get_xatom_by_name_for_display (display, "_HILDON_NOTIFICATION_TYPE");
543
544     if (priv->note_n == HILDON_NOTE_TYPE_INFORMATION ||
545         priv->note_n == HILDON_NOTE_TYPE_INFORMATION_THEME) {
546         notification_type = "_HILDON_NOTIFICATION_TYPE_INFO";
547     } else {
548         notification_type = "_HILDON_NOTIFICATION_TYPE_CONFIRMATION";
549     }
550
551     XChangeProperty (GDK_WINDOW_XDISPLAY (widget->window), GDK_WINDOW_XID (widget->window),
552                      atom, XA_STRING, 8, PropModeReplace, (guchar *) notification_type,
553                      strlen (notification_type));
554 }
555
556 /* Helper function for removing a widget from it's container.
557    we own a separate reference to each object we try to unpack,
558    so extra referencing is not needed. */
559 static void 
560 unpack_widget                                   (GtkWidget *widget)
561 {
562     g_assert (widget == NULL || GTK_IS_WIDGET (widget));
563
564     if (widget && widget->parent)
565         gtk_container_remove (GTK_CONTAINER (widget->parent), widget);
566 }
567
568 static void
569 hildon_note_rebuild                             (HildonNote *note)
570 {
571     GtkDialog *dialog;
572     HildonNotePrivate *priv;
573     gboolean IsHorizontal = TRUE;
574
575     g_assert (HILDON_IS_NOTE (note));
576
577     priv = HILDON_NOTE_GET_PRIVATE (note);
578     g_assert (priv);
579
580     dialog = GTK_DIALOG (note);
581
582     /* Reuse exiting content widgets for new layout */
583     unpack_widget (priv->label);
584     unpack_widget (priv->icon);
585     unpack_widget (priv->progressbar);
586
587     /* Destroy old layout and buttons */
588     if (priv->box) {
589         gtk_widget_destroy (priv->box);
590         priv->box = NULL;
591     }
592     if (priv->okButton) {
593         gtk_widget_destroy (priv->okButton);
594         priv->okButton = NULL;
595     }
596     if (priv->cancelButton) {
597         gtk_widget_destroy (priv->cancelButton);
598         priv->cancelButton = NULL;
599     }
600
601     /* By default the note won't be closed when pressing outside */
602     priv->close_if_pressed_outside = FALSE;
603
604     /* Add needed buttons and images for each note type */
605     switch (priv->note_n)
606     {
607         case HILDON_NOTE_TYPE_CONFIRMATION:
608             priv->okButton = gtk_dialog_add_button (dialog,
609                     _("ecdg_bd_confirmation_note_ok"), GTK_RESPONSE_OK);
610             priv->cancelButton = gtk_dialog_add_button (dialog,
611                     _("ecdg_bd_confirmation_note_cancel"), GTK_RESPONSE_CANCEL);
612
613             /* Fall through */
614         case HILDON_NOTE_TYPE_CONFIRMATION_BUTTON:
615             gtk_image_set_from_icon_name (GTK_IMAGE (priv->icon),
616                     HILDON_NOTE_CONFIRMATION_ICON, 
617                     HILDON_ICON_SIZE_BIG_NOTE);
618             break;
619
620         case HILDON_NOTE_TYPE_INFORMATION_THEME:
621         case HILDON_NOTE_TYPE_INFORMATION:
622             priv->close_if_pressed_outside = TRUE;
623             gtk_image_set_from_icon_name (GTK_IMAGE (priv->icon),
624                     HILDON_NOTE_INFORMATION_ICON,
625                     HILDON_ICON_SIZE_BIG_NOTE);
626             break;
627
628         case HILDON_NOTE_TYPE_PROGRESSBAR:
629             priv->cancelButton = gtk_dialog_add_button (dialog,
630                     _("ecdg_bd_cancel_note_cancel"), GTK_RESPONSE_CANCEL);
631             IsHorizontal = FALSE;
632             break;
633
634         default:
635             break;
636     }
637
638     if (IsHorizontal) {
639         /* Pack item with label horizontally */
640         priv->box = gtk_hbox_new (FALSE, HILDON_MARGIN_DEFAULT);
641         gtk_container_add (GTK_CONTAINER (dialog->vbox), priv->box);
642
643         if (priv->icon) {
644             GtkWidget *alignment = gtk_alignment_new (0, 0, 0, 0);
645
646             gtk_box_pack_start (GTK_BOX (priv->box), alignment, FALSE, FALSE, 0);
647             gtk_container_add (GTK_CONTAINER (alignment), priv->icon);
648         }
649         gtk_box_pack_start (GTK_BOX (priv->box), priv->label, TRUE, TRUE, 0);
650
651     } else {
652         /* Pack item with label vertically */
653         priv->box = gtk_vbox_new (FALSE, HILDON_MARGIN_DOUBLE);
654         gtk_container_add (GTK_CONTAINER (dialog->vbox), priv->box);
655         gtk_box_pack_start (GTK_BOX (priv->box), priv->label, TRUE, TRUE, 0);
656
657         if (priv->progressbar)
658             gtk_box_pack_start (GTK_BOX (priv->box), priv->progressbar, FALSE, FALSE, 0);
659     }
660
661     gtk_widget_show_all (priv->box);
662 }
663
664 /**
665  * hildon_note_new_confirmation_add_buttons:
666  * @parent: the parent window. The X window ID of the parent window
667  *   has to be the same as the X window ID of the application. This is
668  *   important so that the window manager could handle the windows
669  *   correctly.
670  *   In GTK the X window ID can be checked using
671  *   GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
672  * @description: the message to confirm
673  * @Varargs: arguments pairs for new buttons(label and return value). 
674  *   Terminate the list with %NULL value.
675  * 
676  * Create a new confirmation note with custom buttons. Confirmation
677  * note has a text and any number of buttons. It's important to note
678  * that even though the name of the function might suggest, the
679  * default ok/cancel buttons are not appended but you have to provide
680  * all of the buttons.
681  *
682  * FIXME: This doc seems to be wrong, the two buttons aren't added so
683  * it would only contain the "additional" buttons? However, changing
684  * this would break those applications that rely on current behaviour.
685  *
686  * Returns: A #GtkWidget pointer of the note
687  */
688 GtkWidget*
689 hildon_note_new_confirmation_add_buttons        (GtkWindow *parent,
690                                                  const gchar *description,
691                                                  ...)
692 {
693     va_list args;
694     char *message;
695     int value;
696
697     g_return_val_if_fail (description != NULL, NULL);
698
699     GtkWidget *conf_note =
700         g_object_new (HILDON_TYPE_NOTE,
701                 "note-type", HILDON_NOTE_TYPE_CONFIRMATION_BUTTON,
702                 "description", description,
703                 "icon", HILDON_NOTE_CONFIRMATION_ICON, 
704                 NULL);
705
706     if (parent != NULL)
707         gtk_window_set_transient_for (GTK_WINDOW (conf_note), parent);
708
709     /* Add the buttons from varargs */
710     va_start(args, description);
711
712     while (TRUE) {
713         message = va_arg (args, char *);
714
715         if (! message) {
716             break;
717         }
718         value = va_arg (args, int);
719
720         gtk_dialog_add_button (GTK_DIALOG (conf_note), message, value);
721     }
722
723     va_end (args);
724
725     return conf_note;
726 }
727
728
729 /**
730  * hildon_note_new_confirmation:
731  * @parent: the parent window. The X window ID of the parent window
732  *   has to be the same as the X window ID of the application. This is
733  *   important so that the window manager could handle the windows
734  *   correctly. In GTK the X window ID can be checked using
735  *   GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
736  * @description: the message to confirm
737  * 
738  * Create a new confirmation note. Confirmation note has text (description)
739  * that you specify, two buttons and a default confirmation stock icon.
740  *
741  * Returns: a #GtkWidget pointer of the note
742  */
743 GtkWidget*
744 hildon_note_new_confirmation                    (GtkWindow *parent,
745                                                  const gchar *description)
746 {
747     return hildon_note_new_confirmation_with_icon_name
748         (parent, description, HILDON_NOTE_CONFIRMATION_ICON);
749 }
750
751 /**
752  * hildon_note_new_confirmation_with_icon_name:
753  * @parent: the parent window. The X window ID of the parent window
754  *   has to be the same as the X window ID of the application. This is
755  *   important so that the window manager could handle the windows
756  *   correctly. In GTK the X window ID can be checked using
757  *   GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
758  * @description: the message to confirm
759  * @icon_name: icon to be displayed. If NULL, default icon is used.
760  * 
761  * Create a new confirmation note. Confirmation note has text(description) 
762  * that you specify, two buttons and an icon.
763  *
764  * Returns: a #GtkWidget pointer of the note
765  */
766 GtkWidget*
767 hildon_note_new_confirmation_with_icon_name     (GtkWindow *parent,
768                                                  const gchar *description,
769                                                  const gchar *icon_name)
770 {
771     GtkWidget *dialog = NULL;
772
773     g_return_val_if_fail (description != NULL, NULL);
774
775     dialog = g_object_new (HILDON_TYPE_NOTE,
776             "note-type",
777             HILDON_NOTE_TYPE_CONFIRMATION,
778             "description", description, "icon",
779             icon_name, NULL);
780
781     if (parent != NULL)
782         gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
783
784     return dialog;
785 }
786
787 /**
788  * hildon_note_new_information:
789  * @parent: the parent window. The X window ID of the parent window
790  *   has to be the same as the X window ID of the application. This is
791  *   important so that the window manager could handle the windows
792  *   correctly. In GTK the X window ID can be checked using
793  *   GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
794  * @description: the message to confirm
795  * 
796  * Create a new information note. Information note has a text(description) 
797  * that you specify, an OK button and an icon.
798  * 
799  * Returns: a #GtkWidget pointer of the note
800  */
801 GtkWidget*
802 hildon_note_new_information                     (GtkWindow *parent,
803                                                  const gchar *description)
804 {
805     return hildon_note_new_information_with_icon_name
806         (parent, description, HILDON_NOTE_INFORMATION_ICON);
807 }
808
809 /**
810  * hildon_note_new_information_with_icon_name:
811  * @parent: the parent window. The X window ID of the parent window
812  *   has to be the same as the X window ID of the application. This is
813  *   important so that the window manager could handle the windows
814  *   correctly. In GTK the X window ID can be checked using
815  *   GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
816  * @description: the message to confirm
817  * @icon_name: icon to be displayed. If NULL, default icon is used.
818  * 
819  * Create a new information note. Information note has text(description) 
820  * that you specify, an OK button and an icon.
821  * 
822  * Returns: a #GtkWidget pointer of the note
823  */
824 GtkWidget*
825 hildon_note_new_information_with_icon_name      (GtkWindow * parent,
826                                                  const gchar *description,
827                                                  const gchar *icon_name)
828 {
829     GtkWidget *dialog = NULL;
830
831     g_return_val_if_fail (description != NULL, NULL);
832     g_return_val_if_fail (icon_name != NULL, NULL);
833
834     dialog = g_object_new (HILDON_TYPE_NOTE,
835             "note-type",
836             HILDON_NOTE_TYPE_INFORMATION_THEME,
837             "description", description,
838             "icon", icon_name, NULL);
839
840     if (parent != NULL)
841         gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
842
843     return dialog;
844 }
845
846 /* FIXME This documentation string LIES! */
847
848 /**
849  * hildon_note_new_cancel_with_progress_bar:
850  * @parent: the parent window. The X window ID of the parent window
851  *   has to be the same as the X window ID of the application. This is
852  *   important so that the window manager could handle the windows
853  *   correctly. In GTK the X window ID can be checked using
854  *   GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
855  * @description: the action to cancel
856  * @progressbar: a pointer to #GtkProgressBar to be filled with the
857  *   progressbar assigned to this note. Use this to set the fraction of
858  *   progressbar done. This parameter can be %NULL as well, in which
859  *   case plain text cancel note appears.
860  *
861  * Create a new cancel note with a progress bar. Cancel note has 
862  * text(description) that you specify, a Cancel button and a progress bar.
863  *
864  * Returns: a #GtkDialog. Use this to get rid of this note when you
865  *   no longer need it.
866  */
867 GtkWidget*
868 hildon_note_new_cancel_with_progress_bar        (GtkWindow *parent,
869                                                  const gchar *description,
870                                                  GtkProgressBar *progressbar)
871 {
872     GtkWidget *dialog = NULL;
873
874     g_return_val_if_fail (description != NULL, NULL);
875
876     dialog = g_object_new (HILDON_TYPE_NOTE,
877             "note-type",
878             HILDON_NOTE_TYPE_PROGRESSBAR,
879             "description", description,
880             "progressbar",
881             progressbar, NULL);
882
883     if (parent != NULL)
884         gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
885
886     return dialog;
887 }
888
889
890 /**
891  * hildon_note_set_button_text:
892  * @note: a #HildonNote
893  * @text: sets the button text and if there is two buttons in dialog, 
894  *   the button texts will be &lt;text&gt;, "Cancel".  
895  *
896  * Sets the button text to be used by the hildon_note widget.
897  */
898 void 
899 hildon_note_set_button_text                     (HildonNote *note, 
900                                                  const gchar *text)
901 {
902     HildonNotePrivate *priv;
903
904     g_return_if_fail (HILDON_IS_NOTE (note));
905
906     priv = HILDON_NOTE_GET_PRIVATE (HILDON_NOTE (note));
907     g_assert (priv);
908
909     if (priv->okButton) {
910         gtk_button_set_label (GTK_BUTTON (priv->okButton), text);
911         gtk_button_set_label (GTK_BUTTON (priv->cancelButton),
912                 _("ecdg_bd_confirmation_note_cancel"));
913     } else {
914         gtk_button_set_label (GTK_BUTTON (priv->cancelButton), text);
915     }
916 }
917
918 /**
919  * hildon_note_set_button_texts:
920  * @note: a #HildonNote
921  * @text_ok: the new text of the default OK button
922  * @text_cancel: the new text of the default cancel button 
923  *
924  * Sets the button texts to be used by this hildon_note widget.
925  */
926 void 
927 hildon_note_set_button_texts                    (HildonNote *note,
928                                                  const gchar *text_ok,
929                                                  const gchar *text_cancel)
930 {
931     HildonNotePrivate *priv;
932
933     g_return_if_fail (HILDON_IS_NOTE (note));
934
935     priv = HILDON_NOTE_GET_PRIVATE (HILDON_NOTE (note));
936     g_assert (priv);
937
938     if (priv->okButton) {
939         gtk_button_set_label (GTK_BUTTON (priv->okButton), text_ok);
940         gtk_button_set_label (GTK_BUTTON (priv->cancelButton), text_cancel);
941     } else {
942         gtk_button_set_label (GTK_BUTTON (priv->cancelButton), text_cancel);
943     }
944 }
945
946 /* We play a system sound when the note comes visible */
947 static gboolean
948 sound_handling                                  (GtkWidget *widget, 
949                                                  GdkEventExpose *event, 
950                                                  gpointer data)
951 {
952     HildonNotePrivate *priv = HILDON_NOTE_GET_PRIVATE (widget);
953     g_assert (priv);
954
955     g_signal_handler_disconnect (widget, priv->sound_signal_handler);
956
957     priv->sound_signal_handler = 0;
958
959     switch (priv->note_n)
960     {
961         case HILDON_NOTE_TYPE_INFORMATION:
962         case HILDON_NOTE_TYPE_INFORMATION_THEME:
963             hildon_play_system_sound (INFORMATION_SOUND_PATH);
964             break;
965
966         case HILDON_NOTE_TYPE_CONFIRMATION:
967         case HILDON_NOTE_TYPE_CONFIRMATION_BUTTON:
968             hildon_play_system_sound (CONFIRMATION_SOUND_PATH);
969             break;
970
971         default:
972             break;
973     };
974
975     return FALSE;
976 }