1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
3 * Copyright (C) 2009 Artem Garmash. All rights reserved.
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.
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.
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
19 * Contact: Artem Garmash <artemgarmash@gmail.com>
24 #include "el-home-applet.h"
26 #include <hildon/hildon.h>
27 #include <rtcom-eventlogger/eventlogger.h>
31 #define EL_HOME_APPLET_GET_PRIVATE(obj) ( \
32 G_TYPE_INSTANCE_GET_PRIVATE (obj, \
33 EL_TYPE_HOME_APPLET, ELHomeAppletPrivate))
36 #define BOX_HEIGHT 256
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
43 #define HEADER_HEIGHT 48
44 #define MESSAGE_HEIGHT (C_HEIGHT - HEADER_HEIGHT)
45 #define MESSAGE_WIDTH (C_WIDTH - 2*HILDON_MARGIN_DEFAULT)
47 #define BOX_RADIOUS 10
51 struct _ELHomeAppletPrivate
68 const gchar *current_font;
73 HD_DEFINE_PLUGIN_MODULE (ELHomeApplet, el_home_applet, HD_TYPE_HOME_PLUGIN_ITEM);
75 const gchar* g_module_check_init(GModule *module);
77 g_module_check_init(GModule *module)
79 g_module_make_resident (module);
84 el_home_applet_class_finalize (ELHomeAppletClass *klass)
89 el_home_applet_realize (GtkWidget *widget)
93 screen = gtk_widget_get_screen (widget);
94 gtk_widget_set_colormap (widget,
95 gdk_screen_get_rgba_colormap (screen));
97 gtk_widget_set_app_paintable (widget,
100 GTK_WIDGET_CLASS (el_home_applet_parent_class)->realize (widget);
104 * Thanks http://cairographics.org/cookbook/roundedrectangles/
107 rounded_rectangle (cairo_t *cr,
114 cairo_move_to (cr, x + r, y);
115 cairo_line_to (cr, x + w - r, y);
116 cairo_curve_to (cr, x + w, y,
119 cairo_line_to (cr, x + w, y + h - r);
120 cairo_curve_to (cr, x + w, y + h,
123 cairo_line_to (cr, x + r, y + h);
124 cairo_curve_to (cr, x, y + h,
127 cairo_line_to (cr, x, y + r);
128 cairo_curve_to (cr, x, y,
134 draw_text (cairo_t *cr,
142 PangoFontDescription *desc;
144 /* Create a PangoLayout, set the font and text */
145 layout = pango_cairo_create_layout (cr);
146 pango_layout_set_text (layout,
149 desc = pango_font_description_from_string ("Sans 17");
150 pango_layout_set_font_description (layout, desc);
151 pango_font_description_free (desc);
153 pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
154 pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
155 pango_layout_set_width (layout, PANGO_SCALE*width);
156 pango_layout_set_height (layout, PANGO_SCALE*height);
159 cairo_move_to (cr, x + 1, y + 1);
160 cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 0.8);
161 pango_cairo_show_layout (cr, layout);
164 cairo_move_to (cr, x, y);
165 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0);
166 pango_cairo_show_layout (cr, layout);
168 g_object_unref (layout);
172 expose_event (GtkWidget *self, GdkEventExpose *event)
174 ELHomeAppletPrivate *priv = EL_HOME_APPLET(self)->priv;
178 float red, green, blue;
180 /* find theme active color */
181 gtk_style_lookup_color (self->style, "ActiveTextColor", &color);
182 red = color.red/(float)G_MAXUINT16;
183 green = color.green/(float)G_MAXUINT16;
184 blue = color.blue/(float)G_MAXUINT16;
186 cr = gdk_cairo_create (self->window);
187 gdk_cairo_region (cr, event->region);
191 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
193 cairo_set_source_rgba (cr, 0.4f, 0.4f, 0.4f, 0.1f);
194 cairo_set_line_width (cr, 3.0f);
196 rounded_rectangle (cr,
203 cairo_close_path(cr);
207 cairo_set_line_width (cr, 1.0f);
209 cairo_translate (cr, C_X, C_Y);
210 cairo_move_to (cr, 0, HEADER_HEIGHT);
211 cairo_line_to (cr, 0, BOX_RADIOUS);
212 cairo_curve_to (cr, 0, 0, 0, 0, BOX_RADIOUS, 0);
213 cairo_line_to (cr, C_WIDTH - BOX_RADIOUS, 0);
214 cairo_curve_to (cr, C_WIDTH, 0, C_WIDTH, 0, C_WIDTH, BOX_RADIOUS);
215 cairo_line_to (cr, C_WIDTH, HEADER_HEIGHT);
216 cairo_line_to (cr, 0, HEADER_HEIGHT);
218 cairo_close_path(cr);
220 cairo_set_source_rgba (cr, 0.2f, 0.2f, 0.2f, 0.8f);
221 cairo_fill_preserve (cr);
222 cairo_set_source_rgba (cr, red, green, blue, 1.0f);
226 cairo_move_to (cr, 0, HEADER_HEIGHT);
227 cairo_line_to (cr, 0, C_HEIGHT - BOX_RADIOUS);
228 cairo_curve_to (cr, 0, C_HEIGHT, 0, C_HEIGHT, BOX_RADIOUS, C_HEIGHT);
229 cairo_line_to (cr, C_WIDTH - BOX_RADIOUS, C_HEIGHT);
230 cairo_curve_to (cr, C_WIDTH, C_HEIGHT, C_WIDTH, C_HEIGHT, C_WIDTH, C_HEIGHT - BOX_RADIOUS);
231 cairo_line_to (cr, C_WIDTH, HEADER_HEIGHT);
232 cairo_line_to (cr, 0, HEADER_HEIGHT);
233 cairo_close_path(cr);
235 /* draw body filling depending on (in)active state */
236 cairo_pattern_t *grad;
237 grad = cairo_pattern_create_linear(0, HEADER_HEIGHT,
241 cairo_pattern_add_color_stop_rgba (grad, 0.5f,
242 red, green, blue, 0.8f);
243 cairo_pattern_add_color_stop_rgba (grad, 1.0f,
244 red/2, green/2, blue/2, 0.8f);
247 cairo_pattern_add_color_stop_rgba (grad, 0.5f,
248 0.4f, 0.4f, 0.4f, 0.8f);
249 cairo_pattern_add_color_stop_rgba (grad, 1.0f,
250 0.2f, 0.2f, 0.2f, 0.8f);
252 cairo_set_source (cr, grad);
255 /* cairo_set_source_rgba (cr, red, green, blue, 1.0f); */
256 /* cairo_translate (cr, -C_X, -C_Y); */
257 /* rounded_rectangle (cr, */
260 /* BOX_WIDTH - 2*C_X, */
261 /* BOX_HEIGHT - 2*C_Y, */
263 /* cairo_close_path(cr); */
264 /* cairo_stroke (cr); */
267 draw_text (cr, priv->message,
268 2*C_X, HEADER_HEIGHT,
270 MESSAGE_HEIGHT - 2*C_Y);
272 cairo_pattern_destroy (grad);
275 return GTK_WIDGET_CLASS (el_home_applet_parent_class)->expose_event (self, event);
279 dispose (GObject *self)
281 ELHomeAppletPrivate *priv = EL_HOME_APPLET(self)->priv;
284 g_source_remove (priv->idle_id);
287 if (priv->eventlogger){
288 g_object_unref (priv->eventlogger);
289 priv->eventlogger = NULL;
293 g_free (priv->message);
294 priv->message = NULL;
297 G_OBJECT_CLASS (el_home_applet_parent_class)->dispose (self);
301 finalize (GObject *self)
303 G_OBJECT_CLASS (el_home_applet_parent_class)->finalize (self);
307 format_time (time_t t)
309 static const guint RESULT_SIZE = 32;
312 struct tm now_tm, t_tm;
313 const gchar *format = "%Y.%m.%d %T";
314 gchar *result = g_malloc0 (RESULT_SIZE);
317 localtime_r (&now, &now_tm);
318 localtime_r (&t, &t_tm);
320 if ((now_tm.tm_year == t_tm.tm_year) &&
321 (now_tm.tm_mon == t_tm.tm_mon) &&
322 (now_tm.tm_mday == t_tm.tm_mday))
325 strftime (result, RESULT_SIZE, format, &t_tm);
331 show_event (ELHomeApplet *self, RTComElIter *it)
333 ELHomeAppletPrivate *priv = self->priv;
335 gchar *remote = NULL;
336 gchar *received = NULL;
337 const gchar *icon_name = NULL;
340 g_free (priv->message);
341 priv->message = NULL;
344 if (it && rtcom_el_iter_first (it)){
345 rtcom_el_iter_dup_string (it, "free-text", &priv->message);
347 const gchar *service;
350 rtcom_el_iter_get_int (it, "id", &priv->event_id);
351 if (rtcom_el_iter_get_int (it, "start-time", (gint*)&received_t))
352 received = format_time (received_t);
354 if(!rtcom_el_iter_dup_string (it, "remote-name", &remote))
355 rtcom_el_iter_dup_string (it, "remote-id", &remote);
356 service = rtcom_el_iter_get_service (it);
357 if (!g_strcmp0 (service, "RTCOM_EL_SERVICE_SMS"))
358 icon_name = "chat_unread_sms";
359 else if (!g_strcmp0 (service, "RTCOM_EL_SERVICE_CHAT"))
360 icon_name = "chat_unread_chat";
368 gtk_widget_hide (priv->empty);
370 gtk_widget_show (priv->empty);
372 gtk_label_set_text (GTK_LABEL (priv->sender), remote);
373 gtk_label_set_text (GTK_LABEL (priv->received), received);
376 const gchar *current_icon_name;
377 gtk_image_get_icon_name (GTK_IMAGE (priv->icon),
380 if (g_strcmp0 (current_icon_name, icon_name))
381 gtk_image_set_from_icon_name (GTK_IMAGE (priv->icon),
383 HILDON_ICON_SIZE_FINGER);
384 gtk_widget_show (priv->icon);
387 gtk_widget_hide (priv->icon);
391 gtk_widget_queue_draw (GTK_WIDGET (self));
395 make_query (RTComEl *el, gint event_id)
397 RTComElQuery *query = NULL;
398 RTComElIter *it = NULL;
400 static const gchar *services[] = {"RTCOM_EL_SERVICE_SMS",
401 "RTCOM_EL_SERVICE_CHAT",
403 static const gchar *event_types[] = {"RTCOM_EL_EVENTTYPE_SMS_INBOUND",
404 "RTCOM_EL_EVENTTYPE_CHAT_INBOUND",
407 query = rtcom_el_query_new (el);
408 rtcom_el_query_set_limit (query, 1);
410 rtcom_el_query_prepare (query,
411 "is-read", FALSE, RTCOM_EL_OP_EQUAL,
412 "id", event_id, RTCOM_EL_OP_EQUAL,
413 "service", services, RTCOM_EL_OP_IN_STRV,
414 "event-type", event_types, RTCOM_EL_OP_IN_STRV,
418 rtcom_el_query_prepare (query,
419 "is-read", FALSE, RTCOM_EL_OP_EQUAL,
420 "service", services, RTCOM_EL_OP_IN_STRV,
421 "event-type", event_types, RTCOM_EL_OP_IN_STRV,
424 it = rtcom_el_get_events (el, query);
425 g_object_unref(query);
431 update_unread_label (ELHomeApplet *self)
433 ELHomeAppletPrivate *priv = self->priv;
436 if (priv->unread_count > 0){
437 text = g_strdup_printf ("%d", priv->unread_count);
438 gtk_label_set_text (GTK_LABEL (priv->unread), text);
442 gtk_label_set_text (GTK_LABEL (priv->unread), NULL);
446 query_unread_events (RTComEl *el)
453 g_object_get (el, "db", &db, NULL);
455 if (sqlite3_prepare_v2 (db,
456 "SELECT SUM(total_events)-SUM(read_events) FROM GroupCache;",
460 g_error ("%s: can't compile SQL", G_STRFUNC);
464 while (SQLITE_BUSY == (ret = sqlite3_step (stmt)));
466 if (ret == SQLITE_ROW){
467 count = sqlite3_column_int (stmt, 0);
470 g_error ("%s: error while executing SQL", G_STRFUNC);
473 sqlite3_finalize (stmt);
479 read_event (ELHomeApplet *self)
481 ELHomeAppletPrivate *priv = self->priv;
482 RTComElIter *it = NULL;
484 it = make_query (priv->eventlogger, -1);
485 show_event (self, it);
486 if (it) g_object_unref (it);
490 mark_as_read (ELHomeApplet *self)
492 ELHomeAppletPrivate *priv = self->priv;
494 if (priv->event_id >= 0){
495 rtcom_el_set_read_event (priv->eventlogger,
500 priv->unread_count--;
501 update_unread_label (self);
506 read_new_event (ELHomeApplet *self)
508 ELHomeAppletPrivate *priv = self->priv;
511 priv->unread_count = query_unread_events (priv->eventlogger);
512 update_unread_label (self);
520 add_new_idle (ELHomeApplet *self)
522 ELHomeAppletPrivate *priv = self->priv;
525 g_source_remove (priv->idle_id);
526 priv->idle_id = g_idle_add ((GSourceFunc)read_new_event,
531 new_event_cb (RTComEl *backend,
533 const gchar *local_uid,
534 const gchar *remote_uid,
535 const gchar *remote_ebook_uid,
536 const gchar *group_uid,
537 const gchar *service,
544 button_release_event_cb (GtkWidget *widget,
545 GdkEventButton *event,
548 ELHomeAppletPrivate *priv = self->priv;
551 priv->active = FALSE;
552 gtk_widget_queue_draw (widget);
562 button_press_event_cb (GtkWidget *widget,
563 GdkEventButton *event,
566 ELHomeAppletPrivate *priv = self->priv;
568 if (priv->event_id > 0){
570 gtk_widget_queue_draw (widget);
577 leave_notify_event_cb (GtkWidget *widget,
578 GdkEventCrossing *event,
581 ELHomeAppletPrivate *priv = self->priv;
584 priv->active = FALSE;
585 gtk_widget_queue_draw (widget);
592 el_home_applet_init (ELHomeApplet *self)
594 ELHomeAppletPrivate *priv;
595 GtkWidget *event_box;
596 GtkWidget *hbox, *vbox, *align;
598 self->priv = EL_HOME_APPLET_GET_PRIVATE (self);
601 gtk_widget_set_app_paintable (GTK_WIDGET (self), TRUE);
603 priv->unread = gtk_label_new ("12");
604 hildon_helper_set_logical_color (priv->unread,
608 gtk_misc_set_alignment (GTK_MISC (priv->unread),
611 gtk_widget_set_size_request (priv->unread,
615 priv->icon = gtk_image_new_from_icon_name ("chat_unread_sms",
616 HILDON_ICON_SIZE_FINGER);
617 gtk_misc_set_alignment (GTK_MISC (priv->icon),
621 priv->sender = gtk_label_new ("asdf asdf asdf asdf asdf");
622 gtk_misc_set_alignment (GTK_MISC (priv->sender),
625 gtk_label_set_ellipsize (GTK_LABEL (priv->sender),
626 PANGO_ELLIPSIZE_END);
627 gtk_widget_set_name (priv->sender, "hildon-shadow-label");
628 hildon_helper_set_logical_font (priv->sender, "SystemFont");
630 priv->message = g_strdup ("One two three four five six seven eight nine ten"
631 "one two three four five six seven eight nine ten"
632 "one two three four five six seven eight nine ten"
633 "one two three four five six seven eight nine ten"
634 "one two three four five six seven eight nine ten"
635 "one two three four five six seven eight nine ten");
638 priv->empty = gtk_label_new ("No new messages");
639 gtk_widget_set_name (priv->empty, "hildon-shadow-label");
640 GTK_WIDGET_SET_FLAGS (priv->empty, GTK_NO_SHOW_ALL);
642 priv->received = gtk_label_new ("aewf aewf aewf awef");
643 gtk_misc_set_alignment (GTK_MISC (priv->received),
646 gtk_widget_set_size_request (priv->received,
649 hildon_helper_set_logical_font (priv->received, "SmallSystemFont");
650 gtk_widget_set_name (priv->received, "hildon-shadow-label");
652 hbox = gtk_hbox_new (FALSE, 0);
653 gtk_box_pack_start (GTK_BOX (hbox), priv->unread, FALSE, FALSE, 0);
654 gtk_box_pack_start (GTK_BOX (hbox), priv->icon, FALSE, FALSE, 0);
655 gtk_box_pack_start (GTK_BOX (hbox), priv->sender, TRUE, TRUE, 0);
657 vbox = gtk_vbox_new (FALSE, 0);
658 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
659 gtk_box_pack_start (GTK_BOX (vbox), priv->empty, TRUE, TRUE, 0);
660 gtk_box_pack_end (GTK_BOX (vbox), priv->received, FALSE, FALSE, 0);
662 align = gtk_alignment_new (0.5f, 0.0f, 1.0f, 1.0f);
663 gtk_alignment_set_padding (GTK_ALIGNMENT (align),
664 0, 0, HILDON_MARGIN_DEFAULT, HILDON_MARGIN_DEFAULT);
666 gtk_container_set_border_width (GTK_CONTAINER (vbox), HILDON_MARGIN_HALF);
668 event_box = gtk_event_box_new ();
669 gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE);
670 gtk_widget_set_size_request (event_box, BOX_WIDTH, BOX_HEIGHT);
672 gtk_container_add (GTK_CONTAINER (align), vbox);
673 gtk_container_add (GTK_CONTAINER (event_box), align);
674 gtk_container_add (GTK_CONTAINER (self), event_box);
676 g_signal_connect (event_box, "button-press-event",
677 G_CALLBACK (button_press_event_cb), self);
678 g_signal_connect (event_box, "button-release-event",
679 G_CALLBACK (button_release_event_cb), self);
680 g_signal_connect (event_box, "leave-notify-event",
681 G_CALLBACK (leave_notify_event_cb), self);
683 gtk_widget_show_all (GTK_WIDGET (event_box));
686 priv->eventlogger = rtcom_el_new ();
687 g_signal_connect (priv->eventlogger,
689 G_CALLBACK (new_event_cb),
691 g_signal_connect (priv->eventlogger,
693 G_CALLBACK (new_event_cb),
696 read_new_event (self);
701 el_home_applet_class_init (ELHomeAppletClass *klass)
703 GObjectClass *object_class = G_OBJECT_CLASS (klass);
704 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
706 object_class->dispose = dispose;
707 object_class->finalize = finalize;
708 widget_class->expose_event = expose_event;
709 widget_class->realize = el_home_applet_realize;
711 g_type_class_add_private (klass, sizeof (ELHomeAppletPrivate));