Merge lp:~larsu/indicator-messages/draw-lozenges into lp:indicator-messages/12.10

Proposed by Lars Karlitski
Status: Merged
Approved by: Lars Karlitski
Approved revision: 310
Merged at revision: 307
Proposed branch: lp:~larsu/indicator-messages/draw-lozenges
Merge into: lp:indicator-messages/12.10
Diff against target: 623 lines (+484/-62)
4 files modified
src/Makefile.am (+2/-0)
src/ido-detail-label.c (+396/-0)
src/ido-detail-label.h (+59/-0)
src/im-source-menu-item.c (+27/-62)
To merge this branch: bzr merge lp:~larsu/indicator-messages/draw-lozenges
Reviewer Review Type Date Requested Status
jenkins (community) continuous-integration Needs Fixing
Charles Kerr (community) Approve
Review via email: mp+122522@code.launchpad.net

Commit message

Draw counts as lozenges again.

Introduces IdoDetailLabel, a GtkWidget that renders detail strings (e.g. as lozenges) on the right side of a menu item.

Description of the change

Put lozenges back into the messaging menu.

I factored lozenge drawing out into its own widget IdoDetailLabel. It draws both lozenges and other detail labels, so that the text inside lozenges and the text of other labels line up on the right side.

To post a comment you must log in.
Revision history for this message
jenkins (martin-mrazik+qa) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Charles Kerr (charlesk) wrote :

Adding a separate widget is a much cleaner approach than the previous numbers_draw_cb(). Nice work. :)

Needs Fixing:

 * ido_detail_label_dispose() doesn't chain up to superclass

 * ido_detail_label_finalize() doesn't chain up to superclass

Comment:

 * ido_detail_label_clear() is an odd function. It looks like it was designed to extract duplicate code from _set_text() and _set_count(), but it leaves the widget in an odd state (dangling pointer) and, more importantly, there's still a lot of duplicated code in _set_text() and _set_count(). How about something like this:

static void
ido_detail_label_set_text_impl (IdoDetailLabel * label, const gchar * text, gboolean draw_lozenge)
{
  IdoDetailLabelPrivate * priv = label->priv;

  g_clear_object (&priv->layout);
  g_free (priv->text);
  priv->text = g_strdup (text);
  priv->draw_lozenge = draw_lozenge;

  g_object_notify_by_pspec (G_OBJECT (label), properties[PROP_TEXT]);
  gtk_widget_queue_resize (GTK_WIDGET (label));
}

void
ido_detail_label_set_count (IdoDetailLabel *label, gint count)
{
  g_return_if_fail (IDO_IS_DETAIL_LABEL (label));

  gchar * text = g_strdup_printf ("%d", count);
  ido_detail_label_set_text_impl (label, text, TRUE);
  g_free (text);
}

void
ido_detail_label_set_text (IdoDetailLabel *label, const gchar *text)
{
  g_return_if_fail (IDO_IS_DETAIL_LABEL (label));

  gchar * str = collapse_whitespace (text);
  ido_detail_label_set_text_impl (label, str, FALSE);
  g_free (str);
}

review: Needs Fixing
Revision history for this message
Lars Karlitski (larsu) wrote :

> Needs Fixing:
>
> * ido_detail_label_dispose() doesn't chain up to superclass
>
> * ido_detail_label_finalize() doesn't chain up to superclass

Argh, fixed in r309.

> Comment:

> * ido_detail_label_clear() is an odd function. It looks like it was designed to extract
> duplicate code from _set_text() and _set_count(), but it leaves the widget in an odd state
> (dangling pointer) and, more importantly, there's still a lot of duplicated code in
> _set_text() and _set_count(). How about something like this:

Yeah, *much* better. Implemented as suggested (with minor style changes to keep it consistent) in r310.

Thank you!

Revision history for this message
Charles Kerr (charlesk) :
review: Approve
Revision history for this message
jenkins (martin-mrazik+qa) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
jenkins (martin-mrazik+qa) wrote :

FAILED: Autolanding.
More details in the following jenkins job:
http://jenkins.qa.ubuntu.com/job/indicator-messages-autolanding/2/

review: Needs Fixing (continuous-integration)
Revision history for this message
jenkins (martin-mrazik+qa) wrote :
review: Approve (continuous-integration)
Revision history for this message
jenkins (martin-mrazik+qa) wrote :

FAILED: Autolanding.
No commit message was specified.
http://jenkins.qa.ubuntu.com/job/indicator-messages-autolanding/3/

