Merge lp:~indicator-applet-developers/ido/add-messaging-menu into lp:ido/13.10

Proposed by Ted Gould
Status: Merged
Approved by: Ted Gould
Approved revision: 148
Merged at revision: 145
Proposed branch: lp:~indicator-applet-developers/ido/add-messaging-menu
Merge into: lp:ido/13.10
Diff against target: 1163 lines (+1044/-2)
11 files modified
debian/libido3-0.1-0.symbols (+10/-0)
src/Makefile.am (+8/-2)
src/idoactionhelper.c (+24/-0)
src/idoactionhelper.h (+3/-0)
src/idoapplicationmenuitem.c (+195/-0)
src/idoapplicationmenuitem.h (+36/-0)
src/idodetaillabel.c (+401/-0)
src/idodetaillabel.h (+59/-0)
src/idomenuitemfactory.c (+8/-0)
src/idosourcemenuitem.c (+264/-0)
src/idosourcemenuitem.h (+36/-0)
To merge this branch: bzr merge lp:~indicator-applet-developers/ido/add-messaging-menu
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Ted Gould (community) Approve
Review via email: mp+179962@code.launchpad.net

Commit message

Add widgets for messaging menu

Description of the change

Adds the widgets needed for messaging menu integration. Might be broken, getting a diff and Jenkins comment right now while doing further testing.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
147. By Ted Gould

Adding new symbols

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:147
http://jenkins.qa.ubuntu.com/job/ido-ci/33/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ido-saucy-amd64-ci/32
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ido-saucy-armhf-ci/15

Click here to trigger a rebuild:
http://s-jenkins:8080/job/ido-ci/33/rebuild

review: Approve (continuous-integration)
148. By Ted Gould

