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