diff --git a/data/images/meson.build b/data/images/meson.build index 5f49d09..50682e1 100644 --- a/data/images/meson.build +++ b/data/images/meson.build @@ -1,6 +1,6 @@ install_data('go-up.png', 'go-down.png', 'battery.png', 'start.png', 'stop.png', - 'kill.png', 'cancel.png', + 'kill.png', 'cancel.png', 'network.png', 'increase.png', 'decrease.png', 'sensor.png', 'mount.png', 'ladyhand.png', 'find.png', 'bug.png', 'exit.png', 'cpu.png', diff --git a/data/images/network.png b/data/images/network.png new file mode 100644 index 0000000..3c3db90 Binary files /dev/null and b/data/images/network.png differ diff --git a/src/bin/evisum_actions.h b/src/bin/evisum_actions.h index e5071d1..895967c 100644 --- a/src/bin/evisum_actions.h +++ b/src/bin/evisum_actions.h @@ -9,6 +9,7 @@ typedef enum EVISUM_ACTION_MEM = 3, EVISUM_ACTION_STORAGE = 4, EVISUM_ACTION_SENSORS = 5, + EVISUM_ACTION_NETWORK = 6, } Evisum_Action; #endif diff --git a/src/bin/evisum_config.h b/src/bin/evisum_config.h index 67e0867..767cdc0 100644 --- a/src/bin/evisum_config.h +++ b/src/bin/evisum_config.h @@ -3,7 +3,7 @@ #include "ui/ui.h" -#define CONFIG_VERSION 0x000f +#define CONFIG_VERSION 0x0010 typedef struct _Evisum_Config { @@ -64,6 +64,14 @@ typedef struct _Evisum_Config Eina_Bool restart; } sensors; + struct + { + int width; + int height; + int x, y; + Eina_Bool restart; + } network; + } Evisum_Config; void config_init(void); diff --git a/src/bin/main.c b/src/bin/main.c index 7ae9bbb..92e5e3b 100644 --- a/src/bin/main.c +++ b/src/bin/main.c @@ -49,6 +49,8 @@ elm_main(int argc, char **argv) " Launch memory view.\n" " -d\n" " Launch storage view.\n" + " -n\n" + " Launch network view.\n" " -s\n" " Launch sensors view.\n" " -p \n" @@ -66,6 +68,8 @@ elm_main(int argc, char **argv) action = EVISUM_ACTION_STORAGE; else if (!strcmp(argv[i], "-s")) action = EVISUM_ACTION_SENSORS; + else if (!strcmp(argv[i], "-n")) + action = EVISUM_ACTION_NETWORK; else if (!strcmp(argv[i], "-p") && i < (argc -1)) { action = EVISUM_ACTION_PROCESS; diff --git a/src/bin/ui/meson.build b/src/bin/ui/meson.build index bfbabf8..4ecb2db 100644 --- a/src/bin/ui/meson.build +++ b/src/bin/ui/meson.build @@ -6,6 +6,8 @@ src += files([ 'ui_util.c', 'ui_cache.c', 'ui_cache.h', + 'ui_network.c', + 'ui_network.h', 'ui_sensors.c', 'ui_sensors.h', 'ui_disk.c', diff --git a/src/bin/ui/ui.c b/src/bin/ui/ui.c index d8955f5..abde9af 100644 --- a/src/bin/ui/ui.c +++ b/src/bin/ui/ui.c @@ -10,6 +10,7 @@ #include "ui/ui_memory.h" #include "ui/ui_disk.h" #include "ui/ui_sensors.h" +#include "ui/ui_network.h" #include "ui/ui_process_view.h" #include "ui/ui_process_list.h" @@ -55,7 +56,7 @@ evisum_ui_config_save(Ui *ui) _evisum_config->proc.show_scroller = ui->proc.show_scroller; _evisum_config->proc.transparant = ui->proc.transparant; _evisum_config->proc.alpha = ui->proc.alpha; - _evisum_config->proc.fields = ui->proc.fields; + _evisum_config->proc.fields = ui->proc.fields; proc_info_kthreads_show_set(ui->proc.show_kthreads); } @@ -99,6 +100,16 @@ evisum_ui_config_save(Ui *ui) _evisum_config->sensors.restart = ui->sensors.restart; } + if (ui->network.win) + { + evas_object_geometry_get(ui->network.win, &x, &y, &w, &h); + _evisum_config->network.width = ui->network.width = w; + _evisum_config->network.height = ui->network.height = h; + _evisum_config->network.x = x; + _evisum_config->network.y = y; + _evisum_config->network.restart = ui->network.restart; + } + config_save(_evisum_config); if (notify) @@ -154,6 +165,12 @@ evisum_ui_config_load(Ui *ui) ui->sensors.x = _evisum_config->sensors.x; ui->sensors.y = _evisum_config->sensors.y; ui->sensors.restart = _evisum_config->sensors.restart; + + ui->network.width = _evisum_config->network.width; + ui->network.height = _evisum_config->network.height; + ui->network.x = _evisum_config->network.x; + ui->network.y = _evisum_config->network.y; + ui->network.restart = _evisum_config->network.restart; } void @@ -164,6 +181,7 @@ evisum_ui_restart(Ui *ui) if (ui->mem.win) ui->mem.restart = 1; if (ui->disk.win) ui->disk.restart = 1; if (ui->sensors.win) ui->sensors.restart = 1; + if (ui->network.win) ui->network.restart = 1; evisum_ui_config_save(ui); evisum_server_shutdown(); @@ -189,6 +207,15 @@ _menu_memory_activity_clicked_cb(void *data, Evas_Object *obj EINA_UNUSED, ui_mem_win_add(ui); } +static void +_menu_network_activity_clicked_cb(void *data, Evas_Object *obj EINA_UNUSED, + void *event_info EINA_UNUSED) +{ + Ui *ui = data; + + ui_network_win_add(ui); +} + static void _menu_disk_activity_clicked_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) @@ -438,6 +465,13 @@ evisum_ui_main_menu_create(Ui *ui, Evas_Object *parent, Evas_Object *obj) elm_table_pack(tb, rec, i, 0, 1, 1); elm_table_pack(tb, btn, i++, 0, 1, 1); + btn = _btn_create(tb, "network", _("Network"), + _menu_network_activity_clicked_cb, ui); + rec = evas_object_rectangle_add(evas_object_evas_get(obx)); + evas_object_size_hint_min_set(rec, ELM_SCALE_SIZE(BTN_HEIGHT), ELM_SCALE_SIZE(BTN_HEIGHT)); + elm_table_pack(tb, rec, i, 0, 1, 1); + elm_table_pack(tb, btn, i++, 0, 1, 1); + sep = elm_separator_add(tb); evas_object_size_hint_align_set(sep, FILL, FILL); evas_object_size_hint_weight_set(sep, EXPAND, EXPAND); @@ -654,11 +688,17 @@ evisum_ui_activate(Ui *ui, Evisum_Action action, int pid) restart = 1; } + if (ui->network.restart) + { + ui_network_win_add(ui); + restart = 1; + } + if (restart) { ui->proc.restart = ui->cpu.restart = 0; ui->mem.restart = ui->disk.restart = 0; - ui->sensors.restart = 0; + ui->sensors.restart = ui->network.restart = 0; evisum_ui_config_save(ui); return; } @@ -683,6 +723,9 @@ evisum_ui_activate(Ui *ui, Evisum_Action action, int pid) case EVISUM_ACTION_SENSORS: ui_sensors_win_add(ui); break; + case EVISUM_ACTION_NETWORK: + ui_network_win_add(ui); + break; } } diff --git a/src/bin/ui/ui.h b/src/bin/ui/ui.h index d6b0cf7..bd4ea30 100644 --- a/src/bin/ui/ui.h +++ b/src/bin/ui/ui.h @@ -82,6 +82,15 @@ typedef struct Ui int x, y; Eina_Bool restart; } sensors; + + struct + { + Evas_Object *win; + int width; + int height; + int x, y; + Eina_Bool restart; + } network; } Ui; Ui * diff --git a/src/bin/ui/ui_network.c b/src/bin/ui/ui_network.c new file mode 100644 index 0000000..6fc3963 --- /dev/null +++ b/src/bin/ui/ui_network.c @@ -0,0 +1,360 @@ +#include "ui_network.h" +#include "system/machine.h" + +typedef struct +{ + Ecore_Thread *thread; + Eina_List *interfaces; + Evas_Object *bx; + Eina_List *purge; + Eina_Bool skip_wait; + Ui *ui; +} Ui_Data; + +typedef struct +{ + char name[128]; + uint64_t total_in; + uint64_t total_out; + + uint64_t peak_in; + uint64_t peak_out; + + uint64_t in; + uint64_t out; + + Evas_Object *obj; + Eina_Bool is_new; +} Network_Interface; + +static void +_network_update(void *data, Ecore_Thread *thread) +{ + Ui_Data *pd = data; + int n; + + while (!ecore_thread_check(thread)) + { + Eina_List *l, *l2; + Network_Interface *iface, *iface2; + + net_iface_t *nwif, **ifaces = system_network_ifaces_get(&n); + EINA_LIST_FOREACH_SAFE(pd->interfaces, l, l2, iface2) + { + Eina_Bool found = 0; + for (int i = 0; i < n; i++) + { + nwif = ifaces[i]; + if (!strcmp(nwif->name, iface2->name)) + { + found = 1; + break; + } + } + if (!found) + { + if (iface2->obj) + pd->purge = eina_list_append(pd->purge, iface2->obj); + free(iface2); + pd->interfaces = eina_list_remove_list(pd->interfaces, l); + } + } + for (int i = 0; i < n; i++) + { + nwif = ifaces[i]; + iface = NULL; + EINA_LIST_FOREACH(pd->interfaces, l, iface2) + { + if (!strcmp(nwif->name, iface2->name)) + { + iface = iface2; + break; + } + } + if (!iface) + { + iface = calloc(1, sizeof(Network_Interface)); + iface->is_new = 1; + snprintf(iface->name, sizeof(iface->name), "%s", nwif->name); + pd->interfaces = eina_list_sorted_insert(pd->interfaces, (Eina_Compare_Cb) (void *)strcmp, iface->name); + } + else + { + iface->is_new = 0; + if ((nwif->xfer.in == iface->total_in) || (iface->total_in == 0)) + iface->in = 0; + else + iface->in = (nwif->xfer.in - iface->total_in); + if ((nwif->xfer.out == iface->total_out) || (iface->total_out == 0)) + iface->out = 0; + else + iface->out = (nwif->xfer.out - iface->total_out); + + if (iface->in > iface->peak_in) + iface->peak_in = iface->in; + if (iface->out > iface->peak_out) + iface->peak_out = iface->out; + iface->total_in = nwif->xfer.in; + iface->total_out = nwif->xfer.out; + + } + free(nwif); + } + free(ifaces); + + ecore_thread_feedback(thread, NULL); + for (int i = 0; i < 8; i++) + { + if (pd->skip_wait || ecore_thread_check(thread)) break; + usleep(250000); + } + pd->skip_wait = 0; + } +} + +static Evas_Object * +_lb_add(Evas_Object *base, const char *txt) +{ + Evas_Object *lb = elm_label_add(base); + evas_object_size_hint_weight_set(lb, 1.0, 1.0); + evas_object_size_hint_align_set(lb, FILL, FILL); + elm_object_text_set(lb, txt); + evas_object_show(lb); + + return lb; +} + +static Evas_Object * +_iface_obj_add(Evas_Object *base, const char *name) +{ + Evas_Object *tb, *lb; + + tb = elm_table_add(base); + evas_object_size_hint_weight_set(tb, 1.0, 1.0); + evas_object_size_hint_align_set(tb, FILL, FILL); + evas_object_show(tb); + + lb = _lb_add(base, _("Name")); + elm_table_pack(tb, lb, 0, 0, 1, 1); + lb = _lb_add(base, name); + elm_table_pack(tb, lb, 1, 0, 1, 1); + + lb = _lb_add(base, _("Total In/Out")); + elm_table_pack(tb, lb, 0, 1, 1, 1); + lb = _lb_add(base, ""); + evas_object_data_set(tb, "total", lb); + elm_table_pack(tb, lb, 1, 1, 1, 1); + + lb = _lb_add(base, _("Peak In/Out")); + elm_table_pack(tb, lb, 0, 2, 1, 1); + lb = _lb_add(base, ""); + evas_object_data_set(tb, "peak", lb); + elm_table_pack(tb, lb, 1, 2, 1, 1); + + lb = _lb_add(base, _("In/Out")); + elm_table_pack(tb, lb, 0, 3, 1, 1); + lb = _lb_add(base, ""); + evas_object_data_set(tb, "inout", lb); + elm_table_pack(tb, lb, 1, 3, 1, 1); + + return tb; +} + +static char * +_network_transfer_format(double rate) +{ + const char *unit = "B/s"; + + if (rate > 1048576) + { + rate /= 1048576; + unit = "MB/s"; + } + else if (rate > 1024 && rate < 1048576) + { + rate /= 1024; + unit = "KB/s"; + } + + return strdup(eina_slstr_printf("%.2f %s", rate, unit)); +} + +static void +_network_update_feedback_cb(void *data, Ecore_Thread *thread, void *msgdata) +{ + Network_Interface *iface; + Evas_Object *obj; + Eina_List *l; + char *s; + Eina_Strbuf *buf; + Ui_Data *pd = data; + + EINA_LIST_FREE(pd->purge, obj) + { + elm_box_unpack(pd->bx, obj); + evas_object_del(obj); + } + + buf = eina_strbuf_new(); + + EINA_LIST_FOREACH(pd->interfaces, l, iface) + { + if (iface->is_new) + { + iface->obj = _iface_obj_add(pd->bx, iface->name); + elm_box_pack_end(pd->bx, iface->obj); + } + else + { + obj = evas_object_data_get(iface->obj, "total"); + elm_object_text_set(obj, eina_slstr_printf("%s / %s", + evisum_size_format(iface->total_in), + evisum_size_format(iface->total_out))); + + obj = evas_object_data_get(iface->obj, "peak"); + s = _network_transfer_format(iface->peak_in); + eina_strbuf_append(buf, s); + free(s); + s = _network_transfer_format(iface->peak_out); + eina_strbuf_append_printf(buf, " / %s", s); + free(s); + elm_object_text_set(obj, eina_strbuf_string_get(buf)); + eina_strbuf_reset(buf); + + obj = evas_object_data_get(iface->obj, "inout"); + s = _network_transfer_format(iface->in); + eina_strbuf_append(buf, s); + free(s); + s = _network_transfer_format(iface->out); + eina_strbuf_append_printf(buf, " / %s", s); + free(s); + elm_object_text_set(obj, eina_strbuf_string_get(buf)); + eina_strbuf_reset(buf); + } + + } + eina_strbuf_free(buf); +} + +static void +_win_key_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Evas_Event_Key_Down *ev; + Ui_Data *pd; + + pd = data; + ev = event_info; + + if (!ev || !ev->keyname) + return; + + if (!strcmp(ev->keyname, "Escape")) + evas_object_del(pd->ui->network.win); +} + +static void +_win_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + Ui_Data *pd; + Ui *ui; + + pd = data; + ui = pd->ui; + + evas_object_geometry_get(obj, &ui->network.x, &ui->network.y, NULL, NULL); +} + +static void +_win_del_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, + void *event_info EINA_UNUSED) +{ + Ui_Data *pd = data; + Ui *ui = pd->ui; + Network_Interface *iface; + + evisum_ui_config_save(ui); + + ecore_thread_cancel(pd->thread); + ecore_thread_wait(pd->thread, 0.5); + eina_list_free(pd->purge); + EINA_LIST_FREE(pd->interfaces, iface) + free(iface); + ui->network.win = NULL; + free(pd); +} + +static void +_win_resize_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Ui_Data *pd = data; + + evisum_ui_config_save(pd->ui); +} + +void +ui_network_win_add(Ui *ui) +{ + Evas_Object *win, *pop, *scr, *bx; + + if (ui->network.win) + { + elm_win_raise(ui->network.win); + return; + } + + Ui_Data *pd = calloc(1, sizeof(Ui_Data)); + if (!pd) return; + pd->ui = ui; + + ui->network.win = win = elm_win_util_standard_add("evisum", _("Network")); + elm_win_autodel_set(win, 1); + evas_object_size_hint_weight_set(win, EXPAND, EXPAND); + evas_object_size_hint_align_set(win, FILL, FILL); + evisum_ui_background_random_add(win, + evisum_ui_backgrounds_enabled_get()); + evas_object_event_callback_add(win, EVAS_CALLBACK_DEL, _win_del_cb, pd); + evas_object_event_callback_add(win, EVAS_CALLBACK_MOVE, _win_move_cb, pd); + evas_object_event_callback_add(win, EVAS_CALLBACK_RESIZE, _win_resize_cb, pd); + evas_object_event_callback_add(win, EVAS_CALLBACK_KEY_DOWN, _win_key_down_cb, pd); + + pop = elm_popup_add(win); + elm_object_style_set(pop, "transparent"); + elm_object_part_text_set(pop, "title,text", "Interfaces"); + evas_object_size_hint_weight_set(pop, 1.0, 1.0); + evas_object_size_hint_align_set(pop, FILL, FILL); + evas_object_show(pop); + + scr = elm_scroller_add(win); + elm_scroller_content_min_limit(scr, 0, 1); + evas_object_size_hint_weight_set(scr, 1.0, 1.0); + evas_object_size_hint_align_set(scr, FILL, FILL); + evas_object_size_hint_min_set(scr, 1, ELM_SCALE_SIZE(400)); + evas_object_show(scr); + + pd->bx = bx = elm_box_add(win); + evas_object_size_hint_weight_set(bx, 1.0, 1.0); + evas_object_size_hint_align_set(bx, FILL, FILL); + elm_box_padding_set(bx, ELM_SCALE_SIZE(10), ELM_SCALE_SIZE(10)); + evas_object_show(bx); + elm_object_content_set(scr, bx); + elm_object_content_set(pop, scr); + + if (ui->network.width > 0 && ui->network.height > 0) + evas_object_resize(win, ui->network.width, ui->network.height); + else + evas_object_resize(win, UI_CHILD_WIN_WIDTH, UI_CHILD_WIN_HEIGHT); + + if (ui->network.x > 0 && ui->network.y > 0) + evas_object_move(win, ui->network.x, ui->network.y); + else + elm_win_center(win, 1, 1); + + evas_object_show(win); + + pd->thread = ecore_thread_feedback_run(_network_update, + _network_update_feedback_cb, + NULL, + NULL, + pd, 1); +} + diff --git a/src/bin/ui/ui_network.h b/src/bin/ui/ui_network.h new file mode 100644 index 0000000..40af2aa --- /dev/null +++ b/src/bin/ui/ui_network.h @@ -0,0 +1,10 @@ +#ifndef __UI_NETWORK_H__ +#define __UI_NETWORK_H__ + +#include "ui.h" +#include "../system/machine.h" + +void +ui_network_win_add(Ui *ui); + +#endif