review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/Makefile.am'
2--- src/Makefile.am 2012-08-27 13:38:04 +0000
3+++ src/Makefile.am 2012-09-04 17:24:18 +0000
4@@ -21,6 +21,8 @@
5 im-app-menu-item.h \
6 im-source-menu-item.c \
7 im-source-menu-item.h \
8+ ido-detail-label.c \
9+ ido-detail-label.h \
10 indicator-messages-service.c \
11 indicator-messages-service.h
12 dbus-data.h
13
14=== added file 'src/ido-detail-label.c'
15--- src/ido-detail-label.c 1970-01-01 00:00:00 +0000
16+++ src/ido-detail-label.c 2012-09-04 17:24:18 +0000
17@@ -0,0 +1,396 @@
18+/*
19+ * Copyright 2012 Canonical Ltd.
20+ *
21+ * This program is free software: you can redistribute it and/or modify it
22+ * under the terms of the GNU General Public License version 3, as published
23+ * by the Free Software Foundation.
24+ *
25+ * This program is distributed in the hope that it will be useful, but
26+ * WITHOUT ANY WARRANTY; without even the implied warranties of
27+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
28+ * PURPOSE. See the GNU General Public License for more details.
29+ *
30+ * You should have received a copy of the GNU General Public License along
31+ * with this program. If not, see <http://www.gnu.org/licenses/>.
32+ *
33+ * Authors:
34+ * Lars Uebernickel <lars.uebernickel@canonical.com>
35+ */
36+
37+#include "ido-detail-label.h"
38+
39+#include <math.h>
40+
41+G_DEFINE_TYPE (IdoDetailLabel, ido_detail_label, GTK_TYPE_WIDGET)
42+
43+struct _IdoDetailLabelPrivate
44+{
45+ gchar *text;
46+ PangoLayout *layout;
47+ gboolean draw_lozenge;
48+};
49+
50+enum
51+{
52+ PROP_0,
53+ PROP_TEXT,
54+ NUM_PROPERTIES
55+};
56+
57+static GParamSpec *properties[NUM_PROPERTIES];
58+
59+static void
60+ido_detail_label_get_property (GObject *object,
61+ guint property_id,
62+ GValue *value,
63+ GParamSpec *pspec)
64+{
65+ IdoDetailLabel *self = IDO_DETAIL_LABEL (object);
66+
67+ switch (property_id)
68+ {
69+ case PROP_TEXT:
70+ g_value_set_string (value, self->priv->text);
71+ break;
72+
73+ default:
74+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
75+ }
76+}
77+
78+static void
79+ido_detail_label_set_property (GObject *object,
80+ guint property_id,
81+ const GValue *value,
82+ GParamSpec *pspec)
83+{
84+ IdoDetailLabel *self = IDO_DETAIL_LABEL (object);
85+
86+ switch (property_id)
87+ {
88+ case PROP_TEXT:
89+ ido_detail_label_set_text (self, g_value_get_string (value));
90+ break;
91+
92+ default:
93+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
94+ }
95+}
96+
97+
98+static void
99+ido_detail_label_finalize (GObject *object)
100+{
101+ IdoDetailLabelPrivate *priv = IDO_DETAIL_LABEL (object)->priv;
102+
103+ g_free (priv->text);
104+
105+ G_OBJECT_CLASS (ido_detail_label_parent_class)->finalize (object);
106+}
107+
108+static void
109+ido_detail_label_dispose (GObject *object)
110+{
111+ IdoDetailLabelPrivate *priv = IDO_DETAIL_LABEL (object)->priv;
112+
113+ g_clear_object (&priv->layout);
114+
115+ G_OBJECT_CLASS (ido_detail_label_parent_class)->dispose (object);
116+}
117+
118+static void
119+ido_detail_label_ensure_layout (IdoDetailLabel *label)
120+{
121+ IdoDetailLabelPrivate *priv = label->priv;
122+
123+ if (priv->layout == NULL)
124+ {
125+ priv->layout = gtk_widget_create_pango_layout (GTK_WIDGET (label), priv->text);
126+ pango_layout_set_alignment (priv->layout, PANGO_ALIGN_CENTER);
127+ pango_layout_set_ellipsize (priv->layout, PANGO_ELLIPSIZE_END);
128+ pango_layout_set_height (priv->layout, -1);
129+
130+ // TODO update layout on "style-updated" and "direction-changed"
131+ }
132+}
133+
134+static void
135+cairo_lozenge (cairo_t *cr,
136+ double x,
137+ double y,
138+ double w,
139+ double h,
140+ double radius)
141+{
142+ double x1 = x + w - radius;
143+ double x2 = x + radius;
144+ double y1 = y + radius;
145+ double y2 = y + h - radius;
146+
147+ cairo_move_to (cr, x + radius, y);
148+ cairo_arc (cr, x1, y1, radius, G_PI * 1.5, G_PI * 2);
149+ cairo_arc (cr, x1, y2, radius, 0, G_PI * 0.5);
150+ cairo_arc (cr, x2, y2, radius, G_PI * 0.5, G_PI);
151+ cairo_arc (cr, x2, y1, radius, G_PI, G_PI * 1.5);
152+}
153+
154+static PangoFontMetrics *
155+gtk_widget_get_font_metrics (GtkWidget *widget,
156+ PangoContext *context)
157+{
158+ const PangoFontDescription *font;
159+
160+ font = gtk_style_context_get_font (gtk_widget_get_style_context (widget),
161+ gtk_widget_get_state_flags (widget));
162+
163+ return pango_context_get_metrics (context,
164+ font,
165+ pango_context_get_language (context));
166+}
167+
168+static gint
169+ido_detail_label_get_minimum_text_width (IdoDetailLabel *label)
170+{
171+ IdoDetailLabelPrivate *priv = label->priv;
172+ PangoContext *context;
173+ PangoFontMetrics *metrics;
174+ gint char_width;
175+ gint w;
176+
177+ context = pango_layout_get_context (priv->layout);
178+ metrics = gtk_widget_get_font_metrics (GTK_WIDGET (label), context);
179+ char_width = pango_font_metrics_get_approximate_digit_width (metrics);
180+
181+ w = 2 * char_width / PANGO_SCALE;
182+ pango_font_metrics_unref (metrics);
183+ return w;
184+}
185+
186+static gboolean
187+ido_detail_label_draw (GtkWidget *widget,
188+ cairo_t *cr)
189+{
190+ IdoDetailLabel *label = IDO_DETAIL_LABEL (widget);
191+ IdoDetailLabelPrivate *priv = IDO_DETAIL_LABEL (widget)->priv;
192+ PangoRectangle extents;
193+ GtkAllocation allocation;
194+ double x, w, h, radius;
195+ GdkRGBA color;
196+
197+ if (!priv->text || !*priv->text)
198+ return TRUE;
199+
200+ gtk_widget_get_allocation (widget, &allocation);
201+
202+ ido_detail_label_ensure_layout (IDO_DETAIL_LABEL (widget));
203+
204+ pango_layout_get_extents (priv->layout, NULL, &extents);
205+ pango_extents_to_pixels (&extents, NULL);
206+
207+ h = MIN (allocation.height, extents.height);
208+ radius = floor (h / 2.0);
209+ w = MAX (ido_detail_label_get_minimum_text_width (label), extents.width) + 2.0 * radius;
210+ x = allocation.width - w;
211+
212+ pango_layout_set_width (priv->layout, (allocation.width - 2 * radius) * PANGO_SCALE);
213+ pango_layout_get_extents (priv->layout, NULL, &extents);
214+ pango_extents_to_pixels (&extents, NULL);
215+
216+ gtk_style_context_get_color (gtk_widget_get_style_context (widget),
217+ gtk_widget_get_state_flags (widget),
218+ &color);
219+ gdk_cairo_set_source_rgba (cr, &color);
220+
221+ cairo_set_line_width (cr, 1.0);
222+ cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
223+
224+ if (priv->draw_lozenge)
225+ cairo_lozenge (cr, x, 0.0, w, h, radius);
226+
227+ cairo_move_to (cr, x + radius, (allocation.height - extents.height) / 2.0);
228+ pango_cairo_layout_path (cr, priv->layout);
229+ cairo_fill (cr);
230+
231+ return TRUE;
232+}
233+
234+static void
235+ido_detail_label_get_preferred_width (GtkWidget *widget,
236+ gint *minimum,
237+ gint *natural)
238+{
239+ IdoDetailLabelPrivate *priv = IDO_DETAIL_LABEL (widget)->priv;
240+ PangoRectangle extents;
241+ double radius;
242+
243+ ido_detail_label_ensure_layout (IDO_DETAIL_LABEL (widget));
244+
245+ pango_layout_get_extents (priv->layout, NULL, &extents);
246+ pango_extents_to_pixels (&extents, NULL);
247+
248+ radius = floor (extents.height / 2.0);
249+
250+ *minimum = ido_detail_label_get_minimum_text_width (IDO_DETAIL_LABEL (widget)) + 2.0 * radius;
251+ *natural = MAX (*minimum, extents.width + 2.0 * radius);
252+}
253+
254+static void
255+ido_detail_label_get_preferred_height (GtkWidget *widget,
256+ gint *minimum,
257+ gint *natural)
258+{
259+ IdoDetailLabelPrivate *priv = IDO_DETAIL_LABEL (widget)->priv;
260+ PangoContext *context;
261+ PangoFontMetrics *metrics;
262+ PangoRectangle extents;
263+
264+ ido_detail_label_ensure_layout (IDO_DETAIL_LABEL (widget));
265+
266+ pango_layout_get_extents (priv->layout, NULL, &extents);
267+ pango_extents_to_pixels (&extents, NULL);
268+ context = pango_layout_get_context (priv->layout);
269+ metrics = gtk_widget_get_font_metrics (widget, context);
270+
271+ *minimum = *natural = (pango_font_metrics_get_ascent (metrics) +
272+ pango_font_metrics_get_descent (metrics)) / PANGO_SCALE;
273+
274+ pango_font_metrics_unref (metrics);
275+}
276+
277+static void
278+ido_detail_label_class_init (IdoDetailLabelClass *klass)
279+{
280+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
281+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
282+
283+ object_class->get_property = ido_detail_label_get_property;
284+ object_class->set_property = ido_detail_label_set_property;
285+ object_class->finalize = ido_detail_label_finalize;
286+ object_class->dispose = ido_detail_label_dispose;
287+
288+ widget_class->draw = ido_detail_label_draw;
289+ widget_class->get_preferred_width = ido_detail_label_get_preferred_width;
290+ widget_class->get_preferred_height = ido_detail_label_get_preferred_height;
291+
292+ g_type_class_add_private (klass, sizeof (IdoDetailLabelPrivate));
293+
294+ properties[PROP_TEXT] = g_param_spec_string ("text",
295+ "Text",
296+ "The text of the label",
297+ NULL,
298+ G_PARAM_READWRITE |
299+ G_PARAM_STATIC_STRINGS);
300+
301+ g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
302+}
303+
304+static void
305+ido_detail_label_init (IdoDetailLabel *self)
306+{
307+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
308+ IDO_TYPE_DETAIL_LABEL,
309+ IdoDetailLabelPrivate);
310+
311+ gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
312+}
313+
314+GtkWidget *
315+ido_detail_label_new (const gchar *label)
316+{
317+ return g_object_new (IDO_TYPE_DETAIL_LABEL,
318+ "text", label,
319+ NULL);
320+}
321+
322+const gchar *
323+ido_detail_label_get_text (IdoDetailLabel *label)
324+{
325+ g_return_val_if_fail (IDO_IS_DETAIL_LABEL (label), NULL);
326+ return label->priv->text;
327+}
328+
329+/* collapse_whitespace:
330+ * @str: the source string
331+ *
332+ * Collapses all occurences of consecutive whitespace charactes in @str
333+ * into a single space.
334+ *
335+ * Returns: (transfer full): a newly-allocated string
336+ */
337+static gchar *
338+collapse_whitespace (const gchar *str)
339+{
340+ GString *result;
341+ gboolean in_space = FALSE;
342+
343+ if (str == NULL)
344+ return NULL;
345+
346+ result = g_string_new ("");
347+
348+ while (*str)
349+ {
350+ gunichar c = g_utf8_get_char_validated (str, -1);
351+
352+ if (c < 0)
353+ break;
354+
355+ if (!g_unichar_isspace (c))
356+ {
357+ g_string_append_unichar (result, c);
358+ in_space = FALSE;
359+ }
360+ else if (!in_space)
361+ {
362+ g_string_append_c (result, ' ');
363+ in_space = TRUE;
364+ }
365+
366+ str = g_utf8_next_char (str);
367+ }
368+
369+ return g_string_free (result, FALSE);
370+}
371+
372+static void
373+ido_detail_label_set_text_impl (IdoDetailLabel *label,
374+ const gchar *text,
375+ gboolean draw_lozenge)
376+{
377+ IdoDetailLabelPrivate * priv = label->priv;
378+
379+ g_clear_object (&priv->layout);
380+ g_free (priv->text);
381+
382+ priv->text = g_strdup (text);
383+ priv->draw_lozenge = draw_lozenge;
384+
385+ g_object_notify_by_pspec (G_OBJECT (label), properties[PROP_TEXT]);
386+ gtk_widget_queue_resize (GTK_WIDGET (label));
387+}
388+
389+void
390+ido_detail_label_set_text (IdoDetailLabel *label,
391+ const gchar *text)
392+{
393+ gchar *str;
394+
395+ g_return_if_fail (IDO_IS_DETAIL_LABEL (label));
396+
397+ str = collapse_whitespace (text);
398+ ido_detail_label_set_text_impl (label, str, FALSE);
399+ g_free (str);
400+}
401+
402+void
403+ido_detail_label_set_count (IdoDetailLabel *label,
404+ gint count)
405+{
406+ gchar *text;
407+
408+ g_return_if_fail (IDO_IS_DETAIL_LABEL (label));
409+
410+ text = g_strdup_printf ("%d", count);
411+ ido_detail_label_set_text_impl (label, text, TRUE);
412+ g_free (text);
413+}
414
415=== added file 'src/ido-detail-label.h'
416--- src/ido-detail-label.h 1970-01-01 00:00:00 +0000
417+++ src/ido-detail-label.h 2012-09-04 17:24:18 +0000
418@@ -0,0 +1,59 @@
419+/*
420+ * Copyright 2012 Canonical Ltd.
421+ *
422+ * This program is free software: you can redistribute it and/or modify it
423+ * under the terms of the GNU General Public License version 3, as published
424+ * by the Free Software Foundation.
425+ *
426+ * This program is distributed in the hope that it will be useful, but
427+ * WITHOUT ANY WARRANTY; without even the implied warranties of
428+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
429+ * PURPOSE. See the GNU General Public License for more details.
430+ *
431+ * You should have received a copy of the GNU General Public License along
432+ * with this program. If not, see <http://www.gnu.org/licenses/>.
433+ *
434+ * Authors:
435+ * Lars Uebernickel <lars.uebernickel@canonical.com>
436+ */
437+
438+#ifndef __IDO_DETAIL_LABEL_H__
439+#define __IDO_DETAIL_LABEL_H__
440+
441+#include <gtk/gtk.h>
442+
443+#define IDO_TYPE_DETAIL_LABEL (ido_detail_label_get_type())
444+#define IDO_DETAIL_LABEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IDO_TYPE_DETAIL_LABEL, IdoDetailLabel))
445+#define IDO_DETAIL_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IDO_TYPE_DETAIL_LABEL, IdoDetailLabelClass))
446+#define IDO_IS_DETAIL_LABEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IDO_TYPE_DETAIL_LABEL))
447+#define IDO_IS_DETAIL_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IDO_TYPE_DETAIL_LABEL))
448+#define IDO_DETAIL_LABEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IDO_TYPE_DETAIL_LABEL, IdoDetailLabelClass))
449+
450+typedef struct _IdoDetailLabel IdoDetailLabel;
451+typedef struct _IdoDetailLabelClass IdoDetailLabelClass;
452+typedef struct _IdoDetailLabelPrivate IdoDetailLabelPrivate;
453+
454+struct _IdoDetailLabel
455+{
456+ GtkWidget parent;
457+ IdoDetailLabelPrivate *priv;
458+};
459+
460+struct _IdoDetailLabelClass
461+{
462+ GtkWidgetClass parent_class;
463+};
464+
465+GType ido_detail_label_get_type (void) G_GNUC_CONST;
466+
467+GtkWidget * ido_detail_label_new (const gchar *str);
468+
469+const gchar * ido_detail_label_get_text (IdoDetailLabel *label);
470+
471+void ido_detail_label_set_text (IdoDetailLabel *label,
472+ const gchar *text);
473+
474+void ido_detail_label_set_count (IdoDetailLabel *label,
475+ gint count);
476+
477+#endif
478
479=== modified file 'src/im-source-menu-item.c'
480--- src/im-source-menu-item.c 2012-08-27 14:42:05 +0000
481+++ src/im-source-menu-item.c 2012-09-04 17:24:18 +0000
482@@ -20,6 +20,7 @@
483 #include "im-source-menu-item.h"
484
485 #include <libintl.h>
486+#include "ido-detail-label.h"
487
488 struct _ImSourceMenuItemPrivate
489 {
490@@ -59,11 +60,13 @@
491 gtk_widget_set_margin_left (priv->icon, icon_width + 6);
492
493 priv->label = g_object_ref (gtk_label_new (""));
494+ gtk_label_set_max_width_chars (GTK_LABEL (priv->label), 40);
495+ gtk_label_set_ellipsize (GTK_LABEL (priv->label), PANGO_ELLIPSIZE_END);
496+ gtk_misc_set_alignment (GTK_MISC (priv->label), 0.0, 0.5);
497
498- priv->detail = g_object_ref (gtk_label_new (""));
499+ priv->detail = g_object_ref (ido_detail_label_new (""));
500 gtk_widget_set_halign (priv->detail, GTK_ALIGN_END);
501 gtk_widget_set_hexpand (priv->detail, TRUE);
502- gtk_misc_set_alignment (GTK_MISC (priv->label), 1.0, 0.5);
503 gtk_style_context_add_class (gtk_widget_get_style_context (priv->detail), "accelerator");
504
505 grid = gtk_grid_new ();
506@@ -77,49 +80,6 @@
507 G_OBJECT_CLASS (im_source_menu_item_parent_class)->constructed (object);
508 }
509
510-/* collapse_whitespace:
511- * @str: the source string
512- *
513- * Collapses all occurences of consecutive whitespace charactes in @str
514- * into a single space.
515- *
516- * Returns: (transfer full): a newly-allocated string
517- */
518-static gchar *
519-collapse_whitespace (const gchar *str)
520-{
521- GString *result;
522- gboolean in_space = FALSE;
523-
524- if (str == NULL)
525- return NULL;
526-
527- result = g_string_new ("");
528-
529- while (*str)
530- {
531- gunichar c = g_utf8_get_char_validated (str, -1);
532-
533- if (c < 0)
534- break;
535-
536- if (!g_unichar_isspace (c))
537- {
538- g_string_append_unichar (result, c);
539- in_space = FALSE;
540- }
541- else if (!in_space)
542- {
543- g_string_append_c (result, ' ');
544- in_space = TRUE;
545- }
546-
547- str = g_utf8_next_char (str);
548- }
549-
550- return g_string_free (result, FALSE);
551-}
552-
553 static gchar *
554 im_source_menu_item_time_span_string (gint64 timestamp)
555 {
556@@ -146,16 +106,28 @@
557 return str;
558 }
559
560+static void
561+im_source_menu_item_set_detail_time (ImSourceMenuItem *self,
562+ gint64 time)
563+{
564+ ImSourceMenuItemPrivate *priv = self->priv;
565+ gchar *str;
566+
567+ priv->time = time;
568+
569+ str = im_source_menu_item_time_span_string (priv->time);
570+ ido_detail_label_set_text (IDO_DETAIL_LABEL (priv->detail), str);
571+
572+ g_free (str);
573+}
574+
575 static gboolean
576 im_source_menu_item_update_time (gpointer data)
577 {
578 ImSourceMenuItem *self = data;
579- gchar *str;
580-
581- str = im_source_menu_item_time_span_string (self->priv->time);
582- gtk_label_set_text (GTK_LABEL (self->priv->detail), str);
583-
584- g_free (str);
585+
586+ im_source_menu_item_set_detail_time (self, self->priv->time);
587+
588 return TRUE;
589 }
590
591@@ -167,7 +139,6 @@
592 guint32 count;
593 gint64 time;
594 const gchar *str;
595- gchar *detail;
596
597 if (priv->timer_id != 0)
598 {
599@@ -180,21 +151,15 @@
600 g_variant_get (state, "(ux&sb)", &count, &time, &str, NULL);
601
602 if (count != 0)
603- detail = g_strdup_printf ("%d", count);
604+ ido_detail_label_set_count (IDO_DETAIL_LABEL (priv->detail), count);
605 else if (time != 0)
606 {
607- priv->time = time;
608- detail = im_source_menu_item_time_span_string (time);
609+ im_source_menu_item_set_detail_time (self, time);
610 priv->timer_id = g_timeout_add_seconds (59, im_source_menu_item_update_time, self);
611 }
612 else if (str != NULL && *str)
613- detail = collapse_whitespace (str);
614- else
615- detail = NULL;
616-
617- gtk_label_set_text (GTK_LABEL (priv->detail), detail ? detail : "");
618-
619- g_free (detail);
620+ ido_detail_label_set_text (IDO_DETAIL_LABEL (priv->detail), str);
621+
622 return TRUE;
623 }
624

Subscribers

People subscribed via source and target branches