summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlastair Poole <netstar@gmail.com>2018-06-04 11:11:21 +0100
committerAlastair Poole <netstar@gmail.com>2018-06-04 11:11:21 +0100
commitde2818a3947eb9bdc7e7a294db1eb253cfb370eb (patch)
treedcc7bd44151bc6a627f2cf9a1ce89ce588d93a5c
First commit
-rw-r--r--LICENSE26
-rw-r--r--README.md7
-rw-r--r--makefile22
-rw-r--r--src/main.c59
-rw-r--r--src/makefile24
-rw-r--r--src/process.c568
-rw-r--r--src/process.h69
-rw-r--r--src/system.c1184
-rw-r--r--src/system.h7
-rw-r--r--src/ui.c1401
-rw-r--r--src/ui.h114
11 files changed, 3481 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..de6c88e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,26 @@
1
2 Copyright (c) 2018, Al Poole <netstar@gmail.com>
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the <organization> nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a1ec6db
--- /dev/null
+++ b/README.md
@@ -0,0 +1,7 @@
1# esysinfo
2System Information (EFL)
3
4This is a process monitor.
5
6Currently have full engines for Linux, FreeBSD, OpenBSD and MacOS.
7
diff --git a/makefile b/makefile
new file mode 100644
index 0000000..845aac0
--- /dev/null
+++ b/makefile
@@ -0,0 +1,22 @@
1LIBS=
2
3OSNAME := $(shell uname -s)
4
5ifeq ($(OSNAME), OpenBSD)
6 LIBS += -lkvm
7 LDFLAGS += -I/usr/local/include -L/usr/local/lib -L/usr/X11R6/lib
8endif
9
10export CFLAGS = -g -ggdb3 -O
11
12export PKGS = eina elementary
13
14export LIBS
15
16export LDFLAGS
17
18default:
19 $(MAKE) -C src
20
21clean:
22 $(MAKE) -C src clean
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..49ccd1b
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,59 @@
1/* Copyright 2018. Alastair Poole <netstar@gmail.com>
2 See LICENSE file for details.
3*/
4
5#include "process.h"
6#include "system.h"
7#include "ui.h"
8
9static void
10_win_del_cb(void *data EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
11{
12 evas_object_del(obj);
13 ecore_main_loop_quit();
14}
15
16static Evas_Object *
17_win_add(void)
18{
19 Evas_Object *win, *icon;
20
21 elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
22
23 win = elm_win_util_standard_add("esysinfo", "esysinfo");
24 icon = elm_icon_add(win);
25 elm_icon_standard_set(icon, "system-preferences");
26 elm_win_icon_object_set(win, icon);
27
28 evas_object_resize(win, 768 * elm_config_scale_get(), 420 * elm_config_scale_get());
29 evas_object_smart_callback_add(win, "delete,request", _win_del_cb, NULL);
30
31 elm_win_title_set(win, "System Information");
32
33 return win;
34}
35
36int
37main(int argc, char **argv)
38{
39 Evas_Object *win;
40
41 eina_init();
42 ecore_init();
43 elm_init(argc, argv);
44
45 win = _win_add();
46 ui_add(win);
47
48 elm_win_center(win, EINA_TRUE, EINA_TRUE);
49 evas_object_show(win);
50
51 ecore_main_loop_begin();
52
53 eina_shutdown();
54 ecore_shutdown();
55 elm_shutdown();
56
57 return 0;
58}
59
diff --git a/src/makefile b/src/makefile
new file mode 100644
index 0000000..1bb054a
--- /dev/null
+++ b/src/makefile
@@ -0,0 +1,24 @@
1TARGET = ../esysinfo
2
3OBJECTS = system.o process.o ui.o main.o
4
5default: $(TARGET)
6
7$(TARGET) : $(OBJECTS)
8 $(CC) $(OBJECTS) $(shell pkg-config --libs $(PKGS)) $(LIBS) $(LDFLAGS) -o $@
9
10main.o: main.c
11 $(CC) -c $(CFLAGS) $(shell pkg-config --cflags $(PKGS)) main.c -o $@
12
13system.o: system.c
14 $(CC) -c $(CFLAGS) system.c -o $@
15
16process.o: process.c
17 $(CC) -c $(CFLAGS) $(shell pkg-config --cflags $(PKGS)) process.c -o $@
18
19ui.o: ui.c
20 $(CC) -c $(CFLAGS) $(shell pkg-config --cflags $(PKGS)) ui.c -o $@
21
22clean:
23 -rm $(OBJECTS)
24 -rm $(TARGET)
diff --git a/src/process.c b/src/process.c
new file mode 100644
index 0000000..ab1d4a8
--- /dev/null
+++ b/src/process.c
@@ -0,0 +1,568 @@
1#if defined(__MACH__) && defined(__APPLE__)
2# define __MacOS__
3#endif
4
5#if defined(__MacOS__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
6# include <sys/types.h>
7# include <sys/sysctl.h>
8# include <sys/user.h>
9# include <sys/proc.h>
10#endif
11
12#if defined(__OpenBSD__)
13# include <kvm.h>
14# include <limits.h>
15# include <sys/proc.h>
16# include <sys/param.h>
17# include <sys/resource.h>
18#endif
19
20#if defined(__MacOS__)
21# include <libproc.h>
22# include <sys/proc_info.h>
23#endif
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <ctype.h>
29#include <unistd.h>
30#include <limits.h>
31
32#include "process.h"
33#include <Eina.h>
34#include <Ecore.h>
35#include <Ecore_File.h>
36
37static const char *
38_process_state_name(char state)
39{
40 const char *statename = NULL;
41#if defined(__linux__)
42
43 switch (state)
44 {
45 case 'D':
46 statename = "DSLEEP";
47 break;
48
49 case 'I':
50 statename = "IDLE";
51 break;
52
53 case 'R':
54 statename = "RUN";
55 break;
56
57 case 'S':
58 statename = "SLEEP";
59 break;
60
61 case 'T':
62 case 't':
63 statename = "STOP";
64 break;
65
66 case 'X':
67 statename = "DEAD";
68 break;
69
70 case 'Z':
71 statename = "ZOMB";
72 break;
73 }
74#else
75 switch (state)
76 {
77 case SIDL:
78 statename = "IDLE";
79 break;
80
81 case SRUN:
82 statename = "RUN";
83 break;
84
85 case SSLEEP:
86 statename = "SLEEP";
87 break;
88
89 case SSTOP:
90 statename = "STOP";
91 break;
92
93#if !defined(__MacOS__)
94#if !defined(__OpenBSD__)
95 case SWAIT:
96 statename = "WAIT";
97 break;
98
99 case SLOCK:
100 statename = "LOCK";
101 break;
102
103#endif
104 case SZOMB:
105 statename = "ZOMB";
106 break;
107
108#endif
109#if defined(__OpenBSD__)
110 case SDEAD:
111 statename = "DEAD";
112 break;
113
114 case SONPROC:
115 statename = "ONPROC";
116 break;
117#endif
118 }
119#endif
120 return statename;
121}
122
123#if defined(__linux__)
124
125static unsigned long
126_parse_line(const char *line)
127{
128 char *p, *tok;
129
130 p = strchr(line, ':') + 1;
131 while (isspace(*p))
132 p++;
133 tok = strtok(p, " ");
134
135 return atol(tok);
136}
137
138static Eina_List *
139_process_list_linux_get(void)
140{
141 char *name;
142 Eina_List *files, *list = NULL;
143 FILE *f;
144 char path[PATH_MAX], line[4096], program_name[1024], state;
145 int pid, res, utime, stime, cutime, cstime, uid, psr, pri, nice, numthreads;
146 unsigned int mem_size, mem_rss;
147
148 int pagesize = getpagesize();
149
150 files = ecore_file_ls("/proc");
151 EINA_LIST_FREE(files, name)
152 {
153 pid = atoi(name);
154 free(name);
155
156 if (!pid) continue;
157
158 snprintf(path, sizeof(path), "/proc/%d/stat", pid);
159
160 f = fopen(path, "r");
161 if (!f) continue;
162
163 if (fgets(line, sizeof(line), f))
164 {
165 int dummy;
166 char *end, *start = strchr(line, '(') + 1;
167 end = strchr(line, ')');
168 strncpy(program_name, start, end - start);
169 program_name[end - start] = '\0';
170
171 res = sscanf(end + 2, "%c %d %d %d %d %d %u %u %u %u %u %d %d %d %d %d %d %u %u %d %u %u %u %u %u %u %u %u %d %d %d %d %u %d %d %d %d %d %d %d %d %d",
172 &state, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &utime, &stime, &cutime, &cstime,
173 &pri, &nice, &numthreads, &dummy, &dummy, &mem_size, &mem_rss, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy,
174 &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &psr, &dummy, &dummy, &dummy, &dummy, &dummy);
175 }
176
177 fclose(f);
178
179 if (res != 42) continue;
180
181 snprintf(path, sizeof(path), "/proc/%d/status", pid);
182
183 f = fopen(path, "r");
184 if (!f) continue;
185
186 while ((fgets(line, sizeof(line), f)) != NULL)
187 {
188 if (!strncmp(line, "Uid:", 4))
189 {
190 uid = _parse_line(line);
191 break;
192 }
193 }
194
195 fclose(f);
196
197 Proc_Stats *p = calloc(1, sizeof(Proc_Stats));
198
199 p->pid = pid;
200 p->uid = uid;
201 p->cpu_id = psr;
202 snprintf(p->command, sizeof(p->command), "%s", program_name);
203 p->state = _process_state_name(state);
204 p->cpu_time = utime + stime;
205 p->mem_size = mem_size;
206 p->mem_rss = mem_rss * pagesize;
207 p->nice = nice;
208 p->priority = pri;
209 p->numthreads = numthreads;
210
211 list = eina_list_append(list, p);
212 }
213
214 if (files)
215 eina_list_free(files);
216
217 return list;
218}
219
220Proc_Stats *
221proc_info_by_pid(int pid)
222{
223 FILE *f;
224 char path[PATH_MAX];
225 char line[4096];
226 char state, program_name[1024];
227 int res, dummy, utime, stime, cutime, cstime, uid, psr;
228 unsigned int mem_size, mem_rss, pri, nice, numthreads;
229
230 snprintf(path, sizeof(path), "/proc/%d/stat", pid);
231 if (!ecore_file_exists(path))
232 return NULL;
233
234 f = fopen(path, "r");
235 if (!f) return NULL;
236
237 if (fgets(line, sizeof(line), f))
238 {
239 char *end, *start = strchr(line, '(') + 1;
240 end = strchr(line, ')');
241 strncpy(program_name, start, end - start);
242 program_name[end - start] = '\0';
243
244 res = sscanf(end + 2, "%c %d %d %d %d %d %u %u %u %u %u %d %d %d %d %d %d %u %u %d %u %u %u %u %u %u %u %u %d %d %d %d %u %d %d %d %d %d %d %d %d %d",
245 &state, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &utime, &stime, &cutime, &cstime,
246 &pri, &nice, &numthreads, &dummy, &dummy, &mem_size, &mem_rss, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy,
247 &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &psr, &dummy, &dummy, &dummy, &dummy, &dummy);
248 }
249 fclose(f);
250
251 if (res != 42) return NULL;
252
253 snprintf(path, sizeof(path), "/proc/%d/status", pid);
254
255 f = fopen(path, "r");
256 if (!f) return NULL;
257
258 while ((fgets(line, sizeof(line), f)) != NULL)
259 {
260 if (!strncmp(line, "Uid:", 4))
261 {
262 uid = _parse_line(line);
263 break;
264 }
265 }
266 fclose(f);
267
268 Proc_Stats *p = calloc(1, sizeof(Proc_Stats));
269 p->pid = pid;
270 p->uid = uid;
271 p->cpu_id = psr;
272 snprintf(p->command, sizeof(p->command), "%s", program_name);
273 p->state = _process_state_name(state);
274 p->cpu_time = utime + stime;
275 p->mem_size = mem_size;
276 p->mem_rss = mem_rss * getpagesize();
277 p->priority = pri;
278 p->nice = nice;
279 p->numthreads = numthreads;
280
281 return p;
282}
283
284#endif
285
286#if defined(__OpenBSD__)
287
288Proc_Stats *
289proc_info_by_pid(int pid)
290{
291 struct kinfo_proc *kp;
292 kvm_t *kern;
293 char errbuf[4096];
294 int count, pagesize, pid_count;
295
296 kern = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
297 if (!kern) return NULL;
298
299 kp = kvm_getprocs(kern, KERN_PROC_PID, pid, sizeof(*kp), &count);
300 if (!kp) return NULL;
301
302 if (count == 0) return NULL;
303 pagesize = getpagesize();
304
305 Proc_Stats *p = malloc(sizeof(Proc_Stats));
306 p->pid = kp->p_pid;
307 p->uid = kp->p_uid;
308 p->cpu_id = kp->p_cpuid;
309 snprintf(p->command, sizeof(p->command), "%s", kp->p_comm);
310 p->state = _process_state_name(kp->p_stat);
311 p->cpu_time = kp->p_uticks + kp->p_sticks + kp->p_iticks;
312 p->mem_size = (kp->p_vm_tsize * pagesize) + (kp->p_vm_dsize * pagesize) + (kp->p_vm_ssize * pagesize);
313 p->mem_rss = kp->p_vm_rssize * pagesize;
314 p->priority = kp->p_priority - PZERO;
315 p->nice = kp->p_nice - NZERO;
316 p->numthreads = -1;
317
318 kp = kvm_getprocs(kern, KERN_PROC_SHOW_THREADS, 0, sizeof(*kp), &pid_count);
319
320 for (int i = 0; i < pid_count; i++)
321 {
322 if (kp[i].p_pid == p->pid)
323 p->numthreads++;
324 }
325
326 kvm_close(kern);
327
328 return p;
329}
330
331static Eina_List *
332_process_list_openbsd_get(void)
333{
334 struct kinfo_proc *kp;
335 Proc_Stats *p;
336 char errbuf[4096];
337 kvm_t *kern;
338 int pid_count, pagesize;
339 Eina_List *l, *list = NULL;
340
341 kern = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
342 if (!kern) return NULL;
343
344 kp = kvm_getprocs(kern, KERN_PROC_ALL, 0, sizeof(*kp), &pid_count);
345 if (!kp) return NULL;
346
347 pagesize = getpagesize();
348
349 for (int i = 0; i < pid_count; i++)
350 {
351 p = malloc(sizeof(Proc_Stats));
352 p->pid = kp[i].p_pid;
353 p->uid = kp[i].p_uid;
354 p->cpu_id = kp[i].p_cpuid;
355 snprintf(p->command, sizeof(p->command), "%s", kp[i].p_comm);
356 p->state = _process_state_name(kp[i].p_stat);
357 p->cpu_time = kp[i].p_uticks + kp[i].p_sticks + kp[i].p_iticks;
358 p->mem_size = (kp[i].p_vm_tsize * pagesize) + (kp[i].p_vm_dsize * pagesize) + (kp[i].p_vm_ssize * pagesize);
359 p->mem_rss = kp[i].p_vm_rssize * pagesize;
360 p->priority = kp[i].p_priority - PZERO;
361 p->nice = kp[i].p_nice - NZERO;
362 p->numthreads = -1;
363 list = eina_list_append(list, p);
364 }
365
366 kp = kvm_getprocs(kern, KERN_PROC_SHOW_THREADS, 0, sizeof(*kp), &pid_count);
367
368 EINA_LIST_FOREACH (list, l, p)
369 {
370 for (int i = 0; i < pid_count; i++)
371 {
372 if (kp[i].p_pid == p->pid)
373 p->numthreads++;
374 }
375 }
376
377 kvm_close(kern);
378
379 return list;
380}
381
382#endif
383
384#if defined(__MacOS__)
385static Eina_List *
386_process_list_macos_get(void)
387{
388 Eina_List *list = NULL;
389
390 for (int i = 1; i <= PID_MAX; i++)
391 {
392 struct proc_taskallinfo taskinfo;
393 int size = proc_pidinfo(i, PROC_PIDTASKALLINFO, 0, &taskinfo, sizeof(taskinfo));
394 if (size != sizeof(taskinfo)) continue;
395
396 Proc_Stats *p = calloc(1, sizeof(Proc_Stats));
397 p->pid = i;
398 p->uid = taskinfo.pbsd.pbi_uid;
399 p->cpu_id = -1;
400 snprintf(p->command, sizeof(p->command), "%s", taskinfo.pbsd.pbi_comm);
401 p->cpu_time = taskinfo.ptinfo.pti_total_user + taskinfo.ptinfo.pti_total_system;
402 p->cpu_time /= 10000000;
403 p->state = _process_state_name(taskinfo.pbsd.pbi_status);
404 p->mem_size = taskinfo.ptinfo.pti_virtual_size;
405 p->mem_rss = taskinfo.ptinfo.pti_resident_size;
406 p->priority = taskinfo.ptinfo.pti_priority;
407 p->nice = taskinfo.pbsd.pbi_nice;
408 p->numthreads = taskinfo.ptinfo.pti_threadnum;
409
410 list = eina_list_append(list, p);
411 }
412
413 return list;
414}
415
416Proc_Stats *
417proc_info_by_pid(int pid)
418{
419 struct kinfo_proc kp;
420 struct proc_taskallinfo taskinfo;
421 struct proc_workqueueinfo workqueue;
422 size_t size;
423
424 size = proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, &taskinfo, sizeof(taskinfo));
425 if (size != sizeof(taskinfo))
426 return NULL;
427
428 size = proc_pidinfo(pid, PROC_PIDWORKQUEUEINFO, 0, &workqueue, sizeof(workqueue));
429 if (size != sizeof(workqueue))
430 return NULL;
431
432 Proc_Stats *p = calloc(1, sizeof(Proc_Stats));
433 p->pid = pid;
434 p->uid = taskinfo.pbsd.pbi_uid;
435 p->cpu_id = workqueue.pwq_nthreads;
436 snprintf(p->command, sizeof(p->command), "%s", taskinfo.pbsd.pbi_comm);
437 p->cpu_time = taskinfo.ptinfo.pti_total_user + taskinfo.ptinfo.pti_total_system;
438 p->cpu_time /= 10000000;
439 p->state = _process_state_name(taskinfo.pbsd.pbi_status);
440 p->mem_size = taskinfo.ptinfo.pti_virtual_size;
441 p->mem_rss = taskinfo.ptinfo.pti_resident_size;
442 p->priority = taskinfo.ptinfo.pti_priority;
443 p->nice = taskinfo.pbsd.pbi_nice;
444 p->numthreads = taskinfo.ptinfo.pti_threadnum;
445
446 return p;
447}
448
449#endif
450
451#if defined(__FreeBSD__) || defined(__DragonFly__)
452static Eina_List *
453_process_list_freebsd_get(void)
454{
455 Eina_List *list;
456 struct rusage *usage;
457 struct kinfo_proc kp;
458 int mib[4];
459 size_t len;
460 int pagesize = getpagesize();
461
462 list = NULL;
463
464 len = sizeof(int);
465 if (sysctlnametomib("kern.proc.pid", mib, &len) == -1)
466 return NULL;
467
468 for (int i = 1; i <= PID_MAX; i++)
469 {
470 mib[3] = i;
471 len = sizeof(kp);
472 if (sysctl(mib, 4, &kp, &len, NULL, 0) == -1)
473 {
474 continue;
475 }
476
477 if (kp.ki_flag & P_SYSTEM)
478 continue;
479
480 Proc_Stats *p = calloc(1, sizeof(Proc_Stats));
481
482 p->pid = kp.ki_pid;
483 p->uid = kp.ki_uid;
484 snprintf(p->command, sizeof(p->command), "%s", kp.ki_comm);
485 p->cpu_id = kp.ki_oncpu;
486 if (p->cpu_id == -1)
487 p->cpu_id = kp.ki_lastcpu;
488
489 usage = &kp.ki_rusage;
490
491 p->cpu_time = (usage->ru_utime.tv_sec * 1000000) + usage->ru_utime.tv_usec + (usage->ru_stime.tv_sec * 1000000) + usage->ru_stime.tv_usec;
492 p->cpu_time /= 10000;
493 p->state = _process_state_name(kp.ki_stat);
494 p->mem_size = kp.ki_size;
495 p->mem_rss = kp.ki_rssize * pagesize;
496 p->nice = kp.ki_nice - NZERO;
497 p->priority = kp.ki_pri.pri_level - PZERO;
498 p->numthreads = kp.ki_numthreads;
499
500 list = eina_list_append(list, p);
501 }
502
503 return list;
504}
505
506Proc_Stats *
507proc_info_by_pid(int pid)
508{
509 struct rusage *usage;
510 struct kinfo_proc kp;
511 int mib[4];
512 size_t len;
513 int pagesize = getpagesize();
514
515 len = sizeof(int);
516 if (sysctlnametomib("kern.proc.pid", mib, &len) == -1)
517 return NULL;
518
519 mib[3] = pid;
520
521 len = sizeof(kp);
522 if (sysctl(mib, 4, &kp, &len, NULL, 0) == -1)
523 return NULL;
524
525 Proc_Stats *p = calloc(1, sizeof(Proc_Stats));
526 p->pid = kp.ki_pid;
527 p->uid = kp.ki_uid;
528 snprintf(p->command, sizeof(p->command), "%s", kp.ki_comm);
529 p->cpu_id = kp.ki_oncpu;
530 if (p->cpu_id == -1)
531 p->cpu_id = kp.ki_lastcpu;
532
533 usage = &kp.ki_rusage;
534
535 p->cpu_time = (usage->ru_utime.tv_sec * 1000000) + usage->ru_utime.tv_usec + (usage->ru_stime.tv_sec * 1000000) + usage->ru_stime.tv_usec;
536 p->cpu_time /= 10000;
537 p->state = _process_state_name(kp.ki_stat);
538 p->mem_size = kp.ki_size;
539 p->mem_rss = kp.ki_rssize * pagesize;
540 p->nice = kp.ki_nice = NZERO;
541 p->priority = kp.ki_pri.pri_level - PZERO;
542 p->numthreads = kp.ki_numthreads;
543
544 return p;
545}
546
547#endif
548
549Eina_List *
550proc_info_all_get(void)
551{
552 Eina_List *processes;
553
554#if defined(__linux__)
555 processes = _process_list_linux_get();
556#elif defined(__FreeBSD__) || defined(__DragonFly__)
557 processes = _process_list_freebsd_get();
558#elif defined(__MacOS__)
559 processes = _process_list_macos_get();
560#elif defined(__OpenBSD__)
561 processes = _process_list_openbsd_get();
562#else
563 processes = NULL;
564#endif
565
566 return processes;
567}
568
diff --git a/src/process.h b/src/process.h
new file mode 100644
index 0000000..78c20fa
--- /dev/null
+++ b/src/process.h
@@ -0,0 +1,69 @@
1#ifndef __PROC_H__
2#define __PROC_H__
3
4/**
5 * @file
6 * @brief Routines for querying processes.
7 */
8
9/**
10 * @brief Querying Processes
11 * @defgroup Proc
12 *
13 * @{
14 *
15 * Query processes.
16 *
17 */
18
19#include <Eina.h>
20#include <stdint.h>
21#include <unistd.h>
22
23#if !defined(PID_MAX)
24# define PID_MAX 99999
25#endif
26
27#define CMD_NAME_MAX 256
28
29typedef struct _Proc_Stats
30{
31 pid_t pid;
32 uid_t uid;
33 int8_t nice;
34 int8_t priority;
35 int cpu_id;
36 int32_t numthreads;
37 int64_t mem_size;
38 int64_t mem_rss;
39 double cpu_usage;
40 char command[CMD_NAME_MAX];
41 const char *state;
42
43 // Not used yet in UI.
44 long cpu_time;
45} Proc_Stats;
46
47/**
48 * Query a full list of running processes and return a list.
49 *
50 * @return A list of proc_t members for all processes.
51 */
52Eina_List *
53proc_info_all_get(void);
54
55/**
56 * Query a process for its current state.
57 *
58 * @param pid The process ID to query.
59 *
60 * @return A proc_t pointer containing the process information.
61 */
62Proc_Stats *
63proc_info_by_pid(int pid);
64
65/**
66 * @}
67 */
68
69#endif
diff --git a/src/system.c b/src/system.c
new file mode 100644
index 0000000..86b0601
--- /dev/null
+++ b/src/system.c
@@ -0,0 +1,1184 @@
1/*
2 Copyright (c) 2017, Al Poole <netstar@gmail.com>
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 1. Redistributions of source code must retain the above copyright notice, this
9 list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright notice,
11 this list of conditions and the following disclaimer in the documentation
12 and/or other materials provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#define _DEFAULT_SOURCE
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <ctype.h>
31#include <stdbool.h>
32#include <stdint.h>
33#include <unistd.h>
34#include <dirent.h>
35#include <errno.h>
36#include <fcntl.h>
37#include <math.h>
38#include <sys/types.h>
39#include <sys/param.h>
40#include <sys/sysctl.h>
41#include <sys/ioctl.h>
42#include <sys/socket.h>
43#include <net/if.h>
44#include <pthread.h>
45
46#if defined(__APPLE__) && defined(__MACH__)
47#define __MacOS__
48# include <mach/mach.h>
49# include <mach/vm_statistics.h>
50# include <mach/mach_types.h>
51# include <mach/mach_init.h>
52# include <mach/mach_host.h>
53# include <net/if_mib.h>
54#endif
55
56#if defined(__OpenBSD__) || defined(__NetBSD__)
57# include <sys/swap.h>
58# include <sys/mount.h>
59# include <sys/sensors.h>
60# include <net/if_types.h>
61# include <ifaddrs.h>
62#endif
63
64#if defined(__FreeBSD__) || defined(__DragonFly__)
65# include <net/if_mib.h>
66# include <vm/vm_param.h>
67#endif
68
69#define CPU_STATES 5
70
71#define MAX_BATTERIES 5
72#define INVALID_TEMP -999
73
74/* Filter requests and results */
75#define RESULTS_CPU 0x01
76#define RESULTS_MEM 0x02
77#define RESULTS_PWR 0x04
78#define RESULTS_TMP 0x08
79#define RESULTS_AUD 0x10
80#define RESULTS_NET 0x20
81#define RESULTS_DEFAULT 0x3f
82#define RESULTS_MEM_MB 0x40
83#define RESULTS_MEM_GB 0x80
84#define RESULTS_CPU_CORES 0x100
85
86typedef struct
87{
88 float percent;
89 unsigned long total;
90 unsigned long idle;
91} cpu_core_t;
92
93typedef struct
94{
95 unsigned long total;
96 unsigned long used;
97 unsigned long cached;
98 unsigned long buffered;
99 unsigned long shared;
100 unsigned long swap_total;
101 unsigned long swap_used;
102} meminfo_t;
103
104typedef struct
105{
106 bool have_ac;
107 int battery_count;
108
109 double charge_full;
110 double charge_current;
111 uint8_t percent;
112
113 char battery_names[256];
114 int *bat_mibs[MAX_BATTERIES];
115 int ac_mibs[5];
116} power_t;
117
118typedef struct results_t results_t;
119struct results_t
120{
121 int cpu_count;
122 cpu_core_t **cores;
123
124 meminfo_t memory;
125
126 power_t power;
127
128 unsigned long incoming;
129 unsigned long outgoing;
130
131 int temperature;
132};
133
134static void
135_memsize_bytes_to_kb(unsigned long *bytes)
136{
137 *bytes = (unsigned int)*bytes >> 10;
138}
139
140#define _memsize_kb_to_mb _memsize_bytes_to_kb
141
142static void
143_memsize_kb_to_gb(unsigned long *bytes)
144{
145 *bytes = (unsigned int)*bytes >> 20;
146}
147
148#if defined(__linux__)
149static char *
150Fcontents(const char *path)
151{
152 char *buf;
153 char byte[1];
154 size_t count, bytes = 0;
155 FILE *f = fopen(path, "r");
156 if (!f) return NULL;
157
158 int n = 1024;
159
160 buf = malloc(n * sizeof(byte) + 1);
161 if (!buf) exit(0 << 1);
162
163 while ((count = (fread(byte, sizeof(byte), 1, f))) > 0)
164 {
165 bytes += sizeof(byte);
166 if (bytes == (n * sizeof(byte)))
167 {
168 n *= 2;
169 char *tmp = realloc(buf, n * sizeof(byte) + 1);
170 if (!tmp) exit(1 << 1);
171 buf = tmp;
172 }
173 memcpy(&buf[bytes - sizeof(byte)], byte, sizeof(byte));
174 }
175
176 if (!feof(f)) exit(2 << 1);
177 fclose(f);
178
179 buf[bytes] = 0;
180
181 return buf;
182}
183
184#endif
185
186#if defined(__FreeBSD__) || defined(__DragonFly__)
187static long int
188_sysctlfromname(const char *name, void *mib, int depth, size_t *len)
189{
190 long int result;
191
192 if (sysctlnametomib(name, mib, len) < 0)
193 return -1;
194
195 *len = sizeof(result);
196 if (sysctl(mib, depth, &result, len, NULL, 0) < 0)
197 return -1;
198
199 return result;
200}
201
202#endif
203
204static int
205cpu_count(void)
206{
207 int cores = 0;
208#if defined(__linux__)
209 char buf[4096];
210 FILE *f;
211 int line = 0;
212
213 f = fopen("/proc/stat", "r");
214 if (!f) return 0;
215
216 while (fgets(buf, sizeof(buf), f))
217 {
218 if (line)
219 {
220 if (!strncmp(buf, "cpu", 3))
221 cores++;
222 else
223 break;
224 }
225 line++;
226 }
227
228 fclose(f);
229#elif defined(__MacOS__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__NetBSD__)
230 size_t len;
231 int mib[2] = { CTL_HW, HW_NCPU };
232
233 len = sizeof(cores);
234 if (sysctl(mib, 2, &cores, &len, NULL, 0) < 0)
235 return 0;
236#endif
237 return cores;
238}
239
240static void
241_cpu_state_get(cpu_core_t **cores, int ncpu)
242{
243 int diff_total, diff_idle;
244 double ratio, percent;
245 unsigned long total, idle, used;
246 cpu_core_t *core;
247#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__NetBSD__)
248 size_t size;
249 int i, j;
250#endif
251#if defined(__FreeBSD__) || defined(__DragonFly__)
252 if (!ncpu)
253 return;
254 size = sizeof(unsigned long) * (CPU_STATES * ncpu);
255 unsigned long cpu_times[ncpu][CPU_STATES];
256
257 if (sysctlbyname("kern.cp_times", cpu_times, &size, NULL, 0) < 0)
258 return;
259
260 for (i = 0; i < ncpu; i++) {
261 core = cores[i];
262 unsigned long *cpu = cpu_times[i];
263
264 total = 0;
265 for (j = 0; j < CPU_STATES; j++)
266 total += cpu[j];
267
268 idle = cpu[4];
269
270 diff_total = total - core->total;
271 diff_idle = idle - core->idle;
272 if (diff_total == 0) diff_total = 1;
273
274 ratio = diff_total / 100.0;
275 used = diff_total - diff_idle;
276 percent = used / ratio;
277
278 if (percent > 100) percent = 100;
279 else if (percent < 0)
280 percent = 0;
281
282 core->percent = percent;
283 core->total = total;
284 core->idle = idle;
285 }
286#elif defined(__OpenBSD__)
287 unsigned long cpu_times[CPU_STATES];
288 if (!ncpu)
289 return;
290 if (ncpu == 1)
291 {
292 core = cores[0];
293 int cpu_time_mib[] = { CTL_KERN, KERN_CPTIME };
294 size = CPU_STATES * sizeof(unsigned long);
295 if (sysctl(cpu_time_mib, 2, &cpu_times, &size, NULL, 0) < 0)
296 return;
297
298 total = 0;
299 for (j = 0; j < CPU_STATES; j++)
300 total += cpu_times[j];
301
302 idle = cpu_times[4];
303
304 diff_total = total - core->total;
305 diff_idle = idle - core->idle;
306 if (diff_total == 0) diff_total = 1;
307
308 ratio = diff_total / 100.0;
309 used = diff_total - diff_idle;
310 percent = used / ratio;
311
312 if (percent > 100) percent = 100;
313 else if (percent < 0)
314 percent = 0;
315
316 core->percent = percent;
317 core->total = total;
318 core->idle = idle;
319 }
320 else if (ncpu > 1)
321 {
322 for (i = 0; i < ncpu; i++) {
323 core = cores[i];
324 int cpu_time_mib[] = { CTL_KERN, KERN_CPTIME2, 0 };
325 size = CPU_STATES * sizeof(unsigned long);
326 cpu_time_mib[2] = i;
327 if (sysctl(cpu_time_mib, 3, &cpu_times, &size, NULL, 0) < 0)
328 return;
329
330 total = 0;
331 for (j = 0; j < CPU_STATES; j++)
332 total += cpu_times[j];
333
334 idle = cpu_times[4];
335
336 diff_total = total - core->total;
337 if (diff_total == 0) diff_total = 1;
338
339 diff_idle = idle - core->idle;
340 ratio = diff_total / 100.0;
341 used = diff_total - diff_idle;
342 percent = used / ratio;
343
344 if (percent > 100) percent = 100;
345 else if (percent < 0)
346 percent = 0;
347
348 core->percent = percent;
349 core->total = total;
350 core->idle = idle;
351 }
352 }
353#elif defined(__linux__)
354 char *buf, name[128];
355 int i;
356
357 buf = Fcontents("/proc/stat");
358 if (!buf) return;
359
360 for (i = 0; i < ncpu; i++) {
361 core = cores[i];
362 snprintf(name, sizeof(name), "cpu%d", i);
363 char *line = strstr(buf, name);
364 if (line)
365 {
366 line = strchr(line, ' ') + 1;
367 unsigned long cpu_times[4] = { 0 };
368
369 if (4 != sscanf(line, "%lu %lu %lu %lu", &cpu_times[0], &cpu_times[1], &cpu_times[2], &cpu_times[3]))
370 return;
371
372 total = cpu_times[0] + cpu_times[1] + cpu_times[2] + cpu_times[3];
373 idle = cpu_times[3];
374 diff_total = total - core->total;
375 if (diff_total == 0) diff_total = 1;
376
377 diff_idle = idle - core->idle;
378 ratio = diff_total / 100.0;
379 used = diff_total - diff_idle;
380 percent = used / ratio;
381
382 if (percent > 100) percent = 100;
383 else if (percent < 0)
384 percent = 0;
385
386 core->percent = percent;
387 core->total = total;
388 core->idle = idle;
389 }
390 }
391 free(buf);
392#elif defined(__MacOS__)
393 mach_msg_type_number_t count;
394 processor_cpu_load_info_t load;
395 mach_port_t mach_port;
396 unsigned int cpu_count;
397 int i;
398
399 cpu_count = ncpu;
400
401 count = HOST_CPU_LOAD_INFO_COUNT;
402 mach_port = mach_host_self();
403 if (host_processor_info(mach_port, PROCESSOR_CPU_LOAD_INFO, &cpu_count, (processor_info_array_t *)&load, &count) != KERN_SUCCESS)
404 exit(4 << 1);
405
406 for (i = 0; i < ncpu; i++) {
407 core = cores[i];
408
409 total = load[i].cpu_ticks[CPU_STATE_USER] + load[i].cpu_ticks[CPU_STATE_SYSTEM] + load[i].cpu_ticks[CPU_STATE_IDLE] + load[i].cpu_ticks[CPU_STATE_NICE];
410 idle = load[i].cpu_ticks[CPU_STATE_IDLE];
411
412 diff_total = total - core->total;
413 if (diff_total == 0) diff_total = 1;
414 diff_idle = idle - core->idle;
415 ratio = diff_total / 100.0;
416 used = diff_total - diff_idle;
417 percent = used / ratio;
418
419 if (percent > 100) percent = 100;
420 else if (percent < 0)
421 percent = 0;
422
423 core->percent = percent;
424 core->total = total;
425 core->idle = idle;
426 }
427#endif
428}
429
430static cpu_core_t **
431_cpu_cores_state_get(int *ncpu)
432{
433 cpu_core_t **cores;
434 int i;
435
436 *ncpu = cpu_count();
437
438 cores = malloc((*ncpu) * sizeof(cpu_core_t *));
439
440 for (i = 0; i < *ncpu; i++)
441 cores[i] = calloc(1, sizeof(cpu_core_t));
442
443 _cpu_state_get(cores, *ncpu);
444 usleep(1000000);
445 _cpu_state_get(cores, *ncpu);
446
447 return cores;
448}
449
450#if defined(__linux__)
451static unsigned long
452_meminfo_parse_line(const char *line)
453{
454 char *p, *tok;
455
456 p = strchr(line, ':') + 1;
457 while (isspace(*p))
458 p++;
459 tok = strtok(p, " ");
460
461 return atol(tok);
462}
463
464#endif
465
466static void
467_memory_usage_get(meminfo_t *memory)
468{
469#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
470 size_t len = 0;
471 int i = 0;
472#endif
473 memset(memory, 0, sizeof(meminfo_t));
474#if defined(__linux__)
475 FILE *f;
476 unsigned long swap_free = 0, tmp_free = 0, tmp_slab = 0;
477 char line[256];
478 int fields = 0;
479
480 f = fopen("/proc/meminfo", "r");
481 if (!f) return;
482
483 while (fgets(line, sizeof(line), f) != NULL)
484 {
485 if (!strncmp("MemTotal:", line, 9))
486 {
487 memory->total = _meminfo_parse_line(line);
488 fields++;
489 }
490 else if (!strncmp("MemFree:", line, 8))
491 {
492 tmp_free = _meminfo_parse_line(line);
493 fields++;
494 }
495 else if (!strncmp("Cached:", line, 7))
496 {
497 memory->cached = _meminfo_parse_line(line);
498 fields++;
499 }
500 else if (!strncmp("Slab:", line, 5))
501 {
502 tmp_slab = _meminfo_parse_line(line);
503 fields++;
504 }
505 else if (!strncmp("Buffers:", line, 8))
506 {
507 memory->buffered = _meminfo_parse_line(line);
508 fields++;
509 }
510 else if (!strncmp("Shmem:", line, 6))
511 {
512 memory->shared = _meminfo_parse_line(line);
513 fields++;
514 }
515 else if (!strncmp("SwapTotal:", line, 10))
516 {
517 memory->swap_total = _meminfo_parse_line(line);
518 fields++;
519 }
520 else if (!strncmp("SwapFree:", line, 9))
521 {
522 swap_free = _meminfo_parse_line(line);
523 fields++;
524 }
525
526 if (fields >= 8)
527 break;
528 }
529
530 memory->cached += tmp_slab;
531 memory->used = memory->total - tmp_free - memory->cached - memory->buffered;
532 memory->swap_used = memory->swap_total = swap_free;
533
534 fclose(f);
535#elif defined(__FreeBSD__) || defined(__DragonFly__)
536 int total_pages = 0, free_pages = 0, inactive_pages = 0;
537 long int result = 0;
538 int page_size = getpagesize();
539 int mib[4] = { CTL_HW, HW_PHYSMEM, 0, 0 };
540
541 len = sizeof(memory->total);
542 if (sysctl(mib, 2, &memory->total, &len, NULL, 0) == -1)
543 return;
544 memory->total /= 1024;
545
546 total_pages =
547 _sysctlfromname("vm.stats.vm.v_page_count", mib, 4, &len);
548 if (total_pages < 0)
549 return;
550
551 free_pages = _sysctlfromname("vm.stats.vm.v_free_count", mib, 4, &len);
552 if (free_pages < 0)
553 return;
554
555 inactive_pages =
556 _sysctlfromname("vm.stats.vm.v_inactive_count", mib, 4, &len);
557 if (inactive_pages < 0)
558 return;
559
560 memory->used = (total_pages - free_pages - inactive_pages) * page_size;
561 _memsize_bytes_to_kb(&memory->used);
562
563 result = _sysctlfromname("vfs.bufspace", mib, 2, &len);
564 if (result < 0)
565 return;
566 memory->buffered = (result);
567 _memsize_bytes_to_kb(&memory->buffered);
568
569 result = _sysctlfromname("vm.stats.vm.v_active_count", mib, 4, &len);
570 if (result < 0)
571 return;
572 memory->cached = (result * page_size);
573 _memsize_bytes_to_kb(&memory->cached);
574
575 result = _sysctlfromname("vm.stats.vm.v_cache_count", mib, 4, &len);
576 if (result < 0)
577 return;
578 memory->shared = (result * page_size);
579 _memsize_bytes_to_kb(&memory->shared);
580
581 result = _sysctlfromname("vm.swap_total", mib, 2, &len);
582 if (result < 0)
583 return;
584 memory->swap_total = (result / 1024);
585
586 struct xswdev xsw;
587 /* previous mib is important for this one... */
588
589 while (i++)
590 {
591 mib[2] = i;
592 len = sizeof(xsw);
593 if (sysctl(mib, 3, &xsw, &len, NULL, 0) == -1)
594 break;
595
596 memory->swap_used += xsw.xsw_used * page_size;
597 }
598
599 memory->swap_used >>= 10;
600
601#elif defined(__OpenBSD__)
602 static int mib[] = { CTL_HW, HW_PHYSMEM64 };
603 static int bcstats_mib[] = { CTL_VFS, VFS_GENERIC, VFS_BCACHESTAT };
604 struct bcachestats bcstats;
605 static int uvmexp_mib[] = { CTL_VM, VM_UVMEXP };
606 struct uvmexp uvmexp;
607 int nswap, rnswap;
608 struct swapent *swdev = NULL;
609
610 len = sizeof(memory->total);
611 if (sysctl(mib, 2, &memory->total, &len, NULL, 0) == -1)
612 return;
613
614 len = sizeof(uvmexp);
615 if (sysctl(uvmexp_mib, 2, &uvmexp, &len, NULL, 0) == -1)
616 return;
617
618 len = sizeof(bcstats);
619 if (sysctl(bcstats_mib, 3, &bcstats, &len, NULL, 0) == -1)
620 return;
621
622 /* Don't fail if there's not swap! */
623 nswap = swapctl(SWAP_NSWAP, 0, 0);
624 if (nswap == 0)
625 goto swap_out;
626
627 swdev = calloc(nswap, sizeof(*swdev));
628 if (swdev == NULL)
629 goto swap_out;
630
631 rnswap = swapctl(SWAP_STATS, swdev, nswap);
632 if (rnswap == -1)
633 goto swap_out;
634
635 for (i = 0; i < nswap; i++) {
636 if (swdev[i].se_flags & SWF_ENABLE)
637 {
638 memory->swap_used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
639 memory->swap_total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
640 }
641 }
642swap_out:
643 if (swdev)
644 free(swdev);
645
646 memory->total /= 1024;
647
648 memory->cached = (uvmexp.pagesize * bcstats.numbufpages);
649 _memsize_bytes_to_kb(&memory->cached);
650
651 memory->used = (uvmexp.active * uvmexp.pagesize);
652 _memsize_bytes_to_kb(&memory->used);
653
654 memory->buffered = (uvmexp.pagesize * (uvmexp.npages - uvmexp.free));
655 _memsize_bytes_to_kb(&memory->buffered);
656
657 memory->shared = (uvmexp.pagesize * uvmexp.wired);
658 _memsize_bytes_to_kb(&memory->shared);
659#elif defined(__MacOS__)
660 int mib[2] = { CTL_HW, HW_MEMSIZE };
661 size_t total;
662 vm_size_t page_size;
663 mach_port_t mach_port;
664 mach_msg_type_number_t count;
665 vm_statistics64_data_t vm_stats;
666 struct xsw_usage xsu;
667
668 size_t len = sizeof(size_t);
669 if (sysctl(mib, 2, &total, &len, NULL, 0) == -1)
670 return;
671 mach_port = mach_host_self();
672 count = sizeof(vm_stats) / sizeof(natural_t);
673
674 total >>= 10;
675 memory->total = total;
676
677 if (host_page_size(mach_port, &page_size) == KERN_SUCCESS &&
678 host_statistics64(mach_port, HOST_VM_INFO, (host_info64_t)&vm_stats, &count) == KERN_SUCCESS)
679 {
680 memory->used = vm_stats.active_count + vm_stats.inactive_count + vm_stats.wire_count * page_size;
681 memory->used >>= 10;
682 memory->cached = vm_stats.active_count * page_size;
683 memory->cached >>= 10;
684 memory->shared = vm_stats.wire_count * page_size;
685 memory->shared >>= 10;
686 memory->buffered = vm_stats.inactive_count * page_size;
687 memory->buffered >>= 10;
688 }
689
690 total = sizeof(xsu);
691 if (sysctlbyname("vm.swapusage", &xsu, &total, NULL, 0) != -1)
692 {
693 memory->swap_total = xsu.xsu_total;
694 memory->swap_used = xsu.xsu_used;
695 }
696#endif
697}
698
699static void
700_temperature_cpu_get(int *temperature)
701{
702#if defined(__OpenBSD__) || defined(__NetBSD__)
703 int mibs[5] = { CTL_HW, HW_SENSORS, 0, 0, 0 };
704 int devn, numt;
705 struct sensor snsr;
706 size_t slen = sizeof(struct sensor);
707 struct sensordev snsrdev;
708 size_t sdlen = sizeof(struct sensordev);
709
710 for (devn = 0;; devn++) {
711 mibs[2] = devn;
712
713 if (sysctl(mibs, 3, &snsrdev, &sdlen, NULL, 0) == -1)
714 {
715 if (errno == ENOENT)
716 break;
717 else
718 continue;
719 }
720 if (!strcmp("cpu0", snsrdev.xname))
721 break;
722 else if (!strcmp("km0", snsrdev.xname))
723 break;
724 }
725
726 for (numt = 0; numt < snsrdev.maxnumt[SENSOR_TEMP]; numt++) {
727 mibs[4] = numt;
728
729 if (sysctl(mibs, 5, &snsr, &slen, NULL, 0) == -1)
730 continue;
731
732 if (slen > 0 && (snsr.flags & SENSOR_FINVALID) == 0)
733 break;
734 }
735
736 if (sysctl(mibs, 5, &snsr, &slen, NULL, 0)
737 != -1)
738 {
739 *temperature = (snsr.value - 273150000) / 1000000.0;
740 }
741 else
742 *temperature = INVALID_TEMP;
743#elif defined(__FreeBSD__) || defined(__DragonFly__)
744 unsigned int value;
745 size_t len = sizeof(value);
746 if ((sysctlbyname
747 ("hw.acpi.thermal.tz0.temperature", &value, &len, NULL,
748 0)) != -1)
749 {
750 *temperature = (value - 2732) / 10;
751 }
752 else
753 *temperature = INVALID_TEMP;
754#elif defined(__linux__)
755 struct dirent *dh;
756 DIR *dir;
757 char path[PATH_MAX];
758
759 *temperature = INVALID_TEMP;
760
761 dir = opendir("/sys/class/thermal");
762 if (!dir) return;
763
764 while ((dh = readdir(dir)) != NULL)
765 {
766 if (!strncmp(dh->d_name, "thermal_zone", 12))
767 {
768 snprintf(path, sizeof(path), "/sys/class/thermal/%s/type", dh->d_name);
769 char *type = Fcontents(path);
770 if (type)
771 {
772 /* This should ensure we get the highest available core temperature */
773 if (strstr(type, "_pkg_temp"))
774 {
775 snprintf(path, sizeof(path), "/sys/class/thermal/%s/temp", dh->d_name);
776 char *value = Fcontents(path);
777 if (value)
778 {
779 *temperature = atoi(value) / 1000;
780 free(value);
781 free(type);
782 break;
783 }
784 }
785 free(type);
786 }
787 }
788 }
789
790 closedir(dir);
791#elif defined(__MacOS__)
792 *temperature = INVALID_TEMP;
793#endif
794}
795
796static int
797_power_battery_count_get(power_t *power)
798{
799#if defined(__OpenBSD__) || defined(__NetBSD__)
800 struct sensordev snsrdev;
801 size_t sdlen = sizeof(struct sensordev);
802 int mib[5] = { CTL_HW, HW_SENSORS, 0, 0, 0 };
803 int i, devn;
804 for (devn = 0;; devn++) {
805 mib[2] = devn;
806 if (sysctl(mib, 3, &snsrdev, &sdlen, NULL, 0) == -1)
807 {
808 if (errno == ENXIO)
809 continue;
810 if (errno == ENOENT)
811 break;
812 }
813
814 for (i = 0; i < MAX_BATTERIES; i++) {
815 char buf[64];
816 snprintf(buf, sizeof(buf), "acpibat%d", i);
817 if (!strcmp(buf, snsrdev.xname))
818 {
819 power->bat_mibs[power->battery_count] =
820 malloc(sizeof(int) * 5);
821 int *tmp = power->bat_mibs[power->battery_count++];
822 tmp[0] = mib[0];
823 tmp[1] = mib[1];
824 tmp[2] = mib[2];
825 }
826 }
827
828 if (!strcmp("acpiac0", snsrdev.xname))
829 {
830 power->ac_mibs[0] = mib[0];
831 power->ac_mibs[1] = mib[1];
832 power->ac_mibs[2] = mib[2];
833 }
834 }
835#elif defined(__FreeBSD__) || defined(__DragonFly__)
836 size_t len;
837 if ((sysctlbyname("hw.acpi.battery.life", NULL, &len, NULL, 0)) != -1)
838 {
839 power->bat_mibs[power->battery_count] = malloc(sizeof(int) * 5);
840 sysctlnametomib("hw.acpi.battery.life",
841 power->bat_mibs[power->battery_count], &len);
842 power->battery_count = 1;
843 }
844
845 if ((sysctlbyname("hw.acpi.acline", NULL, &len, NULL, 0)) != -1)
846 {
847 sysctlnametomib("hw.acpi.acline", power->ac_mibs, &len);
848 }
849#elif defined(__linux__)
850 struct dirent *dh;
851 DIR *dir;
852
853 dir = opendir("/sys/class/power_supply");
854 if (!dir) return 0;
855
856 while ((dh = readdir(dir)) != NULL)
857 {
858 if (dh->d_name[0] == '.') continue;
859 if (!strncmp(dh->d_name, "BAT", 3))
860 {
861 power->battery_names[power->battery_count++] = (char)dh->d_name[3];
862 }
863 }
864
865 closedir(dir);
866#endif
867 return power->battery_count;
868}
869
870static void
871_battery_state_get(power_t *power, int *mib)
872{
873#if defined(__OpenBSD__) || defined(__NetBSD__)
874 double charge_full = 0;
875 double charge_current = 0;
876 size_t slen = sizeof(struct sensor);
877 struct sensor snsr;
878
879 mib[3] = 7;
880 mib[4] = 0;
881
882 if (sysctl(mib, 5, &snsr, &slen, NULL, 0) != -1)
883 charge_full = (double)snsr.value;
884
885 mib[3] = 7;
886 mib[4] = 3;
887
888 if (sysctl(mib, 5, &snsr, &slen, NULL, 0) != -1)
889 charge_current = (double)snsr.value;
890
891 /* ACPI bug workaround... */
892 if (charge_current == 0 || charge_full == 0)
893 {
894 mib[3] = 8;
895 mib[4] = 0;
896
897 if (sysctl(mib, 5, &snsr, &slen, NULL, 0) != -1)
898 charge_full = (double)snsr.value;
899
900 mib[3] = 8;
901 mib[4] = 3;
902
903 if (sysctl(mib, 5, &snsr, &slen, NULL, 0) != -1)
904 charge_current = (double)snsr.value;
905 }
906
907 power->charge_full += charge_full;
908 power->charge_current += charge_current;
909#elif defined(__FreeBSD__) || defined(__DragonFly__)
910 unsigned int value;
911 size_t len = sizeof(value);
912 if ((sysctl(mib, 4, &value, &len, NULL, 0)) != -1)
913 power->percent = value;
914#elif defined(__linux__)
915 char path[PATH_MAX];
916 struct dirent *dh;
917 DIR *dir;
918 char *buf, *naming = NULL;
919 int i = 0;
920 unsigned long charge_full = 0;
921 unsigned long charge_current = 0;
922
923 while (power->battery_names[i] != '\0')
924 {
925 snprintf(path, sizeof(path), "/sys/class/power_supply/BAT%c", power->battery_names[i]);
926 dir = opendir(path);
927 if (!dir) return;
928 while ((dh = readdir(dir)) != NULL)
929 {
930 if (!strcmp(dh->d_name, "energy_full"))
931 {
932 naming = "energy"; break;
933 }
934 else if (!strcmp(dh->d_name, "capacity_full"))
935 {
936 naming = "capacity"; break;
937 }
938 }
939 closedir(dir);
940 if (!naming) continue;
941 snprintf(path, sizeof(path), "/sys/class/power_supply/BAT%c/%s_full", power->battery_names[i], naming);
942 buf = Fcontents(path);
943 if (buf)
944 {
945 charge_full = atol(buf);
946 free(buf);
947 }
948 snprintf(path, sizeof(path), "/sys/class/power_supply/BAT%c/%s_now", power->battery_names[i], naming);
949 buf = Fcontents(path);
950 if (buf)
951 {
952 charge_current = atol(buf);
953 free(buf);
954 }
955 power->charge_full += charge_full;
956 power->charge_current += charge_current;
957 naming = NULL;
958 i++;
959 }
960#endif
961}
962
963static void
964_power_state_get(power_t *power)
965{
966 int i;
967#if defined(__OpenBSD__) || defined(__NetBSD__)
968 struct sensor snsr;
969 int have_ac = 0;
970 size_t slen = sizeof(struct sensor);
971#elif defined(__FreeBSD__) || defined(__DragonFly__)
972 unsigned int value;
973 size_t len;
974#elif defined(__linux__)
975 char *buf;
976 int have_ac = 0;
977#endif
978
979#if defined(__OpenBSD__) || defined(__NetBSD__)
980 power->ac_mibs[3] = 9;
981 power->ac_mibs[4] = 0;
982
983 if (sysctl(power->ac_mibs, 5, &snsr, &slen, NULL, 0) != -1)
984 have_ac = (int)snsr.value;
985#elif defined(__FreeBSD__) || defined(__DragonFly__)
986 len = sizeof(value);
987 if ((sysctl(power->ac_mibs, 3, &value, &len, NULL, 0)) == -1)
988 {
989 return;
990 }
991 power->have_ac = value;
992#elif defined(__linux__)
993 buf = Fcontents("/sys/class/power_supply/AC/online");
994 if (buf)
995 {
996 have_ac = atoi(buf);
997 free(buf);
998 }
999#endif
1000
1001 for (i = 0; i < power->battery_count; i++)
1002 _battery_state_get(power, power->bat_mibs[i]);
1003
1004#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__linux__)
1005 double percent =
1006 100 * (power->charge_current / power->charge_full);
1007
1008 power->percent = percent;
1009 power->have_ac = have_ac;
1010#elif defined(__FreeBSD__) || defined(__DragonFly__)
1011 len = sizeof(value);
1012 if ((sysctl(power->bat_mibs[0], 4, &value, &len, NULL, 0)) == -1)
1013 {
1014 return;
1015 }
1016
1017 power->percent = value;
1018
1019#endif
1020 for (i = 0; i < power->battery_count; i++)
1021 if (power->bat_mibs[i]) free(power->bat_mibs[i]);
1022}
1023
1024#if defined(__MacOS__) || defined(__FreeBSD__) || defined(__DragonFly__)
1025static void
1026_freebsd_generic_network_status(unsigned long int *in,
1027 unsigned long int *out)
1028{
1029 struct ifmibdata *ifmd;
1030 size_t len;
1031 int i, count;
1032 len = sizeof(count);
1033
1034 if (sysctlbyname
1035 ("net.link.generic.system.ifcount", &count, &len, NULL, 0) < 0)
1036 return;
1037
1038 ifmd = malloc(sizeof(struct ifmibdata));
1039 if (!ifmd)
1040 return;
1041
1042 for (i = 1; i <= count; i++) {
1043 int mib[] = { CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_IFDATA, i, IFDATA_GENERAL };
1044 len = sizeof(*ifmd);
1045 if (sysctl(mib, 6, ifmd, &len, NULL, 0) < 0) continue;
1046 if (!strcmp(ifmd->ifmd_name, "lo0"))
1047 continue;
1048 *in += ifmd->ifmd_data.ifi_ibytes;
1049 *out += ifmd->ifmd_data.ifi_obytes;
1050 }
1051 free(ifmd);
1052}
1053
1054#endif
1055
1056#if defined(__OpenBSD__)
1057static void
1058_openbsd_generic_network_status(unsigned long int *in,
1059 unsigned long int *out)
1060{
1061 struct ifaddrs *interfaces, *ifa;
1062
1063 if (getifaddrs(&interfaces) < 0)
1064 return;
1065
1066 int sock = socket(AF_INET, SOCK_STREAM, 0);
1067 if (sock < 0)
1068 return;
1069
1070 for (ifa = interfaces; ifa; ifa = ifa->ifa_next) {
1071 struct ifreq ifreq;
1072 struct if_data if_data;
1073
1074 ifreq.ifr_data = (void *)&if_data;
1075 strncpy(ifreq.ifr_name, ifa->ifa_name, IFNAMSIZ - 1);
1076 if (ioctl(sock, SIOCGIFDATA, &ifreq) < 0)
1077 return;
1078
1079 struct if_data *const ifi = &if_data;
1080 if (ifi->ifi_type == IFT_ETHER ||
1081 ifi->ifi_type == IFT_FASTETHER ||
1082 ifi->ifi_type == IFT_GIGABITETHERNET ||
1083 ifi->ifi_type == IFT_IEEE80211)
1084 {
1085 if (ifi->ifi_ibytes)
1086 *in += ifi->ifi_ibytes;
1087
1088 if (ifi->ifi_obytes)
1089 *out += ifi->ifi_obytes;
1090 }
1091 }
1092 close(sock);
1093}
1094
1095#endif
1096
1097#if defined(__linux__)
1098static void
1099_linux_generic_network_status(unsigned long int *in,
1100 unsigned long int *out)
1101{
1102 FILE *f;
1103 char buf[4096], dummy_s[256];
1104 unsigned long int tmp_in, tmp_out, dummy;
1105
1106 f = fopen("/proc/net/dev", "r");
1107 if (!f) return;
1108
1109 while (fgets(buf, sizeof(buf), f))
1110 {
1111 if (17 == sscanf(buf, "%s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu "
1112 "%lu %lu %lu %lu\n", dummy_s, &tmp_in, &dummy, &dummy,
1113 &dummy, &dummy, &dummy, &dummy, &dummy, &tmp_out, &dummy,
1114 &dummy, &dummy, &dummy, &dummy, &dummy, &dummy))
1115 {
1116 *in += tmp_in;
1117 *out += tmp_out;
1118 }
1119 }
1120
1121 fclose(f);
1122}
1123
1124#endif
1125
1126static void
1127_network_transfer_get(results_t *results)
1128{
1129 unsigned long first_in = 0, first_out = 0;
1130 unsigned long last_in = 0, last_out = 0;
1131#if defined(__linux__)
1132 _linux_generic_network_status(&first_in, &first_out);
1133 usleep(1000000);
1134 _linux_generic_network_status(&last_in, &last_out);
1135#elif defined(__OpenBSD__)
1136 _openbsd_generic_network_status(&first_in, &first_out);
1137 usleep(1000000);
1138 _openbsd_generic_network_status(&last_in, &last_out);
1139#elif defined(__MacOS__) || defined(__FreeBSD__) || defined(__DragonFly__)
1140 _freebsd_generic_network_status(&first_in, &first_out);
1141 usleep(1000000);
1142 _freebsd_generic_network_status(&last_in, &last_out);
1143#endif
1144 results->incoming = last_in - first_in;
1145 results->outgoing = last_out - first_out;
1146}
1147
1148static double
1149_results_cpu(cpu_core_t **cores, int cpu_count)
1150{
1151 double total = 0;
1152 for (int i = 0; i < cpu_count; i++)
1153 total += cores[i]->percent;
1154
1155 total = total / cpu_count;
1156
1157 return total;
1158}
1159
1160int
1161system_cpu_memory_get(double *percent_cpu, long *memory_total, long *memory_used)
1162{
1163 results_t results;
1164
1165 memset(&results, 0, sizeof(results));
1166
1167 results.cores = _cpu_cores_state_get(&results.cpu_count);
1168
1169 _memory_usage_get(&results.memory);
1170
1171 *percent_cpu = _results_cpu(results.cores, results.cpu_count);
1172 *memory_total = results.memory.total;
1173 *memory_used = results.memory.used;
1174
1175 for (int i = 0; i < results.cpu_count; i++)
1176 {
1177 free(results.cores[i]);
1178 }
1179
1180 free(results.cores);
1181
1182 return results.cpu_count;
1183}
1184
diff --git a/src/system.h b/src/system.h
new file mode 100644
index 0000000..9491aa0
--- /dev/null
+++ b/src/system.h
@@ -0,0 +1,7 @@
1#ifndef __SYSTEM_H__
2#define __SYSTEM_H__
3
4int
5system_cpu_memory_get(double *percent_cpu, long *memory_total, long *memory_used);
6
7#endif
diff --git a/src/ui.c b/src/ui.c
new file mode 100644
index 0000000..264b854
--- /dev/null
+++ b/src/ui.c
@@ -0,0 +1,1401 @@
1#include "system.h"
2#include "process.h"
3#include "ui.h"
4#include <stdio.h>
5#include <sys/types.h>
6#include <pwd.h>
7
8#if defined(__APPLE__) && defined(__MACH__)
9# define __MacOS__
10#endif
11
12static Eina_Lock _lock;
13
14static long _memory_total = 0;
15static long _memory_used = 0;
16
17static void
18_system_stats(void *data, Ecore_Thread *thread)
19{
20 Ui *ui;
21 Sys_Stats *sys;
22 int i;
23
24 ui = data;
25
26 while (1)
27 {
28 sys = malloc(sizeof(Sys_Stats));
29 sys->cpu_count = system_cpu_memory_get(&sys->cpu_usage, &sys->mem_total, &sys->mem_used);
30
31 ecore_thread_feedback(thread, sys);
32
33 for (i = 0; i < ui->poll_delay * 2; i++)
34 {
35 if (ecore_thread_check(thread))
36 return;
37
38 usleep(500000);
39 }
40 }
41}
42
43static void
44_system_stats_feedback_cb(void *data, Ecore_Thread *thread, void *msg)
45{
46 Ui *ui;
47 Sys_Stats *sys;
48
49 ui = data;
50 sys = msg;
51
52 if (ecore_thread_check(thread))
53 goto out;
54
55 _memory_total = sys->mem_total >>= 10;
56 _memory_used = sys->mem_used >>= 10;
57
58 elm_progressbar_value_set(ui->progress_cpu, (double)sys->cpu_usage / 100);
59 elm_progressbar_value_set(ui->progress_mem, (double)((sys->mem_total / 100.0) * sys->mem_used) / 1000000);
60
61out:
62 free(sys);
63}
64
65static int
66_sort_by_pid(const void *p1, const void *p2)
67{
68 const Proc_Stats *inf1, *inf2;
69
70 inf1 = p1; inf2 = p2;
71
72 return inf1->pid - inf2->pid;
73}
74
75static int
76_sort_by_uid(const void *p1, const void *p2)
77{
78 const Proc_Stats *inf1, *inf2;
79
80 inf1 = p1; inf2 = p2;
81
82 return inf1->uid - inf2->uid;
83}
84
85static int
86_sort_by_nice(const void *p1, const void *p2)
87{
88 const Proc_Stats *inf1, *inf2;
89
90 inf1 = p1; inf2 = p2;
91
92 return inf1->nice - inf2->nice;
93}
94
95static int
96_sort_by_pri(const void *p1, const void *p2)
97{
98 const Proc_Stats *inf1, *inf2;
99
100 inf1 = p1; inf2 = p2;
101
102 return inf1->priority - inf2->priority;
103}
104
105static int
106_sort_by_cpu(const void *p1, const void *p2)
107{
108 const Proc_Stats *inf1, *inf2;
109
110 inf1 = p1; inf2 = p2;
111
112 return inf1->cpu_id - inf2->cpu_id;
113}
114
115static int
116_sort_by_threads(const void *p1, const void *p2)
117{
118 const Proc_Stats *inf1, *inf2;
119
120 inf1 = p1; inf2 = p2;
121
122 return inf1->numthreads - inf2->numthreads;
123}
124
125static int
126_sort_by_size(const void *p1, const void *p2)
127{
128 const Proc_Stats *inf1, *inf2;
129 int64_t size1, size2;
130
131 inf1 = p1; inf2 = p2;
132
133 size1 = inf1->mem_size;
134 size2 = inf2->mem_size;
135
136 if (size1 < size2)
137 return -1;
138 if (size2 > size1)
139 return 1;
140
141 return 0;
142}
143
144static int
145_sort_by_rss(const void *p1, const void *p2)
146{
147 const Proc_Stats *inf1, *inf2;
148 int64_t size1, size2;
149
150 inf1 = p1; inf2 = p2;
151
152 size1 = inf1->mem_rss;
153 size2 = inf2->mem_rss;
154
155 if (size1 < size2)
156 return -1;
157 if (size2 > size1)
158 return 1;
159
160 return 0;
161}
162
163static int
164_sort_by_cpu_usage(const void *p1, const void *p2)
165{
166 const Proc_Stats *inf1, *inf2;
167 double one, two;
168
169 inf1 = p1; inf2 = p2;
170
171 one = inf1->cpu_usage;
172 two = inf2->cpu_usage;
173
174 if (one < two)
175 return -1;
176 if (two > one)
177 return 1;
178
179 return 0;
180}
181
182static int
183_sort_by_cmd(const void *p1, const void *p2)
184{
185 const Proc_Stats *inf1, *inf2;
186
187 inf1 = p1; inf2 = p2;
188
189 return strcasecmp(inf1->command, inf2->command);
190}
191
192static int
193_sort_by_state(const void *p1, const void *p2)
194{
195 const Proc_Stats *inf1, *inf2;
196
197 inf1 = p1; inf2 = p2;
198
199 return strcmp(inf1->state, inf2->state);
200}
201
202static void
203_fields_append(Ui *ui, Proc_Stats *proc)
204{
205 // FIXME: hiding self from the list until more efficient.
206 // It's not too bad but it pollutes a lovely list.
207 if (ui->program_pid == proc->pid)
208 return;
209
210 eina_strlcat(ui->fields[PROCESS_INFO_FIELD_PID], eina_slstr_printf("<link>%d</link> <br>", proc->pid), TEXT_FIELD_MAX);
211 eina_strlcat(ui->fields[PROCESS_INFO_FIELD_UID], eina_slstr_printf("%d <br>", proc->uid), TEXT_FIELD_MAX);
212 eina_strlcat(ui->fields[PROCESS_INFO_FIELD_SIZE], eina_slstr_printf("%lld K<br>", proc->mem_size >> 10), TEXT_FIELD_MAX);
213 eina_strlcat(ui->fields[PROCESS_INFO_FIELD_RSS], eina_slstr_printf("%lld K<br>", proc->mem_rss >> 10), TEXT_FIELD_MAX);
214 eina_strlcat(ui->fields[PROCESS_INFO_FIELD_COMMAND], eina_slstr_printf("%s<br>", proc->command), TEXT_FIELD_MAX);
215 eina_strlcat(ui->fields[PROCESS_INFO_FIELD_STATE], eina_slstr_printf("%s <br>", proc->state), TEXT_FIELD_MAX);
216 eina_strlcat(ui->fields[PROCESS_INFO_FIELD_CPU_USAGE], eina_slstr_printf("%.1f%% <br>", proc->cpu_usage), TEXT_FIELD_MAX);
217}
218
219static void
220_fields_show(Ui *ui)
221{
222 elm_object_text_set(ui->entry_pid, ui->fields[PROCESS_INFO_FIELD_PID]);
223 elm_object_text_set(ui->entry_uid, ui->fields[PROCESS_INFO_FIELD_UID]);
224 elm_object_text_set(ui->entry_size, ui->fields[PROCESS_INFO_FIELD_SIZE]);
225 elm_object_text_set(ui->entry_rss, ui->fields[PROCESS_INFO_FIELD_RSS]);
226 elm_object_text_set(ui->entry_cmd, ui->fields[PROCESS_INFO_FIELD_COMMAND]);
227 elm_object_text_set(ui->entry_state, ui->fields[PROCESS_INFO_FIELD_STATE]);
228 elm_object_text_set(ui->entry_cpu_usage, ui->fields[PROCESS_INFO_FIELD_CPU_USAGE]);
229}
230
231static void
232_fields_clear(Ui *ui)
233{
234 for (int i = 0; i < PROCESS_INFO_FIELDS; i++)
235 {
236 ui->fields[i][0] = '\0';
237 }
238}
239
240static void
241_fields_free(Ui *ui)
242{
243 for (int i = 0; i < PROCESS_INFO_FIELDS; i++)
244 {
245 free(ui->fields[i]);
246 }
247}
248
249static Eina_List *
250_list_sort(Ui *ui, Eina_List *list)
251{
252 switch (ui->sort_type)
253 {
254 case SORT_BY_NONE:
255 case SORT_BY_PID:
256 list = eina_list_sort(list, eina_list_count(list), _sort_by_pid);
257 break;
258
259 case SORT_BY_UID:
260 list = eina_list_sort(list, eina_list_count(list), _sort_by_uid);
261 break;
262
263 case SORT_BY_NICE:
264 list = eina_list_sort(list, eina_list_count(list), _sort_by_nice);
265 break;
266
267 case SORT_BY_PRI:
268 list = eina_list_sort(list, eina_list_count(list), _sort_by_pri);
269 break;
270
271 case SORT_BY_CPU:
272 list = eina_list_sort(list, eina_list_count(list), _sort_by_cpu);
273 break;
274
275 case SORT_BY_THREADS:
276 list = eina_list_sort(list, eina_list_count(list), _sort_by_threads);
277 break;
278
279 case SORT_BY_SIZE:
280 list = eina_list_sort(list, eina_list_count(list), _sort_by_size);
281 break;
282
283 case SORT_BY_RSS:
284 list = eina_list_sort(list, eina_list_count(list), _sort_by_rss);
285 break;
286
287 case SORT_BY_CMD:
288 list = eina_list_sort(list, eina_list_count(list), _sort_by_cmd);
289 break;
290
291 case SORT_BY_STATE:
292 list = eina_list_sort(list, eina_list_count(list), _sort_by_state);
293 break;
294
295 case SORT_BY_CPU_USAGE:
296 list = eina_list_sort(list, eina_list_count(list), _sort_by_cpu_usage);
297 break;
298 }
299
300 if (ui->sort_reverse)
301 list = eina_list_reverse(list);
302
303 return list;
304}
305
306static void
307_system_process_list_feedback_cb(void *data, Ecore_Thread *thread EINA_UNUSED, void *msg EINA_UNUSED)
308{
309 Ui *ui;
310 Eina_List *list, *l;
311 Proc_Stats *proc;
312
313 eina_lock_take(&_lock);
314
315 ui = data;
316
317 list = proc_info_all_get();
318
319 EINA_LIST_FOREACH (list, l, proc)
320 {
321 int64_t time_prev = ui->cpu_times[proc->pid];
322 proc->cpu_usage = 0;
323 if (!ui->first_run && proc->cpu_time > time_prev)
324 {
325 proc->cpu_usage = (double) (proc->cpu_time - time_prev) / ui->poll_delay;
326 }
327 }
328
329 list = _list_sort(ui, list);
330
331 EINA_LIST_FREE (list, proc)
332 {
333 _fields_append(ui, proc);
334 ui->first_run = EINA_FALSE;
335 ui->cpu_times[proc->pid] = proc->cpu_time;
336
337 free(proc);
338 }
339
340 if (list)
341 eina_list_free(list);
342
343 _fields_show(ui);
344 _fields_clear(ui);
345
346 eina_lock_release(&_lock);
347}
348
349static void
350_system_process_list_update(Ui *ui)
351{
352 _system_process_list_feedback_cb(ui, NULL, NULL);
353}
354
355static void
356_system_process_list(void *data, Ecore_Thread *thread)
357{
358 Ui *ui;
359 int i;
360
361 ui = data;
362
363 while (1)
364 {
365 ecore_thread_feedback(thread, ui);
366 for (i = 0; i < ui->poll_delay * 2; i++)
367 {
368 if (ecore_thread_check(thread))
369 return;
370 usleep(500000);
371 }
372 }
373}
374
375static void
376_thread_end_cb(void *data EINA_UNUSED, Ecore_Thread *thread)
377{
378 thread = NULL;
379}
380
381static void
382_thread_error_cb(void *data EINA_UNUSED, Ecore_Thread *thread)
383{
384 thread = NULL;
385}
386
387static char *
388_progress_mem_format_cb(double val)
389{
390 char buf[1024];
391
392 snprintf(buf, sizeof(buf), "%ld M out of %ld M", _memory_used, _memory_total);
393
394 return strdup(buf);
395}
396
397static void
398_progress_mem_format_free_cb(char *str)
399{
400 if (str)
401 free(str);
402}
403
404static void
405_btn_icon_state_set(Evas_Object *button, Eina_Bool reverse)
406{
407 Evas_Object *icon = elm_icon_add(button);
408 if (reverse)
409 elm_icon_standard_set(icon, "go-down");
410 else
411 elm_icon_standard_set(icon, "go-up");
412
413 elm_object_part_content_set(button, "icon", icon);
414 evas_object_show(icon);
415}
416
417static void
418_btn_pid_clicked_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
419{
420 Ui *ui = data;
421
422 if (ui->sort_type == SORT_BY_PID)
423 ui->sort_reverse = !ui->sort_reverse;
424
425 _btn_icon_state_set(ui->btn_pid, ui->sort_reverse);
426
427 ui->sort_type = SORT_BY_PID;
428
429 _system_process_list_update(ui);
430
431 elm_scroller_page_bring_in(ui->scroller, 0, 0);
432}
433
434static void
435_btn_uid_clicked_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
436{
437 Ui *ui = data;
438
439 if (ui->sort_type == SORT_BY_UID)
440 ui->sort_reverse = !ui->sort_reverse;
441
442 _btn_icon_state_set(ui->btn_uid, ui->sort_reverse);
443
444 ui->sort_type = SORT_BY_UID;
445
446 _system_process_list_update(ui);
447
448 elm_scroller_page_bring_in(ui->scroller, 0, 0);
449}
450
451
452static void
453_btn_cpu_usage_clicked_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
454{
455 Ui *ui = data;
456
457 if (ui->sort_type == SORT_BY_CPU_USAGE)
458 ui->sort_reverse = !ui->sort_reverse;
459
460 _btn_icon_state_set(ui->btn_cpu_usage, ui->sort_reverse);
461
462 ui->sort_type = SORT_BY_CPU_USAGE;
463
464 _system_process_list_update(ui);
465
466 elm_scroller_page_bring_in(ui->scroller, 0, 0);
467}
468
469static void
470_btn_size_clicked_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
471{
472 Ui *ui = data;
473
474 if (ui->sort_type == SORT_BY_SIZE)
475 ui->sort_reverse = !ui->sort_reverse;
476
477 _btn_icon_state_set(ui->btn_size, ui->sort_reverse);
478
479 ui->sort_type = SORT_BY_SIZE;
480
481 _system_process_list_update(ui);
482
483 elm_scroller_page_bring_in(ui->scroller, 0, 0);
484}
485
486static void
487_btn_rss_clicked_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
488{
489 Ui *ui = data;
490
491 if (ui->sort_type == SORT_BY_RSS)
492 ui->sort_reverse = !ui->sort_reverse;
493
494 _btn_icon_state_set(ui->btn_rss, ui->sort_reverse);
495
496 ui->sort_type = SORT_BY_RSS;
497
498 _system_process_list_update(ui);
499
500 elm_scroller_page_bring_in(ui->scroller, 0, 0);
501}
502
503static void
504_btn_cmd_clicked_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
505{
506 Ui *ui = data;
507
508 if (ui->sort_type == SORT_BY_CMD)
509 ui->sort_reverse = !ui->sort_reverse;
510
511 _btn_icon_state_set(ui->btn_cmd, ui->sort_reverse);
512
513 ui->sort_type = SORT_BY_CMD;
514
515 _system_process_list_update(ui);
516
517 elm_scroller_page_bring_in(ui->scroller, 0, 0);
518}
519
520static void
521_btn_state_clicked_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
522{
523 Ui *ui = data;
524
525 if (ui->sort_type == SORT_BY_STATE)
526 ui->sort_reverse = !ui->sort_reverse;
527
528 _btn_icon_state_set(ui->btn_state, ui->sort_reverse);
529
530 ui->sort_type = SORT_BY_STATE;
531
532 _system_process_list_update(ui);
533
534 elm_scroller_page_bring_in(ui->scroller, 0, 0);
535}
536
537static void
538_btn_quit_clicked_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
539{
540 ecore_main_loop_quit();
541
542 elm_exit();
543}
544
545static void
546_btn_about_clicked_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
547{
548 Ui *ui;
549 Evas_Object *win;
550
551 ui = data;
552 win = ui->win;
553
554 printf("(c) Copyright 2018. Alastair Poole <netstar@gmail.com>\n");
555}
556
557static void
558_list_item_del_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
559{
560 pid_t *pid = data;
561
562 free(pid);
563}
564
565static void
566_process_panel_pids_update(Ui *ui)
567{
568 Proc_Stats *proc;
569 Elm_Widget_Item *item;
570 Eina_List *list;
571 pid_t *pid;
572 char buf[64];
573
574 if (!ui->panel_visible)
575 return;
576
577 // FIXME: something fishy going on here (mem-wise).
578 list = proc_info_all_get();
579 list = eina_list_sort(list, eina_list_count(list), _sort_by_pid);
580
581 elm_list_clear(ui->list_pid);
582
583 EINA_LIST_FREE(list, proc)
584 {
585 snprintf(buf, sizeof(buf), "%d", proc->pid);
586
587 pid = malloc(sizeof(pid_t));
588 *pid = proc->pid;
589
590 item = elm_list_item_append(ui->list_pid, buf, NULL, NULL, NULL, pid);
591 elm_object_item_del_cb_set(item, _list_item_del_cb);
592
593 free(proc);
594 }
595
596 elm_list_go(ui->list_pid);
597
598 if (list)
599 eina_list_free(list);
600}
601
602static Eina_Bool
603_process_panel_update(void *data)
604{
605 Ui *ui;
606 const Eina_List *l, *list;
607 Elm_Widget_Item *it;
608 struct passwd *pwd_entry;
609 Proc_Stats *proc;
610 double cpu_usage = 0.0;
611
612 ui = data;
613
614 proc = proc_info_by_pid(ui->selected_pid);
615 if (!proc)
616 {
617 _process_panel_pids_update(ui);
618
619 return ECORE_CALLBACK_CANCEL;
620 }
621
622 list = elm_list_items_get(ui->list_pid);
623 EINA_LIST_FOREACH(list, l, it)
624 {
625 pid_t *pid = elm_object_item_data_get(it);
626 if (pid && *pid == ui->selected_pid)
627 {
628 elm_list_item_selected_set(it, EINA_TRUE);
629 break;
630 }
631 }
632
633 elm_object_text_set(ui->entry_pid_cmd, proc->command);
634
635 pwd_entry = getpwuid(proc->uid);
636 if (pwd_entry)
637 elm_object_text_set(ui->entry_pid_user, pwd_entry->pw_name);
638
639 elm_object_text_set(ui->entry_pid_pid, eina_slstr_printf("%d", proc->pid));
640 elm_object_text_set(ui->entry_pid_uid, eina_slstr_printf("%d", proc->uid));
641 elm_object_text_set(ui->entry_pid_cpu, eina_slstr_printf("%d", proc->cpu_id));
642 elm_object_text_set(ui->entry_pid_threads, eina_slstr_printf("%d", proc->numthreads));
643 elm_object_text_set(ui->entry_pid_size, eina_slstr_printf("%lld bytes", proc->mem_size));
644 elm_object_text_set(ui->entry_pid_rss, eina_slstr_printf("%lld bytes", proc->mem_rss));
645 elm_object_text_set(ui->entry_pid_nice, eina_slstr_printf("%d", proc->nice));
646 elm_object_text_set(ui->entry_pid_pri, eina_slstr_printf("%d", proc->priority));
647 elm_object_text_set(ui->entry_pid_state, proc->state);
648
649 if (proc->cpu_time > ui->pid_cpu_time)
650 {
651 cpu_usage = (double) (proc->cpu_time - ui->pid_cpu_time) / ui->poll_delay;
652 }
653
654 ui->pid_cpu_time = proc->cpu_time;
655 elm_object_text_set(ui->entry_pid_cpu_usage, eina_slstr_printf("%.1f%%", cpu_usage));
656
657 free(proc);
658
659 return ECORE_CALLBACK_RENEW;
660}
661
662static void
663_process_panel_list_selected_cb(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
664{
665 Elm_Object_Item *it;
666 Ui *ui;
667 const char *text;
668
669 ui = data;
670
671 it = elm_list_selected_item_get(obj);
672
673 text = elm_object_item_text_get(it);
674
675 if (ui->timer_pid)
676 {
677 ecore_timer_del(ui->timer_pid);
678 ui->timer_pid = NULL;
679 }
680
681 ui->selected_pid = atoi(text);
682
683 _process_panel_update(ui);
684
685 ui->timer_pid = ecore_timer_add(ui->poll_delay, _process_panel_update, ui);
686
687 elm_scroller_page_bring_in(ui->scroller, 0, 0);
688}
689
690static void
691_panel_scrolled_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
692{
693 Ui *ui = data;
694
695 ui->panel_visible = !ui->panel_visible;
696}
697
698static void
699_btn_start_clicked_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
700{
701 Ui *ui = data;
702
703 if (ui->selected_pid == -1)
704 return;
705
706 kill(ui->selected_pid, SIGCONT);
707}
708
709static void
710_btn_stop_clicked_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
711{
712 Ui *ui = data;
713
714 if (ui->selected_pid == -1)
715 return;
716
717 kill(ui->selected_pid, SIGSTOP);
718}
719
720static void
721_btn_kill_clicked_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
722{
723 Ui *ui = data;
724
725 if (ui->selected_pid == -1)
726 return;
727
728 kill(ui->selected_pid, SIGKILL);
729}
730
731static void
732_entry_pid_clicked_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
733{
734 Ui *ui;
735 Evas_Object *textblock;
736 Evas_Textblock_Cursor *pos;
737 const char *text;
738 char *pid_text, *start, *end;
739
740 ui = data;
741
742 textblock = elm_entry_textblock_get(obj);
743 if (!textblock)
744 return;
745
746 pos = evas_object_textblock_cursor_get(textblock);
747 if (!pos)
748 return;
749
750 text = evas_textblock_cursor_paragraph_text_get(pos);
751 if (!text)
752 return;
753
754 pid_text = strdup(text);
755
756 start = strchr(pid_text, '>') + 1;
757 if (start)
758 {
759 end = strchr(start, '<');
760 if (end)
761 *end = '\0';
762 }
763 else
764 {
765 free(pid_text);
766 return;
767 }
768
769 ui->selected_pid = atol(start);
770
771 free(pid_text);
772
773 _process_panel_update(ui);
774
775 if (ui->timer_pid)
776 {
777 ecore_timer_del(ui->timer_pid);
778 ui->timer_pid = NULL;
779 }
780
781 ui->timer_pid = ecore_timer_add(ui->poll_delay, _process_panel_update, ui);
782
783 elm_panel_toggle(ui->panel);
784 ui->panel_visible = EINA_TRUE;
785}
786
787static void
788_ui_main_view_add(Evas_Object *parent, Ui *ui)
789{
790 Evas_Object *box, *hbox, *frame, *table;
791 Evas_Object *progress, *button, *entry;
792 Evas_Object *scroller;
793
794 box = elm_box_add(parent);
795 evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
796 evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL);
797 evas_object_show(box);
798 elm_object_content_set(parent, box);
799
800 hbox = elm_box_add(box);
801 evas_object_size_hint_weight_set(hbox, EVAS_HINT_EXPAND, 0);
802 evas_object_size_hint_align_set(hbox, EVAS_HINT_FILL, 0);
803 elm_box_horizontal_set(hbox, EINA_TRUE);
804 elm_box_pack_end(box, hbox);
805 evas_object_show(hbox);
806
807 frame = elm_frame_add(hbox);
808 evas_object_size_hint_weight_set(frame, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
809 evas_object_size_hint_align_set(frame, EVAS_HINT_FILL, EVAS_HINT_FILL);
810 elm_object_text_set(frame, "System CPU");
811 elm_box_pack_end(hbox, frame);
812 evas_object_show(frame);
813
814 ui->progress_cpu = progress = elm_progressbar_add(parent);
815 evas_object_size_hint_align_set(progress, EVAS_HINT_FILL, EVAS_HINT_FILL);
816 evas_object_size_hint_weight_set(progress, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
817 elm_progressbar_span_size_set(progress, 1.0);
818 elm_progressbar_unit_format_set(progress, "%1.2f%%");
819 elm_object_content_set(frame, progress);
820 evas_object_show(progress);
821
822 frame = elm_frame_add(hbox);
823 evas_object_size_hint_weight_set(frame, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
824 evas_object_size_hint_align_set(frame, EVAS_HINT_FILL, EVAS_HINT_FILL);
825 elm_object_text_set(frame, "System Memory");
826 elm_box_pack_end(hbox, frame);
827 evas_object_show(frame);
828
829 ui->progress_mem = progress = elm_progressbar_add(parent);
830 evas_object_size_hint_align_set(progress, EVAS_HINT_FILL, EVAS_HINT_FILL);
831 evas_object_size_hint_weight_set(progress, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
832 elm_progressbar_span_size_set(progress, 1.0);
833 elm_progressbar_unit_format_function_set(progress, _progress_mem_format_cb, _progress_mem_format_free_cb);
834 elm_object_content_set(frame, progress);
835 evas_object_show(progress);
836
837 table = elm_table_add(parent);
838 evas_object_size_hint_weight_set(table, EVAS_HINT_EXPAND, 0);
839 evas_object_size_hint_align_set(table, EVAS_HINT_FILL, 0);
840 elm_table_padding_set(table, 0, 0);
841 evas_object_show(table);
842 elm_box_pack_end(box, table);
843
844 ui->btn_pid = button = elm_button_add(parent);
845 _btn_icon_state_set(button, EINA_FALSE);
846 evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0);
847 evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 0.5);
848 elm_object_text_set(button, "PID");
849 evas_object_show(button);
850 elm_table_pack(table, button, 0, 0, 1, 1);
851
852 ui->btn_uid = button = elm_button_add(parent);
853 _btn_icon_state_set(button, EINA_FALSE);
854 evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0);
855 evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 0.5);
856 elm_object_text_set(button, "UID");
857 evas_object_show(button);
858 elm_table_pack(table, button, 1, 0, 1, 1);
859
860 ui->btn_size = button = elm_button_add(parent);
861 _btn_icon_state_set(button, EINA_FALSE);
862 evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0);
863 evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 0.5);
864 elm_object_text_set(button, "Size");
865 evas_object_show(button);
866 elm_table_pack(table, button, 2, 0, 1, 1);
867
868 ui->btn_rss = button = elm_button_add(parent);
869 _btn_icon_state_set(button, EINA_FALSE);
870 evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0);
871 evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 0.5);
872 elm_object_text_set(button, "Res");
873 evas_object_show(button);
874 elm_table_pack(table, button, 3, 0, 1, 1);
875
876 ui->btn_cmd = button = elm_button_add(parent);
877 _btn_icon_state_set(button, EINA_FALSE);
878 evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0);
879 evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 0.5);
880 elm_object_text_set(button, "Command");
881 evas_object_show(button);
882 elm_table_pack(table, button, 4, 0, 1, 1);
883
884 ui->btn_state = button = elm_button_add(parent);
885 _btn_icon_state_set(button, EINA_FALSE);
886 evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0);
887 evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 0.5);
888 elm_object_text_set(button, "State");
889 evas_object_show(button);
890 elm_table_pack(table, button, 5, 0, 1, 1);
891
892 ui->btn_cpu_usage = button = elm_button_add(parent);
893 _btn_icon_state_set(button, EINA_FALSE);
894 evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0);
895 evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 0.5);
896 elm_object_text_set(button, "CPU %");
897 evas_object_show(button);
898 elm_table_pack(table, button, 6, 0, 1, 1);
899
900 table = elm_table_add(parent);
901 evas_object_size_hint_weight_set(table, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
902 evas_object_size_hint_align_set(table, EVAS_HINT_FILL, EVAS_HINT_EXPAND);
903 elm_table_padding_set(table, 0, 0);
904 evas_object_show(table);
905
906 ui->scroller = scroller = elm_scroller_add(parent);
907 evas_object_size_hint_weight_set(scroller, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
908 evas_object_size_hint_align_set(scroller, EVAS_HINT_FILL, EVAS_HINT_FILL);
909 elm_scroller_policy_set(scroller, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_ON);
910 elm_scroller_bounce_set(scroller, EINA_FALSE, EINA_FALSE);
911 elm_scroller_gravity_set(scroller, 0.0, 0.0);
912 elm_scroller_wheel_disabled_set(scroller, 1);
913 elm_scroller_page_relative_set(scroller, 1, 0);
914 evas_object_show(scroller);
915 elm_object_content_set(scroller, table);
916
917 frame = elm_frame_add(box);
918 evas_object_size_hint_weight_set(frame, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
919 evas_object_size_hint_align_set(frame, EVAS_HINT_FILL, EVAS_HINT_FILL);
920 elm_object_text_set(frame, "System Overview");
921 elm_object_style_set(frame, "pad_small");
922 elm_box_pack_end(box, frame);
923 evas_object_show(frame);
924 elm_object_content_set(frame, scroller);
925
926 button = elm_button_add(parent);
927 _btn_icon_state_set(button, EINA_FALSE);
928 evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0);
929 evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 0.5);
930 elm_object_text_set(button, "PID");
931 elm_table_pack(table, button, 0, 0, 1, 1);
932
933 ui->entry_pid = entry = elm_entry_add(parent);
934 elm_entry_text_style_user_push(entry, "DEFAULT='font=default:style=default size=12 align=center'");
935 evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
936 evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
937 elm_entry_scrollable_set(entry, 0);
938 elm_entry_editable_set(entry, 0);
939 evas_object_show(entry);
940 elm_table_pack(table, entry, 0, 0, 1, 1);
941
942 button = elm_button_add(parent);
943 _btn_icon_state_set(button, EINA_FALSE);
944 evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0);
945 evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 0.5);
946 elm_object_text_set(button, "UID");
947 elm_table_pack(table, button, 1, 0, 1, 1);
948
949 ui->entry_uid = entry = elm_entry_add(parent);
950 elm_entry_text_style_user_push(entry, "DEFAULT='font=default:style=default size=12 align=center'");
951 evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
952 evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
953 elm_entry_editable_set(entry, 0);
954 evas_object_show(entry);
955 elm_table_pack(table, entry, 1, 0, 1, 1);
956
957 button = elm_button_add(parent);
958 _btn_icon_state_set(button, EINA_FALSE);
959 evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0);
960 evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 0.5);
961 elm_object_text_set(button, "Size");
962 elm_table_pack(table, button, 2, 0, 1, 1);
963
964 ui->entry_size = entry = elm_entry_add(parent);
965 elm_entry_text_style_user_push(entry, "DEFAULT='font=default:style=default size=12 align=right'");
966 evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
967 evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
968 elm_entry_scrollable_set(entry, 0);
969 elm_entry_editable_set(entry, 0);
970 evas_object_show(entry);
971 elm_table_pack(table, entry, 2, 0, 1, 1);
972
973 button = elm_button_add(parent);
974 _btn_icon_state_set(button, EINA_FALSE);
975 evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0);
976 evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 0.5);
977 elm_object_text_set(button, "Res");
978 elm_table_pack(table, button, 3, 0, 1, 1);
979
980 ui->entry_rss = entry = elm_entry_add(parent);
981 elm_entry_text_style_user_push(entry, "DEFAULT='font=default:style=default size=12 align=right'");
982 evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
983 evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
984 elm_entry_scrollable_set(entry, 0);
985 elm_entry_editable_set(entry, 0);
986 evas_object_show(entry);
987 elm_table_pack(table, entry, 3, 0, 1, 1);
988
989 button = elm_button_add(parent);
990 _btn_icon_state_set(button, EINA_FALSE);
991 evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0);
992 evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 0.5);
993 elm_object_text_set(button, "Command");
994 elm_table_pack(table, button, 4, 0, 1, 1);
995
996 ui->entry_cmd = entry = elm_entry_add(parent);
997 evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
998 evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
999 elm_entry_scrollable_set(entry, 0);
1000 elm_entry_editable_set(entry, 0);
1001 evas_object_show(entry);
1002 elm_table_pack(table, entry, 4, 0, 1, 1);
1003
1004 button = elm_button_add(parent);
1005 _btn_icon_state_set(button, EINA_FALSE);
1006 evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0);
1007 evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 0.5);
1008 elm_object_text_set(button, "State");
1009 elm_table_pack(table, button, 5, 0, 1, 1);
1010
1011 ui->entry_state = entry = elm_entry_add(parent);
1012 elm_entry_text_style_user_push(entry, "DEFAULT='font=default:style=default size=12 align=center'");
1013 evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1014 evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1015 elm_entry_single_line_set(entry, 1);
1016 elm_entry_scrollable_set(entry, 0);
1017 elm_entry_editable_set(entry, 0);
1018 elm_entry_line_wrap_set(entry, 1);
1019 evas_object_show(entry);
1020 elm_table_pack(table, entry, 5, 0, 1, 1);
1021
1022 button = elm_button_add(parent);
1023 _btn_icon_state_set(button, EINA_FALSE);
1024 evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0);
1025 evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 0.5);
1026 elm_object_text_set(button, "CPU %");
1027 elm_table_pack(table, button, 6, 0, 1, 1);
1028
1029 ui->entry_cpu_usage = entry = elm_entry_add(parent);
1030 elm_entry_text_style_user_push(entry, "DEFAULT='font=default:style=default size=12 align=center'");
1031 evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1032 evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1033 elm_entry_single_line_set(entry, 1);
1034 elm_entry_scrollable_set(entry, 0);
1035 elm_entry_editable_set(entry, 0);
1036 elm_entry_line_wrap_set(entry, 1);
1037 evas_object_show(entry);
1038 elm_table_pack(table, entry, 6, 0, 1, 1);
1039
1040 hbox = elm_box_add(parent);
1041 evas_object_size_hint_weight_set(hbox, EVAS_HINT_EXPAND, 0);
1042 evas_object_size_hint_align_set(hbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
1043 elm_box_horizontal_set(hbox, EINA_TRUE);
1044 evas_object_show(hbox);
1045 elm_box_pack_end(box, hbox);
1046
1047 box = elm_box_add(parent);
1048 evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1049 evas_object_size_hint_align_set(hbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
1050 elm_box_horizontal_set(box, EINA_TRUE);
1051 elm_box_pack_end(hbox, box);
1052
1053 button = elm_button_add(parent);
1054 evas_object_size_hint_weight_set(button, 0.1, 0);
1055 evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 0);
1056 elm_object_text_set(button, "Close");
1057 elm_box_pack_end(hbox, button);
1058 evas_object_show(button);
1059 evas_object_smart_callback_add(button, "clicked", _btn_quit_clicked_cb, ui);
1060
1061 evas_object_smart_callback_add(ui->btn_pid, "clicked", _btn_pid_clicked_cb, ui);
1062 evas_object_smart_callback_add(ui->btn_uid, "clicked", _btn_uid_clicked_cb, ui);
1063 evas_object_smart_callback_add(ui->btn_size, "clicked", _btn_size_clicked_cb, ui);
1064 evas_object_smart_callback_add(ui->btn_rss, "clicked", _btn_rss_clicked_cb, ui);
1065 evas_object_smart_callback_add(ui->btn_cmd, "clicked", _btn_cmd_clicked_cb, ui);
1066 evas_object_smart_callback_add(ui->btn_state, "clicked", _btn_state_clicked_cb, ui);
1067 evas_object_smart_callback_add(ui->btn_cpu_usage, "clicked", _btn_cpu_usage_clicked_cb, ui);
1068 evas_object_smart_callback_add(ui->entry_pid, "clicked", _entry_pid_clicked_cb, ui);
1069}
1070
1071static void
1072_ui_process_panel_add(Evas_Object *parent, Ui *ui)
1073{
1074 Evas_Object *panel, *box, *hbox, *frame, *scroller, *table;
1075 Evas_Object *label, *list, *entry, *button;
1076
1077 ui->panel = panel = elm_panel_add(parent);
1078 evas_object_size_hint_weight_set(panel, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1079 evas_object_size_hint_align_set(panel, EVAS_HINT_FILL, EVAS_HINT_FILL);
1080 elm_panel_orient_set(panel, ELM_PANEL_ORIENT_BOTTOM);
1081 elm_panel_toggle(panel);
1082 elm_object_content_set(parent, panel);
1083 evas_object_show(panel);
1084 evas_object_smart_callback_add(ui->panel, "scroll", _panel_scrolled_cb, ui);
1085
1086 hbox = elm_box_add(parent);
1087 evas_object_size_hint_weight_set(hbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1088 evas_object_size_hint_align_set(hbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
1089 elm_box_horizontal_set(hbox, EINA_TRUE);
1090 elm_object_content_set(panel, hbox);
1091 evas_object_show(hbox);
1092
1093 frame = elm_frame_add(hbox);
1094 evas_object_size_hint_weight_set(frame, 0.2, EVAS_HINT_EXPAND);
1095 evas_object_size_hint_align_set(frame, EVAS_HINT_FILL, EVAS_HINT_FILL);
1096 elm_object_text_set(frame, "PID");
1097 elm_box_pack_end(hbox, frame);
1098 evas_object_show(frame);
1099
1100 ui->list_pid = list = elm_list_add(frame);
1101 evas_object_size_hint_weight_set(list, EVAS_HINT_FILL, EVAS_HINT_FILL);
1102 evas_object_size_hint_align_set(list, EVAS_HINT_FILL, EVAS_HINT_FILL);
1103 evas_object_show(list);
1104 elm_object_content_set(frame, list);
1105 evas_object_smart_callback_add(ui->list_pid, "selected", _process_panel_list_selected_cb, ui);
1106
1107 frame = elm_frame_add(hbox);
1108 evas_object_size_hint_weight_set(frame, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1109 evas_object_size_hint_align_set(frame, EVAS_HINT_FILL, EVAS_HINT_FILL);
1110 elm_object_text_set(frame, "Process Statistics");
1111 elm_box_pack_end(hbox, frame);
1112 evas_object_show(frame);
1113
1114 table = elm_table_add(frame);
1115 evas_object_size_hint_weight_set(table, 0.5, EVAS_HINT_EXPAND);
1116 evas_object_size_hint_align_set(table, EVAS_HINT_FILL, EVAS_HINT_FILL);
1117 evas_object_show(table);
1118
1119 scroller = elm_scroller_add(parent);
1120 evas_object_size_hint_weight_set(scroller, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1121 evas_object_size_hint_align_set(scroller, EVAS_HINT_FILL, EVAS_HINT_FILL);
1122 elm_scroller_policy_set(scroller, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_ON);
1123 evas_object_show(scroller);
1124 elm_object_content_set(scroller, table);
1125 elm_object_content_set(frame, scroller);
1126 elm_box_pack_end(hbox, frame);
1127
1128 label = elm_label_add(parent);
1129 evas_object_size_hint_weight_set(scroller, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1130 evas_object_size_hint_align_set(scroller, EVAS_HINT_FILL, EVAS_HINT_FILL);
1131 elm_object_text_set(label, "Name:");
1132 evas_object_show(label);
1133 elm_table_pack(table, label, 0, 0, 1, 1);
1134
1135 ui->entry_pid_cmd = entry = elm_entry_add(parent);
1136 evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1137 evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1138 elm_entry_single_line_set(entry, 1);
1139 elm_entry_scrollable_set(entry, 1);
1140 elm_entry_editable_set(entry, 0);
1141 evas_object_show(entry);
1142 elm_entry_line_wrap_set(entry, 1);
1143 elm_table_pack(table, entry, 1, 0, 1, 1);
1144
1145 label = elm_label_add(parent);
1146 evas_object_size_hint_weight_set(scroller, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1147 evas_object_size_hint_align_set(scroller, EVAS_HINT_FILL, EVAS_HINT_FILL);
1148 elm_object_text_set(label, "PID:");
1149 evas_object_show(label);
1150 elm_table_pack(table, label, 0, 1, 1, 1);
1151
1152 ui->entry_pid_pid = entry = elm_entry_add(parent);
1153 evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1154 evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1155 elm_entry_single_line_set(entry, 1);
1156 elm_entry_scrollable_set(entry, 1);
1157 elm_entry_editable_set(entry, 0);
1158 evas_object_show(entry);
1159 elm_entry_line_wrap_set(entry, 1);
1160 elm_table_pack(table, entry, 1, 1, 1, 1);
1161
1162 label = elm_label_add(parent);
1163 evas_object_size_hint_weight_set(scroller, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1164 evas_object_size_hint_align_set(scroller, EVAS_HINT_FILL, EVAS_HINT_FILL);
1165 elm_object_text_set(label, "Username:");
1166 evas_object_show(label);
1167 elm_table_pack(table, label, 0, 2, 1, 1);
1168
1169 ui->entry_pid_user = entry = elm_entry_add(parent);
1170 evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1171 evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1172 elm_entry_single_line_set(entry, 1);
1173 elm_entry_scrollable_set(entry, 1);
1174 elm_entry_editable_set(entry, 0);
1175 evas_object_show(entry);
1176 elm_entry_line_wrap_set(entry, 1);
1177 elm_table_pack(table, entry, 1, 2, 1, 1);
1178
1179 label = elm_label_add(parent);
1180 evas_object_size_hint_weight_set(scroller, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1181 evas_object_size_hint_align_set(scroller, EVAS_HINT_FILL, EVAS_HINT_FILL);
1182 elm_object_text_set(label, "UID:");
1183 evas_object_show(label);
1184 elm_table_pack(table, label, 0, 3, 1, 1);
1185
1186 ui->entry_pid_uid = entry = elm_entry_add(parent);
1187 evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1188 evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1189 elm_entry_single_line_set(entry, 1);
1190 elm_entry_scrollable_set(entry, 1);
1191 elm_entry_editable_set(entry, 0);
1192 evas_object_show(entry);
1193 elm_entry_line_wrap_set(entry, 1);
1194 elm_table_pack(table, entry, 1, 3, 1, 1);
1195
1196 label = elm_label_add(parent);
1197 evas_object_size_hint_weight_set(scroller, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1198 evas_object_size_hint_align_set(scroller, EVAS_HINT_FILL, EVAS_HINT_FILL);
1199#if defined(__MacOS__)
1200 elm_object_text_set(label, "WQ #:");
1201#else
1202 elm_object_text_set(label, "CPU #:");
1203#endif
1204 evas_object_show(label);
1205 elm_table_pack(table, label, 0, 4, 1, 1);
1206
1207 ui->entry_pid_cpu = entry = elm_entry_add(parent);
1208 evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1209 evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1210 elm_entry_single_line_set(entry, 1);
1211 elm_entry_scrollable_set(entry, 1);
1212 elm_entry_editable_set(entry, 0);
1213 evas_object_show(entry);
1214 elm_entry_line_wrap_set(entry, 1);
1215 elm_table_pack(table, entry, 1, 4, 1, 1);
1216
1217 label = elm_label_add(parent);
1218 evas_object_size_hint_weight_set(scroller, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1219 evas_object_size_hint_align_set(scroller, EVAS_HINT_FILL, EVAS_HINT_FILL);
1220 elm_object_text_set(label, "Threads:");
1221 evas_object_show(label);
1222 elm_table_pack(table, label, 0, 5, 1, 1);
1223
1224 ui->entry_pid_threads = entry = elm_entry_add(parent);
1225 evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1226 evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1227 elm_entry_single_line_set(entry, 1);
1228 elm_entry_scrollable_set(entry, 1);
1229 elm_entry_editable_set(entry, 0);
1230 evas_object_show(entry);
1231 elm_entry_line_wrap_set(entry, 1);
1232 elm_table_pack(table, entry, 1, 5, 1, 1);
1233
1234 label = elm_label_add(parent);
1235 evas_object_size_hint_weight_set(scroller, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1236 evas_object_size_hint_align_set(scroller, EVAS_HINT_FILL, EVAS_HINT_FILL);
1237 elm_object_text_set(label, "Total memory:");
1238 evas_object_show(label);
1239 elm_table_pack(table, label, 0, 6, 1, 1);
1240
1241 ui->entry_pid_size = entry = elm_entry_add(parent);
1242 evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1243 evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1244 elm_entry_single_line_set(entry, 1);
1245 elm_entry_scrollable_set(entry, 1);
1246 elm_entry_editable_set(entry, 0);
1247 evas_object_show(entry);
1248 elm_entry_line_wrap_set(entry, 1);
1249 elm_table_pack(table, entry, 1, 6, 1, 1);
1250
1251 label = elm_label_add(parent);
1252 evas_object_size_hint_weight_set(scroller, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1253 evas_object_size_hint_align_set(scroller, EVAS_HINT_FILL, EVAS_HINT_FILL);
1254 elm_object_text_set(label, " Reserved memory:");
1255 evas_object_show(label);
1256 elm_table_pack(table, label, 0, 7, 1, 1);
1257
1258 ui->entry_pid_rss = entry = elm_entry_add(parent);
1259 evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1260 evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1261 elm_entry_single_line_set(entry, 1);
1262 elm_entry_scrollable_set(entry, 1);
1263 elm_entry_editable_set(entry, 0);
1264 evas_object_show(entry);
1265 elm_entry_line_wrap_set(entry, 1);
1266 elm_table_pack(table, entry, 1, 7, 1, 1);
1267
1268 label = elm_label_add(parent);
1269 evas_object_size_hint_weight_set(scroller, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1270 evas_object_size_hint_align_set(scroller, EVAS_HINT_FILL, EVAS_HINT_FILL);
1271 elm_object_text_set(label, "Nice:");
1272 evas_object_show(label);
1273 elm_table_pack(table, label, 0, 8, 1, 1);
1274
1275 ui->entry_pid_nice = entry = elm_entry_add(parent);
1276 evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1277 evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1278 elm_entry_single_line_set(entry, 1);
1279 elm_entry_scrollable_set(entry, 1);
1280 elm_entry_editable_set(entry, 0);
1281 evas_object_show(entry);
1282 elm_entry_line_wrap_set(entry, 1);
1283 elm_table_pack(table, entry, 1, 8, 1, 1);
1284
1285 label = elm_label_add(parent);
1286 evas_object_size_hint_weight_set(scroller, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1287 evas_object_size_hint_align_set(scroller, EVAS_HINT_FILL, EVAS_HINT_FILL);
1288 elm_object_text_set(label, "Priority:");
1289 evas_object_show(label);
1290 elm_table_pack(table, label, 0, 9, 1, 1);
1291
1292 ui->entry_pid_pri = entry = elm_entry_add(parent);
1293 evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1294 evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1295 elm_entry_single_line_set(entry, 1);
1296 elm_entry_scrollable_set(entry, 1);
1297 elm_entry_editable_set(entry, 0);
1298 evas_object_show(entry);
1299 elm_entry_line_wrap_set(entry, 1);
1300 elm_table_pack(table, entry, 1, 9, 1, 1);
1301
1302 label = elm_label_add(parent);
1303 evas_object_size_hint_weight_set(scroller, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1304 evas_object_size_hint_align_set(scroller, EVAS_HINT_FILL, EVAS_HINT_FILL);
1305 elm_object_text_set(label, "State:");
1306 evas_object_show(label);
1307 elm_table_pack(table, label, 0, 10, 1, 1);
1308
1309 ui->entry_pid_state = entry = elm_entry_add(parent);
1310 evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1311 evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1312 elm_entry_single_line_set(entry, 1);
1313 elm_entry_scrollable_set(entry, 1);
1314 elm_entry_editable_set(entry, 0);
1315 evas_object_show(entry);
1316 elm_entry_line_wrap_set(entry, 1);
1317 elm_table_pack(table, entry, 1, 10, 1, 1);
1318
1319 label = elm_label_add(parent);
1320 evas_object_size_hint_weight_set(scroller, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1321 evas_object_size_hint_align_set(scroller, EVAS_HINT_FILL, EVAS_HINT_FILL);
1322 elm_object_text_set(label, "CPU %:");
1323 evas_object_show(label);
1324 elm_table_pack(table, label, 0, 11, 1, 1);
1325
1326 ui->entry_pid_cpu_usage = entry = elm_entry_add(parent);
1327 evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1328 evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1329 elm_entry_single_line_set(entry, 1);
1330 elm_entry_scrollable_set(entry, 1);
1331 elm_entry_editable_set(entry, 0);
1332 evas_object_show(entry);
1333 elm_entry_line_wrap_set(entry, 1);
1334 elm_table_pack(table, entry, 1, 11, 1, 1);
1335
1336 hbox = elm_box_add(parent);
1337 evas_object_size_hint_weight_set(hbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1338 evas_object_size_hint_align_set(hbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
1339 elm_box_horizontal_set(hbox, EINA_TRUE);
1340 evas_object_show(hbox);
1341 elm_table_pack(table, hbox, 1, 12, 1, 1);
1342
1343 button = elm_button_add(parent);
1344 evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0);
1345 evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 0.5);
1346 elm_object_text_set(button, "Stop Process");
1347 elm_box_pack_end(hbox, button);
1348 evas_object_show(button);
1349 evas_object_smart_callback_add(button, "clicked", _btn_stop_clicked_cb, ui);
1350
1351 button = elm_button_add(parent);
1352 evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0);
1353 evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 0.5);
1354 elm_object_text_set(button, "Start Process");
1355 elm_box_pack_end(hbox, button);
1356 evas_object_smart_callback_add(button, "clicked", _btn_start_clicked_cb, ui);
1357 evas_object_show(button);
1358
1359 button = elm_button_add(parent);
1360 evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0);
1361 evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 0.5);
1362 elm_object_text_set(button, "Kill Process");
1363 elm_box_pack_end(hbox, button);
1364 evas_object_show(button);
1365 evas_object_smart_callback_add(button, "clicked", _btn_kill_clicked_cb, ui);
1366}
1367
1368void
1369ui_add(Evas_Object *parent)
1370{
1371 Ui *ui;
1372 int i;
1373
1374 ui = calloc(1, sizeof(Ui));
1375 ui->win = parent;
1376 ui->first_run = EINA_TRUE;
1377 ui->poll_delay = 3;
1378 ui->sort_reverse = EINA_FALSE;
1379 ui->sort_type = SORT_BY_PID;
1380 ui->selected_pid = -1;
1381 ui->program_pid = getpid();
1382 ui->panel_visible = EINA_TRUE;
1383
1384 memset(ui->cpu_times, 0, PID_MAX * sizeof(int64_t));
1385
1386 for (i = 0; i < PROCESS_INFO_FIELDS; i++)
1387 {
1388 ui->fields[i] = malloc(TEXT_FIELD_MAX * sizeof(char));
1389 ui->fields[i][0] = '\0';
1390 }
1391
1392 eina_lock_new(&_lock);
1393
1394 _ui_main_view_add(parent, ui);
1395 _ui_process_panel_add(parent, ui);
1396
1397 _process_panel_update(ui);
1398 ecore_thread_feedback_run(_system_stats, _system_stats_feedback_cb, _thread_end_cb, _thread_error_cb, ui, EINA_FALSE);
1399 ecore_thread_feedback_run(_system_process_list, _system_process_list_feedback_cb, _thread_end_cb, _thread_error_cb, ui, EINA_FALSE);
1400}
1401
diff --git a/src/ui.h b/src/ui.h
new file mode 100644
index 0000000..3712c51
--- /dev/null
+++ b/src/ui.h
@@ -0,0 +1,114 @@
1#ifndef __UI_H__
2#define __UI_H__
3
4#include <Elementary.h>
5
6typedef enum
7{
8 PROCESS_INFO_FIELD_PID,
9 PROCESS_INFO_FIELD_UID,
10 PROCESS_INFO_FIELD_SIZE,
11 PROCESS_INFO_FIELD_RSS,
12 PROCESS_INFO_FIELD_COMMAND,
13 PROCESS_INFO_FIELD_STATE,
14 PROCESS_INFO_FIELD_CPU_USAGE,
15
16 // Not displayed in the main UI.
17 PROCESS_INFO_FIELD_NICE,
18 PROCESS_INFO_FIELD_PRI,
19 PROCESS_INFO_FIELD_CPU,
20 PROCESS_INFO_FIELD_THREADS,
21 // Not used yet in UI.
22 PROCESS_INFO_FIELD_CPU_TIME,
23} Proc_Stats_Field;
24
25#define PROCESS_INFO_FIELDS 7
26
27typedef enum
28{
29 SORT_BY_NONE,
30 SORT_BY_PID,
31 SORT_BY_UID,
32 SORT_BY_NICE,
33 SORT_BY_PRI,
34 SORT_BY_CPU,
35 SORT_BY_THREADS,
36 SORT_BY_SIZE,
37 SORT_BY_RSS,
38 SORT_BY_CMD,
39 SORT_BY_STATE,
40 SORT_BY_CPU_USAGE,
41} Sort_Type;
42
43typedef struct Ui
44{
45 Evas_Object *win;
46 Evas_Object *panel;
47 Evas_Object *scroller;
48
49 Evas_Object *progress_cpu;
50 Evas_Object *progress_mem;
51
52 Evas_Object *entry_pid;
53 Evas_Object *entry_uid;
54 Evas_Object *entry_size;
55 Evas_Object *entry_rss;
56 Evas_Object *entry_cmd;
57 Evas_Object *entry_state;
58 Evas_Object *entry_cpu_usage;
59
60 Evas_Object *btn_pid;
61 Evas_Object *btn_uid;
62 Evas_Object *btn_size;
63 Evas_Object *btn_rss;
64 Evas_Object *btn_cmd;
65 Evas_Object *btn_state;
66 Evas_Object *btn_cpu_usage;
67
68 Evas_Object *entry_pid_cmd;
69 Evas_Object *entry_pid_user;
70 Evas_Object *entry_pid_pid;
71 Evas_Object *entry_pid_uid;
72 Evas_Object *entry_pid_cpu;
73 Evas_Object *entry_pid_threads;
74 Evas_Object *entry_pid_size;
75 Evas_Object *entry_pid_rss;
76 Evas_Object *entry_pid_nice;
77 Evas_Object *entry_pid_pri;
78 Evas_Object *entry_pid_state;
79 Evas_Object *entry_pid_cpu_usage;
80
81 Ecore_Timer *timer_pid;
82 pid_t selected_pid;
83 pid_t program_pid;
84
85#define TEXT_FIELD_MAX 65535
86 char *fields[PROCESS_INFO_FIELDS];
87
88 Evas_Object *list_pid;
89
90 Eina_Bool first_run;
91
92 int64_t cpu_times[PID_MAX];
93 int64_t pid_cpu_time;
94
95 int poll_delay;
96
97 Sort_Type sort_type;
98 Eina_Bool sort_reverse;
99 Eina_Bool panel_visible;
100
101} Ui;
102
103typedef struct Sys_Stats
104{
105 int cpu_count;
106 double cpu_usage;
107 long mem_total;
108 long mem_used;
109} Sys_Stats;
110
111void
112ui_add(Evas_Object *win);
113
114#endif