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