1 /**
2 * This file is a part of the Cairo-Dock project
3 *
4 * Copyright : (C) see the 'copyright' file.
5 * E-mail : see the 'copyright' file.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 3
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "string.h"
21 #include <glib/gi18n.h>
22
23 #include "powermanager-struct.h"
24 #include "powermanager-draw.h"
25
26 /* 3 states:
27 no battery -> empty gauge (0%), on-sector emblem, no alert
28 on battery -> gauge + %, no emblem, alert
29 on sector -> gauge + %, on-sector emblem, alert
30 */
31
_set_data_renderer(GldiModuleInstance * myApplet)32 static void _set_data_renderer (GldiModuleInstance *myApplet)
33 {
34 CairoDataRendererAttribute *pRenderAttr = NULL; // generic attributes of the data-renderer.
35 switch (myConfig.iDisplayType)
36 {
37 case CD_POWERMANAGER_GAUGE:
38 {
39 CairoGaugeAttribute *pGaugeAttr = g_new0 (CairoGaugeAttribute, 1);
40 pRenderAttr = CAIRO_DATA_RENDERER_ATTRIBUTE (pGaugeAttr);
41 pRenderAttr->cModelName = "gauge";
42 pGaugeAttr->cThemePath = myConfig.cGThemePath;
43 }
44 break;
45 case CD_POWERMANAGER_GRAPH:
46 {
47 CairoGraphAttribute *pGraphAttr = g_new0 (CairoGraphAttribute, 1);
48 pRenderAttr = CAIRO_DATA_RENDERER_ATTRIBUTE (pGraphAttr);
49 pRenderAttr->cModelName = "graph";
50 pRenderAttr->iMemorySize = (myIcon->fWidth > 1 ? myIcon->fWidth : 32); // fWidth peut etre <= 1 en mode desklet au chargement.
51 pGraphAttr->iType = myConfig.iGraphType;
52 pGraphAttr->fHighColor = myConfig.fHigholor;
53 pGraphAttr->fLowColor = myConfig.fLowColor;
54 memcpy (pGraphAttr->fBackGroundColor, myConfig.fBgColor, 4*sizeof (double));
55 }
56 break;
57 case CD_POWERMANAGER_ICONS:
58 {
59 myData.iOnBatteryImage = -1; // we'll set the image when we know the current state.
60 CairoProgressBarAttribute *pBarAttr = g_new0 (CairoProgressBarAttribute, 1);
61 pRenderAttr = CAIRO_DATA_RENDERER_ATTRIBUTE (pBarAttr);
62 pRenderAttr->cModelName = "progressbar";
63 }
64 break;
65
66 default:
67 return;
68 }
69
70 if (myConfig.quickInfoType != 0)
71 {
72 pRenderAttr->bWriteValues = TRUE;
73 pRenderAttr->format_value = (CairoDataRendererFormatValueFunc)cd_powermanager_format_value;
74 pRenderAttr->pFormatData = myApplet;
75 }
76
77 CD_APPLET_ADD_DATA_RENDERER_ON_MY_ICON (pRenderAttr);
78 g_free (pRenderAttr);
79 }
80
81
update_icon(void)82 void update_icon (void)
83 {
84 cd_debug ("%s (on battery: %d -> %d; time:%.1f -> %.1f ; charge:%.1f -> %.1f)", __func__, myData.bPrevOnBattery, myData.bOnBattery, (double)myData.iPrevTime, (double)myData.iTime, (double)myData.iPrevPercentage, (double)myData.iPercentage);
85
86 // hide the icon when not on battery or no information available (e.g. with a desktop)
87 if (myConfig.bHideNotOnBattery && myDock && (! myData.bOnBattery))
88 {
89 if (! myData.bIsHidden)
90 { // we remove the icon
91 gldi_icon_detach (myIcon);
92 myData.bIsHidden = TRUE;
93 }
94 return; // no need any redraw if the icon is hidden, and can't display the dialog properly without the icon.
95 }
96 else if (myData.bIsHidden && myData.bOnBattery && myDock) // if the icon is hidden but we are now on battery, we (re-)insert the icon.
97 {
98 cd_debug ("Re-insert the icon");
99 gldi_icon_insert_in_container (myIcon, myContainer, CAIRO_DOCK_ANIMATE_ICON);
100 myData.bIsHidden = FALSE;
101 }
102
103 // no information available or no battery, draw a default icon.
104 if (! myData.bBatteryPresent)
105 {
106 CD_APPLET_REMOVE_MY_DATA_RENDERER;
107 CD_APPLET_SET_IMAGE_ON_MY_ICON (MY_APPLET_SHARE_DATA_DIR"/sector.svg");
108 CD_APPLET_REDRAW_MY_ICON;
109 return;
110 }
111
112 gboolean bInit = (cairo_dock_get_icon_data_renderer (myIcon) == NULL);
113 if (bInit) // first time: init or reload
114 _set_data_renderer (myApplet);
115
116 gboolean bChanged = (myData.bPrevOnBattery != myData.bOnBattery
117 || myData.iPrevPercentage != myData.iPercentage
118 || myData.iTime != myData.iPrevTime
119 || bInit); // just to be sure
120
121 if (bChanged || myConfig.iDisplayType == CD_POWERMANAGER_GRAPH) // graphs need to be updated each time, even if there is no change.
122 {
123 // update the icon representation
124 if (myConfig.iDisplayType == CD_POWERMANAGER_ICONS) // set the icon if needed
125 {
126 if (myData.iOnBatteryImage != myData.bOnBattery)
127 {
128 if (myData.bOnBattery)
129 CD_APPLET_SET_USER_IMAGE_ON_MY_ICON (myConfig.cUserBatteryIconName, "default-battery.svg");
130 else
131 CD_APPLET_SET_USER_IMAGE_ON_MY_ICON (myConfig.cUserChargeIconName, "default-charge.svg");
132 myData.iOnBatteryImage = myData.bOnBattery;
133 }
134 }
135 // render the value
136 double fPercent;
137 if (! myData.bBatteryPresent)
138 fPercent = CAIRO_DATA_RENDERER_UNDEF_VALUE;
139 else
140 fPercent = (double) myData.iPercentage / 100.;
141 CD_APPLET_RENDER_NEW_DATA_ON_MY_ICON (&fPercent);
142
143 if (bChanged)
144 {
145 // add or remove the charge overlay if the 'on_battery' status has changed.
146 if (myData.bPrevOnBattery != myData.bOnBattery || bInit)
147 {
148 if (! myData.bOnBattery)
149 {
150 CD_APPLET_ADD_OVERLAY_ON_MY_ICON (myConfig.cEmblemIconName ? myConfig.cEmblemIconName : MY_APPLET_SHARE_DATA_DIR"/charge.svg", CAIRO_OVERLAY_MIDDLE);
151 }
152 else
153 {
154 CD_APPLET_REMOVE_OVERLAY_ON_MY_ICON (CAIRO_OVERLAY_MIDDLE);
155 }
156 }
157
158 // trigger alarms.
159 if (myData.bOnBattery)
160 {
161 // Alert when battery charge goes under a configured value in %
162 if (myData.iPrevPercentage > myConfig.lowBatteryValue && myData.iPercentage <= myConfig.lowBatteryValue)
163 {
164 cd_powermanager_alert(POWER_MANAGER_CHARGE_LOW);
165 if (myConfig.cSoundPath[POWER_MANAGER_CHARGE_LOW] != NULL)
166 cairo_dock_play_sound (myConfig.cSoundPath[POWER_MANAGER_CHARGE_LOW]);
167 }
168 // Alert when battery charge is under 4%
169 if (myData.iPrevPercentage > 4 && myData.iPercentage <= 4)
170 {
171 cd_powermanager_alert (POWER_MANAGER_CHARGE_CRITICAL);
172 if (myConfig.cSoundPath[POWER_MANAGER_CHARGE_CRITICAL] != NULL)
173 cairo_dock_play_sound (myConfig.cSoundPath[POWER_MANAGER_CHARGE_CRITICAL]);
174 }
175 }
176 else
177 {
178 // Alert when battery is charged
179 if(myData.iPrevPercentage > 0 && myData.iPrevPercentage < 100 && myData.iPercentage == 100) // the first condition is to prevent the dialog on startup.
180 cd_powermanager_alert (POWER_MANAGER_CHARGE_FULL);
181 }
182
183 // update the icon's label.
184 if (myConfig.defaultTitle == NULL || *myConfig.defaultTitle == '\0')
185 {
186 if (! myData.bOnBattery && myData.iPercentage > 99.9)
187 {
188 CD_APPLET_SET_NAME_FOR_MY_ICON_PRINTF ("%d%% - %s",
189 (int)myData.iPercentage,
190 D_("Battery charged"));
191 }
192 else
193 {
194 gchar cFormatBuffer[21];
195 int iBufferLength = 20;
196 if (myData.iTime != 0)
197 {
198 int time = myData.iTime;
199 int hours = time / 3600;
200 int minutes = (time % 3600) / 60;
201 if (hours != 0)
202 snprintf (cFormatBuffer, iBufferLength, "%d%s%02d", hours, D_("h"), abs (minutes));
203 else
204 snprintf (cFormatBuffer, iBufferLength, "%d%s", minutes, D_("mn"));
205 }
206 else
207 {
208 strncpy (cFormatBuffer, "-:--", iBufferLength);
209 }
210 CD_APPLET_SET_NAME_FOR_MY_ICON_PRINTF ("%d%% - %s %s",
211 (int)myData.iPercentage,
212 cFormatBuffer,
213 myData.bOnBattery ? D_("remaining") : D_("until charged"));
214 }
215 }
216
217 myData.bPrevOnBattery = myData.bOnBattery;
218 myData.iPrevPercentage = myData.iPercentage;
219 myData.iPrevTime = myData.iTime;
220 }
221 }
222 }
223
get_hours_minutes(int iTimeInSeconds)224 gchar *get_hours_minutes (int iTimeInSeconds)
225 {
226 gchar *cTimeString;
227 int h = iTimeInSeconds / 3600;
228 int m = (iTimeInSeconds % 3600) / 60;
229 if (h > 0) cTimeString = g_strdup_printf ("%dh%02dm", h, m);
230 else if (m > 0) cTimeString = g_strdup_printf ("%dm", m);
231 else cTimeString = g_strdup (D_("None"));
232
233 return cTimeString;
234 }
235
_cd_powermanager_dialog(const gchar * cInfo,int iDuration)236 static void _cd_powermanager_dialog (const gchar *cInfo, int iDuration)
237 {
238 gldi_dialogs_remove_on_icon (myIcon);
239
240 /**const gchar *cIconPath;
241 if (!myData.bOnBattery)
242 cIconPath = MY_APPLET_SHARE_DATA_DIR"/sector.svg";
243 else
244 cIconPath = MY_APPLET_SHARE_DATA_DIR"/default-battery.svg";
245
246 cd_debug ("%s (%s)", cInfo, cIconPath);*/
247 gldi_dialog_show_temporary_with_icon (cInfo, myIcon, myContainer, 1000*iDuration, "same icon");
248 }
249
cd_powermanager_bubble(void)250 void cd_powermanager_bubble (void)
251 {
252 GString *sInfo = g_string_new ("");
253 if (myData.cBatteryStateFilePath != NULL || myData.pBatteryDeviceList != NULL)
254 {
255 // time and charge.
256 gchar *hms = NULL;
257 if (myData.iTime > 0.)
258 hms = get_hours_minutes (myData.iTime);
259 else
260 hms = g_strdup_printf ("%s", D_("Unknown"));
261 if (myData.bOnBattery)
262 {
263 g_string_printf (sInfo, "%s\n"
264 "%s %d%%\n"
265 "%s %s",
266 D_("Laptop on Battery."),
267 D_("Battery charged at:"), (int)myData.iPercentage,
268 D_("Estimated time before empty:"), hms);
269 }
270 else
271 {
272 g_string_printf (sInfo, "%s\n"
273 "%s %d%%\n"
274 "%s %s",
275 D_("Laptop on Charge."),
276 D_("Battery charged at:"), (int)myData.iPercentage,
277 D_("Estimated time before full:"), (myData.iPercentage > 99.9 ? "0" : hms));
278 }
279 g_free (hms);
280
281 // static info
282 if (myData.cVendor != NULL || myData.cModel != NULL)
283 {
284 g_string_append_printf (sInfo, "\n%s %s %s", D_("Model:"),
285 myData.cVendor ? myData.cVendor : "",
286 myData.cModel ? myData.cModel : "");
287 }
288 if (myData.cTechnology != NULL)
289 {
290 g_string_append_printf (sInfo, "\n%s %s", D_("Technology:"), myData.cTechnology);
291 }
292 if (myData.fMaxAvailableCapacity != 0)
293 {
294 g_string_append_printf (sInfo, "\n%s %d%%", D_("Maximum capacity:"), (int)myData.fMaxAvailableCapacity);
295 }
296 }
297 else
298 {
299 g_string_assign (sInfo, D_("No battery found."));
300 }
301
302 _cd_powermanager_dialog (sInfo->str, 7);
303 g_string_free (sInfo, TRUE);
304 }
305
cd_powermanager_alert(MyAppletCharge alert)306 gboolean cd_powermanager_alert (MyAppletCharge alert)
307 {
308 cd_debug ("%s", __func__);
309 GString *sInfo = g_string_new ("");
310
311 gchar *hms = NULL;
312 if (myData.iTime > 0.)
313 hms = get_hours_minutes (myData.iTime);
314 else
315 hms = g_strdup (D_("Unknown"));
316
317 if ((alert == POWER_MANAGER_CHARGE_LOW && myConfig.lowBatteryWitness) || (alert == POWER_MANAGER_CHARGE_CRITICAL && myConfig.criticalBatteryWitness))
318 {
319 if (myConfig.iNotificationType != 1)
320 {
321 g_string_printf (sInfo, "%s (%d%%) \n %s %s \n %s", D_("PowerManager.\nBattery charge seems to be low"), (int)myData.iPercentage, D_("Estimated time with charge:"), hms, D_("Please put your laptop on charge."));
322 _cd_powermanager_dialog (sInfo->str, myConfig.iNotificationDuration);
323 }
324 if (myConfig.iNotificationType != 2)
325 {
326 CD_APPLET_DEMANDS_ATTENTION (myConfig.cNotificationAnimation, myConfig.iNotificationDuration);
327 }
328 if (myConfig.cSoundPath[alert] != NULL)
329 cairo_dock_play_sound (myConfig.cSoundPath[alert]);
330 }
331 else if (alert == POWER_MANAGER_CHARGE_FULL && myConfig.highBatteryWitness)
332 {
333 if (myConfig.iNotificationType != 1)
334 {
335 g_string_printf (sInfo, "%s (%d%%)", D_("PowerManager.\nYour battery is now charged"), (int)myData.iPercentage);
336 _cd_powermanager_dialog (sInfo->str, myConfig.iNotificationDuration);
337 }
338 if (! myData.bIsHidden && myConfig.iNotificationType != 2)
339 {
340 CD_APPLET_DEMANDS_ATTENTION (myConfig.cNotificationAnimation, myConfig.iNotificationDuration);
341 }
342 if (myConfig.cSoundPath[alert] != NULL)
343 cairo_dock_play_sound (myConfig.cSoundPath[alert]);
344 }
345
346 g_free (hms);
347 g_string_free (sInfo, TRUE);
348 return FALSE;
349 }
350
351
cd_powermanager_format_value(CairoDataRenderer * pRenderer,int iNumValue,gchar * cFormatBuffer,int iBufferLength,GldiModuleInstance * myApplet)352 void cd_powermanager_format_value (CairoDataRenderer *pRenderer, int iNumValue, gchar *cFormatBuffer, int iBufferLength, GldiModuleInstance *myApplet)
353 {
354 // double fValue = cairo_data_renderer_get_normalized_current_value_with_latency (pRenderer, iNumValue);
355 if(myConfig.quickInfoType == POWER_MANAGER_TIME)
356 {
357 if (myData.iTime != 0)
358 {
359 int time = myData.iTime;
360 int hours = time / 3600;
361 int minutes = (time % 3600) / 60;
362 cd_debug ("time: %d -> %d;%d", time, hours, minutes);
363 if (hours != 0)
364 snprintf (cFormatBuffer, iBufferLength, "%dh%02d", hours, abs (minutes));
365 else
366 snprintf (cFormatBuffer, iBufferLength, "%dmn", minutes);
367 }
368 else
369 {
370 strncpy (cFormatBuffer, "-:--", iBufferLength);
371 }
372 }
373 else if(myConfig.quickInfoType == POWER_MANAGER_CHARGE)
374 {
375 snprintf (cFormatBuffer, iBufferLength, "%d%%", (int)myData.iPercentage);
376 }
377 else
378 cFormatBuffer[0] = '\0';
379 }
380