Library functions taking GVariant params need to ref_sink() and unref() always. (reason #24 to not like GVariant)

Revision history for this message
Ted Gould (ted) wrote :

Fixed a couple of little things. But this seems sane.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:148
http://jenkins.qa.ubuntu.com/job/ido-ci/34/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ido-saucy-amd64-ci/33
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ido-saucy-armhf-ci/16

Click here to trigger a rebuild:
http://s-jenkins:8080/job/ido-ci/34/rebuild

review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/libido3-0.1-0.symbols'
--- debian/libido3-0.1-0.symbols 2013-07-31 02:02:53 +0000
+++ debian/libido3-0.1-0.symbols 2013-08-13 20:56:02 +0000
@@ -1,11 +1,14 @@
1libido3-0.1.so.0 libido3-0.1-0 #MINVER#1libido3-0.1.so.0 libido3-0.1-0 #MINVER#
2 ido_action_helper_activate@Base 13.10.0daily13.06.192 ido_action_helper_activate@Base 13.10.0daily13.06.19
3 ido_action_helper_activate_with_parameter@Base 0replaceme
3 ido_action_helper_change_action_state@Base 13.10.0daily13.06.194 ido_action_helper_change_action_state@Base 13.10.0daily13.06.19
4 ido_action_helper_get_action_target@Base 13.10.0daily13.06.195 ido_action_helper_get_action_target@Base 13.10.0daily13.06.19
5 ido_action_helper_get_type@Base 13.10.0daily13.06.196 ido_action_helper_get_type@Base 13.10.0daily13.06.19
6 ido_action_helper_get_widget@Base 13.10.0daily13.06.197 ido_action_helper_get_widget@Base 13.10.0daily13.06.19
7 ido_action_helper_new@Base 13.10.0daily13.06.198 ido_action_helper_new@Base 13.10.0daily13.06.19
8 ido_alarm_menu_item_new_from_model@Base 13.10.0+13.10.201307319 ido_alarm_menu_item_new_from_model@Base 13.10.0+13.10.20130731
10 ido_application_menu_item_get_type@Base 0replaceme
11 ido_application_menu_item_new_from_model@Base 0replaceme
9 ido_appointment_menu_item_new_from_model@Base 13.10.0daily13.06.1912 ido_appointment_menu_item_new_from_model@Base 13.10.0daily13.06.19
10 ido_basic_menu_item_get_type@Base 13.10.0+13.10.2013073113 ido_basic_menu_item_get_type@Base 13.10.0+13.10.20130731
11 ido_basic_menu_item_new@Base 13.10.0+13.10.2013073114 ido_basic_menu_item_new@Base 13.10.0+13.10.20130731
@@ -24,6 +27,11 @@
24 ido_calendar_menu_item_set_date@Base 0.2.227 ido_calendar_menu_item_set_date@Base 0.2.2
25 ido_calendar_menu_item_set_display_options@Base 0.2.128 ido_calendar_menu_item_set_display_options@Base 0.2.1
26 ido_calendar_menu_item_unmark_day@Base 0.2.129 ido_calendar_menu_item_unmark_day@Base 0.2.1
30 ido_detail_label_get_text@Base 0replaceme
31 ido_detail_label_get_type@Base 0replaceme
32 ido_detail_label_new@Base 0replaceme
33 ido_detail_label_set_count@Base 0replaceme
34 ido_detail_label_set_text@Base 0replaceme
27 ido_entry_menu_item_get_entry@Base 0.1.035 ido_entry_menu_item_get_entry@Base 0.1.0
28 ido_entry_menu_item_get_type@Base 0.1.036 ido_entry_menu_item_get_type@Base 0.1.0
29 ido_entry_menu_item_new@Base 0.1.037 ido_entry_menu_item_new@Base 0.1.0
@@ -57,6 +65,8 @@
57 ido_scale_menu_item_set_secondary_label@Base 0.1.965 ido_scale_menu_item_set_secondary_label@Base 0.1.9
58 ido_scale_menu_item_set_style@Base 0.1.966 ido_scale_menu_item_set_style@Base 0.1.9
59 ido_scale_menu_item_style_get_type@Base 0.1.967 ido_scale_menu_item_style_get_type@Base 0.1.9
68 ido_source_menu_item_get_type@Base 0replaceme
69 ido_source_menu_item_new_from_menu_model@Base 0replaceme
60 ido_switch_menu_item_get_content_area@Base 12.10.070 ido_switch_menu_item_get_content_area@Base 12.10.0
61 ido_switch_menu_item_get_type@Base 12.10.071 ido_switch_menu_item_get_type@Base 12.10.0
62 ido_switch_menu_item_new@Base 12.10.072 ido_switch_menu_item_new@Base 12.10.0
6373
=== modified file 'src/Makefile.am'
--- src/Makefile.am 2013-07-25 23:53:48 +0000
+++ src/Makefile.am 2013-08-13 20:56:02 +0000
@@ -27,7 +27,10 @@
27 libido.h \27 libido.h \
28 idoactionhelper.h \28 idoactionhelper.h \
29 idomediaplayermenuitem.h \29 idomediaplayermenuitem.h \
30 idoplaybackmenuitem.h30 idoplaybackmenuitem.h \
31 idoapplicationmenuitem.h \
32 idodetaillabel.h \
33 idosourcemenuitem.h
3134
32EXTRA_DIST = \35EXTRA_DIST = \
33 ido.list \36 ido.list \
@@ -86,7 +89,10 @@
86 idoappointmentmenuitem.c \89 idoappointmentmenuitem.c \
87 idobasicmenuitem.c \90 idobasicmenuitem.c \
88 idotimestampmenuitem.c \91 idotimestampmenuitem.c \
89 idolocationmenuitem.c92 idolocationmenuitem.c \
93 idoapplicationmenuitem.c \
94 idodetaillabel.c \
95 idosourcemenuitem.c
9096
91libido3_0_1_la_SOURCES = $(libido_0_1_la_SOURCES)97libido3_0_1_la_SOURCES = $(libido_0_1_la_SOURCES)
9298
9399
=== modified file 'src/idoactionhelper.c'
--- src/idoactionhelper.c 2013-05-31 22:50:09 +0000
+++ src/idoactionhelper.c 2013-08-13 20:56:02 +0000
@@ -403,6 +403,30 @@
403}403}
404404
405/**405/**
406 * ido_action_helper_activate_with_parameter:
407 * @helper: an #IdoActionHelper
408 * @parameter: a #GVariant containing the parameter
409 *
410 * Activates the action that is associated with this helper passing
411 * @parameter instead the "target" associated with the menu item this
412 * helper is bound to.
413 */
414void
415ido_action_helper_activate_with_parameter (IdoActionHelper *helper,
416 GVariant *parameter)
417{
418 g_return_if_fail (IDO_IS_ACTION_HELPER (helper));
419 g_return_if_fail (parameter != NULL);
420
421 g_variant_ref_sink (parameter);
422
423 if (helper->actions && helper->action_name)
424 g_action_group_activate_action (helper->actions, helper->action_name, parameter);
425
426 g_variant_unref (parameter);
427}
428
429/**
406 * ido_action_helper_change_action_state:430 * ido_action_helper_change_action_state:
407 * @helper: an #IdoActionHelper431 * @helper: an #IdoActionHelper
408 * @state: the proposed new state of the action432 * @state: the proposed new state of the action
409433
=== modified file 'src/idoactionhelper.h'
--- src/idoactionhelper.h 2013-05-31 22:50:09 +0000
+++ src/idoactionhelper.h 2013-08-13 20:56:02 +0000
@@ -41,6 +41,9 @@
4141
42void ido_action_helper_activate (IdoActionHelper *helper);42void ido_action_helper_activate (IdoActionHelper *helper);
4343
44void ido_action_helper_activate_with_parameter (IdoActionHelper *helper,
45 GVariant *parameter);
46
44void ido_action_helper_change_action_state (IdoActionHelper *helper,47void ido_action_helper_change_action_state (IdoActionHelper *helper,
45 GVariant *state);48 GVariant *state);
4649
4750
=== added file 'src/idoapplicationmenuitem.c'
--- src/idoapplicationmenuitem.c 1970-01-01 00:00:00 +0000
+++ src/idoapplicationmenuitem.c 2013-08-13 20:56:02 +0000
@@ -0,0 +1,195 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Lars Uebernickel <lars.uebernickel@canonical.com>
18 */
19
20#include "idoapplicationmenuitem.h"
21#include "idoactionhelper.h"
22
23typedef GtkMenuItemClass IdoApplicationMenuItemClass;
24
25struct _IdoApplicationMenuItem
26{
27 GtkMenuItem parent;
28
29 gboolean is_running;
30
31 GtkWidget *icon;
32 GtkWidget *label;
33};
34
35G_DEFINE_TYPE (IdoApplicationMenuItem, ido_application_menu_item, GTK_TYPE_MENU_ITEM);
36
37static void
38ido_application_menu_item_constructed (GObject *object)
39{
40 IdoApplicationMenuItem *item = IDO_APPLICATION_MENU_ITEM (object);
41 GtkWidget *grid;
42
43 item->icon = g_object_ref (gtk_image_new ());
44 gtk_widget_set_margin_right (item->icon, 6);
45
46 item->label = g_object_ref (gtk_label_new (""));
47
48 grid = gtk_grid_new ();
49 gtk_grid_attach (GTK_GRID (grid), item->icon, 0, 0, 1, 1);
50 gtk_grid_attach (GTK_GRID (grid), item->label, 1, 0, 1, 1);
51
52 gtk_container_add (GTK_CONTAINER (object), grid);
53 gtk_widget_show_all (grid);
54
55 G_OBJECT_CLASS (ido_application_menu_item_parent_class)->constructed (object);
56}
57
58static void
59ido_application_menu_item_dispose (GObject *object)
60{
61 IdoApplicationMenuItem *self = IDO_APPLICATION_MENU_ITEM (object);
62
63 g_clear_object (&self->icon);
64 g_clear_object (&self->label);
65
66 G_OBJECT_CLASS (ido_application_menu_item_parent_class)->dispose (object);
67}
68
69static gboolean
70ido_application_menu_item_draw (GtkWidget *widget,
71 cairo_t *cr)
72{
73 IdoApplicationMenuItem *item = IDO_APPLICATION_MENU_ITEM (widget);
74
75 GTK_WIDGET_CLASS (ido_application_menu_item_parent_class)->draw (widget, cr);
76
77 if (item->is_running)
78 {
79 const int arrow_width = 5;
80 const double half_arrow_height = 4.5;
81 GtkAllocation alloc;
82 GdkRGBA color;
83 double center;
84
85 gtk_widget_get_allocation (widget, &alloc);
86
87 gtk_style_context_get_color (gtk_widget_get_style_context (widget),
88 gtk_widget_get_state_flags (widget),
89 &color);
90 gdk_cairo_set_source_rgba (cr, &color);
91
92 center = alloc.height / 2 + 0.5;
93
94 cairo_move_to (cr, 0, center - half_arrow_height);
95 cairo_line_to (cr, 0, center + half_arrow_height);
96 cairo_line_to (cr, arrow_width, center);
97 cairo_close_path (cr);
98
99 cairo_fill (cr);
100 }
101
102 return FALSE;
103}
104
105void
106ido_application_menu_item_class_init (IdoApplicationMenuItemClass *klass)
107{
108 GObjectClass *object_class = G_OBJECT_CLASS (klass);
109 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
110
111 object_class->constructed = ido_application_menu_item_constructed;
112 object_class->dispose = ido_application_menu_item_dispose;
113
114 widget_class->draw = ido_application_menu_item_draw;
115}
116
117static void
118ido_application_menu_item_init (IdoApplicationMenuItem *self)
119{
120}
121
122static void
123ido_application_menu_item_set_label (IdoApplicationMenuItem *item,
124 const gchar *label)
125{
126 gtk_label_set_label (GTK_LABEL (item->label), label);
127}
128
129static void
130ido_application_menu_item_set_icon (IdoApplicationMenuItem *item,
131 GIcon *icon)
132{
133 gtk_image_set_from_gicon (GTK_IMAGE (item->icon), icon, GTK_ICON_SIZE_MENU);
134}
135
136static void
137ido_application_menu_item_state_changed (IdoActionHelper *helper,
138 GVariant *state,
139 gpointer user_data)
140{
141 IdoApplicationMenuItem *item = user_data;
142
143 item->is_running = g_variant_get_boolean (state);
144 gtk_widget_queue_draw (GTK_WIDGET (item));
145}
146
147GtkMenuItem *
148ido_application_menu_item_new_from_model (GMenuItem *menuitem,
149 GActionGroup *actions)
150{
151 GtkMenuItem *item;
152 gchar *label;
153 GVariant *serialized_icon;
154 gchar *action;
155
156 item = g_object_new (IDO_TYPE_APPLICATION_MENU_ITEM, NULL);
157
158 if (g_menu_item_get_attribute (menuitem, "label", "s", &label))
159 {
160 ido_application_menu_item_set_label (IDO_APPLICATION_MENU_ITEM (item), label);
161 g_free (label);
162 }
163
164 serialized_icon = g_menu_item_get_attribute_value (menuitem, "icon", NULL);
165 if (serialized_icon)
166 {
167 GIcon *icon;
168
169 icon = g_icon_deserialize (serialized_icon);
170 if (icon)
171 {
172 ido_application_menu_item_set_icon (IDO_APPLICATION_MENU_ITEM (item), icon);
173 g_object_unref (icon);
174 }
175
176 g_variant_unref (serialized_icon);
177 }
178
179 if (g_menu_item_get_attribute (menuitem, "action", "s", &action))
180 {
181 IdoActionHelper *helper;
182
183 helper = ido_action_helper_new (GTK_WIDGET (item), actions, action, NULL);
184 g_signal_connect (helper, "action-state-changed",
185 G_CALLBACK (ido_application_menu_item_state_changed), item);
186 g_signal_connect_object (item, "activate",
187 G_CALLBACK (ido_action_helper_activate), helper,
188 G_CONNECT_SWAPPED);
189 g_signal_connect_swapped (item, "destroy", G_CALLBACK (g_object_unref), helper);
190
191 g_free (action);
192 }
193
194 return item;
195}
0196
=== added file 'src/idoapplicationmenuitem.h'
--- src/idoapplicationmenuitem.h 1970-01-01 00:00:00 +0000
+++ src/idoapplicationmenuitem.h 2013-08-13 20:56:02 +0000
@@ -0,0 +1,36 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Lars Uebernickel <lars.uebernickel@canonical.com>
18 */
19
20#ifndef __IDO_APPLICATION_MENU_ITEM_H__
21#define __IDO_APPLICATION_MENU_ITEM_H__
22
23#include <gtk/gtk.h>
24
25#define IDO_TYPE_APPLICATION_MENU_ITEM (ido_application_menu_item_get_type ())
26#define IDO_APPLICATION_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IDO_TYPE_APPLICATION_MENU_ITEM, IdoApplicationMenuItem))
27#define IS_IDO_APPLICATION_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IDO_TYPE_APPLICATION_MENU_ITEM))
28
29typedef struct _IdoApplicationMenuItem IdoApplicationMenuItem;
30
31GType ido_application_menu_item_get_type (void);
32
33GtkMenuItem * ido_application_menu_item_new_from_model (GMenuItem *item,
34 GActionGroup *actions);
35
36#endif
037
=== added file 'src/idodetaillabel.c'
--- src/idodetaillabel.c 1970-01-01 00:00:00 +0000
+++ src/idodetaillabel.c 2013-08-13 20:56:02 +0000
@@ -0,0 +1,401 @@
1/*
2 * Copyright 2012 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Lars Uebernickel <lars.uebernickel@canonical.com>
18 */
19
20#include "idodetaillabel.h"
21
22#include <math.h>
23
24G_DEFINE_TYPE (IdoDetailLabel, ido_detail_label, GTK_TYPE_WIDGET)
25
26struct _IdoDetailLabelPrivate
27{
28 gchar *text;
29 PangoLayout *layout;
30 gboolean draw_lozenge;
31};
32
33enum
34{
35 PROP_0,
36 PROP_TEXT,
37 NUM_PROPERTIES
38};
39
40static GParamSpec *properties[NUM_PROPERTIES];
41
42static void
43ido_detail_label_get_property (GObject *object,
44 guint property_id,
45 GValue *value,
46 GParamSpec *pspec)
47{
48 IdoDetailLabel *self = IDO_DETAIL_LABEL (object);
49
50 switch (property_id)
51 {
52 case PROP_TEXT:
53 g_value_set_string (value, self->priv->text);
54 break;
55
56 default:
57 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
58 }
59}
60
61static void
62ido_detail_label_set_property (GObject *object,
63 guint property_id,
64 const GValue *value,
65 GParamSpec *pspec)
66{
67 IdoDetailLabel *self = IDO_DETAIL_LABEL (object);
68
69 switch (property_id)
70 {
71 case PROP_TEXT:
72 ido_detail_label_set_text (self, g_value_get_string (value));
73 break;
74
75 default:
76 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
77 }
78}
79
80
81static void
82ido_detail_label_finalize (GObject *object)
83{
84 IdoDetailLabelPrivate *priv = IDO_DETAIL_LABEL (object)->priv;
85
86 g_free (priv->text);
87
88 G_OBJECT_CLASS (ido_detail_label_parent_class)->finalize (object);
89}
90
91static void
92ido_detail_label_dispose (GObject *object)
93{
94 IdoDetailLabelPrivate *priv = IDO_DETAIL_LABEL (object)->priv;
95
96 g_clear_object (&priv->layout);
97
98 G_OBJECT_CLASS (ido_detail_label_parent_class)->dispose (object);
99}
100
101static void
102ido_detail_label_ensure_layout (IdoDetailLabel *label)
103{
104 IdoDetailLabelPrivate *priv = label->priv;
105
106 if (priv->layout == NULL)
107 {
108 priv->layout = gtk_widget_create_pango_layout (GTK_WIDGET (label), priv->text);
109 pango_layout_set_alignment (priv->layout, PANGO_ALIGN_CENTER);
110 pango_layout_set_ellipsize (priv->layout, PANGO_ELLIPSIZE_END);
111 pango_layout_set_height (priv->layout, -1);
112
113 // TODO update layout on "style-updated" and "direction-changed"
114 }
115}
116
117static void
118cairo_lozenge (cairo_t *cr,
119 double x,
120 double y,
121 double w,
122 double h,
123 double radius)
124{
125 double x1 = x + w - radius;
126 double x2 = x + radius;
127 double y1 = y + radius;
128 double y2 = y + h - radius;
129
130 cairo_move_to (cr, x + radius, y);
131 cairo_arc (cr, x1, y1, radius, G_PI * 1.5, G_PI * 2);
132 cairo_arc (cr, x1, y2, radius, 0, G_PI * 0.5);
133 cairo_arc (cr, x2, y2, radius, G_PI * 0.5, G_PI);
134 cairo_arc (cr, x2, y1, radius, G_PI, G_PI * 1.5);
135}
136
137static PangoFontMetrics *
138gtk_widget_get_font_metrics (GtkWidget *widget,
139 PangoContext *context)
140{
141 PangoFontDescription *font;
142 PangoFontMetrics *metrics;
143
144 gtk_style_context_get (gtk_widget_get_style_context (widget),
145 gtk_widget_get_state_flags (widget),
146 "font", &font, NULL);
147
148 metrics = pango_context_get_metrics (context,
149 font,
150 pango_context_get_language (context));
151
152 pango_font_description_free (font);
153 return metrics;
154}
155
156static gint
157ido_detail_label_get_minimum_text_width (IdoDetailLabel *label)
158{
159 IdoDetailLabelPrivate *priv = label->priv;
160 PangoContext *context;
161 PangoFontMetrics *metrics;
162 gint char_width;
163 gint w;
164
165 context = pango_layout_get_context (priv->layout);
166 metrics = gtk_widget_get_font_metrics (GTK_WIDGET (label), context);
167 char_width = pango_font_metrics_get_approximate_digit_width (metrics);
168
169 w = 2 * char_width / PANGO_SCALE;
170 pango_font_metrics_unref (metrics);
171 return w;
172}
173
174static gboolean
175ido_detail_label_draw (GtkWidget *widget,
176 cairo_t *cr)
177{
178 IdoDetailLabel *label = IDO_DETAIL_LABEL (widget);
179 IdoDetailLabelPrivate *priv = IDO_DETAIL_LABEL (widget)->priv;
180 PangoRectangle extents;
181 GtkAllocation allocation;
182 double x, w, h, radius;
183 GdkRGBA color;
184
185 if (!priv->text || !*priv->text)
186 return TRUE;
187
188 gtk_widget_get_allocation (widget, &allocation);
189
190 ido_detail_label_ensure_layout (IDO_DETAIL_LABEL (widget));
191
192 pango_layout_get_extents (priv->layout, NULL, &extents);
193 pango_extents_to_pixels (&extents, NULL);
194
195 h = MIN (allocation.height, extents.height);
196 radius = floor (h / 2.0);
197 w = MAX (ido_detail_label_get_minimum_text_width (label), extents.width) + 2.0 * radius;
198 x = allocation.width - w;
199
200 pango_layout_set_width (priv->layout, (allocation.width - 2 * radius) * PANGO_SCALE);
201 pango_layout_get_extents (priv->layout, NULL, &extents);
202 pango_extents_to_pixels (&extents, NULL);
203
204 gtk_style_context_get_color (gtk_widget_get_style_context (widget),
205 gtk_widget_get_state_flags (widget),
206 &color);
207 gdk_cairo_set_source_rgba (cr, &color);
208
209 cairo_set_line_width (cr, 1.0);
210 cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
211
212 if (priv->draw_lozenge)
213 cairo_lozenge (cr, x, 0.0, w, h, radius);
214
215 cairo_move_to (cr, x + radius, (allocation.height - extents.height) / 2.0);
216 pango_cairo_layout_path (cr, priv->layout);
217 cairo_fill (cr);
218
219 return TRUE;
220}
221
222static void
223ido_detail_label_get_preferred_width (GtkWidget *widget,
224 gint *minimum,
225 gint *natural)
226{
227 IdoDetailLabelPrivate *priv = IDO_DETAIL_LABEL (widget)->priv;
228 PangoRectangle extents;
229 double radius;
230
231 ido_detail_label_ensure_layout (IDO_DETAIL_LABEL (widget));
232
233 pango_layout_get_extents (priv->layout, NULL, &extents);
234 pango_extents_to_pixels (&extents, NULL);
235
236 radius = floor (extents.height / 2.0);
237
238 *minimum = ido_detail_label_get_minimum_text_width (IDO_DETAIL_LABEL (widget)) + 2.0 * radius;
239 *natural = MAX (*minimum, extents.width + 2.0 * radius);
240}
241
242static void
243ido_detail_label_get_preferred_height (GtkWidget *widget,
244 gint *minimum,
245 gint *natural)
246{
247 IdoDetailLabelPrivate *priv = IDO_DETAIL_LABEL (widget)->priv;
248 PangoContext *context;
249 PangoFontMetrics *metrics;
250 PangoRectangle extents;
251
252 ido_detail_label_ensure_layout (IDO_DETAIL_LABEL (widget));
253
254 pango_layout_get_extents (priv->layout, NULL, &extents);
255 pango_extents_to_pixels (&extents, NULL);
256 context = pango_layout_get_context (priv->layout);
257 metrics = gtk_widget_get_font_metrics (widget, context);
258
259 *minimum = *natural = (pango_font_metrics_get_ascent (metrics) +
260 pango_font_metrics_get_descent (metrics)) / PANGO_SCALE;
261
262 pango_font_metrics_unref (metrics);
263}
264
265static void
266ido_detail_label_class_init (IdoDetailLabelClass *klass)
267{
268 GObjectClass *object_class = G_OBJECT_CLASS (klass);
269 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
270
271 object_class->get_property = ido_detail_label_get_property;
272 object_class->set_property = ido_detail_label_set_property;
273 object_class->finalize = ido_detail_label_finalize;
274 object_class->dispose = ido_detail_label_dispose;
275
276 widget_class->draw = ido_detail_label_draw;
277 widget_class->get_preferred_width = ido_detail_label_get_preferred_width;
278 widget_class->get_preferred_height = ido_detail_label_get_preferred_height;
279
280 g_type_class_add_private (klass, sizeof (IdoDetailLabelPrivate));
281
282 properties[PROP_TEXT] = g_param_spec_string ("text",
283 "Text",
284 "The text of the label",
285 NULL,
286 G_PARAM_READWRITE |
287 G_PARAM_STATIC_STRINGS);
288
289 g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
290}
291
292static void
293ido_detail_label_init (IdoDetailLabel *self)
294{
295 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
296 IDO_TYPE_DETAIL_LABEL,
297 IdoDetailLabelPrivate);
298
299 gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
300}
301
302GtkWidget *
303ido_detail_label_new (const gchar *label)
304{
305 return g_object_new (IDO_TYPE_DETAIL_LABEL,
306 "text", label,
307 NULL);
308}
309
310const gchar *
311ido_detail_label_get_text (IdoDetailLabel *label)
312{
313 g_return_val_if_fail (IDO_IS_DETAIL_LABEL (label), NULL);
314 return label->priv->text;
315}
316
317/* collapse_whitespace:
318 * @str: the source string
319 *
320 * Collapses all occurences of consecutive whitespace charactes in @str
321 * into a single space.
322 *
323 * Returns: (transfer full): a newly-allocated string
324 */
325static gchar *
326collapse_whitespace (const gchar *str)
327{
328 GString *result;
329 gboolean in_space = FALSE;
330
331 if (str == NULL)
332 return NULL;
333
334 result = g_string_new ("");
335
336 while (*str)
337 {
338 gunichar c = g_utf8_get_char_validated (str, -1);
339
340 if (c == (gunichar) -1)
341 break;
342
343 if (!g_unichar_isspace (c))
344 {
345 g_string_append_unichar (result, c);
346 in_space = FALSE;
347 }
348 else if (!in_space)
349 {
350 g_string_append_c (result, ' ');
351 in_space = TRUE;
352 }
353
354 str = g_utf8_next_char (str);
355 }
356
357 return g_string_free (result, FALSE);
358}
359
360static void
361ido_detail_label_set_text_impl (IdoDetailLabel *label,
362 const gchar *text,
363 gboolean draw_lozenge)
364{
365 IdoDetailLabelPrivate * priv = label->priv;
366
367 g_clear_object (&priv->layout);
368 g_free (priv->text);
369
370 priv->text = g_strdup (text);
371 priv->draw_lozenge = draw_lozenge;
372
373 g_object_notify_by_pspec (G_OBJECT (label), properties[PROP_TEXT]);
374 gtk_widget_queue_resize (GTK_WIDGET (label));
375}
376
377void
378ido_detail_label_set_text (IdoDetailLabel *label,
379 const gchar *text)
380{
381 gchar *str;
382
383 g_return_if_fail (IDO_IS_DETAIL_LABEL (label));
384
385 str = collapse_whitespace (text);
386 ido_detail_label_set_text_impl (label, str, FALSE);
387 g_free (str);
388}
389
390void
391ido_detail_label_set_count (IdoDetailLabel *label,
392 gint count)
393{
394 gchar *text;
395
396 g_return_if_fail (IDO_IS_DETAIL_LABEL (label));
397
398 text = g_strdup_printf ("%d", count);
399 ido_detail_label_set_text_impl (label, text, TRUE);
400 g_free (text);
401}
0402
=== added file 'src/idodetaillabel.h'
--- src/idodetaillabel.h 1970-01-01 00:00:00 +0000
+++ src/idodetaillabel.h 2013-08-13 20:56:02 +0000
@@ -0,0 +1,59 @@
1/*
2 * Copyright 2012 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Lars Uebernickel <lars.uebernickel@canonical.com>
18 */
19
20#ifndef __IDO_DETAIL_LABEL_H__
21#define __IDO_DETAIL_LABEL_H__
22
23#include <gtk/gtk.h>
24
25#define IDO_TYPE_DETAIL_LABEL (ido_detail_label_get_type())
26#define IDO_DETAIL_LABEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IDO_TYPE_DETAIL_LABEL, IdoDetailLabel))
27#define IDO_DETAIL_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IDO_TYPE_DETAIL_LABEL, IdoDetailLabelClass))
28#define IDO_IS_DETAIL_LABEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IDO_TYPE_DETAIL_LABEL))
29#define IDO_IS_DETAIL_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IDO_TYPE_DETAIL_LABEL))
30#define IDO_DETAIL_LABEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IDO_TYPE_DETAIL_LABEL, IdoDetailLabelClass))
31
32typedef struct _IdoDetailLabel IdoDetailLabel;
33typedef struct _IdoDetailLabelClass IdoDetailLabelClass;
34typedef struct _IdoDetailLabelPrivate IdoDetailLabelPrivate;
35
36struct _IdoDetailLabel
37{
38 GtkWidget parent;
39 IdoDetailLabelPrivate *priv;
40};
41
42struct _IdoDetailLabelClass
43{
44 GtkWidgetClass parent_class;
45};
46
47GType ido_detail_label_get_type (void) G_GNUC_CONST;
48
49GtkWidget * ido_detail_label_new (const gchar *str);
50
51const gchar * ido_detail_label_get_text (IdoDetailLabel *label);
52
53void ido_detail_label_set_text (IdoDetailLabel *label,
54 const gchar *text);
55
56void ido_detail_label_set_count (IdoDetailLabel *label,
57 gint count);
58
59#endif
060
=== modified file 'src/idomenuitemfactory.c'
--- src/idomenuitemfactory.c 2013-07-25 23:53:48 +0000
+++ src/idomenuitemfactory.c 2013-08-13 20:56:02 +0000
@@ -29,6 +29,8 @@
29#include "idousermenuitem.h"29#include "idousermenuitem.h"
30#include "idomediaplayermenuitem.h"30#include "idomediaplayermenuitem.h"
31#include "idoplaybackmenuitem.h"31#include "idoplaybackmenuitem.h"
32#include "idoapplicationmenuitem.h"
33#include "idosourcemenuitem.h"
3234
33#define IDO_TYPE_MENU_ITEM_FACTORY (ido_menu_item_factory_get_type ())35#define IDO_TYPE_MENU_ITEM_FACTORY (ido_menu_item_factory_get_type ())
34#define IDO_MENU_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), IDO_TYPE_MENU_ITEM_FACTORY, IdoMenuItemFactory))36#define IDO_MENU_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), IDO_TYPE_MENU_ITEM_FACTORY, IdoMenuItemFactory))
@@ -83,6 +85,12 @@
83 else if (g_str_equal (type, "com.canonical.unity.playback-item"))85 else if (g_str_equal (type, "com.canonical.unity.playback-item"))
84 item = ido_playback_menu_item_new_from_model (menuitem, actions);86 item = ido_playback_menu_item_new_from_model (menuitem, actions);
8587
88 else if (g_str_equal (type, "com.canonical.application"))
89 item = ido_application_menu_item_new_from_model (menuitem, actions);
90
91 else if (g_str_equal (type, "com.canonical.indicator.messages.source"))
92 item = ido_source_menu_item_new_from_menu_model (menuitem, actions);
93
86 return item;94 return item;
87}95}
8896
8997
=== added file 'src/idosourcemenuitem.c'
--- src/idosourcemenuitem.c 1970-01-01 00:00:00 +0000
+++ src/idosourcemenuitem.c 2013-08-13 20:56:02 +0000
@@ -0,0 +1,264 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Lars Uebernickel <lars.uebernickel@canonical.com>
18 */
19
20#include "idosourcemenuitem.h"
21
22#include <libintl.h>
23#include "idodetaillabel.h"
24#include "idoactionhelper.h"
25
26typedef GtkMenuItemClass IdoSourceMenuItemClass;
27
28struct _IdoSourceMenuItem
29{
30 GtkMenuItem parent;
31
32 GtkWidget *icon;
33 GtkWidget *label;
34 GtkWidget *detail;
35
36 gint64 time;
37 guint timer_id;
38};
39
40G_DEFINE_TYPE (IdoSourceMenuItem, ido_source_menu_item, GTK_TYPE_MENU_ITEM);
41
42static void
43ido_source_menu_item_constructed (GObject *object)
44{
45 IdoSourceMenuItem *item = IDO_SOURCE_MENU_ITEM (object);
46 GtkWidget *grid;
47 gint icon_width;
48
49 gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, NULL);
50
51 item->icon = g_object_ref (gtk_image_new ());
52 gtk_widget_set_margin_left (item->icon, icon_width);
53 gtk_widget_set_margin_right (item->icon, 6);
54
55 item->label = g_object_ref (gtk_label_new (""));
56 gtk_label_set_max_width_chars (GTK_LABEL (item->label), 40);
57 gtk_label_set_ellipsize (GTK_LABEL (item->label), PANGO_ELLIPSIZE_END);
58 gtk_misc_set_alignment (GTK_MISC (item->label), 0.0, 0.5);
59
60 item->detail = g_object_ref (ido_detail_label_new (""));
61 gtk_widget_set_halign (item->detail, GTK_ALIGN_END);
62 gtk_widget_set_hexpand (item->detail, TRUE);
63 gtk_style_context_add_class (gtk_widget_get_style_context (item->detail), "accelerator");
64
65 grid = gtk_grid_new ();
66 gtk_grid_attach (GTK_GRID (grid), item->icon, 0, 0, 1, 1);
67 gtk_grid_attach (GTK_GRID (grid), item->label, 1, 0, 1, 1);
68 gtk_grid_attach (GTK_GRID (grid), item->detail, 2, 0, 1, 1);
69
70 gtk_container_add (GTK_CONTAINER (object), grid);
71 gtk_widget_show_all (grid);
72
73 G_OBJECT_CLASS (ido_source_menu_item_parent_class)->constructed (object);
74}
75
76static gchar *
77ido_source_menu_item_time_span_string (gint64 timestamp)
78{
79 gchar *str;
80 gint64 span;
81 gint hours;
82 gint minutes;
83
84 span = MAX (g_get_real_time () - timestamp, 0) / G_USEC_PER_SEC;
85 hours = span / 3600;
86 minutes = (span / 60) % 60;
87
88 if (hours == 0)
89 {
90 /* TRANSLATORS: number of minutes that have passed */
91 str = g_strdup_printf (ngettext ("%d min", "%d min", minutes), minutes);
92 }
93 else
94 {
95 /* TRANSLATORS: number of hours that have passed */
96 str = g_strdup_printf (ngettext ("%d h", "%d h", hours), hours);
97 }
98
99 return str;
100}
101
102static void
103ido_source_menu_item_set_detail_time (IdoSourceMenuItem *self,
104 gint64 time)
105{
106 gchar *str;
107
108 self->time = time;
109
110 str = ido_source_menu_item_time_span_string (self->time);
111 ido_detail_label_set_text (IDO_DETAIL_LABEL (self->detail), str);
112
113 g_free (str);
114}
115
116static gboolean
117ido_source_menu_item_update_time (gpointer data)
118{
119 IdoSourceMenuItem *self = data;
120
121 ido_source_menu_item_set_detail_time (self, self->time);
122
123 return TRUE;
124}
125
126static void
127ido_source_menu_item_dispose (GObject *object)
128{
129 IdoSourceMenuItem *self = IDO_SOURCE_MENU_ITEM (object);
130
131 if (self->timer_id != 0)
132 {
133 g_source_remove (self->timer_id);
134 self->timer_id = 0;
135 }
136
137 g_clear_object (&self->icon);
138 g_clear_object (&self->label);
139 g_clear_object (&self->detail);
140
141 G_OBJECT_CLASS (ido_source_menu_item_parent_class)->dispose (object);
142}
143
144static void
145ido_source_menu_item_class_init (IdoSourceMenuItemClass *klass)
146{
147 GObjectClass *object_class = G_OBJECT_CLASS (klass);
148
149 object_class->constructed = ido_source_menu_item_constructed;
150 object_class->dispose = ido_source_menu_item_dispose;
151}
152
153static void
154ido_source_menu_item_init (IdoSourceMenuItem *self)
155{
156}
157
158static void
159ido_source_menu_item_set_label (IdoSourceMenuItem *item,
160 const gchar *label)
161{
162 gtk_label_set_label (GTK_LABEL (item->label), label ? label : "");
163}
164
165static void
166ido_source_menu_item_set_icon (IdoSourceMenuItem *item,
167 GIcon *icon)
168{
169 if (icon)
170 gtk_image_set_from_gicon (GTK_IMAGE (item->icon), icon, GTK_ICON_SIZE_MENU);
171 else
172 gtk_image_clear (GTK_IMAGE (item->icon));
173}
174
175
176static void
177ido_source_menu_item_activate (GtkMenuItem *item,
178 gpointer user_data)
179{
180 IdoActionHelper *helper = user_data;
181
182 /* The parameter signifies whether this source was activated (TRUE) or
183 * dismissed (FALSE). Since there's no UI to dismiss a gtkmenuitem,
184 * this always passes TRUE. */
185 ido_action_helper_activate_with_parameter (helper, g_variant_new_boolean (TRUE));
186}
187
188static void
189ido_source_menu_item_state_changed (IdoActionHelper *helper,
190 GVariant *state,
191 gpointer user_data)
192{
193 IdoSourceMenuItem *item = user_data;
194 guint32 count;
195 gint64 time;
196 const gchar *str;
197
198 if (item->timer_id != 0)
199 {
200 g_source_remove (item->timer_id);
201 item->timer_id = 0;
202 }
203
204 g_return_val_if_fail (g_variant_is_of_type (state, G_VARIANT_TYPE ("(uxsb)")), FALSE);
205
206 g_variant_get (state, "(ux&sb)", &count, &time, &str, NULL);
207
208 if (count != 0)
209 ido_detail_label_set_count (IDO_DETAIL_LABEL (item->detail), count);
210 else if (time != 0)
211 {
212 ido_source_menu_item_set_detail_time (item, time);
213 item->timer_id = g_timeout_add_seconds (59, ido_source_menu_item_update_time, item);
214 }
215 else if (str != NULL && *str)
216 ido_detail_label_set_text (IDO_DETAIL_LABEL (item->detail), str);
217}
218
219GtkMenuItem *
220ido_source_menu_item_new_from_menu_model (GMenuItem *menuitem,
221 GActionGroup *actions)
222{
223 GtkMenuItem *item;
224 GVariant *serialized_icon;
225 GIcon *icon = NULL;
226 gchar *label;
227 gchar *action = NULL;
228
229 item = g_object_new (IDO_TYPE_SOURCE_MENU_ITEM, NULL);
230
231 if (g_menu_item_get_attribute (menuitem, "label", "s", &label))
232 {
233 ido_source_menu_item_set_label (IDO_SOURCE_MENU_ITEM (item), label);
234 g_free (label);
235 }
236
237 serialized_icon = g_menu_item_get_attribute_value (menuitem, "icon", NULL);
238 if (serialized_icon)
239 {
240 icon = g_icon_deserialize (serialized_icon);
241 g_variant_unref (serialized_icon);
242 }
243 ido_source_menu_item_set_icon (IDO_SOURCE_MENU_ITEM (item), icon);
244
245 if (g_menu_item_get_attribute (menuitem, "action", "s", &action))
246 {
247 IdoActionHelper *helper;
248
249 helper = ido_action_helper_new (GTK_WIDGET (item), actions, action, NULL);
250 g_signal_connect (helper, "action-state-changed",
251 G_CALLBACK (ido_source_menu_item_state_changed), item);
252 g_signal_connect_object (item, "activate",
253 G_CALLBACK (ido_source_menu_item_activate), helper,
254 0);
255 g_signal_connect_swapped (item, "destroy", G_CALLBACK (g_object_unref), helper);
256
257 g_free (action);
258 }
259
260 if (icon)
261 g_object_unref (icon);
262
263 return item;
264}
0265
=== added file 'src/idosourcemenuitem.h'
--- src/idosourcemenuitem.h 1970-01-01 00:00:00 +0000
+++ src/idosourcemenuitem.h 2013-08-13 20:56:02 +0000
@@ -0,0 +1,36 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Lars Uebernickel <lars.uebernickel@canonical.com>
18 */
19
20#ifndef __IDO_SOURCE_MENU_ITEM_H__
21#define __IDO_SOURCE_MENU_ITEM_H__
22
23#include <gtk/gtk.h>
24
25#define IDO_TYPE_SOURCE_MENU_ITEM (ido_source_menu_item_get_type ())
26#define IDO_SOURCE_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IDO_TYPE_SOURCE_MENU_ITEM, IdoSourceMenuItem))
27#define IDO_IS_SOURCE_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IDO_TYPE_SOURCE_MENU_ITEM))
28
29typedef struct _IdoSourceMenuItem IdoSourceMenuItem;
30
31GType ido_source_menu_item_get_type (void);
32
33GtkMenuItem * ido_source_menu_item_new_from_menu_model (GMenuItem *menuitem,
34 GActionGroup *actions);
35
36#endif

Subscribers

People subscribed via source and target branches

to all changes: