Initial scrolling attempt
[conv-inbox] / src / el-home-applet.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2 /*
3  *  Copyright (C) 2009 Artem Garmash. All rights reserved.
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  * Contact: Artem Garmash <artemgarmash@gmail.com>
20  *
21  */
22
23 #include "config.h"
24 #include "el-home-applet.h"
25
26 #include <hildon/hildon.h>
27 #include <rtcom-eventlogger/eventlogger.h>
28 #include <sqlite3.h>
29 #include <string.h>
30
31 #define EL_HOME_APPLET_GET_PRIVATE(obj) ( \
32         G_TYPE_INSTANCE_GET_PRIVATE (obj, \
33                 EL_TYPE_HOME_APPLET, ELHomeAppletPrivate))
34
35 #define BOX_WIDTH 352
36 #define BOX_HEIGHT 256
37
38 #define C_WIDTH (BOX_WIDTH - 2*HILDON_MARGIN_HALF)
39 #define C_HEIGHT (BOX_HEIGHT - 2*HILDON_MARGIN_HALF)
40 #define C_X HILDON_MARGIN_HALF
41 #define C_Y HILDON_MARGIN_HALF
42
43 #define HEADER_HEIGHT 48
44 #define MESSAGE_HEIGHT (C_HEIGHT - HEADER_HEIGHT)
45 #define MESSAGE_WIDTH (C_WIDTH - 2*HILDON_MARGIN_DEFAULT)
46
47 #define BOX_RADIOUS 10
48
49 #define DEBUG_LAYOUT
50
51 struct _ELHomeAppletPrivate
52 {
53         RTComEl *eventlogger;
54
55         GtkWidget *sender;
56         GtkWidget *icon;
57         GtkWidget *unread;
58         GtkWidget *received;
59         GtkWidget *empty;
60
61         gchar *message;
62         gint event_id;
63
64         gboolean active;
65
66         guint unread_count;
67
68         const gchar *current_font;
69
70         guint idle_id;
71
72         gboolean scroll_on_click;
73         gint scroll_offset;
74         guint scroll_anim_id;
75 };
76
77 HD_DEFINE_PLUGIN_MODULE (ELHomeApplet, el_home_applet, HD_TYPE_HOME_PLUGIN_ITEM);
78
79 const gchar* g_module_check_init(GModule *module);
80 const gchar*
81 g_module_check_init(GModule *module)
82 {
83         g_module_make_resident (module);
84         return NULL;
85 }
86
87 static void
88 el_home_applet_class_finalize (ELHomeAppletClass *klass)
89 {
90 }
91
92 static void
93 el_home_applet_realize (GtkWidget *widget)
94 {
95         GdkScreen *screen;
96
97         screen = gtk_widget_get_screen (widget);
98         gtk_widget_set_colormap (widget,
99                                  gdk_screen_get_rgba_colormap (screen));
100
101         gtk_widget_set_app_paintable (widget,
102                                       TRUE);
103
104         GTK_WIDGET_CLASS (el_home_applet_parent_class)->realize (widget);
105 }
106
107 /*
108  * Thanks http://cairographics.org/cookbook/roundedrectangles/
109  */
110 static void
111 rounded_rectangle (cairo_t *cr,
112                    double   x,
113                    double   y,
114                    double   w,
115                    double   h,
116                    double   r)
117 {
118         cairo_move_to (cr, x + r, y);
119         cairo_line_to (cr, x + w - r, y);
120         cairo_curve_to (cr, x + w, y,
121                         x + w, y,
122                         x + w, y + r);
123         cairo_line_to (cr, x + w, y + h - r);
124         cairo_curve_to (cr, x + w, y + h,
125                         x + w, y + h,
126                         x + w - r, y + h);
127         cairo_line_to (cr, x + r, y + h);
128         cairo_curve_to (cr, x, y + h,
129                         x, y + h,
130                         x, y + h - r);
131         cairo_line_to (cr, x, y + r);
132         cairo_curve_to (cr, x, y,
133                         x, y,
134                         x + r, y);
135 }
136
137 static gboolean
138 draw_text (cairo_t *cr,
139            const gchar *text,
140            double x,
141            double y,
142            int width,
143            int height,
144            int offset)
145 {
146         PangoLayout *layout;
147         PangoFontDescription *desc;
148         gboolean result;
149
150         cairo_save (cr);
151         cairo_rectangle (cr,
152                          x, y, width, height);
153         cairo_clip (cr);
154
155         /* Create a PangoLayout, set the font and text */
156         layout = pango_cairo_create_layout (cr);
157         pango_layout_set_text (layout,
158                                text,
159                                -1);
160         desc = pango_font_description_from_string ("Sans 17");
161         pango_layout_set_font_description (layout, desc);
162         pango_font_description_free (desc);
163
164         pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
165         if (!offset)
166                 pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
167         pango_layout_set_width (layout, PANGO_SCALE*width);
168         pango_layout_set_height (layout, PANGO_SCALE*height);
169
170         /* draw shadow */
171         cairo_move_to (cr, x + 1, y + 1 - offset);
172         cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 0.8);
173         pango_cairo_show_layout (cr, layout);
174
175         /* draw fg */
176         cairo_move_to (cr, x, y - offset);
177         cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0);
178         pango_cairo_show_layout (cr, layout);
179
180         result = !offset && pango_layout_is_ellipsized (layout);
181
182         g_object_unref (layout);
183         cairo_restore (cr);
184
185         return result;
186 }
187
188 static gboolean
189 expose_event (GtkWidget *self, GdkEventExpose *event)
190 {
191         ELHomeAppletPrivate *priv = EL_HOME_APPLET(self)->priv;
192
193         cairo_t *cr;
194         GdkColor color;
195         float red, green, blue;
196
197         /* find theme active color */
198         gtk_style_lookup_color (self->style, "ActiveTextColor", &color);
199         red = color.red/(float)G_MAXUINT16;
200         green = color.green/(float)G_MAXUINT16;
201         blue = color.blue/(float)G_MAXUINT16;
202
203         cr = gdk_cairo_create (self->window);
204         gdk_cairo_region (cr, event->region);
205         cairo_clip (cr);
206
207         /* draw bound box */
208         cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
209
210         cairo_set_source_rgba (cr, 0.4f, 0.4f, 0.4f, 0.1f);
211         cairo_set_line_width (cr, 3.0f);
212
213         rounded_rectangle (cr,
214                            C_X,
215                            C_Y,
216                            BOX_WIDTH - 2*C_X,
217                            BOX_HEIGHT - 2*C_Y,
218                            BOX_RADIOUS);
219
220         cairo_close_path(cr);
221         cairo_stroke (cr);
222
223         /* draw header */
224         cairo_set_line_width (cr, 1.0f);
225
226         cairo_translate (cr, C_X, C_Y);
227         cairo_move_to (cr, 0, HEADER_HEIGHT);
228         cairo_line_to (cr, 0, BOX_RADIOUS);
229         cairo_curve_to (cr, 0, 0, 0, 0, BOX_RADIOUS, 0);
230         cairo_line_to (cr, C_WIDTH - BOX_RADIOUS, 0);
231         cairo_curve_to (cr, C_WIDTH, 0, C_WIDTH, 0, C_WIDTH, BOX_RADIOUS);
232         cairo_line_to (cr, C_WIDTH, HEADER_HEIGHT);
233         cairo_line_to (cr, 0, HEADER_HEIGHT);
234
235         cairo_close_path(cr);
236
237         cairo_set_source_rgba (cr, 0.2f, 0.2f, 0.2f, 0.8f);
238         cairo_fill_preserve (cr);
239         cairo_set_source_rgba (cr, red, green, blue, 1.0f);
240         cairo_stroke (cr);
241
242         /* draw body */
243         cairo_move_to (cr, 0, HEADER_HEIGHT);
244         cairo_line_to (cr, 0, C_HEIGHT - BOX_RADIOUS);
245         cairo_curve_to (cr, 0, C_HEIGHT, 0, C_HEIGHT, BOX_RADIOUS, C_HEIGHT);
246         cairo_line_to (cr, C_WIDTH - BOX_RADIOUS, C_HEIGHT);
247         cairo_curve_to (cr, C_WIDTH, C_HEIGHT, C_WIDTH, C_HEIGHT, C_WIDTH, C_HEIGHT - BOX_RADIOUS);
248         cairo_line_to (cr, C_WIDTH, HEADER_HEIGHT);
249         cairo_line_to (cr, 0, HEADER_HEIGHT);
250         cairo_close_path(cr);
251
252         /* draw body filling depending on (in)active state */
253         cairo_pattern_t *grad;
254         grad = cairo_pattern_create_linear(0, HEADER_HEIGHT,
255                                            0, C_HEIGHT);
256
257         if (priv->active){
258                 cairo_pattern_add_color_stop_rgba (grad, 0.5f,
259                                                    red, green, blue, 0.8f);
260                 cairo_pattern_add_color_stop_rgba (grad, 1.0f,
261                                                    red/2, green/2, blue/2, 0.8f);
262         }
263         else {
264                 cairo_pattern_add_color_stop_rgba (grad, 0.5f,
265                                                    0.4f, 0.4f, 0.4f, 0.8f);
266                 cairo_pattern_add_color_stop_rgba (grad, 1.0f,
267                                                    0.2f, 0.2f, 0.2f, 0.8f);
268         }
269         cairo_set_source (cr, grad);
270         cairo_fill (cr);
271
272         /* cairo_set_source_rgba (cr, red, green, blue, 1.0f); */
273         /* cairo_translate (cr, -C_X, -C_Y); */
274         /* rounded_rectangle (cr, */
275         /*                    C_X, */
276         /*                    C_Y, */
277         /*                    BOX_WIDTH - 2*C_X, */
278         /*                    BOX_HEIGHT - 2*C_Y, */
279         /*                    BOX_RADIOUS); */
280         /* cairo_close_path(cr); */
281         /* cairo_stroke (cr); */
282
283         /* draw message */
284         gboolean ellipsized;
285         ellipsized = draw_text (cr, priv->message,
286                                 2*C_X, HEADER_HEIGHT,
287                                 MESSAGE_WIDTH,
288                                 MESSAGE_HEIGHT - 2*C_Y,
289                                 priv->scroll_offset);
290         if (!priv->scroll_offset && !priv->active)
291                 priv->scroll_on_click = ellipsized;
292
293         cairo_pattern_destroy (grad);
294         cairo_destroy (cr);
295
296         return GTK_WIDGET_CLASS (el_home_applet_parent_class)->expose_event (self, event);
297 }
298
299 static void
300 stop_scroll_anim (ELHomeAppletPrivate *priv)
301 {
302         priv->scroll_on_click = FALSE;
303         priv->scroll_offset = 0;
304         if (priv->scroll_anim_id > 0) {
305                 g_source_remove (priv->scroll_anim_id);
306                 priv->scroll_anim_id = 0;
307         }
308 }
309
310 static void
311 dispose (GObject *self)
312 {
313         ELHomeAppletPrivate *priv = EL_HOME_APPLET(self)->priv;
314
315         stop_scroll_anim (priv);
316         if (priv->idle_id){
317                 g_source_remove (priv->idle_id);
318                 priv->idle_id = 0;
319         }
320         if (priv->eventlogger){
321                 g_object_unref (priv->eventlogger);
322                 priv->eventlogger = NULL;
323         }
324
325         if (priv->message){
326                 g_free (priv->message);
327                 priv->message = NULL;
328         }
329
330         G_OBJECT_CLASS (el_home_applet_parent_class)->dispose (self);
331 }
332
333 static void
334 finalize (GObject *self)
335 {
336         G_OBJECT_CLASS (el_home_applet_parent_class)->finalize (self);
337 }
338
339 static gchar*
340 format_time (time_t t)
341 {
342         static const guint RESULT_SIZE = 32;
343
344         time_t now;
345         struct tm now_tm, t_tm;
346         const gchar *format = "%Y.%m.%d %T";
347         gchar *result = g_malloc0 (RESULT_SIZE);
348
349         now = time (NULL);
350         localtime_r (&now, &now_tm);
351         localtime_r (&t, &t_tm);
352
353         if ((now_tm.tm_year == t_tm.tm_year) &&
354             (now_tm.tm_mon  == t_tm.tm_mon) &&
355             (now_tm.tm_mday == t_tm.tm_mday))
356                 format = "%T";
357
358         strftime (result, RESULT_SIZE, format, &t_tm);
359
360         return result;
361 }
362
363 static void
364 show_event (ELHomeApplet *self, RTComElIter *it)
365 {
366         ELHomeAppletPrivate *priv = self->priv;
367
368         gchar *remote = NULL;
369         gchar *received = NULL;
370         const gchar *icon_name = NULL;
371
372         if (priv->message) {
373                 g_free (priv->message);
374                 priv->message = NULL;
375         }
376
377         if (it && rtcom_el_iter_first (it)){
378                 rtcom_el_iter_dup_string (it, "free-text", &priv->message);
379                 if (priv->message){
380                         const gchar *service;
381                         time_t received_t;
382
383                         rtcom_el_iter_get_int (it, "id", &priv->event_id);
384                         if (rtcom_el_iter_get_int (it, "start-time", (gint*)&received_t))
385                                 received = format_time (received_t);
386
387                         if(!rtcom_el_iter_dup_string (it, "remote-name", &remote))
388                                 rtcom_el_iter_dup_string (it, "remote-id", &remote);
389                         service = rtcom_el_iter_get_service (it);
390                         if (!g_strcmp0 (service, "RTCOM_EL_SERVICE_SMS"))
391                                 icon_name = "chat_unread_sms";
392                         else if (!g_strcmp0 (service, "RTCOM_EL_SERVICE_CHAT"))
393                                 icon_name = "chat_unread_chat";
394                 }
395         }
396         else{
397                 priv->event_id = -1;
398         }
399
400         if (priv->message)
401                 gtk_widget_hide (priv->empty);
402         else
403                 gtk_widget_show (priv->empty);
404
405         gtk_label_set_text (GTK_LABEL (priv->sender), remote);
406         gtk_label_set_text (GTK_LABEL (priv->received), received);
407
408         if (icon_name){
409                 const gchar *current_icon_name;
410                 gtk_image_get_icon_name (GTK_IMAGE (priv->icon),
411                                          &current_icon_name,
412                                          NULL);
413                 if (g_strcmp0 (current_icon_name, icon_name))
414                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->icon),
415                                                       icon_name,
416                                                       HILDON_ICON_SIZE_FINGER);
417                 gtk_widget_show (priv->icon);
418         }
419         else
420                 gtk_widget_hide (priv->icon);
421
422         g_free (remote);
423
424         gtk_widget_queue_draw (GTK_WIDGET (self));
425 }
426
427 static RTComElIter*
428 make_query (RTComEl *el, gint event_id)
429 {
430         RTComElQuery *query = NULL;
431         RTComElIter *it = NULL;
432
433         static const gchar *services[] = {"RTCOM_EL_SERVICE_SMS",
434                                           "RTCOM_EL_SERVICE_CHAT",
435                                           NULL};
436         static const gchar *event_types[] = {"RTCOM_EL_EVENTTYPE_SMS_INBOUND",
437                                              "RTCOM_EL_EVENTTYPE_CHAT_INBOUND",
438                                              NULL};
439
440         query = rtcom_el_query_new (el);
441         rtcom_el_query_set_limit (query, 1);
442         if (event_id >= 0){
443                 rtcom_el_query_prepare (query,
444                                         "is-read", FALSE, RTCOM_EL_OP_EQUAL,
445                                         "id", event_id, RTCOM_EL_OP_EQUAL,
446                                         "service", services, RTCOM_EL_OP_IN_STRV,
447                                         "event-type", event_types, RTCOM_EL_OP_IN_STRV,
448                                         NULL);
449         }
450         else{
451                 rtcom_el_query_prepare (query,
452                                         "is-read", FALSE, RTCOM_EL_OP_EQUAL,
453                                         "service", services, RTCOM_EL_OP_IN_STRV,
454                                         "event-type", event_types, RTCOM_EL_OP_IN_STRV,
455                                         NULL);
456         }
457         it = rtcom_el_get_events (el, query);
458         g_object_unref(query);
459
460         return it;
461 }
462
463 static void
464 update_unread_label (ELHomeApplet *self)
465 {
466         ELHomeAppletPrivate *priv = self->priv;
467         gchar *text;
468
469         if (priv->unread_count > 0){
470                 text = g_strdup_printf ("%d", priv->unread_count);
471                 gtk_label_set_text (GTK_LABEL (priv->unread), text);
472                 g_free (text);
473         }
474         else
475                 gtk_label_set_text (GTK_LABEL (priv->unread), NULL);
476 }
477
478 static gint
479 query_unread_events (RTComEl *el)
480 {
481         sqlite3 *db;
482         sqlite3_stmt *stmt;
483         int ret;
484         gint count = 0;
485
486         g_object_get (el, "db", &db, NULL);
487
488         if (sqlite3_prepare_v2 (db,
489                                 "SELECT SUM(total_events)-SUM(read_events) FROM GroupCache;",
490                                 -1,
491                                 &stmt,
492                                 NULL) != SQLITE_OK){
493                 g_error ("%s: can't compile SQL", G_STRFUNC);
494                 return -1;
495         }
496
497         while (SQLITE_BUSY == (ret = sqlite3_step (stmt)));
498
499         if (ret == SQLITE_ROW){
500                 count = sqlite3_column_int (stmt, 0);
501         }
502         else{
503                 g_error ("%s: error while executing SQL", G_STRFUNC);
504         }
505
506         sqlite3_finalize (stmt);
507
508         return count;
509 }
510
511 static void
512 read_event (ELHomeApplet *self)
513 {
514         ELHomeAppletPrivate *priv = self->priv;
515         RTComElIter *it = NULL;
516
517         it = make_query (priv->eventlogger, -1);
518         show_event (self, it);
519         if (it) g_object_unref (it);
520 }
521
522 static void
523 mark_as_read (ELHomeApplet *self)
524 {
525         ELHomeAppletPrivate *priv = self->priv;
526
527         if (priv->event_id >= 0){
528                 rtcom_el_set_read_event (priv->eventlogger,
529                                          priv->event_id,
530                                          TRUE,
531                                          NULL);
532                 read_event (self);
533                 priv->unread_count--;
534                 update_unread_label (self);
535         }
536 }
537
538 static gboolean
539 read_new_event (ELHomeApplet *self)
540 {
541         ELHomeAppletPrivate *priv = self->priv;
542
543         read_event (self);
544         priv->unread_count = query_unread_events (priv->eventlogger);
545         update_unread_label (self);
546
547         priv->idle_id = 0;
548
549         return FALSE;
550 }
551
552 static void
553 add_new_idle (ELHomeApplet *self)
554 {
555         ELHomeAppletPrivate *priv = self->priv;
556
557         if (priv->idle_id)
558                 g_source_remove (priv->idle_id);
559         priv->idle_id = g_idle_add ((GSourceFunc)read_new_event,
560                                     self);
561 }
562
563 static void
564 new_event_cb (RTComEl      *backend,
565               gint          event_id,
566               const gchar  *local_uid,
567               const gchar  *remote_uid,
568               const gchar  *remote_ebook_uid,
569               const gchar  *group_uid,
570               const gchar  *service,
571               ELHomeApplet *self)
572 {
573         add_new_idle (self);
574 }
575
576 static gboolean
577 scroll_anim_cb (ELHomeApplet *self)
578 {
579         ELHomeAppletPrivate *priv = self->priv;
580
581         priv->scroll_offset += 1;
582         gtk_widget_queue_draw (self);
583
584         return TRUE;
585 }
586
587 static gboolean
588 button_press_event_cb (GtkWidget      *widget,
589                        GdkEventButton *event,
590                        ELHomeApplet   *self)
591 {
592         ELHomeAppletPrivate *priv = self->priv;
593
594         if (priv->event_id > 0){
595                 priv->active = TRUE;
596                 gtk_widget_queue_draw (widget);
597         }
598         priv->active = TRUE;
599         if (priv->scroll_on_click) {
600                 stop_scroll_anim (priv);
601                 priv->scroll_anim_id = g_timeout_add (100,
602                                                       scroll_anim_cb,
603                                                       self);
604         }
605
606         gtk_widget_queue_draw (widget);
607         return TRUE;
608 }
609
610 static gboolean
611 button_release_event_cb (GtkWidget      *widget,
612                          GdkEventButton *event,
613                          ELHomeApplet   *self)
614 {
615         ELHomeAppletPrivate *priv = self->priv;
616
617         if (priv->active){
618                 priv->active = FALSE;
619                 /* stop_scroll_anim (priv); */
620 #ifndef DEBUG_LAYOUT
621                 mark_as_read (self);
622 #endif
623                 gtk_widget_queue_draw (widget);
624         }
625
626         return TRUE;
627 }
628
629 static gboolean
630 leave_notify_event_cb (GtkWidget        *widget,
631                        GdkEventCrossing *event,
632                        ELHomeApplet     *self)
633 {
634         ELHomeAppletPrivate *priv = self->priv;
635
636         if (priv->active){
637                 priv->active = FALSE;
638                 stop_scroll_anim (priv);
639                 gtk_widget_queue_draw (widget);
640         }
641
642         return FALSE;
643 }
644
645 static void
646 el_home_applet_init (ELHomeApplet *self)
647 {
648         ELHomeAppletPrivate *priv;
649         GtkWidget *event_box;
650         GtkWidget *hbox, *vbox, *align;
651
652         self->priv = EL_HOME_APPLET_GET_PRIVATE (self);
653         priv = self->priv;
654
655         gtk_widget_set_app_paintable (GTK_WIDGET (self), TRUE);
656
657         priv->unread = gtk_label_new ("12");
658         hildon_helper_set_logical_color (priv->unread,
659                                          GTK_RC_FG,
660                                          GTK_STATE_NORMAL,
661                                          "ActiveTextColor");
662         gtk_misc_set_alignment (GTK_MISC (priv->unread),
663                                 1.0f,
664                                 0.5f);
665         gtk_widget_set_size_request (priv->unread,
666                                      -1,
667                                      HEADER_HEIGHT);
668
669         priv->icon = gtk_image_new_from_icon_name ("chat_unread_sms",
670                                                    HILDON_ICON_SIZE_FINGER);
671         gtk_misc_set_alignment (GTK_MISC (priv->icon),
672                                 0.5f,
673                                 0.5f);
674
675         priv->sender = gtk_label_new ("asdf asdf asdf asdf asdf");
676         gtk_misc_set_alignment (GTK_MISC (priv->sender),
677                                 0.5f,
678                                 0.5f);
679         gtk_label_set_ellipsize (GTK_LABEL (priv->sender),
680                                  PANGO_ELLIPSIZE_END);
681         gtk_widget_set_name (priv->sender, "hildon-shadow-label");
682         hildon_helper_set_logical_font (priv->sender, "SystemFont");
683
684         priv->message = g_strdup ("One two three four five six seven eight nine ten"
685                                   "one two three four five six seven eight nine ten"
686                                   "one two three four five six seven eight nine ten"
687                                   "one two three four five six seven eight nine ten"
688                                   "one two three four five six seven eight nine ten"
689                                   "one two three four five six seven eight nine ten");
690
691         /* TODO: l10n */
692         priv->empty = gtk_label_new ("No new messages");
693         gtk_widget_set_name (priv->empty, "hildon-shadow-label");
694         GTK_WIDGET_SET_FLAGS (priv->empty, GTK_NO_SHOW_ALL);
695
696         priv->received = gtk_label_new ("aewf aewf aewf awef");
697         gtk_misc_set_alignment (GTK_MISC (priv->received),
698                                 1.0f,
699                                 0.5f);
700         gtk_widget_set_size_request (priv->received,
701                                      MESSAGE_WIDTH,
702                                      -1);
703         hildon_helper_set_logical_font (priv->received, "SmallSystemFont");
704         gtk_widget_set_name (priv->received, "hildon-shadow-label");
705
706         hbox = gtk_hbox_new (FALSE, 0);
707         gtk_box_pack_start (GTK_BOX (hbox), priv->unread, FALSE, FALSE, 0);
708         gtk_box_pack_start (GTK_BOX (hbox), priv->icon, FALSE, FALSE, 0);
709         gtk_box_pack_start (GTK_BOX (hbox), priv->sender, TRUE, TRUE, 0);
710
711         vbox = gtk_vbox_new (FALSE, 0);
712         gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
713         gtk_box_pack_start (GTK_BOX (vbox), priv->empty, TRUE, TRUE, 0);
714         gtk_box_pack_end (GTK_BOX (vbox), priv->received, FALSE, FALSE, 0);
715
716         align = gtk_alignment_new (0.5f, 0.0f, 1.0f, 1.0f);
717         gtk_alignment_set_padding (GTK_ALIGNMENT (align),
718                                    0, 0, HILDON_MARGIN_DEFAULT, HILDON_MARGIN_DEFAULT);
719
720         gtk_container_set_border_width (GTK_CONTAINER (vbox), HILDON_MARGIN_HALF);
721
722         event_box = gtk_event_box_new ();
723         gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE);
724         gtk_widget_set_size_request (event_box, BOX_WIDTH, BOX_HEIGHT);
725
726         gtk_container_add (GTK_CONTAINER (align), vbox);
727         gtk_container_add (GTK_CONTAINER (event_box), align);
728         gtk_container_add (GTK_CONTAINER (self), event_box);
729
730         g_signal_connect (event_box, "button-press-event",
731                 G_CALLBACK (button_press_event_cb), self);
732         g_signal_connect (event_box, "button-release-event",
733                 G_CALLBACK (button_release_event_cb), self);
734         g_signal_connect (event_box, "leave-notify-event",
735                 G_CALLBACK (leave_notify_event_cb), self);
736
737         gtk_widget_show_all (GTK_WIDGET (event_box));
738
739 #ifndef DEBUG_LAYOUT
740         priv->eventlogger = rtcom_el_new ();
741         g_signal_connect (priv->eventlogger,
742                           "new-event",
743                           G_CALLBACK (new_event_cb),
744                           self);
745         g_signal_connect (priv->eventlogger,
746                           "event-updated",
747                           G_CALLBACK (new_event_cb),
748                           self);
749
750         read_new_event (self);
751 #endif
752 }
753
754 static void
755 el_home_applet_class_init (ELHomeAppletClass *klass)
756 {
757         GObjectClass *object_class = G_OBJECT_CLASS (klass);
758         GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
759
760         object_class->dispose = dispose;
761         object_class->finalize = finalize;
762         widget_class->expose_event = expose_event;
763         widget_class->realize = el_home_applet_realize;
764
765         g_type_class_add_private (klass, sizeof (ELHomeAppletPrivate));
766 }
767