temporary commit, might not even compile
[cpumem-applet] / src / cpumem_status_area_item.c
1 /*
2  * Cpumem-applet - status area plugin
3  * 
4  * Copyright (c) 2005-2009 Jakub Pavelek
5  * Copyright (c) 2009-2010 Tuomo Tanskanen
6  */
7
8 #include <gtk/gtk.h>
9 #include <hildon/hildon.h>
10 #include <glib/gerror.h>
11 #include <glib.h>
12 #include <string.h>
13 #include <libosso.h>
14
15 #include "cpumem_status_area_item.h"
16
17 #define CPUMEM_ICON_WIDTH  16
18 #define CPUMEM_ICON_HEIGHT 16
19 #define CPUMEM_BOX_WIDTH   5
20 #define CPUMEM_BOX_HEIGHT  3
21 #define CPUMEM_CPU_MAX 5
22
23
24
25 #define CPUMEM_APPLET_STATUS_AREA_ITEM_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE (obj, CPUMEM_APPLET_TYPE_STATUS_AREA_ITEM, CpumemAppletStatusAreaItemPrivate))
26
27 struct _CpumemAppletStatusAreaItemPrivate {
28         guint timeout_id;
29         gint lastU, lastN, lastIO, lastI;
30         guchar last_mem_level;
31         guchar last_cpu_level;
32         GdkPixbuf *pixbuf;
33         GdkPixbuf *pixbuf_on;
34         GdkPixbuf *pixbuf_red;
35         GdkPixbuf *pixbuf_off;
36         osso_context_t *osso;
37         gboolean red;
38 };
39
40 HD_DEFINE_PLUGIN_MODULE (CpumemAppletStatusAreaItem, cpumem_applet_status_area_item, HD_TYPE_STATUS_PLUGIN_ITEM);
41
42
43 /*
44  * Read current MEM usage and return indicator between 5 and 1 - how many bars are "full"
45  */
46 static guchar
47 check_mem (CpumemAppletStatusAreaItemPrivate *priv)
48 {
49         #define MEMFILE "/proc/meminfo"
50         #define MAX_READ_CHARS 128
51         char read_buffer[MAX_READ_CHARS];
52         FILE *fin;
53         int mem_used = 0;
54         int mem_total = 0;
55         int mem_cached = 0;
56         int mem_buffers = 0;
57         int mem_free = 0;
58
59         //Open the memory info file and get current free memory
60         fin = fopen(MEMFILE, "r");
61         if (fin == NULL) {
62                 g_warning("Can't open "MEMFILE"\n");
63                 return TRUE;
64         }
65         while (fgets(read_buffer, MAX_READ_CHARS, fin) != NULL) {
66                 if (strncmp(read_buffer, "MemTotal", 8) == 0) {
67                         sscanf(read_buffer + 10, "%d", &mem_total);
68                 } else if (strncmp(read_buffer, "MemFree", 6) == 0) {
69                         sscanf(read_buffer + 9, "%d", &mem_free);
70                 } else if (strncmp(read_buffer, "Buffers", 6) == 0) {
71                         sscanf(read_buffer + 9, "%d", &mem_buffers);
72                 } else if (strncmp(read_buffer, "Cached", 6) == 0) {
73                         sscanf(read_buffer + 8, "%d", &mem_cached);
74                         break;
75                 }
76         }
77         fclose(fin);
78
79         mem_used = mem_total - mem_free - mem_buffers - mem_cached;
80
81         if (mem_used > 0.9*mem_total)
82                 return 5;
83         else if (mem_used > 0.7*mem_total)
84                 return 4;
85         else if (mem_used > 0.5*mem_total)
86                 return 3;
87         else if (mem_used > 0.3*mem_total)
88                 return 2;
89         else
90                 return 1;
91 }
92
93
94 /*
95  * Read current CPU usage and return indicator between 5 and 1 - how many bars are "full"
96  */
97 static guchar
98 check_cpu (CpumemAppletStatusAreaItemPrivate *priv)
99 {
100         #define CPUFILE "/proc/stat"
101         gint curU, curN, curIO, curI;
102         gint deltaU, deltaN, deltaIO, deltaI;
103         int load, idle;
104         GError *error = NULL;
105         gchar *contents;
106         gsize lenght;
107         gchar **splits;
108
109         if (!g_file_get_contents (CPUFILE, &contents, &lenght, &error)) {
110                 fprintf (stderr, "ERR: can't read file %s: %s\n", CPUFILE, error->message);
111                 g_error_free (error);
112                 return 0;
113         }
114         
115         splits = g_strsplit_set (contents, " ",  -1);
116
117         sscanf(splits[2], "%d", &curU);
118         sscanf(splits[3], "%d", &curN);
119         sscanf(splits[4], "%d", &curIO);
120         sscanf(splits[5], "%d", &curI);
121         
122         g_strfreev (splits);
123         g_free (contents);
124     
125         idle = (curI - priv->lastI);
126         if (idle == 0) load = 100;
127         else load = 100-idle;
128         if (load>100) load = 0;
129         deltaU = curU - priv->lastU;
130         deltaN = curN - priv->lastN;
131         deltaIO = curIO - priv->lastIO;
132         deltaI = curI - priv->lastI;
133         priv->lastU = curU;
134         priv->lastN = curN;
135         priv->lastIO = curIO;
136         priv->lastI = curI;
137
138         if (load > 90)
139                 return 5;
140         else if (load > 70)
141                 return 4;
142         else if (load > 45)
143                 return 3;
144         else if (load > 19)
145                 return 2;
146         else
147                 return 1;
148 }
149
150
151
152 /*
153  * Compose and blit the current status of memory bars
154  */
155 static void
156 blit_mem_barsconst guchar level, CpumemAppletStatusAreaItemPrivate *priv)
157 {
158         guint x, y;
159         
160         gdk_pixbuf_fill(priv->pixbuf, 0x00000000);
161
162         x = 9;
163         y = 1;
164         if (level > 4)
165                 gdk_pixbuf_composite(priv->pixbuf_on, priv->pixbuf, x, y, 
166                         CPUMEM_BOX_WIDTH, CPUMEM_BOX_HEIGHT, x, y, 1, 1, GDK_INTERP_NEAREST, 255);
167         y = 5;
168         if (level > 3)
169                 gdk_pixbuf_composite(priv->pixbuf_on, priv->pixbuf, x, y, 
170                         CPUMEM_BOX_WIDTH, CPUMEM_BOX_HEIGHT, x, y, 1, 1, GDK_INTERP_NEAREST, 255);
171         y = 9;
172         if (level > 2)
173                 gdk_pixbuf_composite(priv->pixbuf_on, priv->pixbuf, x, y, 
174                         CPUMEM_BOX_WIDTH, CPUMEM_BOX_HEIGHT, x, y, 1, 1, GDK_INTERP_NEAREST, 255);
175         y = 13;
176         if (level > 1)
177                 gdk_pixbuf_composite(priv->pixbuf_on, priv->pixbuf, x, y, 
178                         CPUMEM_BOX_WIDTH, CPUMEM_BOX_HEIGHT, x, y, 1, 1, GDK_INTERP_NEAREST, 255);
179         else
180                 gdk_pixbuf_composite(priv->pixbuf_off, priv->pixbuf, x, y, 
181                         CPUMEM_BOX_WIDTH, CPUMEM_BOX_HEIGHT, x, y, 1, 1, GDK_INTERP_NEAREST, 255);
182 }
183
184
185 /* 
186  * Compose and blit current status of CPU bars
187  */
188 static void
189 blit_cpu_bars (const guchar level, CpumemAppletStatusAreaItemPrivate *priv)
190 {
191         guint x, y;
192         
193         x = 2;
194         y = 1;
195         if (level > 4)
196         {
197                 if (priv->red == TRUE) {
198                         gdk_pixbuf_composite(priv->pixbuf_red, priv->pixbuf, x, y, 
199                                 CPUMEM_BOX_WIDTH, CPUMEM_BOX_HEIGHT, x, y, 1, 1, GDK_INTERP_NEAREST, 255);
200                         priv->red = FALSE;
201                 } else {
202                         gdk_pixbuf_composite(priv->pixbuf_on, priv->pixbuf, x, y, 
203                                 CPUMEM_BOX_WIDTH, CPUMEM_BOX_HEIGHT, x, y, 1, 1, GDK_INTERP_NEAREST, 255);
204                         priv->red = TRUE;
205                 }
206         }
207         y = 5;
208         if (level > 3)
209                 gdk_pixbuf_composite(priv->pixbuf_on, priv->pixbuf, x, y, 
210                         CPUMEM_BOX_WIDTH, CPUMEM_BOX_HEIGHT, x, y, 1, 1, GDK_INTERP_NEAREST, 255);
211         y = 9;
212         if (level > 2)
213                 gdk_pixbuf_composite(priv->pixbuf_on, priv->pixbuf, x, y, 
214                         CPUMEM_BOX_WIDTH, CPUMEM_BOX_HEIGHT, x, y, 1, 1, GDK_INTERP_NEAREST, 255);
215         y = 13;
216         if (level > 1)
217                 gdk_pixbuf_composite(priv->pixbuf_on, priv->pixbuf, x, y, 
218                         CPUMEM_BOX_WIDTH, CPUMEM_BOX_HEIGHT, x, y, 1, 1, GDK_INTERP_NEAREST, 255);
219         else
220                 gdk_pixbuf_composite(priv->pixbuf_off, priv->pixbuf, x, y, 
221                         CPUMEM_BOX_WIDTH, CPUMEM_BOX_HEIGHT, x, y, 1, 1, GDK_INTERP_NEAREST, 255);
222 }
223
224
225 /*
226  * Ran to check and update the CPU and memory reading
227  */
228 static gboolean
229 check_load (gpointer data)
230 {
231         guchar current_cpu_level;
232         guchar current_mem_level;
233         CpumemAppletStatusAreaItem *item = (CpumemAppletStatusAreaItem*)data;
234         CpumemAppletStatusAreaItemPrivate *priv = (CpumemAppletStatusAreaItemPrivate*)item->priv;
235    
236         current_cpu_level = check_cpu(priv); 
237         current_mem_level = check_mem(priv);
238         //g_debug(g_strdup_printf("LOADAPLET - UPDATED CPU %d MEM %d", current_cpu_level, current_mem_level));
239         
240         //Update and blit only if data changed!
241         if ((current_mem_level != priv->last_mem_level) || (current_cpu_level != priv->last_cpu_level)) {
242                 blit_mem_bars (current_mem_level, priv);
243                 blit_cpu_bars (current_cpu_level, priv);
244                 if (current_cpu_level == CPUMEM_CPU_MAX)
245                         priv->red = FALSE;
246                 hd_status_plugin_item_set_status_area_icon (HD_STATUS_PLUGIN_ITEM(data), priv->pixbuf);
247                 priv->last_mem_level = current_mem_level;
248                 priv->last_cpu_level = current_cpu_level;
249         } else if (current_cpu_level == CPUMEM_CPU_MAX) {
250                 //Pulsate max CPU load icon also when CPU load stays at max
251                 blit_cpu_bars (current_cpu_level, priv);
252                 hd_status_plugin_item_set_status_area_icon (HD_STATUS_PLUGIN_ITEM(data), priv->pixbuf);
253         }
254
255         return TRUE;  
256 }
257
258 /*
259  * Get callback when display state changes
260  */
261 static void 
262 cpumem_applet_status_area_item_display_cb(osso_display_state_t state, gpointer user_data)
263 {
264         CpumemAppletStatusAreaItem *item = CPUMEM_APPLET_STATUS_AREA_ITEM(user_data);
265
266         g_return_if_fail (item != NULL && item->priv != NULL);
267
268         if (state == OSSO_DISPLAY_ON)
269     {
270                 //Restart the updates, do one right away
271                 if (item->priv->timeout_id == 0) 
272                 {
273                         item->priv->timeout_id = gtk_timeout_add(1000, check_load, item);
274                         check_load(item);
275                 }
276     } else {
277                 //Suspend the updates - screen is off
278                 if (item->priv->timeout_id) != 0) {
279                         g_source_remove(item->priv->timeout_id);
280                         item->priv->timeout_id = 0;
281                 }
282         }
283 }
284
285
286 /*****************************************************************************
287  *
288  * Boilerplate code area - do not enter
289  *
290  *****************************************************************************/
291
292 static void
293 cpumem_applet_status_area_item_set_area_icon (CpumemAppletStatusAreaItem *item)
294 {
295         item->priv = CPUMEM_APPLET_STATUS_AREA_ITEM_GET_PRIVATE (item);
296         
297         hd_status_plugin_item_set_status_area_icon (HD_STATUS_PLUGIN_ITEM(item), item->priv->pixbuf);
298 }
299
300
301 static void
302 cpumem_applet_status_area_item_class_finalize (CpumemAppletStatusAreaItemClass *klass)
303 {
304 }
305
306
307
308 static void
309 cpumem_applet_status_area_item_finalize (GObject *object)
310 {
311         CpumemAppletStatusAreaItemPrivate *priv = CPUMEM_APPLET_STATUS_AREA_ITEM(object)->priv;
312         // Release and clean our stuff
313         G_OBJECT_CLASS (cpumem_applet_status_area_item_parent_class)->finalize (object);
314         if (priv->osso)
315     {
316                 osso_deinitialize(priv->osso);
317                 priv->osso = NULL;
318     }
319
320 }
321
322
323
324 static void
325 cpumem_applet_status_area_item_class_init (CpumemAppletStatusAreaItemClass *klass)
326 {
327         GObjectClass *object_class = G_OBJECT_CLASS (klass);
328
329         object_class->finalize = cpumem_applet_status_area_item_finalize;
330
331         g_type_class_add_private (klass, sizeof (CpumemAppletStatusAreaItemPrivate));
332
333 }
334
335 static void
336 cpumem_applet_status_area_item_init (CpumemAppletStatusAreaItem *item)
337 {
338         item->priv = CPUMEM_APPLET_STATUS_AREA_ITEM_GET_PRIVATE (item);
339         
340         item->priv->last_mem_level = -1;
341         item->priv->last_cpu_level = -1;
342         item->priv->timeout_id = -1;
343         item->priv->red = FALSE;
344         item->priv->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, CPUMEM_ICON_WIDTH, CPUMEM_ICON_HEIGHT);
345         gdk_pixbuf_fill(item->priv->pixbuf, 0x00000000);
346         item->priv->pixbuf_on = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, CPUMEM_BOX_WIDTH, CPUMEM_BOX_HEIGHT);
347         gdk_pixbuf_fill(item->priv->pixbuf_on, 0xffffffff);
348         item->priv->pixbuf_red = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, CPUMEM_BOX_WIDTH, CPUMEM_BOX_HEIGHT);
349         gdk_pixbuf_fill(item->priv->pixbuf_red, 0xff0000ff);    
350         item->priv->pixbuf_off = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, CPUMEM_BOX_WIDTH, CPUMEM_BOX_HEIGHT);
351         gdk_pixbuf_fill(item->priv->pixbuf_off, 0x777777ff);
352         cpumem_applet_status_area_item_set_area_icon(item);
353
354         item->priv->osso = osso_initialize ("cpumem_applet_status_area_item", "Maemo5", TRUE, NULL);
355         item->priv->timeout_id = gtk_timeout_add(1000, check_load, item);
356         osso_hw_set_display_event_cb (item->priv->osso, cpumem_applet_status_area_item_display_cb, item);
357 }
358