1
2 /*
3 Copyright 2011 Canonical Ltd.
4
5 Authors:
6 Conor Curran <conor.curran@canonical.com>
7
8 This program is free software: you can redistribute it and/or modify it
9 under the terms of the GNU General Public License version 3, as published
10 by the Free Software Foundation.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranties of
14 MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
15 PURPOSE. See the GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <glib/gi18n.h>
26 #include <math.h>
27 #include <glib.h>
28 #include "voip-input-widget.h"
29 #include "common-defs.h"
30 #include <libido/idoscalemenuitem.h>
31
32 typedef struct _VoipInputWidgetPrivate VoipInputWidgetPrivate;
33
34 struct _VoipInputWidgetPrivate
35 {
36 DbusmenuMenuitem* twin_item;
37 GtkWidget* ido_voip_input_slider;
38 gboolean grabbed;
39 };
40
41 #define VOIP_INPUT_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), VOIP_INPUT_WIDGET_TYPE, VoipInputWidgetPrivate))
42
43 /* Prototypes */
44 static void voip_input_widget_class_init (VoipInputWidgetClass *klass);
45 static void voip_input_widget_init (VoipInputWidget *self);
46 static void voip_input_widget_dispose (GObject *object);
47 static void voip_input_widget_finalize (GObject *object);
48 static void voip_input_widget_set_twin_item( VoipInputWidget* self,
49 DbusmenuMenuitem* twin_item);
50 static void voip_input_widget_property_update( DbusmenuMenuitem* item, gchar* property,
51 GVariant* value, gpointer userdata );
52
53 static gboolean voip_input_widget_change_value_cb (GtkRange *range,
54 GtkScrollType scroll,
55 gdouble value,
56 gpointer user_data);
57 static gboolean voip_input_widget_value_changed_cb(GtkRange *range, gpointer user_data);
58 static void voip_input_widget_slider_grabbed(GtkWidget *widget, gpointer user_data);
59 static void voip_input_widget_slider_released(GtkWidget *widget, gpointer user_data);
60 static void voip_input_widget_parent_changed (GtkWidget *widget, gpointer user_data);
61
62 G_DEFINE_TYPE (VoipInputWidget, voip_input_widget, G_TYPE_OBJECT);
63
64
65 static void
voip_input_widget_class_init(VoipInputWidgetClass * klass)66 voip_input_widget_class_init (VoipInputWidgetClass *klass)
67 {
68 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
69
70 g_type_class_add_private (klass, sizeof (VoipInputWidgetPrivate));
71
72 gobject_class->dispose = voip_input_widget_dispose;
73 gobject_class->finalize = voip_input_widget_finalize;
74 }
75
76 static void
voip_input_widget_init(VoipInputWidget * self)77 voip_input_widget_init (VoipInputWidget *self)
78 {
79 VoipInputWidgetPrivate * priv = VOIP_INPUT_WIDGET_GET_PRIVATE(self);
80
81 priv->ido_voip_input_slider = ido_scale_menu_item_new_with_range ("VOLUME", IDO_RANGE_STYLE_DEFAULT, 0, 0, 100, 1);
82 g_object_ref (priv->ido_voip_input_slider);
83 ido_scale_menu_item_set_primary_label (IDO_SCALE_MENU_ITEM(priv->ido_voip_input_slider), "VOIP");
84
85 ido_scale_menu_item_set_style (IDO_SCALE_MENU_ITEM (priv->ido_voip_input_slider), IDO_SCALE_MENU_ITEM_STYLE_IMAGE);
86 g_object_set(priv->ido_voip_input_slider, "reverse-scroll-events", TRUE, NULL);
87
88 g_signal_connect (priv->ido_voip_input_slider,
89 "notify::parent", G_CALLBACK (voip_input_widget_parent_changed),
90 NULL);
91
92 GtkWidget* voip_input_widget = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_voip_input_slider);
93
94 g_signal_connect(voip_input_widget, "change-value", G_CALLBACK(voip_input_widget_change_value_cb), self);
95 g_signal_connect(voip_input_widget, "value-changed", G_CALLBACK(voip_input_widget_value_changed_cb), self);
96 g_signal_connect(priv->ido_voip_input_slider, "slider-grabbed", G_CALLBACK(voip_input_widget_slider_grabbed), self);
97 g_signal_connect(priv->ido_voip_input_slider, "slider-released", G_CALLBACK(voip_input_widget_slider_released), self);
98
99 GtkWidget* primary_image = ido_scale_menu_item_get_primary_image((IdoScaleMenuItem*)priv->ido_voip_input_slider);
100 GIcon * primary_gicon = g_themed_icon_new_with_default_fallbacks("audio-input-microphone-low-zero-panel");
101 gtk_image_set_from_gicon(GTK_IMAGE(primary_image), primary_gicon, GTK_ICON_SIZE_MENU);
102 g_object_unref(primary_gicon);
103
104 GtkWidget* secondary_image = ido_scale_menu_item_get_secondary_image((IdoScaleMenuItem*)priv->ido_voip_input_slider);
105 GIcon * secondary_gicon = g_themed_icon_new_with_default_fallbacks("audio-input-microphone-high-panel");
106 gtk_image_set_from_gicon(GTK_IMAGE(secondary_image), secondary_gicon, GTK_ICON_SIZE_MENU);
107 g_object_unref(secondary_gicon);
108
109 GtkAdjustment *adj = gtk_range_get_adjustment (GTK_RANGE (voip_input_widget));
110 gtk_adjustment_set_step_increment(adj, 4);
111 }
112
113 static void
voip_input_widget_dispose(GObject * object)114 voip_input_widget_dispose (GObject *object)
115 {
116 G_OBJECT_CLASS (voip_input_widget_parent_class)->dispose (object);
117 }
118
119 static void
voip_input_widget_finalize(GObject * object)120 voip_input_widget_finalize (GObject *object)
121 {
122 /// we need to unref what we ref'ed
123 VoipInputWidget *self = VOIP_INPUT_WIDGET (object);
124 VoipInputWidgetPrivate * priv = VOIP_INPUT_WIDGET_GET_PRIVATE(self);
125 g_object_unref (priv->twin_item);
126 g_object_unref (priv->ido_voip_input_slider);
127 G_OBJECT_CLASS (voip_input_widget_parent_class)->finalize (object);
128 }
129
130 static void
voip_input_widget_property_update(DbusmenuMenuitem * item,gchar * property,GVariant * value,gpointer userdata)131 voip_input_widget_property_update (DbusmenuMenuitem* item, gchar* property,
132 GVariant* value, gpointer userdata)
133 {
134 g_return_if_fail (IS_VOIP_INPUT_WIDGET (userdata));
135 VoipInputWidget* mitem = VOIP_INPUT_WIDGET(userdata);
136 VoipInputWidgetPrivate * priv = VOIP_INPUT_WIDGET_GET_PRIVATE(mitem);
137 if(g_ascii_strcasecmp(DBUSMENU_VOIP_INPUT_MENUITEM_LEVEL, property) == 0){
138 g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_DOUBLE));
139 if (priv->grabbed == FALSE){
140 GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_voip_input_slider);
141 GtkRange *range = (GtkRange*)slider;
142 gdouble update = g_variant_get_double (value);
143 //g_debug("volume-widget - update level with value %f", update);
144 gtk_range_set_value(range, update);
145 }
146 }
147 if(g_ascii_strcasecmp(DBUSMENU_VOIP_INPUT_MENUITEM_MUTE, property) == 0){
148 if(priv->grabbed == FALSE){
149 g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_INT32));
150 GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_voip_input_slider);
151 GtkRange *range = (GtkRange*)slider;
152 gint update = g_variant_get_int32 (value);
153 gdouble level;
154 if (update == 1){
155 level = 0;
156 }
157 else{
158 GVariant* variant = dbusmenu_menuitem_property_get_variant (priv->twin_item,
159 DBUSMENU_VOIP_INPUT_MENUITEM_LEVEL);
160 g_return_if_fail (g_variant_is_of_type (variant, G_VARIANT_TYPE_DOUBLE));
161 level = g_variant_get_double (variant);
162 }
163 gtk_range_set_value(range, level);
164
165 g_debug ("voip-item-widget - update mute with value %i", update);
166 }
167 }
168 }
169
170 static void
voip_input_widget_set_twin_item(VoipInputWidget * self,DbusmenuMenuitem * twin_item)171 voip_input_widget_set_twin_item (VoipInputWidget* self,
172 DbusmenuMenuitem* twin_item)
173 {
174 VoipInputWidgetPrivate * priv = VOIP_INPUT_WIDGET_GET_PRIVATE(self);
175 priv->twin_item = twin_item;
176 g_object_ref(priv->twin_item);
177 g_signal_connect(G_OBJECT(twin_item), "property-changed",
178 G_CALLBACK(voip_input_widget_property_update), self);
179 gdouble initial_level = g_variant_get_double (dbusmenu_menuitem_property_get_variant(twin_item,
180 DBUSMENU_VOIP_INPUT_MENUITEM_LEVEL));
181 //g_debug("voip_input_widget_set_twin_item initial level = %f", initial_level);
182 GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_voip_input_slider);
183 GtkRange *range = (GtkRange*)slider;
184 gtk_range_set_value(range, initial_level);
185
186 gint mute = g_variant_get_int32 (dbusmenu_menuitem_property_get_variant (priv->twin_item,
187 DBUSMENU_VOIP_INPUT_MENUITEM_MUTE));
188 if (mute == 1){
189 gtk_range_set_value (range, 0.0);
190 }
191 }
192
193 static gboolean
voip_input_widget_change_value_cb(GtkRange * range,GtkScrollType scroll,gdouble new_value,gpointer user_data)194 voip_input_widget_change_value_cb (GtkRange *range,
195 GtkScrollType scroll,
196 gdouble new_value,
197 gpointer user_data)
198 {
199 g_return_val_if_fail (IS_VOIP_INPUT_WIDGET (user_data), FALSE);
200 VoipInputWidget* mitem = VOIP_INPUT_WIDGET(user_data);
201 voip_input_widget_update(mitem, new_value);
202 return FALSE;
203 }
204
205
206 /**
207 * We only want this callback to catch mouse icon press events which set the
208 * slider to 0 or 100. Ignore all other events including the new Mute behaviour
209 * (slider to go to 0 on mute without setting the level to 0 and return to
210 * previous level on unmute)
211 **/
212 static gboolean
voip_input_widget_value_changed_cb(GtkRange * range,gpointer user_data)213 voip_input_widget_value_changed_cb(GtkRange *range, gpointer user_data)
214 {
215 g_return_val_if_fail (IS_VOIP_INPUT_WIDGET (user_data), FALSE);
216 VoipInputWidget* mitem = VOIP_INPUT_WIDGET(user_data);
217 VoipInputWidgetPrivate * priv = VOIP_INPUT_WIDGET_GET_PRIVATE(mitem);
218 GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_voip_input_slider);
219 gdouble current_value = CLAMP(gtk_range_get_value(GTK_RANGE(slider)), 0, 100);
220
221 gint mute = g_variant_get_int32 (dbusmenu_menuitem_property_get_variant (priv->twin_item,
222 DBUSMENU_VOIP_INPUT_MENUITEM_MUTE));
223 if ((current_value == 0 && mute != 1) || current_value == 100 ){
224 voip_input_widget_update(mitem, current_value);
225 }
226 return FALSE;
227 }
228
229 void
voip_input_widget_update(VoipInputWidget * self,gdouble update)230 voip_input_widget_update(VoipInputWidget* self, gdouble update)
231 {
232 VoipInputWidgetPrivate * priv = VOIP_INPUT_WIDGET_GET_PRIVATE(self);
233 gdouble clamped = CLAMP(update, 0, 100);
234 GVariant* new_volume = g_variant_new_double(clamped);
235 dbusmenu_menuitem_handle_event (priv->twin_item, "update", new_volume, 0);
236 }
237
238 GtkWidget*
voip_input_widget_get_ido_slider(VoipInputWidget * self)239 voip_input_widget_get_ido_slider(VoipInputWidget* self)
240 {
241 VoipInputWidgetPrivate * priv = VOIP_INPUT_WIDGET_GET_PRIVATE(self);
242 return priv->ido_voip_input_slider;
243 }
244
245 static void
voip_input_widget_parent_changed(GtkWidget * widget,gpointer user_data)246 voip_input_widget_parent_changed (GtkWidget *widget,
247 gpointer user_data)
248 {
249 gtk_widget_set_size_request (widget, 200, -1);
250 //g_debug("voip_input_widget_parent_changed");
251 }
252
253 static void
voip_input_widget_slider_grabbed(GtkWidget * widget,gpointer user_data)254 voip_input_widget_slider_grabbed(GtkWidget *widget, gpointer user_data)
255 {
256 VoipInputWidget* mitem = VOIP_INPUT_WIDGET(user_data);
257 VoipInputWidgetPrivate * priv = VOIP_INPUT_WIDGET_GET_PRIVATE(mitem);
258 priv->grabbed = TRUE;
259 }
260
261 static void
voip_input_widget_slider_released(GtkWidget * widget,gpointer user_data)262 voip_input_widget_slider_released(GtkWidget *widget, gpointer user_data)
263 {
264 VoipInputWidget* mitem = VOIP_INPUT_WIDGET(user_data);
265 VoipInputWidgetPrivate * priv = VOIP_INPUT_WIDGET_GET_PRIVATE(mitem);
266 priv->grabbed = FALSE;
267 }
268
269 void
voip_input_widget_tidy_up(GtkWidget * widget)270 voip_input_widget_tidy_up (GtkWidget *widget)
271 {
272 VoipInputWidget* mitem = VOIP_INPUT_WIDGET(widget);
273 VoipInputWidgetPrivate * priv = VOIP_INPUT_WIDGET_GET_PRIVATE(mitem);
274 gtk_widget_destroy (priv->ido_voip_input_slider);
275 }
276
277 /**
278 * voip_input_widget_new:
279 * @returns: a new #VoipInputWidget.
280 **/
281 GtkWidget*
voip_input_widget_new(DbusmenuMenuitem * item)282 voip_input_widget_new(DbusmenuMenuitem *item)
283 {
284 GtkWidget* widget = g_object_new(VOIP_INPUT_WIDGET_TYPE, NULL);
285 voip_input_widget_set_twin_item((VoipInputWidget*)widget, item);
286 return widget;
287 }
288
289
290