Render message text to an offscreen cairo surface only once to keep low CPU load...
authorArtem Garmash <artemgarmash@gmail.com>
Sun, 8 Nov 2009 22:42:58 +0000 (00:42 +0200)
committerArtem Garmash <artem.garmash@nokia.com>
Sun, 27 Jun 2010 19:13:40 +0000 (22:13 +0300)
src/el-home-applet.c

index 39da22e..1fda56e 100644 (file)
@@ -75,8 +75,11 @@ struct _ELHomeAppletPrivate
 
         guint idle_id;
 
+        cairo_surface_t *message_surface;
+
         gboolean scroll_on_click;
         gint scroll_offset;
+        gint hidden_message_height;
         guint scroll_anim_id;
 };
 
@@ -140,24 +143,18 @@ rounded_rectangle (cairo_t *cr,
                         x + r, y);
 }
 
-static gboolean
-draw_text (cairo_t *cr,
+static cairo_surface_t*
+draw_text (cairo_t              *cr,
            PangoFontDescription *desc,
-           const gchar *text,
-           double x,
-           double y,
-           int width,
-           int height,
-           int offset)
+           const gchar          *text,
+           gint                  width,
+           gint                 *height)
 {
         PangoLayout *layout;
-        gboolean result;
         PangoRectangle extent;
 
-        cairo_save (cr);
-        cairo_rectangle (cr,
-                         x, y, width, height);
-        cairo_clip (cr);
+        cairo_surface_t *gdk_surface, *result_surface;
+        cairo_t *msg_cr;
 
         /* Create a PangoLayout, set the font and text */
         layout = pango_cairo_create_layout (cr);
@@ -167,31 +164,34 @@ draw_text (cairo_t *cr,
         pango_layout_set_font_description (layout, desc);
 
         pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
-        if (!offset)
-                pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
         pango_layout_set_width (layout, PANGO_SCALE*width);
-        pango_layout_set_height (layout, PANGO_SCALE*height);
 
+        pango_layout_get_pixel_extents (layout, NULL, &extent);
+        *height = extent.height;
+
+        gdk_surface = cairo_get_target (cr);
+        result_surface = cairo_surface_create_similar
+                (gdk_surface,
+                 CAIRO_CONTENT_COLOR_ALPHA,
+                 width,
+                 extent.height);
+        msg_cr = cairo_create (result_surface);
+
+        pango_cairo_update_layout (msg_cr, layout);
         /* draw shadow */
-        cairo_move_to (cr, x + 1, y + 1 - offset);
-        cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 0.8);
-        pango_cairo_show_layout (cr, layout);
+        cairo_move_to (msg_cr, 1, 1);
+        cairo_set_source_rgba (msg_cr, 0.2, 0.2, 0.2, 0.8);
+        pango_cairo_show_layout (msg_cr, layout);
 
         /* draw fg */
-        cairo_move_to (cr, x, y - offset);
-        cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0);
-        pango_cairo_show_layout (cr, layout);
-
-        pango_layout_get_pixel_extents (layout, NULL, &extent);
-        if (offset)
-                result = height < (extent.height - offset);
-        else
-                result = pango_layout_is_ellipsized (layout);
+        cairo_move_to (msg_cr, 0, 0);
+        cairo_set_source_rgba (msg_cr, 1.0, 1.0, 1.0, 1.0);
+        pango_cairo_show_layout (msg_cr, layout);
 
+        cairo_destroy (msg_cr);
         g_object_unref (layout);
-        cairo_restore (cr);
 
-        return result;
+        return result_surface;
 }
 
 static void
@@ -243,7 +243,9 @@ notify_on_current_desktop (GObject      *object,
         g_object_get (object, "is-on-current-desktop", &on, NULL);
         if (!on) {
                 stop_scroll_anim (self->priv);
+                priv->scroll_on_click = priv->scroll_offset;
                 priv->scroll_offset = 0;
+                gtk_widget_queue_draw (GTK_WIDGET (self));
         }
 }
 
@@ -349,23 +351,36 @@ expose_event (GtkWidget *self, GdkEventExpose *event)
         /* cairo_stroke (cr); */
 
         /* draw message */
-        gboolean ellipsized;
-        ellipsized = draw_text (cr,
-                                priv->font_desc,
-                                priv->message,
-                                2*C_X, HEADER_HEIGHT,
-                                MESSAGE_WIDTH,
-                                message_height,
-                                priv->scroll_offset);
-        if (!priv->scroll_anim_id && !priv->scroll_offset)
-                priv->scroll_on_click = ellipsized;
+        if (!priv->message_surface) {
+                gint height;
+
+                priv->message_surface = draw_text (cr,
+                                                   priv->font_desc,
+                                                   priv->message,
+                                                   MESSAGE_WIDTH,
+                                                   &height);
+
+                priv->hidden_message_height = height - message_height;
+                priv->scroll_on_click = priv->hidden_message_height > 0;
+        }
+
+        cairo_rectangle (cr,
+                         2*C_X,
+                         HEADER_HEIGHT,
+                         MESSAGE_WIDTH,
+                         message_height);
+        cairo_clip (cr);
+
+        cairo_set_source_surface (cr,
+                                  priv->message_surface,
+                                  2*C_X,
+                                  HEADER_HEIGHT - priv->scroll_offset);
+        cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+        cairo_paint (cr);
 
         cairo_pattern_destroy (grad);
         cairo_destroy (cr);
 
-        if (!priv->scroll_on_click && !ellipsized && priv->scroll_offset)
-                stop_scroll_anim (priv);
-
         return GTK_WIDGET_CLASS (el_home_applet_parent_class)->expose_event (self, event);
 }
 
@@ -487,8 +502,12 @@ show_event (ELHomeApplet *self, RTComElIter *it)
 
         g_free (remote);
 
-        stop_scroll_anim (self->priv);
+        stop_scroll_anim (priv);
         priv->scroll_offset = 0;
+        if (priv->message_surface) {
+                cairo_surface_destroy (priv->message_surface);
+                priv->message_surface = NULL;
+        }
         gtk_widget_queue_draw (GTK_WIDGET (self));
 }
 
@@ -645,6 +664,7 @@ static gboolean
 scroll_anim_cb (ELHomeApplet *self)
 {
         ELHomeAppletPrivate *priv = self->priv;
+        gboolean to_continue;
 
         priv->scroll_offset += SCROLL_STEP;
         gtk_widget_queue_draw_area (GTK_WIDGET (self),
@@ -653,7 +673,11 @@ scroll_anim_cb (ELHomeApplet *self)
                                     MESSAGE_WIDTH,
                                     C_HEIGHT - priv->received->allocation.height - HEADER_HEIGHT);
 
-        return TRUE;
+        to_continue = priv->scroll_offset <= priv->hidden_message_height;
+        if (!to_continue)
+                priv->scroll_anim_id = 0;
+
+        return to_continue;
 }
 
 static gboolean
@@ -687,10 +711,12 @@ button_release_event_cb (GtkWidget      *widget,
                                                               (GSourceFunc)scroll_anim_cb,
                                                               self);
                 }
-                else
+                else {
 #ifndef DEBUG_LAYOUT
                         mark_as_read (self);
 #endif
+                }
+
                 gtk_widget_queue_draw (widget);
         }