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