Fix information notes size request
[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 + 2*HILDON_MARGIN_DOUBLE);
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 #ifdef MAEMO_GTK
767             gtk_dialog_set_padding (dialog,
768                                     HILDON_MARGIN_DOUBLE,
769                                     HILDON_MARGIN_DEFAULT,
770                                     HILDON_MARGIN_DOUBLE,
771                                     HILDON_MARGIN_DOUBLE);
772 #endif /* MAEMO_GTK */
773             break;
774
775         case HILDON_NOTE_TYPE_PROGRESSBAR:
776             priv->cancelButton = gtk_dialog_add_button (dialog,
777                     _("wdgt_bd_stop"), GTK_RESPONSE_CANCEL);
778             gtk_widget_show (priv->cancelButton);
779             gtk_widget_set_no_show_all (priv->cancelButton, FALSE);
780             break;
781
782         case HILDON_NOTE_TYPE_INFORMATION_THEME:
783         case HILDON_NOTE_TYPE_INFORMATION:
784 #ifdef MAEMO_GTK
785             gtk_dialog_set_padding (dialog,
786                                     HILDON_MARGIN_DOUBLE,
787                                     HILDON_MARGIN_DOUBLE,
788                                     0,
789                                     0);
790 #endif /* MAEMO_GTK */
791             is_info_note = TRUE;
792             break;
793
794         case HILDON_NOTE_TYPE_CONFIRMATION_BUTTON:
795         default:
796             break;
797     }
798
799     /* Don't display the action area if this is just an information
800      * note. This prevents text from being slightly aligned to the
801      * left
802      */
803     if (is_info_note) {
804         gtk_widget_hide (dialog->action_area);
805     } else {
806         gtk_widget_show (dialog->action_area);
807     }
808     gtk_widget_set_no_show_all (dialog->action_area, is_info_note);
809
810     /* Pack label vertically. Spacing is only necessary for the progressbar note. */
811     priv->box = gtk_vbox_new (FALSE, priv->progressbar ? HILDON_MARGIN_DOUBLE : 0);
812     gtk_container_add (GTK_CONTAINER (priv->event_box), priv->box);
813     gtk_box_pack_start (GTK_BOX (priv->box), priv->label, TRUE, TRUE, 0);
814
815     if (priv->progressbar)
816         gtk_box_pack_start (GTK_BOX (priv->box), priv->progressbar, FALSE, FALSE, 0);
817
818 #ifdef MAEMO_GTK
819     hildon_note_set_padding (note);
820 #endif /* MAEMO_GTK */
821
822     gtk_container_add (GTK_CONTAINER (dialog->vbox), priv->event_box);
823
824     gtk_widget_show_all (priv->event_box);
825 }
826
827 /**
828  * hildon_note_new_confirmation_add_buttons:
829  * @parent: the parent window. The X window ID of the parent window
830  *   has to be the same as the X window ID of the application. This is
831  *   important so that the window manager could handle the windows
832  *   correctly.
833  *   In GTK the X window ID can be checked using
834  *   GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
835  * @description: the message to confirm
836  * @Varargs: arguments pairs for new buttons(label and return value). 
837  *   Terminate the list with %NULL value.
838  * 
839  * Create a new confirmation note with custom buttons. Confirmation
840  * note has a text and any number of buttons. It's important to note
841  * that even though the name of the function might suggest, the
842  * default ok/cancel buttons are not appended but you have to provide
843  * all of the buttons.
844  *
845  * FIXME: This doc seems to be wrong, the two buttons aren't added so
846  * it would only contain the "additional" buttons? However, changing
847  * this would break those applications that rely on current behaviour.
848  *
849  * Returns: A new #HildonNote.
850  */
851 GtkWidget*
852 hildon_note_new_confirmation_add_buttons        (GtkWindow *parent,
853                                                  const gchar *description,
854                                                  ...)
855 {
856     va_list args;
857     char *message;
858     int value;
859     GtkWidget *button;
860
861     g_return_val_if_fail (description != NULL, NULL);
862
863     GtkWidget *conf_note =
864         g_object_new (HILDON_TYPE_NOTE,
865                 "note-type", HILDON_NOTE_TYPE_CONFIRMATION_BUTTON,
866                 "description", description,
867                 NULL);
868
869     if (parent != NULL)
870         gtk_window_set_transient_for (GTK_WINDOW (conf_note), parent);
871
872     /* Add the buttons from varargs */
873     va_start(args, description);
874
875     while (TRUE) {
876         message = va_arg (args, char *);
877
878         if (! message) {
879             break;
880         }
881         value = va_arg (args, int);
882
883         button = gtk_dialog_add_button (GTK_DIALOG (conf_note), message, value);
884         /* maemo-gtk is going to set the "no-show-all" property all
885            cancel/close-like buttons to TRUE, so that they are not shown. On
886            the other hand, this confirmation note with custom buttons should
887            not obey this rule, so we need to make sure they are shown. */
888         gtk_widget_show (button);
889         gtk_widget_set_no_show_all (button, FALSE);
890     }
891
892     va_end (args);
893
894     return conf_note;
895 }
896
897
898 /**
899  * hildon_note_new_confirmation:
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  *
907  * Create a new confirmation note. Confirmation note has a text (description)
908  * that you specify and two buttons.
909  *
910  * Returns: a new #HildonNote.
911  */
912 GtkWidget*
913 hildon_note_new_confirmation                    (GtkWindow *parent,
914                                                  const gchar *description)
915 {
916     GtkWidget *dialog = NULL;
917
918     g_return_val_if_fail (description != NULL, NULL);
919
920     dialog = g_object_new (HILDON_TYPE_NOTE,
921             "note-type",
922             HILDON_NOTE_TYPE_CONFIRMATION,
923             "description", description, NULL);
924
925     if (parent != NULL)
926         gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
927
928     return dialog;
929 }
930
931 /**
932  * hildon_note_new_confirmation_with_icon_name:
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 message to confirm
939  * @icon_name: icon to be displayed. If NULL, default icon is used.
940  * 
941  * Create a new confirmation note. Confirmation note has a text (description) 
942  * that you specify and two buttons.
943  *
944  * Deprecated: Since 2.2, icons are not shown in confirmation notes. Icons set
945  * with this function will be ignored. Use hildon_note_new_confirmation() instead.
946  *
947  * Returns: a new #HildonNote.
948  */
949 GtkWidget*
950 hildon_note_new_confirmation_with_icon_name     (GtkWindow *parent,
951                                                  const gchar *description,
952                                                  const gchar *icon_name)
953 {
954     GtkWidget *dialog;
955
956     dialog = hildon_note_new_confirmation (parent, description);
957     g_object_set (dialog, "icon", icon_name, NULL);
958
959     return dialog;
960 }
961
962 /**
963  * hildon_note_new_information:
964  * @parent: the parent window. The X window ID of the parent window
965  *   has to be the same as the X window ID of the application. This is
966  *   important so that the window manager could handle the windows
967  *   correctly. In GTK the X window ID can be checked using
968  *   GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
969  * @description: the message to confirm.
970  * 
971  * Create a new information note. Information note has text (a description)
972  * that you specify and an OK button.
973  * 
974  * Returns: a new #HildonNote.
975  */
976 GtkWidget*
977 hildon_note_new_information                     (GtkWindow *parent,
978                                                  const gchar *description)
979 {
980     GtkWidget *dialog = NULL;
981
982     g_return_val_if_fail (description != NULL, NULL);
983
984     dialog = g_object_new (HILDON_TYPE_NOTE,
985             "note-type",
986             HILDON_NOTE_TYPE_INFORMATION_THEME,
987             "description", description, NULL);
988
989     if (parent != NULL)
990         gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
991
992     return dialog;
993 }
994
995 /**
996  * hildon_note_new_information_with_icon_name:
997  * @parent: the parent window. The X window ID of the parent window
998  *   has to be the same as the X window ID of the application. This is
999  *   important so that the window manager could handle the windows
1000  *   correctly. In GTK the X window ID can be checked using
1001  *   GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
1002  * @description: the message to confirm.
1003  * @icon_name: icon to be displayed. If %NULL, the default icon is used.
1004  * 
1005  * Create a new information note. An information note has text (a description)
1006  * that you specify, an OK button and an icon.
1007  * 
1008  * Deprecated: Since 2.2, icons are not shown in confirmation notes. Icons set
1009  * with this function will be ignored. Use hildon_note_new_information()
1010  * instead.
1011  *
1012  * Returns: a new #HildonNote.
1013  */
1014 GtkWidget*
1015 hildon_note_new_information_with_icon_name      (GtkWindow * parent,
1016                                                  const gchar *description,
1017                                                  const gchar *icon_name)
1018 {
1019     GtkWidget *dialog;
1020
1021     dialog = hildon_note_new_information (parent, description);
1022     g_object_set (dialog, "icon", icon_name, NULL);
1023
1024     return dialog;
1025 }
1026
1027 /* FIXME This documentation string LIES! */
1028
1029 /**
1030  * hildon_note_new_cancel_with_progress_bar:
1031  * @parent: the parent window. The X window ID of the parent window
1032  *   has to be the same as the X window ID of the application. This is
1033  *   important so that the window manager could handle the windows
1034  *   correctly. In GTK the X window ID can be checked using
1035  *   GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
1036  * @description: the action to cancel.
1037  * @progressbar: a pointer to #GtkProgressBar to be filled with the
1038  *   progressbar assigned to this note. Use this to set the fraction of
1039  *   progressbar done. This parameter can be %NULL as well, in which
1040  *   case plain text cancel note appears.
1041  *
1042  * Create a new cancel note with a progress bar. Cancel note has 
1043  * text(description) that you specify, a Cancel button and a progress bar.
1044  *
1045  * Returns: a #GtkDialog. Use this to get rid of this note when you
1046  *   no longer need it.
1047  */
1048 GtkWidget*
1049 hildon_note_new_cancel_with_progress_bar        (GtkWindow *parent,
1050                                                  const gchar *description,
1051                                                  GtkProgressBar *progressbar)
1052 {
1053     GtkWidget *dialog = NULL;
1054
1055     g_return_val_if_fail (description != NULL, NULL);
1056
1057     dialog = g_object_new (HILDON_TYPE_NOTE,
1058             "note-type",
1059             HILDON_NOTE_TYPE_PROGRESSBAR,
1060             "description", description,
1061             "progressbar",
1062             progressbar, NULL);
1063
1064     if (parent != NULL)
1065         gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
1066
1067     return dialog;
1068 }
1069
1070
1071 /**
1072  * hildon_note_set_button_text:
1073  * @note: a #HildonNote.
1074  * @text: sets the button text. If there are two buttons in dialog,
1075  *   the button texts will be &lt;text&gt;, "Cancel".  
1076  *
1077  * Sets the text of the button in @note.
1078  */
1079 void 
1080 hildon_note_set_button_text                     (HildonNote *note, 
1081                                                  const gchar *text)
1082 {
1083     HildonNotePrivate *priv;
1084
1085     g_return_if_fail (HILDON_IS_NOTE (note));
1086
1087     priv = HILDON_NOTE_GET_PRIVATE (HILDON_NOTE (note));
1088     g_assert (priv);
1089
1090     if (priv->okButton) {
1091         gtk_button_set_label (GTK_BUTTON (priv->okButton), text);
1092         gtk_button_set_label (GTK_BUTTON (priv->cancelButton),
1093                 _("wdgt_bd_no"));
1094     } else {
1095         gtk_button_set_label (GTK_BUTTON (priv->cancelButton), text);
1096     }
1097 }
1098
1099 /**
1100  * hildon_note_set_button_texts:
1101  * @note: a #HildonNote.
1102  * @text_ok: the new text of the default OK button.
1103  * @text_cancel: the new text of the default cancel button.
1104  *
1105  * Sets the text for the buttons in @note.
1106  */
1107 void 
1108 hildon_note_set_button_texts                    (HildonNote *note,
1109                                                  const gchar *text_ok,
1110                                                  const gchar *text_cancel)
1111 {
1112     HildonNotePrivate *priv;
1113
1114     g_return_if_fail (HILDON_IS_NOTE (note));
1115
1116     priv = HILDON_NOTE_GET_PRIVATE (HILDON_NOTE (note));
1117     g_assert (priv);
1118
1119     if (priv->okButton) {
1120         gtk_button_set_label (GTK_BUTTON (priv->okButton), text_ok);
1121         gtk_button_set_label (GTK_BUTTON (priv->cancelButton), text_cancel);
1122     } else {
1123         gtk_button_set_label (GTK_BUTTON (priv->cancelButton), text_cancel);
1124     }
1125 }
1126
1127 static void
1128 on_show_cb                                      (GtkWidget *widget,
1129                                                  gpointer data)
1130 {
1131     HildonNotePrivate *priv;
1132
1133     priv = HILDON_NOTE_GET_PRIVATE (widget);
1134     priv->idle_handler = g_idle_add (sound_handling, widget);
1135 }
1136
1137 /* We play a system sound when the note comes visible */
1138 static gboolean
1139 sound_handling                                  (gpointer data)
1140 {
1141     HildonNotePrivate *priv = HILDON_NOTE_GET_PRIVATE (data);
1142     g_assert (priv);
1143
1144     switch (priv->note_n)
1145     {
1146         case HILDON_NOTE_TYPE_INFORMATION:
1147         case HILDON_NOTE_TYPE_INFORMATION_THEME:
1148             hildon_play_system_sound (INFORMATION_SOUND_PATH);
1149             break;
1150
1151         case HILDON_NOTE_TYPE_CONFIRMATION:
1152         case HILDON_NOTE_TYPE_CONFIRMATION_BUTTON:
1153             hildon_play_system_sound (CONFIRMATION_SOUND_PATH);
1154             break;
1155
1156         default:
1157             break;
1158     };
1159
1160     priv->idle_handler = 0;
1161
1162     return FALSE;
1163 }