1 /**
2 * This file is a part of the Cairo-Dock project
3 *
4 * Copyright : (C) see the 'copyright' file.
5 * based on indicator-me.c written by :
6 *  Ted Gould <ted@canonical.com>
7 *  Cody Russell <cody.russell@canonical.com>
8 * E-mail    : see the 'copyright' file.
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 3
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22 
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include "indicator-applet.h"
27 
28 static gboolean s_bIndicatorIconThemeAdded = FALSE;
29 
_on_menu_destroyed(CDAppletIndicator * pIndicator,GObject * old_menu_pointer)30 static void _on_menu_destroyed (CDAppletIndicator *pIndicator, GObject *old_menu_pointer)
31 {
32 	cd_debug ("no more menu (%p / %p)", old_menu_pointer, pIndicator->pMenu);
33 	if (old_menu_pointer == (GObject*)pIndicator->pMenu)
34 		pIndicator->pMenu = NULL;
35 }
_on_service_destroyed(CDAppletIndicator * pIndicator,GObject * old_menu_pointer)36 static void _on_service_destroyed (CDAppletIndicator *pIndicator, GObject *old_menu_pointer)
37 {
38 	cd_debug ("no more service (%p / %p)", old_menu_pointer, pIndicator->service);
39 	if (old_menu_pointer == (GObject*)pIndicator->service)
40 		pIndicator->service = NULL;
41 }
42 
_cd_indicator_make_menu(CDAppletIndicator * pIndicator)43 static void _cd_indicator_make_menu (CDAppletIndicator *pIndicator)
44 {
45 	if (pIndicator->pMenu == NULL)
46 	{
47 		pIndicator->pMenu = dbusmenu_gtkmenu_new ((gchar*)pIndicator->cBusName, (gchar*)pIndicator->cMenuObject);  // the cast is unorthodox, but the function definition is clumsy (it should require 2 const gchar*, since it actually duplicates the strings).
48 		if (pIndicator->pMenu != NULL)
49 		{
50 			g_object_ref_sink (G_OBJECT (pIndicator->pMenu));  // the object is floating -> take the reference
51 			g_object_weak_ref (G_OBJECT (pIndicator->pMenu),
52 				(GWeakNotify)_on_menu_destroyed,
53 				pIndicator);
54 			gldi_menu_init (GTK_WIDGET(pIndicator->pMenu), myIcon);
55 
56 			DbusmenuGtkClient * client = dbusmenu_gtkmenu_get_client (pIndicator->pMenu);
57 			if (pIndicator->add_menu_handler)
58 				pIndicator->add_menu_handler (client);
59 		}
60 	}
61 }
62 
_get_menu_once(CDAppletIndicator * pIndicator)63 static gboolean _get_menu_once (CDAppletIndicator *pIndicator)
64 {
65 	_cd_indicator_make_menu (pIndicator);
66 	pIndicator->iSidGetMenuOnce = 0;
67 	return FALSE;
68 }
69 
70 static void
connection_changed(IndicatorServiceManager * sm,gboolean connected,CDAppletIndicator * pIndicator)71 connection_changed (IndicatorServiceManager * sm, gboolean connected, CDAppletIndicator *pIndicator)
72 {
73 	cd_debug ("%s (%s : %d)", __func__, pIndicator->cBusName, connected);
74 	GldiModuleInstance *myApplet = pIndicator->pApplet;
75 	if (connected)
76 	{
77 		if (!pIndicator->bConnected)
78 		{
79 			// connect to the service.
80 			if (pIndicator->pServiceProxy == NULL)
81 			{
82 				/**GError * error = NULL;
83 				DBusGConnection * sbus = cairo_dock_get_session_connection ();
84 				pIndicator->pServiceProxy = dbus_g_proxy_new_for_name_owner(sbus,
85 					pIndicator->cBusName,
86 					pIndicator->cServiceObject,
87 					pIndicator->cServiceInterface,
88 					&error);
89 				if (error != NULL)
90 				{
91 					cd_warning ("'%s' service not found on the bus : %s", pIndicator->cServiceObject, error->message);
92 					g_error_free(error);
93 				}*/
94 				pIndicator->pServiceProxy = cairo_dock_create_new_session_proxy (
95 					pIndicator->cBusName,
96 					pIndicator->cServiceObject,
97 					pIndicator->cServiceInterface);
98 				if (pIndicator->pServiceProxy == NULL)
99 					return;
100 
101 				if (pIndicator->on_connect)
102 					pIndicator->on_connect (myApplet);
103 			}
104 
105 			// query the service to display initial values.
106 			if (pIndicator->get_initial_values)
107 				pIndicator->get_initial_values (myApplet);
108 
109 			pIndicator->iSidGetMenuOnce = g_idle_add ((GSourceFunc)_get_menu_once, pIndicator);
110 			pIndicator->bConnected = TRUE;
111 		}
112 	}
113 	else  // If we're disconnecting, go back to offline.
114 	{
115 		if (pIndicator->bConnected)
116 		{
117 			if (pIndicator->on_disconnect)
118 				pIndicator->on_disconnect (myApplet);
119 			if (pIndicator->pMenu)
120 			{
121 				cd_debug ("destroy menu...");
122 				g_object_unref (pIndicator->pMenu);
123 				cd_debug ("done.");
124 				pIndicator->pMenu = NULL;
125 			}
126 			if (pIndicator->pServiceProxy != NULL)
127 			{
128 				g_object_unref (pIndicator->pServiceProxy);  // this removes all the signals connected on the proxy
129 				pIndicator->pServiceProxy = NULL;
130 			}
131 			pIndicator->bConnected = FALSE;
132 		}
133 	}
134 
135 	return;
136 }
137 
_check_indicator(CDAppletIndicator * pIndicator)138 static gboolean _check_indicator (CDAppletIndicator *pIndicator)
139 {
140 	GldiModuleInstance *myApplet = pIndicator->pApplet;
141 	if (!pIndicator->bConnected && pIndicator->on_disconnect)
142 		pIndicator->on_disconnect (myApplet);
143 
144 	pIndicator->iSidCheckIndicator = 0;
145 	return FALSE;
146 }
147 
cd_indicator_new(GldiModuleInstance * pApplet,const gchar * cBusName,const gchar * cServiceObject,const gchar * cServiceInterface,const gchar * cMenuObject,int iVersion)148 CDAppletIndicator *cd_indicator_new (GldiModuleInstance *pApplet, const gchar *cBusName, const gchar *cServiceObject, const gchar *cServiceInterface, const gchar *cMenuObject, int iVersion)
149 {
150 	if (!s_bIndicatorIconThemeAdded)
151 	{
152 		s_bIndicatorIconThemeAdded = TRUE;
153 		cairo_dock_add_path_to_icon_theme (INDICATOR_ICONS_DIR);  /// maybe we should add it back when the icons manager is reloaded ?...
154 	}
155 	CDAppletIndicator *pIndicator = g_new0 (CDAppletIndicator, 1);
156 	pIndicator->pApplet = pApplet;
157 	pIndicator->cBusName = cBusName;
158 	pIndicator->cServiceObject = cServiceObject;
159 	pIndicator->cServiceInterface = cServiceInterface;
160 	pIndicator->cMenuObject = cMenuObject;
161 
162 	pIndicator->service = indicator_service_manager_new_version ((gchar*)cBusName, iVersion);
163 	g_object_weak_ref (G_OBJECT (pIndicator->service),
164 		(GWeakNotify)_on_service_destroyed,
165 		pIndicator);  // most probably useless, but let's be parano, since we're using the dreadful "libindicator" :p
166 
167 	g_signal_connect (G_OBJECT(pIndicator->service), INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE, G_CALLBACK(connection_changed), pIndicator);  // on sera appele une fois la connexion etablie.  // pour le cast, cf plus haut.
168 
169 	// indicators don't send the 'connection-change' signal if the connection couldn't be done, so we have to handle this case ourselves.
170 	pIndicator->iSidCheckIndicator = g_timeout_add_seconds (3, (GSourceFunc)_check_indicator, pIndicator);
171 
172 	return pIndicator;
173 }
174 
175 
cd_indicator_destroy(CDAppletIndicator * pIndicator)176 void cd_indicator_destroy (CDAppletIndicator *pIndicator)
177 {
178 	if (!pIndicator)
179 		return;
180 	if (pIndicator->iSidGetMenuOnce != 0)
181 		g_source_remove (pIndicator->iSidGetMenuOnce);
182 	if (pIndicator->iSidCheckIndicator != 0)
183 		g_source_remove (pIndicator->iSidCheckIndicator);
184 	pIndicator->bConnected = FALSE;
185 	pIndicator->on_disconnect = NULL;  // since the indicator has been explicitely destroyed, we don't want to call the callback when we'll disconnect from the service.
186 	cd_debug ("destroy indicator menu...");
187 	if (pIndicator->pMenu)
188 		g_object_unref (pIndicator->pMenu);
189 	cd_debug ("done.");
190 	if (pIndicator->pServiceProxy)
191 	{
192 		g_object_unref (pIndicator->pServiceProxy);
193 		pIndicator->pServiceProxy = NULL;
194 	}
195 	cd_debug ("destroy service...");
196 	if (pIndicator->service)
197 	{
198 		//g_object_unref (pIndicator->service);  // this causes a crash in libindicator (beacuse they keep the service as parameter of the callback 'service_proxy_name_changed'). so just be sure to disconnect from this object, and forget it.
199 		g_signal_handlers_disconnect_by_func (G_OBJECT(pIndicator->service), G_CALLBACK(connection_changed), pIndicator);
200 		g_object_weak_unref (G_OBJECT (pIndicator->service),
201 			(GWeakNotify)_on_service_destroyed,
202 			pIndicator);
203 		pIndicator->service = NULL;
204 	}
205 	cd_debug ("done.");
206 	g_free (pIndicator);
207 }
208 
209 
cd_indicator_set_icon(CDAppletIndicator * pIndicator,const gchar * cStatusIcon)210 void cd_indicator_set_icon (CDAppletIndicator *pIndicator, const gchar *cStatusIcon)
211 {
212 	GldiModuleInstance *myApplet = pIndicator->pApplet;
213 	if (cStatusIcon != pIndicator->cStatusIcon)
214 	{
215 		g_free (pIndicator->cStatusIcon);
216 		pIndicator->cStatusIcon = g_strdup (cStatusIcon);
217 	}
218 	if (cStatusIcon == NULL)
219 		return;
220 
221 	int iWidth, iHeight;
222 	cairo_dock_get_icon_extent (myIcon, &iWidth, &iHeight);
223 	const gchar *cIconName = cStatusIcon;
224 	gchar *tmp_icon_name = NULL;
225 	gchar *cIconPath = cairo_dock_search_icon_s_path (cIconName, MAX (iWidth, iHeight));  // on regarde si l'icone sera trouvee.
226 	gchar *cIconPathFallback = NULL;
227 	if (cIconPath == NULL)  // l'icone ne sera pas trouvee, on regarde si ce n'est pas une icone en carton d'Ubuntu.
228 	{
229 		gchar *str = g_strstr_len (cIconName, -1, "-panel");
230 		if (str)
231 		{
232 			tmp_icon_name = g_strndup (cIconName, str - cIconName);
233 			cIconName = tmp_icon_name;
234 			cIconPath = cairo_dock_search_icon_s_path (cIconName, MAX (iWidth, iHeight));
235 		}
236 	}
237 	if (cIconPath == NULL)  // l'icone ne sera pas trouvee, on met une icone par defaut.
238 	{
239 		gboolean bAddSuffix = (!g_str_has_suffix (cIconName, ".png") && !g_str_has_suffix (cIconName, ".svg"));
240 		cIconPathFallback = g_strdup_printf ("%s/%s%s", myApplet->pModule->pVisitCard->cShareDataDir, cIconName, bAddSuffix ? ".svg" : "");
241 	}
242 
243 	cd_debug ("set %s", cIconPathFallback ? cIconPathFallback : cIconName);
244 	//CD_APPLET_SET_IMAGE_ON_MY_ICON (cIconPathFallback ? cIconPathFallback : cIconName);
245 	cairo_dock_set_image_on_icon_with_default (myDrawContext,
246 		cIconPathFallback ? cIconPathFallback : cIconName,
247 		myIcon,
248 		myContainer,
249 		myApplet->pModule->pVisitCard->cIconFilePath);
250 
251 	g_free (tmp_icon_name);
252 	g_free (cIconPath);
253 	g_free (cIconPathFallback);
254 }
255 
256 
cd_indicator_reload_icon(CDAppletIndicator * pIndicator)257 void cd_indicator_reload_icon (CDAppletIndicator *pIndicator)
258 {
259 	g_return_if_fail (pIndicator != NULL);
260 	cd_indicator_set_icon (pIndicator, pIndicator->cStatusIcon);
261 }
262 
263 
cd_indicator_show_menu(CDAppletIndicator * pIndicator)264 gboolean cd_indicator_show_menu (CDAppletIndicator *pIndicator)
265 {
266 	if (pIndicator->bConnected)
267 	{
268 		_cd_indicator_make_menu (pIndicator);
269 		if (pIndicator->pMenu != NULL)
270 		{
271 			gldi_menu_popup (GTK_WIDGET (pIndicator->pMenu));
272 			return TRUE;
273 		}
274 	}
275 	return FALSE;
276 }
277