Convert LTTngTop to C++ and state system
[lttngtop.git] / src / cursesdisplay.cpp
diff --git a/src/cursesdisplay.cpp b/src/cursesdisplay.cpp
new file mode 100644 (file)
index 0000000..3cd273f
--- /dev/null
@@ -0,0 +1,1797 @@
+/*
+ * Copyright (C) 2011-2012 Julien Desfossez
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <ncurses.h>
+#include <panel.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+#include <state/StateSystem.hpp>
+#include <state/statevalue/StateValue.hpp>
+#include <state/statevalue/IntegerStateValue.hpp>
+#include <state/statevalue/StringStateValue.hpp>
+#include <state/statevalue/NullStateValue.hpp>
+#include <state/statevalue/QuarkStateValue.hpp>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include "cursesdisplay.h"
+#include "lttngtoptypes.h"
+#include "iostreamtop.h"
+#include "common.h"
+
+#define DEFAULT_DELAY 15
+#define MAX_LINE_LENGTH 50
+#define MAX_LOG_LINES 4
+
+using namespace State;
+
+enum view_list current_view;
+enum view_list previous_view;
+
+/* to prevent concurrent updates of the different windows */
+sem_t update_display_sem;
+
+char *termtype;
+WINDOW *footer, *header, *center, *status;
+WINDOW *pref_panel_window = NULL;
+PANEL *pref_panel, *main_panel;
+
+int pref_panel_visible = 0;
+int pref_line_selected = 0;
+int pref_current_sort = 0;
+
+Quark selected_process;
+int selected_ret;
+
+int selected_line = 0; /* select bar position */
+int selected_in_list = 0; /* selection relative to the whole list */
+int list_offset = 0; /* first index in the list to display (scroll) */
+int nb_log_lines = 0;
+char log_lines[MAX_LINE_LENGTH * MAX_LOG_LINES + MAX_LOG_LINES];
+
+int max_elements = 80;
+
+int toggle_threads = 1;
+int toggle_pause = -1;
+
+int max_center_lines;
+GPtrArray *selected_processes;
+
+pthread_t keyboard_thread;
+
+struct header_view cputopview[4];
+struct header_view iostreamtopview[3];
+struct header_view fileview[3];
+
+unsigned long i_start = 0;
+unsigned long i_end = 0;
+
+std::string sort_perf_key;
+
+
+void reset_ncurses()
+{
+       curs_set(1);
+       endwin();
+       exit(0);
+}
+
+static void handle_sigterm(int signal)
+{
+       reset_ncurses();
+}
+
+void init_screen()
+{
+       initscr();
+       noecho();
+       halfdelay(DEFAULT_DELAY);
+       nonl();
+       intrflush(stdscr, false);
+       keypad(stdscr, true);
+       curs_set(0);
+
+       if (has_colors()) {
+               start_color();
+               init_pair(1, COLOR_RED, COLOR_BLACK); /* - */
+               init_pair(2, COLOR_GREEN, COLOR_BLACK); /* + */
+               init_pair(3, COLOR_BLACK, COLOR_WHITE); /* keys */
+               init_pair(4, COLOR_WHITE, COLOR_GREEN); /* keys activated */
+               init_pair(5, COLOR_WHITE, COLOR_BLUE); /* select line */
+               init_pair(6, COLOR_WHITE, COLOR_GREEN); /* selected process */
+       }
+       termtype = getenv("TERM");
+       if (!strcmp(termtype, "xterm") ||  !strcmp(termtype, "xterm-color") ||
+                       !strcmp(termtype, "vt220")) {
+               define_key("\033[H", KEY_HOME);
+               define_key("\033[F", KEY_END);
+               define_key("\033OP", KEY_F(1));
+               define_key("\033OQ", KEY_F(2));
+               define_key("\033OR", KEY_F(3));
+               define_key("\033OS", KEY_F(4));
+               define_key("\0330U", KEY_F(6));
+               define_key("\033[11~", KEY_F(1));
+               define_key("\033[12~", KEY_F(2));
+               define_key("\033[13~", KEY_F(3));
+               define_key("\033[14~", KEY_F(4));
+               define_key("\033[16~", KEY_F(6));
+               define_key("\033[17;2~", KEY_F(18));
+       }
+       signal(SIGTERM, handle_sigterm);
+       mousemask(BUTTON1_CLICKED, NULL);
+       refresh();
+}
+
+WINDOW *create_window(int height, int width, int startx, int starty)
+{
+       WINDOW *win;
+       win = newwin(height, width, startx, starty);
+       box(win, 0 , 0);
+       wrefresh(win);
+       return win;
+}
+
+WINDOW *create_window_no_border(int height, int width, int startx, int starty)
+{
+       WINDOW *win;
+       win = newwin(height, width, startx, starty);
+       wrefresh(win);
+       return win;
+}
+
+void print_digit(WINDOW *win, int digit)
+{
+       if (digit < 0) {
+               wattron(win, COLOR_PAIR(1));
+               wprintw(win, "%d", digit);
+               wattroff(win, COLOR_PAIR(1));
+       } else if (digit > 0) {
+               wattron(win, COLOR_PAIR(2));
+               wprintw(win, "+%d", digit);
+               wattroff(win, COLOR_PAIR(2));
+       } else {
+               wprintw(win, "0");
+       }
+}
+
+void print_digits(WINDOW *win, int first, int second)
+{
+       wprintw(win, "(");
+       print_digit(win, first);
+       wprintw(win, ", ");
+       print_digit(win, second);
+       wprintw(win, ")");
+}
+
+void print_headers(int line, const char desc[], int value, int first, int second)
+{
+       wattron(header, A_BOLD);
+       mvwprintw(header, line, 4, "%s", desc);
+       wattroff(header, A_BOLD);
+       mvwprintw(header, line, 16, "%d", value);
+       wmove(header, line, 24);
+       print_digits(header, first, second);
+       wmove(header, line, 40);
+}
+
+void set_window_title(WINDOW *win, const char title[])
+{
+       wattron(win, A_BOLD);
+       mvwprintw(win, 0, 1, title);
+       wattroff(win, A_BOLD);
+}
+
+void print_log(const char str[])
+{
+       unsigned int i;
+       int current_line = 1;
+       int current_char = 1;
+       char *tmp, *tmp2;
+       /* rotate the line buffer */
+       if (nb_log_lines >= MAX_LOG_LINES) {
+               tmp = strndup(log_lines, MAX_LINE_LENGTH * MAX_LOG_LINES + MAX_LOG_LINES);
+               tmp2 = strchr(tmp, '\n');
+               memset(log_lines, '\0', strlen(log_lines));
+               strncat(log_lines, tmp2 + 1, strlen(tmp2) - 1);
+               log_lines[strlen(log_lines)] = '\n';
+               log_lines[strlen(log_lines)] = '\0';
+               free(tmp);
+       }
+       nb_log_lines++;
+
+       strncat(log_lines, str, MAX_LINE_LENGTH - 1);
+
+       if (nb_log_lines < MAX_LOG_LINES)
+               log_lines[strlen(log_lines)] = '\n';
+       log_lines[strlen(log_lines)] = '\0';
+
+       werase(status);
+       box(status, 0 , 0);
+       set_window_title(status, "Status");
+       for (i = 0; i < strlen(log_lines); i++) {
+               if (log_lines[i] == '\n') {
+                       wmove(status, ++current_line, 1);
+                       current_char = 1;
+               } else {
+                       mvwprintw(status, current_line, current_char++, "%c",
+                                       log_lines[i]);
+               }
+       }
+       wrefresh(status);
+}
+
+int process_selected(Quark proc)
+{
+       int selected;
+       get_current_attribute_value_int(&proc, "selected", selected);
+       return selected;
+}
+
+void update_selected_processes()
+{
+       Quark selected = state_system->getQuark(selected_process, "selected");
+       if (process_selected(selected_process)) {
+               state_system->updateCurrentState(selected, 0);
+               print_log("Process removed");
+       } else {
+               state_system->updateCurrentState(selected, 1);
+               print_log("Process added");
+       }
+}
+
+void print_key(WINDOW *win, const char key[], const char desc[], int toggle)
+{
+       int pair;
+       if (toggle > 0)
+               pair = 4;
+       else
+               pair = 3;
+       wattron(win, COLOR_PAIR(pair));
+       wprintw(footer, "%s", key);
+       wattroff(win, COLOR_PAIR(pair));
+       wprintw(footer, ":%s", desc);
+}
+
+void update_footer()
+{
+       sem_wait(&update_display_sem);
+       werase(footer);
+       wmove(footer, 1, 1);
+       print_key(footer, "F2", "CPUtop  ", current_view == cpu);
+       print_key(footer, "F3", "PerfTop  ", current_view == perf);
+       print_key(footer, "F4", "IOTop  ", current_view == iostream);
+       print_key(footer, "Enter", "Details  ", current_view == process_details);
+       print_key(footer, "Space", "Highlight  ", 0);
+       print_key(footer, "q", "Quit ", 0);
+       print_key(footer, "r", "Pref  ", 0);
+       print_key(footer, "t", "Threads  ", toggle_threads);
+       print_key(footer, "p", "Pause  ", toggle_pause);
+
+       wrefresh(footer);
+       sem_post(&update_display_sem);
+}
+
+void basic_header()
+{
+       werase(header);
+       box(header, 0 , 0);
+       set_window_title(header, "Statistics for interval [gathering data...[");
+       wattron(header, A_BOLD);
+       mvwprintw(header, 1, 4, "CPUs");
+       mvwprintw(header, 2, 4, "Threads");
+       mvwprintw(header, 3, 4, "FDs");
+       wattroff(header, A_BOLD);
+       wrefresh(header);
+}
+
+struct tm format_timestamp(uint64_t timestamp)
+{
+       struct tm tm;
+       uint64_t ts_sec = 0, ts_nsec;
+       time_t time_s;
+
+       ts_nsec = timestamp;
+       ts_sec += ts_nsec / NSEC_PER_SEC;
+       ts_nsec = ts_nsec % NSEC_PER_SEC;
+
+       time_s = (time_t) ts_sec;
+
+       localtime_r(&time_s, &tm);
+
+       return tm;
+}
+
+static void scale_unit(uint64_t bytes, char *ret)
+{
+       if (bytes >= 1000000000)
+               sprintf(ret, "%" PRIu64 "G", bytes/1000000000);
+       if (bytes >= 1000000)
+               sprintf(ret, "%" PRIu64 "M", bytes/1000000);
+       else if (bytes >= 1000)
+               sprintf(ret, "%" PRIu64 "K", bytes/1000);
+       else
+               sprintf(ret, "%" PRIu64, bytes);
+}
+
+uint64_t total_io()
+{
+       uint64_t total = 0;
+       int read, write;
+       unsigned long birth;
+       unsigned long real_start;
+       Quark proc;
+
+       if (get_attribute_value_at_quark(i_end, NULL, "proc", proc)) {
+               do {
+                       get_attribute_value_at_ulong(
+                               i_end, &proc, "birth", birth);
+                       if (birth > i_start)
+                               real_start = birth;
+                       else
+                               real_start = i_start;
+                       get_interval_value_int(real_start, i_end, &proc,
+                                                "fileread", read);
+                       get_interval_value_int(real_start, i_end, &proc,
+                                                "filewrite", write);
+                       total += read + write;
+
+               } while (get_attribute_value_at_quark(
+                                i_end, &proc, "next", proc));
+       }
+
+       return total;
+}
+
+void update_header()
+{
+       struct tm start, end;
+       uint64_t ts_nsec_start, ts_nsec_end;
+       char io[16];
+       int cpu_nb;
+       int nbthreads, nbnewthreads, nbdeadthreads;
+       int nbfiles, nbnewfiles, nbdeadfiles;
+
+       ts_nsec_start = i_start % NSEC_PER_SEC;
+       start = format_timestamp(i_start);
+
+       ts_nsec_end = i_end % NSEC_PER_SEC;
+       end = format_timestamp(i_end);
+
+       werase(header);
+       box(header, 0 , 0);
+       set_window_title(header, "Statistics for interval ");
+       wattron(header, A_BOLD);
+
+       wprintw(header,
+               "[%02d:%02d:%02d.%09" PRIu64 ", %02d:%02d:%02d.%09" PRIu64 "[",
+               start.tm_hour, start.tm_min, start.tm_sec, ts_nsec_start,
+               end.tm_hour, end.tm_min, end.tm_sec, ts_nsec_end);
+       mvwprintw(header, 1, 4, "CPUs");
+       wattroff(header, A_BOLD);
+
+       cpu_nb = get_sequence_length(i_end, state_system->getQuark("cpu"));
+       get_attribute_value_at_int(i_end, NULL, "nbthreads", nbthreads);
+       get_interval_value_int(i_start, i_end, NULL, "nbnewthreads",
+                              nbnewthreads);
+       get_interval_value_int(i_start, i_end, NULL, "nbdeadthreads",
+                              nbdeadthreads);
+       get_attribute_value_at_int(i_end, NULL, "nbfiles", nbfiles);
+       get_interval_value_int(i_start, i_end, NULL, "nbnewfiles", nbnewfiles);
+       get_interval_value_int(i_start, i_end, NULL, "nbdeadfiles",
+                              nbdeadfiles);
+
+       wprintw(header, "\t%d\t(max/cpu : %0.2f%)", cpu_nb,
+                       100.0/cpu_nb);
+       print_headers(2, "Threads", nbthreads, nbnewthreads,-1*nbdeadthreads);
+       print_headers(3, "FDs", nbfiles, nbnewfiles,-1*nbdeadfiles);
+       scale_unit(total_io(), io);
+       mvwprintw(header, 3, 43, "%sB/sec", io);
+       wrefresh(header);
+}
+
+int sort_by_cpu_desc(const void *pp1, const void *pp2)
+{
+       Quark p1 = *(Quark *)pp1;
+       Quark p2 = *(Quark *)pp2;
+       unsigned long total1, total2;
+       unsigned long birth1, birth2;
+       unsigned long start1 = i_start;
+       unsigned long start2 = i_start;
+
+       get_attribute_value_at_ulong(i_end, &p1, "birth", birth1);
+       get_attribute_value_at_ulong(i_end, &p2, "birth", birth2);
+       if (birth1 > i_start)
+               start1 = birth1;
+       if (birth2 > i_start)
+               start2 = birth2;
+
+       get_interval_value_ulong(start1, i_end, &p1, "totalcpunsec", total1);
+       get_interval_value_ulong(start2, i_end, &p2, "totalcpunsec", total2);
+
+       if (total1 > total2)
+               return 1;
+       if (total1 == total2)
+               return 0;
+       return -1;
+}
+
+int sort_by_tid_desc(const void *pp1, const void *pp2)
+{
+       Quark p1 = *(Quark *)pp1;
+       Quark p2 = *(Quark *)pp2;
+       int tid1, tid2;
+
+       get_attribute_value_at_int(i_end, &p1, "tid", tid1);
+       get_attribute_value_at_int(i_end, &p2, "tid", tid2);
+
+       if (tid1 > tid2)
+               return 1;
+       if (tid1 == tid2)
+               return 0;
+       return -1;
+}
+
+int sort_by_pid_desc(const void *pp1, const void *pp2)
+{
+       Quark p1 = *(Quark *)pp1;
+       Quark p2 = *(Quark *)pp2;
+       int pid1, pid2;
+
+       get_attribute_value_at_int(i_end, &p1, "pid", pid1);
+       get_attribute_value_at_int(i_end, &p2, "pid", pid2);
+
+       if (pid1 > pid2)
+               return 1;
+       if (pid1 == pid2)
+               return 0;
+       return -1;
+}
+
+
+int sort_by_process_read_desc(const void *pp1, const void *pp2)
+{
+       Quark p1 = *(Quark *)pp1;
+       Quark p2 = *(Quark *)pp2;
+       int total1, total2;
+       unsigned long birth1, birth2;
+       unsigned long start1 = i_start;
+       unsigned long start2 = i_start;
+
+       get_attribute_value_at_ulong(i_end, &p1, "birth", birth1);
+       get_attribute_value_at_ulong(i_end, &p2, "birth", birth2);
+       if (birth1 > i_start)
+               start1 = birth1;
+       if (birth2 > i_start)
+               start2 = birth2;
+
+       get_interval_value_int(start1, i_end, &p1, "fileread", total1);
+       get_interval_value_int(start2, i_end, &p2, "fileread", total2);
+
+       if (total1 > total2)
+               return 1;
+       if (total1 == total2)
+               return 0;
+       return -1;
+}
+
+int sort_by_process_write_desc(const void *pp1, const void *pp2)
+{
+       Quark p1 = *(Quark *)pp1;
+       Quark p2 = *(Quark *)pp2;
+       int total1, total2;
+       unsigned long birth1, birth2;
+       unsigned long start1 = i_start;
+       unsigned long start2 = i_start;
+
+       get_attribute_value_at_ulong(i_end, &p1, "birth", birth1);
+       get_attribute_value_at_ulong(i_end, &p2, "birth", birth2);
+       if (birth1 > i_start)
+               start1 = birth1;
+       if (birth2 > i_start)
+               start2 = birth2;
+
+       get_interval_value_int(start1, i_end, &p1, "filewrite", total1);
+       get_interval_value_int(start2, i_end, &p2, "filewrite", total2);
+
+       if (total1 > total2)
+               return 1;
+       if (total1 == total2)
+               return 0;
+       return -1;
+}
+
+int sort_by_process_total_desc(const void *pp1, const void *pp2)
+{
+       Quark p1 = *(Quark *)pp1;
+       Quark p2 = *(Quark *)pp2;
+       int p1Read, p2Read;
+       int p1Write, p2Write;
+       int total1, total2;
+       unsigned long birth1, birth2;
+       unsigned long start1 = i_start;
+       unsigned long start2 = i_start;
+
+       get_attribute_value_at_ulong(i_end, &p1, "birth", birth1);
+       get_attribute_value_at_ulong(i_end, &p2, "birth", birth2);
+       if (birth1 > i_start)
+               start1 = birth1;
+       if (birth2 > i_start)
+               start2 = birth2;
+
+       get_interval_value_int(start1, i_end, &p1, "fileread", p1Read);
+       get_interval_value_int(start2, i_end, &p2, "fileread", p2Read);
+       get_interval_value_int(start1, i_end, &p1, "filewrite", p1Write);
+       get_interval_value_int(start2, i_end, &p2, "filewrite", p2Write);
+
+       total1 = p1Read + p1Write;
+       total2 = p2Read + p2Write;
+
+       if (total1 > total2)
+               return 1;
+       if (total1 == total2)
+               return 0;
+       return -1;
+}
+
+int sort_by_file_read_desc(const void *pf1, const void *pf2)
+{
+       Quark f1 = *(Quark *)pf1;
+       Quark f2 = *(Quark *)pf2;
+       int total1, total2;
+       unsigned long birth1, birth2;
+       unsigned long start1 = i_start;
+       unsigned long start2 = i_start;
+
+       get_attribute_value_at_ulong(i_end, &f1, "file/birth", birth1);
+       get_attribute_value_at_ulong(i_end, &f2, "file/birth", birth2);
+       if (birth1 > i_start)
+               start1 = birth1;
+       if (birth2 > i_start)
+               start2 = birth2;
+
+       get_interval_value_int(start1, i_end, &f1, "file/read", total1);
+       get_interval_value_int(start2, i_end, &f2, "file/read", total2);
+
+       if (total1 > total2)
+               return 1;
+       if (total1 == total2)
+               return 0;
+       return -1;
+}
+
+int sort_by_file_write_desc(const void *pf1, const void *pf2)
+{
+       Quark f1 = *(Quark *)pf1;
+       Quark f2 = *(Quark *)pf2;
+       int total1, total2;
+       unsigned long birth1, birth2;
+       unsigned long start1 = i_start;
+       unsigned long start2 = i_start;
+
+       get_attribute_value_at_ulong(i_end, &f1, "file/birth", birth1);
+       get_attribute_value_at_ulong(i_end, &f2, "file/birth", birth2);
+       if (birth1 > i_start)
+               start1 = birth1;
+       if (birth2 > i_start)
+               start2 = birth2;
+
+       get_interval_value_int(start1, i_end, &f1, "file/write", total1);
+       get_interval_value_int(start2, i_end, &f2, "file/write", total2);
+
+       if (total1 > total2)
+               return 1;
+       if (total1 == total2)
+               return 0;
+       return -1;
+}
+
+int sort_by_file_fd_desc(const void *pf1, const void *pf2)
+{
+       Quark f1 = *(Quark *)pf1;
+       Quark f2 = *(Quark *)pf2;
+       int fd1, fd2;
+
+       get_attribute_value_at_int(i_end, &f1, "file/fd", fd1);
+       get_attribute_value_at_int(i_end, &f2, "file/fd", fd2);
+
+       if (fd1 > fd2)
+               return 1;
+       if (fd1 == fd2)
+               return 0;
+       return -1;
+}
+
+int sort_by_cpu_group_by_threads_desc(const void *pp1, const void *pp2)
+{
+       Quark p1 = *(Quark *)pp1;
+       Quark p2 = *(Quark *)pp2;
+       unsigned long total1, total2;
+       unsigned long birth1, birth2;
+       unsigned long start1 = i_start;
+       unsigned long start2 = i_start;
+
+       get_attribute_value_at_ulong(i_end, &p1, "birth", birth1);
+       get_attribute_value_at_ulong(i_end, &p2, "birth", birth2);
+       if (birth1 > i_start)
+               start1 = birth1;
+       if (birth2 > i_start)
+               start2 = birth2;
+
+       get_interval_value_ulong(start1, i_end, &p1, "threadstotalcpunsec",
+                                total1);
+       get_interval_value_ulong(start2, i_end, &p2, "threadstotalcpunsec",
+                                total2);
+
+       if (total1 > total2)
+               return 1;
+       if (total1 == total2)
+               return 0;
+       return -1;
+}
+
+void update_cputop_display()
+{
+       unsigned int i;
+       int header_offset = 2;
+       unsigned long elapsed;
+       double maxcputime;
+       int nblinedisplayed = 0;
+       int current_line = 0;
+       int column;
+       Quark *processes;
+       int tid, pid;
+       unsigned long totalcpunsec;
+       std::string comm;
+
+       Quark cpu_root = state_system->getQuark("cpu");
+       Quark proc_root = state_system->getQuark("proc");
+       unsigned int cpu_nb = get_sequence_length(i_end, cpu_root);
+       unsigned int proc_nb = get_sequence_length(i_end, proc_root);
+
+       elapsed = i_end - i_start;
+       maxcputime = elapsed * cpu_nb / 100.0;
+
+       processes = g_new(Quark, proc_nb);
+       sequence_to_array(i_end, proc_root, processes, proc_nb);
+
+       if (cputopview[0].sort == 1)
+               qsort(processes, proc_nb, sizeof(Quark), sort_by_cpu_desc);
+       else if (cputopview[1].sort == 1)
+               qsort(processes, proc_nb, sizeof(Quark), sort_by_pid_desc);
+       else if (cputopview[2].sort == 1)
+               qsort(processes, proc_nb, sizeof(Quark), sort_by_tid_desc);
+       else if (cputopview[3].sort == 1)
+               qsort(processes, proc_nb, sizeof(Quark), sort_by_cpu_desc);
+       else
+               qsort(processes, proc_nb, sizeof(Quark), sort_by_cpu_desc);
+
+       set_window_title(center, "CPU Top");
+       wattron(center, A_BOLD);
+       column = 1;
+       for (i = 0; i < 4; i++) {
+               if (cputopview[i].sort) {
+                       wattron(center, A_UNDERLINE);
+                       pref_current_sort = i;
+               }
+               mvwprintw(center, 1, column, cputopview[i].title);
+               wattroff(center, A_UNDERLINE);
+               column += 10;
+       }
+       wattroff(center, A_BOLD);
+
+       max_center_lines = LINES - 5 - 7 - 1 - header_offset;
+
+       /* iterate the process (thread) list */
+       for (i = list_offset; i < proc_nb && nblinedisplayed < max_center_lines;
+            i++) {
+               get_attribute_value_at_int(i_end, processes + i, "tid", tid);
+               get_attribute_value_at_int(i_end, processes + i, "pid", pid);
+
+               if (pid != tid)
+                       if (toggle_threads == -1)
+                               continue;
+
+               if (process_selected(processes[i])) {
+                       wattron(center, COLOR_PAIR(6));
+                       mvwhline(center, current_line + header_offset, 1, ' ',
+                                COLS-3);
+               }
+               if (current_line == selected_line) {
+                       selected_process = processes[i];
+                       wattron(center, COLOR_PAIR(5));
+                       mvwhline(center, current_line + header_offset, 1, ' ',
+                                COLS-3);
+               }
+               /* CPU(%) */
+               get_interval_value_ulong(i_start, i_end, processes + i,
+                                        "totalcpunsec", totalcpunsec);
+               mvwprintw(center, current_line + header_offset, 1, "%1.2f",
+                               totalcpunsec / maxcputime);
+               /* PID */
+               mvwprintw(center, current_line + header_offset, 11, "%d", pid);
+               /* TID */
+               mvwprintw(center, current_line + header_offset, 21, "%d", tid);
+               /* NAME */
+               get_attribute_value_at_string(i_end, processes + i, "comm",
+                                             comm);
+               mvwprintw(center, current_line + header_offset, 31, "%s",
+                         comm.c_str());
+               wattroff(center, COLOR_PAIR(6));
+               wattroff(center, COLOR_PAIR(5));
+               nblinedisplayed++;
+               current_line++;
+       }
+
+       g_free(processes);
+}
+
+int sort_perf(const void *pp1, const void *pp2)
+{
+       Quark p1 = *(Quark *)pp1;
+       Quark p2 = *(Quark *)pp2;
+       std::string key = sort_perf_key;
+       int total1;
+       int total2;
+       int tid1;
+       int tid2;
+
+       if (!get_attribute_value_at_int(i_end, &p1, "perf/" + key + "/count",
+                                   total1))
+               total1 = 0;
+
+       if (!get_attribute_value_at_int(i_end, &p2, "perf/" + key + "/count",
+                                   total2))
+               total2 = 0;
+
+
+       if (total1 < total2)
+               return 1;
+       if (total1 == total2) {
+               get_attribute_value_at_int(i_end, &p1, "tid", tid1);
+               get_attribute_value_at_int(i_end, &p2, "tid", tid2);
+               if (tid1 < tid2)
+                       return 1;
+               return -1;
+       }
+       return -1;
+}
+
+void print_key_title(const char key[], int line)
+{
+       wattron(center, A_BOLD);
+       mvwprintw(center, line, 1, "%s", key);
+       mvwprintw(center, line, 30, " ");
+       wattroff(center, A_BOLD);
+}
+
+void update_process_details()
+{
+       unsigned long elapsed;
+       double maxcputime;
+       unsigned int i, j = 0;
+       char unit[4];
+       char filename_buf[COLS];
+       int line = 1;
+       int column;
+       unsigned int cpu_nb;
+       std::string comm;
+       int tid = -1, pid, ppid, fileread, filewrite;
+       unsigned long totalcpunsec;
+       Quark *global_perf;
+       unsigned int global_perf_nb;
+       std::string key;
+       int count;
+       Quark *files;
+       unsigned int file_nb;
+       int fd, read, write;
+       std::string name;
+
+       set_window_title(center, "Process details");
+
+       elapsed = i_end - i_start;
+       cpu_nb = get_sequence_length(i_end, state_system->getQuark("cpu"));
+       maxcputime = elapsed * cpu_nb / 100.0;
+
+       get_attribute_value_at_int(i_end, &selected_process, "tid", tid);
+       if (tid == -1) {
+               print_key_title("Does not exit at this time", 3);
+               return;
+       }
+
+       print_key_title("Name", line++);
+       get_attribute_value_at_string(i_end, &selected_process, "comm", comm);
+       wprintw(center, "%s", comm.c_str());
+       print_key_title("TID", line++);
+       wprintw(center, "%d", tid);
+
+       print_key_title("PID", line++);
+       get_attribute_value_at_int(i_end, &selected_process, "pid", pid);
+       wprintw(center, "%d", pid);
+       print_key_title("PPID", line++);
+       get_attribute_value_at_int(i_end, &selected_process, "ppid", ppid);
+       wprintw(center, "%d", ppid);
+       print_key_title("CPU", line++);
+       get_attribute_value_at_ulong(i_end, &selected_process, "totalcpunsec",
+                                  totalcpunsec);
+       wprintw(center, "%1.2f %%", totalcpunsec/maxcputime);
+
+       print_key_title("READ B/s", line++);
+       get_attribute_value_at_int(i_end, &selected_process, "fileread",
+                                  fileread);
+       scale_unit(fileread, unit);
+       wprintw(center, "%s", unit);
+
+       print_key_title("WRITE B/s", line++);
+       get_attribute_value_at_int(i_end, &selected_process, "filewrite",
+                                  filewrite);
+       scale_unit(filewrite, unit);
+       wprintw(center, "%s", unit);
+
+
+       global_perf_nb = get_global_perf_list_size(i_end);
+       global_perf = g_new(Quark, global_perf_nb);
+       get_global_perf_list(i_end, global_perf, global_perf_nb);
+       for (i = 0; i < global_perf_nb; i++) {
+               get_attribute_value_at_string(i_end, global_perf + i, "key",
+                                             key);
+               print_key_title(key.c_str(), line++);
+               if (!get_attribute_value_at_int(i_end, global_perf + i, "count",
+                                              count))
+                       count = 0;
+               wprintw(center, "%d", count);
+       }
+       line++;
+
+       wattron(center, A_BOLD);
+       column = 1;
+       for (i = 0; i < 3; i++) {
+               if (fileview[i].sort) {
+                       pref_current_sort = i;
+                       wattron(center, A_UNDERLINE);
+               }
+               mvwprintw(center, line, column, fileview[i].title);
+               wattroff(center, A_UNDERLINE);
+               column += 10;
+       }
+       mvwprintw(center, line++, column, "FILENAME");
+       wattroff(center, A_BOLD);
+
+       file_nb = get_number_of_opened_files(i_end, selected_process);
+       files = g_new(Quark, file_nb);
+       get_opened_files(i_end, selected_process, files, file_nb);
+
+       if (fileview[0].sort == 1)
+               qsort(files, file_nb, sizeof(Quark), sort_by_file_fd_desc);
+       else if (fileview[1].sort == 1)
+               qsort(files, file_nb, sizeof(Quark), sort_by_file_read_desc);
+       else if (fileview[2].sort == 1)
+               qsort(files, file_nb, sizeof(Quark), sort_by_file_write_desc);
+       else
+               qsort(files, file_nb, sizeof(Quark), sort_by_file_fd_desc);
+
+       for (i = selected_line;
+            i < file_nb && i < (selected_line + max_center_lines - line + 2);
+            i++) {
+               get_attribute_value_at_int(i_end, files + i, "fd", fd);
+               mvwprintw(center, line + j, 1, "%d", fd);
+               get_attribute_value_at_int(i_end, files + i, "read", read);
+               scale_unit(read, unit);
+               mvwprintw(center, line + j, 11, "%s", unit);
+               get_attribute_value_at_int(i_end, files + i, "write", write);
+               scale_unit(write, unit);
+               mvwprintw(center, line + j, 21, "%s", unit);
+               get_attribute_value_at_string(i_end, files + i, "name", name);
+               snprintf(filename_buf, COLS - 25, "%s", name.c_str());
+               mvwprintw(center, line + j, 31, "%s", filename_buf);
+               j++;
+       }
+       g_free(global_perf);
+       g_free(files);
+}
+
+void update_perf()
+{
+       unsigned int i, j;
+       int nblinedisplayed = 0;
+       int current_line = 0;
+       int header_offset = 2;
+       int perf_row = 40;
+       int value;
+       unsigned int global_perf_nb;
+       Quark *global_perf;
+       int sort = 0;
+       int visible = 0;
+       std::string key;
+       bool sort_exists;
+       unsigned int proc_nb;
+       Quark *procs;
+       Quark proc_beg;
+       int tid, pid;
+       std::string comm;
+
+       set_window_title(center, "Perf Top");
+       wattron(center, A_BOLD);
+       mvwprintw(center, 1, 1, "PID");
+       mvwprintw(center, 1, 11, "TID");
+       mvwprintw(center, 1, 22, "NAME");
+
+       perf_row = 40;
+       global_perf_nb = get_global_perf_list_size(i_end);
+       global_perf = g_new(Quark, global_perf_nb);
+       get_global_perf_list(i_end, global_perf, global_perf_nb);
+       for (i = 0; i < global_perf_nb; i++) {
+               get_attribute_value_at_int(i_end, global_perf + i, "visible",
+                                          visible);
+               get_attribute_value_at_string(i_end, global_perf + i, "key",
+                                             key);
+               sort_exists = get_attribute_value_at_int(i_end, global_perf + i,
+                                                        "sort", sort);
+               if (visible) {
+                       if (sort_exists && sort) {
+                               wattron(center, A_UNDERLINE);
+                       }
+                       /* + 5 to strip the "perf_" prefix */
+                       mvwprintw(center, 1, perf_row, "%s",
+                                 key.c_str() + 5);
+                       wattroff(center, A_UNDERLINE);
+                       perf_row += 20;
+               }
+               if (sort_exists && sort) {
+                       sort_perf_key = key;
+               }
+       }
+       wattroff(center, A_BOLD);
+
+       proc_beg = state_system->getQuark("proc");
+       proc_nb = get_sequence_length(i_end, proc_beg);
+       procs = g_new(Quark, proc_nb);
+       sequence_to_array(i_end, proc_beg, procs, proc_nb);
+       for (i = 0; i < proc_nb && nblinedisplayed < max_center_lines; i++) {
+               get_attribute_value_at_int(i_end, procs + i, "tid", tid);
+               get_attribute_value_at_int(i_end, procs + i, "pid", pid);
+               get_attribute_value_at_string(i_end, procs + 1, "comm", comm);
+
+               if (pid != tid)
+                       if (toggle_threads == -1)
+                               continue;
+
+               if (process_selected(procs[i])) {
+                       wattron(center, COLOR_PAIR(6));
+                       mvwhline(center, current_line + header_offset, 1, ' ',
+                                COLS-3);
+               }
+               if (current_line == selected_line) {
+                       selected_process = procs[i];
+                       wattron(center, COLOR_PAIR(5));
+                       mvwhline(center, current_line + header_offset, 1, ' ',
+                                COLS-3);
+               }
+
+               mvwprintw(center, current_line + header_offset, 1, "%d", pid);
+               mvwprintw(center, current_line + header_offset, 11, "%d", tid);
+               mvwprintw(center, current_line + header_offset, 22, "%s",
+                         comm.c_str());
+
+               perf_row = 40;
+               for (j = 0; j < global_perf_nb; j++) {
+                       get_attribute_value_at_int(i_end, global_perf + j,
+                                                  "visible", visible);
+                       get_attribute_value_at_string(i_end, global_perf + j,
+                                                     "key", key);
+
+                       if (visible) {
+                               if (!get_interval_value_int(i_start, i_end,
+                                                          procs + i, "perf/" +
+                                                           key + "/count",
+                                                           value)) {
+                                       value = 0;
+                               }
+                               mvwprintw(center, current_line + header_offset,
+                                         perf_row, "%d", value);
+                               perf_row += 20;
+                       }
+               }
+
+               wattroff(center, COLOR_PAIR(6));
+               wattroff(center, COLOR_PAIR(5));
+               nblinedisplayed++;
+               current_line++;
+       }
+       g_free(global_perf);
+       g_free(procs);
+}
+
+void update_iostream()
+{
+       unsigned int i;
+       int header_offset = 2;
+       int nblinedisplayed = 0;
+       int current_line = 0;
+       char unit[4];
+       int column;
+       unsigned int proc_nb;
+       Quark *procs;
+       Quark proc_root;
+       int pid, tid, read, write, totalread, totalwrite;
+       std::string comm;
+
+       set_window_title(center, "IO Top");
+       wattron(center, A_BOLD);
+       mvwprintw(center, 1, 1, "PID");
+       mvwprintw(center, 1, 11, "TID");
+       mvwprintw(center, 1, 22, "NAME");
+       column = 40;
+       for (i = 0; i < 3; i++) {
+               if (iostreamtopview[i].sort) {
+                       pref_current_sort = i;
+                       wattron(center, A_UNDERLINE);
+               }
+               mvwprintw(center, 1, column, iostreamtopview[i].title);
+               wattroff(center, A_UNDERLINE);
+               column += 12;
+       }
+       wattroff(center, A_BOLD);
+       wattroff(center, A_UNDERLINE);
+
+       proc_root = state_system->getQuark("proc");
+       proc_nb = get_sequence_length(i_end, proc_root);
+       procs = g_new(Quark, proc_nb);
+       sequence_to_array(i_end, proc_root, procs, proc_nb);
+
+       if (iostreamtopview[0].sort == 1)
+               qsort(procs, proc_nb, sizeof(Quark), sort_by_process_read_desc);
+       else if (iostreamtopview[1].sort == 1)
+               qsort(procs, proc_nb, sizeof(Quark),
+                     sort_by_process_write_desc);
+       else if (iostreamtopview[2].sort == 1)
+               qsort(procs, proc_nb, sizeof(Quark),
+                     sort_by_process_total_desc);
+       else
+               qsort(procs, proc_nb, sizeof(Quark),
+                     sort_by_process_total_desc);
+
+       for (i = list_offset; i < proc_nb && nblinedisplayed < max_center_lines;
+            i++) {
+               get_attribute_value_at_int(i_end, procs + i, "tid", tid);
+               get_attribute_value_at_int(i_end, procs + i, "pid", pid);
+               get_attribute_value_at_string(i_end, procs + i, "comm", comm);
+               get_attribute_value_at_int(i_end, procs + i, "fileread",
+                                            read);
+               get_attribute_value_at_int(i_end, procs + i, "filewrite",
+                                            write);
+               get_attribute_value_at_int(i_end, procs + i, "totalfileread",
+                                            totalread);
+               get_attribute_value_at_int(i_end, procs + i, "totalfilewrite",
+                                            totalwrite);
+
+
+               if (pid != tid)
+                       if (toggle_threads == -1)
+                               continue;
+
+               if (process_selected(procs[i])) {
+                       wattron(center, COLOR_PAIR(6));
+                       mvwhline(center, current_line + header_offset, 1, ' ',
+                                COLS-3);
+               }
+               if (current_line == selected_line) {
+                       selected_process = procs[i];
+                       wattron(center, COLOR_PAIR(5));
+                       mvwhline(center, current_line + header_offset, 1, ' ',
+                                COLS-3);
+               }
+               /* PID */
+               mvwprintw(center, current_line + header_offset, 1, "%d", pid);
+               /* TID */
+               mvwprintw(center, current_line + header_offset, 11, "%d", tid);
+               /* NAME */
+               mvwprintw(center, current_line + header_offset, 22, "%s",
+                         comm.c_str());
+
+               /* READ (bytes/sec) */
+               scale_unit(read, unit);
+               mvwprintw(center, current_line + header_offset, 40, "%s", unit);
+
+               /* WRITE (bytes/sec) */
+               scale_unit(write, unit);
+               mvwprintw(center, current_line + header_offset, 52, "%s", unit);
+
+               /* TOTAL STREAM */
+               scale_unit(totalread + totalwrite, unit);
+               mvwprintw(center, current_line + header_offset, 64, "%s", unit);
+
+               wattroff(center, COLOR_PAIR(6));
+               wattroff(center, COLOR_PAIR(5));
+               nblinedisplayed++;
+               current_line++;
+       }
+       g_free(procs);
+}
+
+void update_current_view()
+{
+       sem_wait(&update_display_sem);
+       update_header();
+
+       werase(center);
+       box(center, 0, 0);
+       switch (current_view) {
+       case cpu:
+               update_cputop_display();
+               break;
+       case perf:
+               update_perf();
+               break;
+       case process_details:
+               update_process_details();
+               break;
+       case iostream:
+               update_iostream();
+               break;
+       case tree:
+               update_cputop_display();
+               break;
+       default:
+               break;
+       }
+       update_panels();
+       doupdate();
+       sem_post(&update_display_sem);
+}
+
+void update_process_detail_sort(int *line_selected)
+{
+       int i;
+       int size;
+
+       size = 3;
+
+       if (*line_selected > (size - 1))
+               *line_selected = size - 1;
+       else if (*line_selected < 0)
+               *line_selected = 0;
+
+       if (fileview[*line_selected].sort == 1)
+               fileview[*line_selected].reverse = 1;
+       for (i = 0; i < size; i++)
+               fileview[i].sort = 0;
+       fileview[*line_selected].sort = 1;
+}
+
+void update_process_detail_pref(int *line_selected, int toggle_view, int toggle_sort)
+{
+       int i;
+       int size;
+
+       if (pref_panel_window) {
+               del_panel(pref_panel);
+               delwin(pref_panel_window);
+       }
+       size = 3;
+
+       pref_panel_window = create_window(size + 2, 30, 10, 10);
+       pref_panel = new_panel(pref_panel_window);
+
+       werase(pref_panel_window);
+       box(pref_panel_window, 0 , 0);
+       set_window_title(pref_panel_window, "Process Detail Preferences ");
+       wattron(pref_panel_window, A_BOLD);
+       mvwprintw(pref_panel_window, size + 1, 1,
+                       " 's' : sort, space : toggle");
+       wattroff(pref_panel_window, A_BOLD);
+
+       if (*line_selected > (size - 1))
+               *line_selected = size - 1;
+       else if (*line_selected < 0)
+               *line_selected = 0;
+       if (toggle_sort == 1) {
+               update_process_detail_sort(line_selected);
+               update_current_view();
+       }
+
+       for (i = 0; i < size; i++) {
+               if (i == *line_selected) {
+                       wattron(pref_panel_window, COLOR_PAIR(5));
+                       mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
+               }
+               if (fileview[i].sort == 1)
+                       wattron(pref_panel_window, A_BOLD);
+               mvwprintw(pref_panel_window, i + 1, 1, "[-] %s",
+                               fileview[i].title);
+               wattroff(pref_panel_window, A_BOLD);
+               wattroff(pref_panel_window, COLOR_PAIR(5));
+
+       }
+       update_panels();
+       doupdate();
+}
+
+void update_iostream_sort(int *line_selected)
+{
+       int i;
+       int size;
+
+       size = 3;
+       if (*line_selected > (size - 1))
+               *line_selected = size - 1;
+       else if (*line_selected < 0)
+               *line_selected = 0;
+       if (iostreamtopview[*line_selected].sort == 1)
+               iostreamtopview[*line_selected].reverse = 1;
+       for (i = 0; i < size; i++)
+               iostreamtopview[i].sort = 0;
+       iostreamtopview[*line_selected].sort = 1;
+
+}
+
+void update_iostream_pref(int *line_selected, int toggle_view, int toggle_sort)
+{
+       int i;
+       int size;
+
+       if (pref_panel_window) {
+               del_panel(pref_panel);
+               delwin(pref_panel_window);
+       }
+       size = 3;
+
+       pref_panel_window = create_window(size + 2, 30, 10, 10);
+       pref_panel = new_panel(pref_panel_window);
+
+       werase(pref_panel_window);
+       box(pref_panel_window, 0 , 0);
+       set_window_title(pref_panel_window, "IOTop Preferences ");
+       wattron(pref_panel_window, A_BOLD);
+       mvwprintw(pref_panel_window, size + 1, 1,
+                       " 's' : sort, space : toggle");
+       wattroff(pref_panel_window, A_BOLD);
+
+       if (*line_selected > (size - 1))
+               *line_selected = size - 1;
+       else if (*line_selected < 0)
+               *line_selected = 0;
+       if (toggle_sort == 1) {
+               update_iostream_sort(line_selected);
+               update_current_view();
+       }
+
+       for (i = 0; i < size; i++) {
+               if (i == *line_selected) {
+                       wattron(pref_panel_window, COLOR_PAIR(5));
+                       mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
+               }
+               if (iostreamtopview[i].sort == 1)
+                       wattron(pref_panel_window, A_BOLD);
+               mvwprintw(pref_panel_window, i + 1, 1, "[-] %s",
+                               iostreamtopview[i].title);
+               wattroff(pref_panel_window, A_BOLD);
+               wattroff(pref_panel_window, COLOR_PAIR(5));
+
+       }
+       update_panels();
+       doupdate();
+}
+
+void update_cpu_sort(int *line_selected)
+{
+       int i;
+       int size = 3;
+
+       if (*line_selected > (size - 1))
+               *line_selected = size - 1;
+       else if (*line_selected < 0)
+               *line_selected = 0;
+
+       /* special case, we don't support sorting by procname for now */
+       if (*line_selected != 3) {
+               if (cputopview[*line_selected].sort == 1)
+                       cputopview[*line_selected].reverse = 1;
+               for (i = 0; i < size; i++)
+                       cputopview[i].sort = 0;
+               cputopview[*line_selected].sort = 1;
+       }
+}
+
+void update_cpu_pref(int *line_selected, int toggle_view, int toggle_sort)
+{
+       int i;
+       int size;
+
+       if (pref_panel_window) {
+               del_panel(pref_panel);
+               delwin(pref_panel_window);
+       }
+       size = 4;
+
+       pref_panel_window = create_window(size + 2, 30, 10, 10);
+       pref_panel = new_panel(pref_panel_window);
+
+       werase(pref_panel_window);
+       box(pref_panel_window, 0 , 0);
+       set_window_title(pref_panel_window, "CPUTop Preferences ");
+       wattron(pref_panel_window, A_BOLD);
+       mvwprintw(pref_panel_window, size + 1, 1,
+                       " 's' : sort, space : toggle");
+       wattroff(pref_panel_window, A_BOLD);
+
+       if (*line_selected > (size - 1))
+               *line_selected = size - 1;
+       else if (*line_selected < 0)
+               *line_selected = 0;
+       if (toggle_sort == 1) {
+               update_cpu_sort(line_selected);
+               update_current_view();
+       }
+
+       for (i = 0; i < size; i++) {
+               if (i == *line_selected) {
+                       wattron(pref_panel_window, COLOR_PAIR(5));
+                       mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
+               }
+               if (cputopview[i].sort == 1)
+                       wattron(pref_panel_window, A_BOLD);
+               mvwprintw(pref_panel_window, i + 1, 1, "[-] %s",
+                               cputopview[i].title);
+               wattroff(pref_panel_window, A_BOLD);
+               wattroff(pref_panel_window, COLOR_PAIR(5));
+
+       }
+       update_panels();
+       doupdate();
+}
+
+void update_perf_sort(int *line_selected)
+{
+       int i;
+       int size;
+       Quark *global_perf;
+
+       size = get_global_perf_list_size(i_end);
+       global_perf = g_new(Quark, size);
+       get_global_perf_list(i_end, global_perf, size);
+
+       if (*line_selected > (size - 1))
+               *line_selected = size - 1;
+       else if (*line_selected < 0)
+               *line_selected = 0;
+
+       for (i = 0; i < size; i++) {
+               if (i != *line_selected)
+                       modify_attribute(i_end, global_perf + i, "sort", 0);
+               else
+                       modify_attribute(i_end, global_perf + i, "sort", 1);
+       }
+
+       g_free(global_perf);
+}
+
+void update_perf_pref(int *line_selected, int toggle_view, int toggle_sort)
+{
+       int i;
+       int size;
+       Quark *global_perf;
+       int visible;
+       int sort;
+       std::string key;
+
+       if (pref_panel_window) {
+               del_panel(pref_panel);
+               delwin(pref_panel_window);
+       }
+
+       size = get_global_perf_list_size(i_end);
+       global_perf = g_new(Quark, size);
+       get_global_perf_list(i_end, global_perf, size);
+
+       pref_panel_window = create_window(size + 2, 30, 10, 10);
+       pref_panel = new_panel(pref_panel_window);
+
+       werase(pref_panel_window);
+       box(pref_panel_window, 0 , 0);
+       set_window_title(pref_panel_window, "Perf Preferences ");
+       wattron(pref_panel_window, A_BOLD);
+       mvwprintw(pref_panel_window, size + 1, 1,
+                       " 's' : sort, space : toggle");
+       wattroff(pref_panel_window, A_BOLD);
+
+       if (*line_selected > (size - 1))
+               *line_selected = size - 1;
+       else if (*line_selected < 0)
+               *line_selected = 0;
+
+       if (toggle_sort == 1) {
+               update_perf_sort(line_selected);
+               update_current_view();
+       }
+
+       for (i = 0; i < size; i++) {
+               get_attribute_value_at_int(i_end, global_perf + i,
+                                          "visible", visible);
+               get_attribute_value_at_string(i_end, global_perf + i, "key",
+                                             key);
+               if (i == *line_selected && toggle_view == 1) {
+                       visible = visible == 1 ? 0 : 1;
+                       modify_attribute(i_end, global_perf + i, "visible",
+                                        visible);
+                       update_current_view();
+               }
+               if (i == *line_selected) {
+                       wattron(pref_panel_window, COLOR_PAIR(5));
+                       mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
+               }
+
+               if (get_attribute_value_at_int(i_end, global_perf + 1, "sort",
+                                              sort) && sort) {
+                       wattron(pref_panel_window, A_BOLD);
+               }
+               mvwprintw(pref_panel_window, i + 1, 1, "[%c] %s",
+                         visible == 1 ? 'x' : ' ', key.c_str() + 5);
+               wattroff(pref_panel_window, A_BOLD);
+               wattroff(pref_panel_window, COLOR_PAIR(5));
+       }
+       update_panels();
+       doupdate();
+
+       g_free(global_perf);
+}
+
+int update_preference_panel(int *line_selected, int toggle_view, int toggle_sort)
+{
+       int ret = 0;
+
+       switch(current_view) {
+               case perf:
+                       update_perf_pref(line_selected, toggle_view, toggle_sort);
+                       break;
+               case cpu:
+                       update_cpu_pref(line_selected, toggle_view, toggle_sort);
+                       break;
+               case iostream:
+                       update_iostream_pref(line_selected, toggle_view, toggle_sort);
+                       break;
+               case process_details:
+                       update_process_detail_pref(line_selected, toggle_view, toggle_sort);
+                       break;
+               default:
+                       ret = -1;
+                       break;
+       }
+
+       return ret;
+}
+
+int update_sort(int *line_selected)
+{
+       int ret = 0;
+
+       switch(current_view) {
+               case perf:
+                       update_perf_sort(line_selected);
+                       break;
+               case cpu:
+                       update_cpu_sort(line_selected);
+                       break;
+               case iostream:
+                       update_iostream_sort(line_selected);
+                       break;
+               case process_details:
+                       update_process_detail_sort(line_selected);
+                       break;
+               default:
+                       ret = -1;
+                       break;
+       }
+
+       return ret;
+}
+
+
+void toggle_pref_panel(void)
+{
+       int ret;
+
+       if (pref_panel_visible) {
+               hide_panel(pref_panel);
+               pref_panel_visible = 0;
+       } else {
+               ret = update_preference_panel(&pref_line_selected, 0, 0);
+               if (ret < 0)
+                       return;
+               show_panel(pref_panel);
+               pref_panel_visible = 1;
+       }
+       update_panels();
+       doupdate();
+}
+
+void display()
+{
+       if (i_start == 0)
+               i_start = first_display_update;
+       else
+               i_start += refresh_display;
+       i_end = i_start + refresh_display;
+
+       max_elements = get_sequence_length(
+               i_end, state_system->getQuark("proc"));
+       update_current_view();
+       update_footer();
+       update_panels();
+       doupdate();
+}
+
+void pause_display()
+{
+       toggle_pause = 1;
+       print_log("Pause");
+       sem_wait(&pause_sem);
+}
+
+void resume_display()
+{
+       toggle_pause = -1;
+       print_log("Resume");
+       sem_post(&pause_sem);
+}
+
+void *handle_keyboard(void *p)
+{
+       int ch;
+       while((ch = getch())) {
+               switch(ch) {
+               /* Move the cursor and scroll */
+               case 'j':
+               case KEY_DOWN:
+                       if (pref_panel_visible) {
+                               pref_line_selected++;
+                               update_preference_panel(&pref_line_selected, 0, 0);
+                       } else {
+                               if (selected_line < (max_center_lines - 1) &&
+                                               selected_line < max_elements - 1) {
+                                       selected_line++;
+                                       selected_in_list++;
+                               } else if (selected_in_list < (max_elements - 1)
+                                               && (list_offset < (max_elements - max_center_lines))) {
+                                       selected_in_list++;
+                                       list_offset++;
+                               }
+                               update_current_view();
+                       }
+                       break;
+               case KEY_NPAGE:
+                       break;
+               case 'k':
+               case KEY_UP:
+                       if (pref_panel_visible) {
+                               if (pref_line_selected > 0)
+                                       pref_line_selected--;
+                               update_preference_panel(&pref_line_selected, 0, 0);
+                       } else {
+                               if (selected_line > 0) {
+                                       selected_line--;
+                                       selected_in_list--;
+                               } else if (selected_in_list > 0 && list_offset > 0) {
+                                       selected_in_list--;
+                                       list_offset--;
+                               }
+                               update_current_view();
+                       }
+                       break;
+               case KEY_PPAGE:
+                       break;
+
+               /* Navigate the history with arrows */
+               case KEY_LEFT:
+                       if ((i_start - refresh_display) >=
+                           first_display_update) {
+                               i_start -= refresh_display;
+                               i_end = i_start + refresh_display;
+                               print_log("Going back in time");
+                       } else {
+                               print_log("Cannot rewind, last data is already displayed");
+                       }
+                       max_elements = get_sequence_length(
+                               i_end, state_system->getQuark("proc"));
+
+                       /* we force to pause the display when moving in time */
+                       if (toggle_pause < 0)
+                               pause_display();
+
+                       update_current_view();
+                       update_footer();
+                       break;
+               case KEY_RIGHT:
+                       if ((i_end + refresh_display) <=
+                            last_display_update) {
+                                   i_end += refresh_display;
+                                   i_start = i_end - refresh_display;
+                                   print_log("Going forward in time");
+                                   max_elements = get_sequence_length(
+                                           i_end, state_system->getQuark(
+                                                   "proc"));
+                                   update_current_view();
+                                   update_footer();
+                       } else {
+                               print_log("Manually moving forward");
+                               sem_post(&timer);
+                               if (toggle_pause > 0) {
+                                       sem_post(&pause_sem);
+                                       update_current_view();
+                                       sem_wait(&pause_sem);
+                               }
+                       }
+
+                       break;
+               case ' ':
+                       if (pref_panel_visible) {
+                               update_preference_panel(&pref_line_selected, 1, 0);
+                       } else {
+                               update_selected_processes();
+                               update_current_view();
+                       }
+                       break;
+               case 's':
+                       if (pref_panel_visible)
+                               update_preference_panel(&pref_line_selected, 0, 1);
+                       break;
+               case '>':
+                       /* perf uses a hashtable, it is ordered backward */
+                       if (current_view == perf) {
+                               pref_current_sort--;
+                       } else if (!pref_panel_visible) {
+                               pref_current_sort++;
+                       }
+                       update_sort(&pref_current_sort);
+                       update_current_view();
+                       break;
+               case '<':
+                       /* perf uses a hashtable, it is ordered backward */
+                       if (current_view == perf) {
+                               pref_current_sort++;
+                       } else if (!pref_panel_visible) {
+                               pref_current_sort--;
+                       }
+                       update_sort(&pref_current_sort);
+                       update_current_view();
+                       break;
+
+               case 13: /* FIXME : KEY_ENTER ?? */
+                       if (pref_panel_visible)
+                               break;
+                       if (current_view != process_details) {
+                               previous_view = current_view;
+                               current_view = process_details;
+                       } else {
+                               current_view = previous_view;
+                               previous_view = process_details;
+                       }
+                       update_current_view();
+                       break;
+
+               case KEY_F(1):
+                       if (pref_panel_visible)
+                               toggle_pref_panel();
+                       current_view = cpu;
+                       selected_line = 0;
+                       update_current_view();
+                       break;
+               case KEY_F(2):
+                       if (pref_panel_visible)
+                               toggle_pref_panel();
+                       current_view = cpu;
+                       selected_line = 0;
+                       update_current_view();
+                       break;
+               case KEY_F(3):
+                       if (pref_panel_visible)
+                               toggle_pref_panel();
+                       current_view = perf;
+                       selected_line = 0;
+                       update_current_view();
+                       break;
+               case KEY_F(4):
+                       if (pref_panel_visible)
+                               toggle_pref_panel();
+                       current_view = iostream;
+                       selected_line = 0;
+                       update_current_view();
+                       break;
+               case KEY_F(10):
+               case 'q':
+                       reset_ncurses();
+                       break;
+               case 't':
+                       toggle_threads *= -1;
+                       update_current_view();
+                       break;
+               case 'p':
+                       if (toggle_pause < 0) {
+                               pause_display();
+                       } else {
+                               resume_display();
+                       }
+                       break;
+               case 'r':
+                       toggle_pref_panel();
+                       break;
+               /* ESCAPE, but slow to process, don't know why */
+               case 27:
+                       if (pref_panel_visible)
+                               toggle_pref_panel();
+                       else if (current_view == process_details) {
+                               current_view = previous_view;
+                               previous_view = process_details;
+                       }
+                       update_current_view();
+                       break;
+               default:
+                       update_current_view();
+                       break;
+               }
+               update_footer();
+       }
+       return NULL;
+}
+
+void init_view_headers()
+{
+       cputopview[0].title = strdup("CPU(%)");
+       cputopview[0].sort = 1;
+       cputopview[1].title = strdup("PID");
+       cputopview[2].title = strdup("TID");
+       cputopview[3].title = strdup("NAME");
+
+       iostreamtopview[0].title = strdup("R (B/sec)");
+       iostreamtopview[1].title = strdup("W (B/sec)");
+       iostreamtopview[2].title = strdup("Total (B)");
+       iostreamtopview[2].sort = 1;
+
+       fileview[0].title = strdup("FD");
+       fileview[1].title = strdup("READ");
+       fileview[1].sort = 1;
+       fileview[2].title = strdup("WRITE");
+}
+
+void init_ncurses()
+{
+       selected_processes = g_ptr_array_new();
+       sem_init(&update_display_sem, 0, 1);
+       init_view_headers();
+       init_screen();
+
+       header = create_window(5, COLS - 1, 0, 0);
+       center = create_window(LINES - 5 - 7, COLS - 1, 5, 0);
+       status = create_window(MAX_LOG_LINES + 2, COLS - 1, LINES - 7, 0);
+       footer = create_window(1, COLS - 1, LINES - 1, 0);
+
+       print_log("Starting display");
+
+       main_panel = new_panel(center);
+
+       current_view = cpu;
+
+       basic_header();
+       update_footer();
+
+       pthread_create(&keyboard_thread, NULL, handle_keyboard, (void *)NULL);
+}
This page took 0.040916 seconds and 4 git commands to generate.