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