htop.c 27.8 KB
Newer Older
Hisham Muhammad's avatar
Hisham Muhammad committed
1
2
/*
htop - htop.c
3
(C) 2004-2011 Hisham H. Muhammad
Hisham Muhammad's avatar
Hisham Muhammad committed
4
5
6
7
8
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/

#include "ProcessList.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
9

Hisham Muhammad's avatar
Hisham Muhammad committed
10
#include "CRT.h"
11
#include "Panel.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
12
13
14
15
16
17
#include "UsersTable.h"
#include "RichString.h"
#include "Settings.h"
#include "ScreenManager.h"
#include "FunctionBar.h"
#include "ListItem.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
18
19
#include "String.h"
#include "ColumnsPanel.h"
20
21
#include "CategoriesPanel.h"
#include "SignalsPanel.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
22
#include "TraceScreen.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
23
#include "OpenFilesScreen.h"
24
#include "AffinityPanel.h"
25
#include "IOPriorityPanel.h"
26
#include "IncSet.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
27

Hisham Muhammad's avatar
Hisham Muhammad committed
28
29
30
31
32
33
34
35
36
37
38
39
#include <unistd.h>
#include <math.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#include <locale.h>
#include <getopt.h>
#include <pwd.h>
#include <string.h>
#include <sys/param.h>
#include <sys/time.h>

Hisham Muhammad's avatar
Hisham Muhammad committed
40
41
//#link m

42
#define COPYRIGHT "(C) 2004-2012 Hisham Muhammad"
43

44
static void printVersionFlag() {
45
46
47
   fputs("htop " VERSION " - " COPYRIGHT "\n"
         "Released under the GNU GPL.\n\n",
         stdout);
Hisham Muhammad's avatar
Hisham Muhammad committed
48
49
50
   exit(0);
}

51
static void printHelpFlag() {
52
53
   fputs("htop " VERSION " - " COPYRIGHT "\n"
         "Released under the GNU GPL.\n\n"
54
55
56
57
58
59
         "-C --no-color               Use a monochrome color scheme\n"
         "-d --delay=DELAY            Set the delay between updates, in tenths of seconds\n"
         "-h --help                   Print this help screen\n"
         "-s --sort-key=COLUMN        Sort by COLUMN (try --sort-key=help for a list)\n"
         "-u --user=USERNAME          Show only processes of a given user\n"
         "-p --pid=PID,[,PID,PID...]  Show only the given PIDs\n"
60
61
62
63
64
65
         "-v --version          Print version info\n"
         "\n"
         "Long options may be passed with a single dash.\n\n"
         "Press F1 inside htop for online help.\n"
         "See 'man htop' for more information.\n",
         stdout);
Hisham Muhammad's avatar
Hisham Muhammad committed
66
67
68
   exit(0);
}

69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
static struct { const char* key; const char* info; } helpLeft[] = {
   { .key = " Arrows: ", .info = "scroll process list" },
   { .key = " Digits: ", .info = "incremental PID search" },
   { .key = "   F3 /: ", .info = "incremental name search" },
   { .key = "   F4 \\: ",.info = "incremental name filtering" },
   { .key = "   F5 t: ", .info = "tree view" },
   { .key = "      u: ", .info = "show processes of a single user" },
   { .key = "      H: ", .info = "hide/show user threads" },
   { .key = "      K: ", .info = "hide/show kernel threads" },
   { .key = "      F: ", .info = "cursor follows process" },
   { .key = "    + -: ", .info = "expand/collapse tree" },
   { .key = "  P M T: ", .info = "sort by CPU%, MEM% or TIME" },
   { .key = "      I: ", .info = "invert sort order" },
   { .key = "   F6 >: ", .info = "select sort column" },
   { .key = NULL, .info = NULL }
};

static struct { const char* key; const char* info; } helpRight[] = {
   { .key = "  Space: ", .info = "tag process" },
   { .key = "      c: ", .info = "tag process and its children" },
   { .key = "      U: ", .info = "untag all processes" },
   { .key = "   F9 k: ", .info = "kill process/tagged processes" },
   { .key = "   F7 ]: ", .info = "higher priority (root only)" },
   { .key = "   F8 [: ", .info = "lower priority (+ nice)" },
#if (HAVE_LIBHWLOC || HAVE_NATIVE_AFFINITY)
   { .key = "      a: ", .info = "set CPU affinity" },
#endif
   { .key = "      i: ", .info = "set IO prority" },
   { .key = "      l: ", .info = "list open files with lsof" },
   { .key = "      s: ", .info = "trace syscalls with strace" },
   { .key = "         ", .info = "" },
   { .key = "   F2 S: ", .info = "setup" },
   { .key = "   F1 h: ", .info = "show this help screen" },
   { .key = "  F10 q: ", .info = "quit" },
   { .key = NULL, .info = NULL }
};

106
static void showHelp(ProcessList* pl) {
Hisham Muhammad's avatar
Hisham Muhammad committed
107
108
   clear();
   attrset(CRT_colors[HELP_BOLD]);
109
110
111
112

   for (int i = 0; i < LINES-1; i++)
      mvhline(i, 0, ' ', COLS);

113
   mvaddstr(0, 0, "htop " VERSION " - " COPYRIGHT);
Hisham Muhammad's avatar
Hisham Muhammad committed
114
115
116
117
118
119
   mvaddstr(1, 0, "Released under the GNU GPL. See 'man' page for more info.");

   attrset(CRT_colors[DEFAULT_COLOR]);
   mvaddstr(3, 0, "CPU usage bar: ");
   #define addattrstr(a,s) attrset(a);addstr(s)
   addattrstr(CRT_colors[BAR_BORDER], "[");
120
   if (pl->detailedCPUTime) {
121
122
123
124
      addattrstr(CRT_colors[CPU_NICE], "low"); addstr("/");
      addattrstr(CRT_colors[CPU_NORMAL], "normal"); addstr("/");
      addattrstr(CRT_colors[CPU_KERNEL], "kernel"); addstr("/");
      addattrstr(CRT_colors[CPU_IRQ], "irq"); addstr("/");
125
      addattrstr(CRT_colors[CPU_SOFTIRQ], "soft-irq"); addstr("/");
126
      addattrstr(CRT_colors[CPU_STEAL], "steal"); addstr("/");
127
128
      addattrstr(CRT_colors[CPU_GUEST], "guest"); addstr("/");
      addattrstr(CRT_colors[CPU_IOWAIT], "io-wait");
129
130
131
132
      addattrstr(CRT_colors[BAR_SHADOW], " used%");
   } else {
      addattrstr(CRT_colors[CPU_NICE], "low-priority"); addstr("/");
      addattrstr(CRT_colors[CPU_NORMAL], "normal"); addstr("/");
133
134
135
      addattrstr(CRT_colors[CPU_KERNEL], "kernel"); addstr("/");
      addattrstr(CRT_colors[CPU_STEAL], "virtualiz");
      addattrstr(CRT_colors[BAR_SHADOW], "               used%");
136
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
137
138
139
140
141
142
143
   addattrstr(CRT_colors[BAR_BORDER], "]");
   attrset(CRT_colors[DEFAULT_COLOR]);
   mvaddstr(4, 0, "Memory bar:    ");
   addattrstr(CRT_colors[BAR_BORDER], "[");
   addattrstr(CRT_colors[MEMORY_USED], "used"); addstr("/");
   addattrstr(CRT_colors[MEMORY_BUFFERS], "buffers"); addstr("/");
   addattrstr(CRT_colors[MEMORY_CACHE], "cache");
144
   addattrstr(CRT_colors[BAR_SHADOW], "                            used/total");
Hisham Muhammad's avatar
Hisham Muhammad committed
145
146
147
148
149
   addattrstr(CRT_colors[BAR_BORDER], "]");
   attrset(CRT_colors[DEFAULT_COLOR]);
   mvaddstr(5, 0, "Swap bar:      ");
   addattrstr(CRT_colors[BAR_BORDER], "[");
   addattrstr(CRT_colors[SWAP], "used");
150
   addattrstr(CRT_colors[BAR_SHADOW], "                                          used/total");
Hisham Muhammad's avatar
Hisham Muhammad committed
151
152
   addattrstr(CRT_colors[BAR_BORDER], "]");
   attrset(CRT_colors[DEFAULT_COLOR]);
153
   mvaddstr(6,0, "Type and layout of header meters are configurable in the setup screen.");
154
155
156
157
   if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
      mvaddstr(7, 0, "In monochrome, meters are displayed through different chars, in order: |#*@$%&");
   }
   mvaddstr( 8, 0, " Status: R: running; S: sleeping; T: traced/stopped; Z: zombie; D: disk sleep");
158
159
   for (int i = 0; helpLeft[i].info; i++) { mvaddstr(9+i, 9,  helpLeft[i].info); }
   for (int i = 0; helpRight[i].info; i++) { mvaddstr(9+i, 49, helpRight[i].info); }
Hisham Muhammad's avatar
Hisham Muhammad committed
160
   attrset(CRT_colors[HELP_BOLD]);
161
162
   for (int i = 0; helpLeft[i].key;  i++) { mvaddstr(9+i, 0,  helpLeft[i].key); }
   for (int i = 0; helpRight[i].key; i++) { mvaddstr(9+i, 40, helpRight[i].key); }
Hisham Muhammad's avatar
Hisham Muhammad committed
163
164
165
166
167
168
169
170
171

   attrset(CRT_colors[HELP_BOLD]);
   mvaddstr(23,0, "Press any key to return.");
   attrset(CRT_colors[DEFAULT_COLOR]);
   refresh();
   CRT_readKey();
   clear();
}

Hisham Muhammad's avatar
Hisham Muhammad committed
172
static const char* CategoriesFunctions[] = {"      ", "      ", "      ", "      ", "      ", "      ", "      ", "      ", "      ", "Done  ", NULL};
173

174
175
static void Setup_run(Settings* settings, const Header* header) {
   ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, true);
Hisham Muhammad's avatar
Hisham Muhammad committed
176
   CategoriesPanel* panelCategories = CategoriesPanel_new(settings, scr);
Hisham Muhammad's avatar
Hisham Muhammad committed
177
   ScreenManager_add(scr, (Panel*) panelCategories, FunctionBar_new(CategoriesFunctions, NULL, NULL), 16);
Hisham Muhammad's avatar
Hisham Muhammad committed
178
179
   CategoriesPanel_makeMetersPage(panelCategories);
   Panel* panelFocus;
Hisham Muhammad's avatar
Hisham Muhammad committed
180
   int ch;
Hisham Muhammad's avatar
Hisham Muhammad committed
181
   ScreenManager_run(scr, &panelFocus, &ch);
Hisham Muhammad's avatar
Hisham Muhammad committed
182
183
184
   ScreenManager_delete(scr);
}

185
186
187
typedef bool(*ForeachProcessFn)(Process*, size_t);

static bool foreachProcess(Panel* panel, ForeachProcessFn fn, int arg, bool* wasAnyTagged) {
188
   bool ok = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
189
   bool anyTagged = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
190
   for (int i = 0; i < Panel_size(panel); i++) {
Hisham Muhammad's avatar
Hisham Muhammad committed
191
      Process* p = (Process*) Panel_get(panel, i);
Hisham Muhammad's avatar
Hisham Muhammad committed
192
      if (p->tag) {
193
         ok = fn(p, arg) && ok;
Hisham Muhammad's avatar
Hisham Muhammad committed
194
195
196
197
         anyTagged = true;
      }
   }
   if (!anyTagged) {
Hisham Muhammad's avatar
Hisham Muhammad committed
198
      Process* p = (Process*) Panel_getSelected(panel);
199
      if (p) ok = fn(p, arg) && ok;
Hisham Muhammad's avatar
Hisham Muhammad committed
200
   }
201
202
203
204
205
206
207
208
   if (wasAnyTagged)
      *wasAnyTagged = anyTagged;
   return ok;
}

static bool changePriority(Panel* panel, int delta) {
   bool anyTagged;
   bool ok = foreachProcess(panel, (ForeachProcessFn) Process_changePriorityBy, delta, &anyTagged);
209
210
   if (!ok)
      beep();
Hisham Muhammad's avatar
Hisham Muhammad committed
211
212
213
   return anyTagged;
}

214
215
216
217
218
219
220
221
static int selectedPid(Panel* panel) {
   Process* p = (Process*) Panel_getSelected(panel);
   if (p) {
      return p->pid;
   }
   return -1;
}

222
static Object* pickFromVector(Panel* panel, Panel* list, int x, int y, const char** keyLabels, FunctionBar* prevBar, Header* header) {
Hisham Muhammad's avatar
Hisham Muhammad committed
223
   const char* fuKeys[] = {"Enter", "Esc", NULL};
224
   int fuEvents[] = {13, 27};
225
   ScreenManager* scr = ScreenManager_new(0, y, 0, -1, HORIZONTAL, header, false);
226
   scr->allowFocusChange = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
227
   ScreenManager_add(scr, list, FunctionBar_new(keyLabels, fuKeys, fuEvents), x - 1);
Hisham Muhammad's avatar
Hisham Muhammad committed
228
229
   ScreenManager_add(scr, panel, NULL, -1);
   Panel* panelFocus;
Hisham Muhammad's avatar
Hisham Muhammad committed
230
   int ch;
231
   bool unfollow = false;
232
   int pid = selectedPid(panel);
233
   if (header->pl->following == -1) {
234
      header->pl->following = pid;
235
236
      unfollow = true;
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
237
   ScreenManager_run(scr, &panelFocus, &ch);
238
239
240
   if (unfollow) {
      header->pl->following = -1;
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
241
   ScreenManager_delete(scr);
Hisham Muhammad's avatar
Hisham Muhammad committed
242
243
   Panel_move(panel, 0, y);
   Panel_resize(panel, COLS, LINES-y-1);
Hisham Muhammad's avatar
Hisham Muhammad committed
244
   FunctionBar_draw(prevBar, NULL);
Hisham Muhammad's avatar
Hisham Muhammad committed
245
   if (panelFocus == list && ch == 13) {
246
      Process* selected = (Process*)Panel_getSelected(panel);
247
      if (selected && selected->pid == pid)
248
249
250
         return Panel_getSelected(list);
      else
         beep();
Hisham Muhammad's avatar
Hisham Muhammad committed
251
252
253
254
   }
   return NULL;
}

Hisham Muhammad's avatar
Hisham Muhammad committed
255
static void addUserToVector(int key, void* userCast, void* panelCast) {
Hisham Muhammad's avatar
Hisham Muhammad committed
256
   char* user = (char*) userCast;
Hisham Muhammad's avatar
Hisham Muhammad committed
257
258
   Panel* panel = (Panel*) panelCast;
   Panel_add(panel, (Object*) ListItem_new(user, key));
Hisham Muhammad's avatar
Hisham Muhammad committed
259
260
}

261
static bool setUserOnly(const char* userName, bool* userOnly, uid_t* userId) {
Hisham Muhammad's avatar
Hisham Muhammad committed
262
263
264
265
   struct passwd* user = getpwnam(userName);
   if (user) {
      *userOnly = true;
      *userId = user->pw_uid;
266
      return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
267
   }
268
   return false;
Hisham Muhammad's avatar
Hisham Muhammad committed
269
270
}

271
272
273
274
275
static inline void setSortKey(ProcessList* pl, ProcessField sortKey, Panel* panel, Settings* settings) {
   pl->sortKey = sortKey;
   pl->direction = 1;
   pl->treeView = false;
   settings->changed = true;
276
   ProcessList_printHeader(pl, Panel_getHeader(panel));
277
278
}

279
280
281
282
283
static const char* getMainPanelValue(Panel* panel, int i) {
   Process* p = (Process*) Panel_get(panel, i);
   if (p)
      return p->comm;
   return "";
Hisham Muhammad's avatar
Hisham Muhammad committed
284
285
}

286
287
288
289
290
291
292
293
294
295
296
static void tagAllChildren(Panel* panel, Process* parent) {
   parent->tag = true;
   pid_t ppid = parent->pid;
   for (int i = 0; i < Panel_size(panel); i++) {
      Process* p = (Process*) Panel_get(panel, i);
      if (!p->tag && p->ppid == ppid) {
         tagAllChildren(panel, p);
      }
   }
}

Hisham Muhammad's avatar
Hisham Muhammad committed
297
298
299
300
301
int main(int argc, char** argv) {

   int delay = -1;
   bool userOnly = false;
   uid_t userId = 0;
302
   int usecolors = 1;
303
304
305
   char *argCopy;
   char *pid;
   Hashtable *pidWhiteList = NULL;
306
307
308
309
310
311
312
313
314
315
316

   int opt, opti=0;
   static struct option long_opts[] =
   {
      {"help",     no_argument,         0, 'h'},
      {"version",  no_argument,         0, 'v'},
      {"delay",    required_argument,   0, 'd'},
      {"sort-key", required_argument,   0, 's'},
      {"user",     required_argument,   0, 'u'},
      {"no-color", no_argument,         0, 'C'},
      {"no-colour",no_argument,         0, 'C'},
317
      {"pid",      required_argument,   0, 'p'},
318
319
      {0,0,0,0}
   };
320
   int sortKey = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
321

322
323
324
   char *lc_ctype = getenv("LC_CTYPE");
   if(lc_ctype != NULL)
      setlocale(LC_CTYPE, lc_ctype);
325
326
   else if ((lc_ctype = getenv("LC_ALL")))
      setlocale(LC_CTYPE, lc_ctype);
327
   else
328
      setlocale(LC_CTYPE, "");
329

330
   /* Parse arguments */
331
   while ((opt = getopt_long(argc, argv, "hvCs:d:u:p:", long_opts, &opti))) {
332
333
334
335
336
337
338
339
340
      if (opt == EOF) break;
      switch (opt) {
         case 'h':
            printHelpFlag();
            break;
         case 'v':
            printVersionFlag();
            break;
         case 's':
Hisham Muhammad's avatar
Hisham Muhammad committed
341
            if (strcmp(optarg, "help") == 0) {
342
343
344
345
346
347
348
349
350
351
352
353
               for (int j = 1; j < LAST_PROCESSFIELD; j++)
                  printf ("%s\n", Process_fieldNames[j]);
               exit(0);
            }

            sortKey = ColumnsPanel_fieldNameToIndex(optarg);
            if (sortKey == -1) {
               fprintf(stderr, "Error: invalid column \"%s\".\n", optarg);
               exit(1);
            }
            break;
         case 'd':
354
355
356
357
358
359
360
            if (sscanf(optarg, "%d", &delay) == 1) {
               if (delay < 1) delay = 1;
               if (delay > 100) delay = 100;
            } else {
               fprintf(stderr, "Error: invalid delay value \"%s\".\n", optarg);
               exit(1);
            }
361
362
            break;
         case 'u':
363
364
365
366
            if (!setUserOnly(optarg, &userOnly, &userId)) {
               fprintf(stderr, "Error: invalid user \"%s\".\n", optarg);
               exit(1);
            }
367
368
369
            break;
         case 'C':
            usecolors=0;
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
            break;
        case 'p':
            argCopy = strdup(optarg);
            pid = strtok(argCopy, ",");

            if( !pidWhiteList ) {
               pidWhiteList = Hashtable_new(8, false);
            }

            while( pid ) {
                unsigned int num_pid = atoi(pid);
                Hashtable_put(pidWhiteList, num_pid, (void *) 1);
                pid = strtok(NULL, ",");
            }
            free(argCopy);

386
            break;
387
388
         default:
            exit(1);
Hisham Muhammad's avatar
Hisham Muhammad committed
389
390
      }
   }
391
392


393
394
395
396
   if (access(PROCDIR, R_OK) != 0) {
      fprintf(stderr, "Error: could not read procfs (compiled to look in %s).\n", PROCDIR);
      exit(1);
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
397
398
399
400
401

   int quit = 0;
   int refreshTimeout = 0;
   int resetRefreshTimeout = 5;
   bool doRefresh = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
402
   bool doRecalculate = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
403
404
405
406
407
   Settings* settings;
   
   ProcessList* pl = NULL;
   UsersTable* ut = UsersTable_new();

408
409
410
411
412
413
414
415
416
417
418
419
420
421
#ifdef HAVE_LIBNCURSESW
   char *locale = setlocale(LC_ALL, NULL);
   if (locale == NULL || locale[0] == '\0')
      locale = setlocale(LC_CTYPE, NULL);
   if (locale != NULL &&
       (strstr(locale, "UTF-8") ||
        strstr(locale, "utf-8") ||
        strstr(locale, "UTF8")  ||
        strstr(locale, "utf8")))
      CRT_utf8 = true;
   else
      CRT_utf8 = false;
#endif

422
   pl = ProcessList_new(ut, pidWhiteList);
423
   Process_getMaxPid();
Hisham Muhammad's avatar
Hisham Muhammad committed
424
425
   
   Header* header = Header_new(pl);
426
   settings = Settings_new(pl, header, pl->cpuCount);
Hisham Muhammad's avatar
Hisham Muhammad committed
427
428
429
430
431
   int headerHeight = Header_calculateHeight(header);

   // FIXME: move delay code to settings
   if (delay != -1)
      settings->delay = delay;
432
433
   if (!usecolors) 
      settings->colorScheme = COLORSCHEME_MONOCHROME;
434

Hisham Muhammad's avatar
Hisham Muhammad committed
435
   CRT_init(settings->delay, settings->colorScheme);
436

437
   Panel* panel = Panel_new(0, headerHeight, COLS, LINES - headerHeight - 2, false, &Process_class);
438
   ProcessList_setPanel(pl, panel);
Hisham Muhammad's avatar
Hisham Muhammad committed
439
   
440
441
442
443
444
   if (sortKey > 0) {
      pl->sortKey = sortKey;
      pl->treeView = false;
      pl->direction = 1;
   }
445
   ProcessList_printHeader(pl, Panel_getHeader(panel));
Hisham Muhammad's avatar
Hisham Muhammad committed
446
447
   
   const char* defaultFunctions[] = {"Help  ", "Setup ", "Search", "Filter", "Tree  ",
Hisham Muhammad's avatar
Hisham Muhammad committed
448
449
       "SortBy", "Nice -", "Nice +", "Kill  ", "Quit  ", NULL};
   FunctionBar* defaultBar = FunctionBar_new(defaultFunctions, NULL, NULL);
Hisham Muhammad's avatar
Hisham Muhammad committed
450

451
452
   IncSet* inc = IncSet_new(defaultBar);

Hisham Muhammad's avatar
Hisham Muhammad committed
453
454
455
456
457
458
459
460
461
462
463
464
465
   ProcessList_scan(pl);
   usleep(75000);
   
   FunctionBar_draw(defaultBar, NULL);
   
   int acc = 0;
   bool follow = false;
 
   struct timeval tv;
   double newTime = 0.0;
   double oldTime = 0.0;
   bool recalculate;

466
   int ch = ERR;
Hisham Muhammad's avatar
Hisham Muhammad committed
467
468
   int closeTimeout = 0;

469
470
   bool idle = false;
   
Hisham Muhammad's avatar
Hisham Muhammad committed
471
472
473
   while (!quit) {
      gettimeofday(&tv, NULL);
      newTime = ((double)tv.tv_sec * 10) + ((double)tv.tv_usec / 100000);
474
      recalculate = (newTime - oldTime > settings->delay);
475
      int following = follow ? selectedPid(panel) : -1;
476
477
      if (recalculate) {
         Header_draw(header);
Hisham Muhammad's avatar
Hisham Muhammad committed
478
         oldTime = newTime;
479
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
480
      if (doRefresh) {
Hisham Muhammad's avatar
Hisham Muhammad committed
481
         if (recalculate || doRecalculate) {
Hisham Muhammad's avatar
Hisham Muhammad committed
482
            ProcessList_scan(pl);
Hisham Muhammad's avatar
Hisham Muhammad committed
483
484
            doRecalculate = false;
         }
485
         if (refreshTimeout == 0 || pl->treeView) {
Hisham Muhammad's avatar
Hisham Muhammad committed
486
487
488
            ProcessList_sort(pl);
            refreshTimeout = 1;
         }
489
         ProcessList_rebuildPanel(pl, true, following, userOnly, userId, IncSet_filter(inc));
490
         idle = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
491
492
493
      }
      doRefresh = true;

494
495
496
      if (!idle)
         Panel_draw(panel, true);
      
Hisham Muhammad's avatar
Hisham Muhammad committed
497
      int prev = ch;
498
      if (inc->active)
499
         move(LINES-1, CRT_cursorX);
Hisham Muhammad's avatar
Hisham Muhammad committed
500
501
502
      ch = getch();

      if (ch == ERR) {
503
         if (!inc->active)
Hisham Muhammad's avatar
Hisham Muhammad committed
504
505
506
            refreshTimeout--;
         if (prev == ch && !recalculate) {
            closeTimeout++;
507
            if (closeTimeout == 100) {
Hisham Muhammad's avatar
Hisham Muhammad committed
508
               break;
509
            }
Hisham Muhammad's avatar
Hisham Muhammad committed
510
511
         } else
            closeTimeout = 0;
512
         idle = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
513
514
         continue;
      }
515
      idle = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
516
517
518
519
520

      if (ch == KEY_MOUSE) {
         MEVENT mevent;
         int ok = getmouse(&mevent);
         if (ok == OK) {
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
            if (mevent.bstate & BUTTON1_CLICKED) {
               if (mevent.y == panel->y) {
                  int x = panel->scrollH + mevent.x + 1;
                  ProcessField field = ProcessList_keyAt(pl, x);
                  if (field == pl->sortKey) {
                     ProcessList_invertSortOrder(pl);
                     pl->treeView = false;
                  } else {
                     setSortKey(pl, field, panel, settings);
                  }
                  refreshTimeout = 0;
                  continue;
               } else if (mevent.y >= panel->y + 1 && mevent.y < LINES - 1) {
                  Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1);
                  doRefresh = false;
                  refreshTimeout = resetRefreshTimeout;
                  follow = true;
                  continue;
               } if (mevent.y == LINES - 1) {
540
                  ch = FunctionBar_synthesizeEvent(inc->bar, mevent.x);
541
               }
542
543
544
545
546
547
            } else if (mevent.bstate & BUTTON4_CLICKED) {
               ch = KEY_UP;
            #if NCURSES_MOUSE_VERSION > 1
            } else if (mevent.bstate & BUTTON5_CLICKED) {
               ch = KEY_DOWN;
            #endif
Hisham Muhammad's avatar
Hisham Muhammad committed
548
549
550
551
            }
         }
      }

552
553
554
555
556
557
558
559
      if (inc->active) {
         doRefresh = IncSet_handleKey(inc, ch, panel, getMainPanelValue, NULL);
         continue;
      }
      
      if (isdigit((char)ch)) {
         if (Panel_size(panel) == 0) continue;
         pid_t pid = ch-48 + acc;
560
         for (int i = 0; i < ProcessList_size(pl); i++) {
561
            Panel_setSelected(panel, i);
562
563
564
565
566
            Process* p = (Process*) Panel_getSelected(panel);
            if (p && p->pid == pid) {
               break;
            }
         }
567
568
569
570
571
572
573
574
         acc = pid * 10;
         if (acc > 10000000)
            acc = 0;
         continue;
      } else {
         acc = 0;
      }

Hisham Muhammad's avatar
Hisham Muhammad committed
575
576
      switch (ch) {
      case KEY_RESIZE:
Hisham Muhammad's avatar
Hisham Muhammad committed
577
         Panel_resize(panel, COLS, LINES-headerHeight-1);
578
         IncSet_drawBar(inc);
Hisham Muhammad's avatar
Hisham Muhammad committed
579
580
581
582
         break;
      case 'M':
      {
         refreshTimeout = 0;
583
         setSortKey(pl, PERCENT_MEM, panel, settings);
Hisham Muhammad's avatar
Hisham Muhammad committed
584
585
586
587
588
         break;
      }
      case 'T':
      {
         refreshTimeout = 0;
589
         setSortKey(pl, TIME, panel, settings);
Hisham Muhammad's avatar
Hisham Muhammad committed
590
591
         break;
      }
592
593
594
595
596
597
598
      case 'c':
      {
         Process* p = (Process*) Panel_getSelected(panel);
         if (!p) break;
         tagAllChildren(panel, p);
         break;
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
599
600
      case 'U':
      {
Hisham Muhammad's avatar
Hisham Muhammad committed
601
         for (int i = 0; i < Panel_size(panel); i++) {
Hisham Muhammad's avatar
Hisham Muhammad committed
602
            Process* p = (Process*) Panel_get(panel, i);
Hisham Muhammad's avatar
Hisham Muhammad committed
603
604
605
606
607
608
609
610
            p->tag = false;
         }
         doRefresh = true;
         break;
      }
      case 'P':
      {
         refreshTimeout = 0;
611
         setSortKey(pl, PERCENT_CPU, panel, settings);
Hisham Muhammad's avatar
Hisham Muhammad committed
612
613
614
615
         break;
      }
      case KEY_F(1):
      case 'h':
616
      case '?':
Hisham Muhammad's avatar
Hisham Muhammad committed
617
      {
618
         showHelp(pl);
Hisham Muhammad's avatar
Hisham Muhammad committed
619
620
621
622
623
624
625
626
627
628
629
630
631
         FunctionBar_draw(defaultBar, NULL);
         refreshTimeout = 0;
         break;
      }
      case '\014': // Ctrl+L
      {
         clear();
         FunctionBar_draw(defaultBar, NULL);
         refreshTimeout = 0;
         break;
      }
      case ' ':
      {
Hisham Muhammad's avatar
Hisham Muhammad committed
632
         Process* p = (Process*) Panel_getSelected(panel);
633
         if (!p) break;
Hisham Muhammad's avatar
Hisham Muhammad committed
634
         Process_toggleTag(p);
Hisham Muhammad's avatar
Hisham Muhammad committed
635
         Panel_onKey(panel, KEY_DOWN);
Hisham Muhammad's avatar
Hisham Muhammad committed
636
637
638
639
         break;
      }
      case 's':
      {
640
641
642
         Process* p = (Process*) Panel_getSelected(panel);
         if (!p) break;
         TraceScreen* ts = TraceScreen_new(p);
Hisham Muhammad's avatar
Hisham Muhammad committed
643
644
645
646
647
648
649
650
         TraceScreen_run(ts);
         TraceScreen_delete(ts);
         clear();
         FunctionBar_draw(defaultBar, NULL);
         refreshTimeout = 0;
         CRT_enableDelay();
         break;
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
651
652
      case 'l':
      {
653
654
655
         Process* p = (Process*) Panel_getSelected(panel);
         if (!p) break;
         OpenFilesScreen* ts = OpenFilesScreen_new(p);
Hisham Muhammad's avatar
Hisham Muhammad committed
656
657
658
659
660
661
662
663
         OpenFilesScreen_run(ts);
         OpenFilesScreen_delete(ts);
         clear();
         FunctionBar_draw(defaultBar, NULL);
         refreshTimeout = 0;
         CRT_enableDelay();
         break;
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
664
665
666
667
      case 'S':
      case 'C':
      case KEY_F(2):
      {
668
         Setup_run(settings, header);
Hisham Muhammad's avatar
Hisham Muhammad committed
669
         // TODO: shouldn't need this, colors should be dynamic
670
         ProcessList_printHeader(pl, Panel_getHeader(panel));
Hisham Muhammad's avatar
Hisham Muhammad committed
671
         headerHeight = Header_calculateHeight(header);
Hisham Muhammad's avatar
Hisham Muhammad committed
672
673
         Panel_move(panel, 0, headerHeight);
         Panel_resize(panel, COLS, LINES-headerHeight-1);
Hisham Muhammad's avatar
Hisham Muhammad committed
674
675
676
677
678
679
680
681
682
683
684
         FunctionBar_draw(defaultBar, NULL);
         refreshTimeout = 0;
         break;
      }
      case 'F':
      {
         follow = true;
         continue;
      }
      case 'u':
      {
685
         Panel* usersPanel = Panel_new(0, 0, 0, 0, true, Class(ListItem));
Hisham Muhammad's avatar
Hisham Muhammad committed
686
         Panel_setHeader(usersPanel, "Show processes of:");
Hisham Muhammad's avatar
Hisham Muhammad committed
687
         UsersTable_foreach(ut, addUserToVector, usersPanel);
688
         Vector_insertionSort(usersPanel->items);
Hisham Muhammad's avatar
Hisham Muhammad committed
689
         ListItem* allUsers = ListItem_new("All users", -1);
Hisham Muhammad's avatar
Hisham Muhammad committed
690
         Panel_insert(usersPanel, 0, (Object*) allUsers);
Hisham Muhammad's avatar
Hisham Muhammad committed
691
         const char* fuFunctions[] = {"Show    ", "Cancel ", NULL};
692
         ListItem* picked = (ListItem*) pickFromVector(panel, usersPanel, 20, headerHeight, fuFunctions, defaultBar, header);
Hisham Muhammad's avatar
Hisham Muhammad committed
693
694
695
696
697
698
699
         if (picked) {
            if (picked == allUsers) {
               userOnly = false;
            } else {
               setUserOnly(ListItem_getRef(picked), &userOnly, &userId);
            }
         }
Hisham Muhammad's avatar
Hisham Muhammad committed
700
         Panel_delete((Object*)usersPanel);
Hisham Muhammad's avatar
Hisham Muhammad committed
701
702
         break;
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
703
704
705
706
707
      case '+':
      case '=':
      case '-':
      {
         Process* p = (Process*) Panel_getSelected(panel);
708
         if (!p) break;
Hisham Muhammad's avatar
Hisham Muhammad committed
709
710
711
712
713
         p->showChildren = !p->showChildren;
         refreshTimeout = 0;
         doRecalculate = true;
         break;
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
714
715
716
      case KEY_F(9):
      case 'k':
      {
717
         Panel* signalsPanel = (Panel*) SignalsPanel_new();
Hisham Muhammad's avatar
Hisham Muhammad committed
718
         const char* fuFunctions[] = {"Send  ", "Cancel ", NULL};
719
         ListItem* sgn = (ListItem*) pickFromVector(panel, signalsPanel, 15, headerHeight, fuFunctions, defaultBar, header);
Hisham Muhammad's avatar
Hisham Muhammad committed
720
         if (sgn) {
Hisham Muhammad's avatar
Hisham Muhammad committed
721
            if (sgn->key != 0) {
Hisham Muhammad's avatar
Hisham Muhammad committed
722
723
               Panel_setHeader(panel, "Sending...");
               Panel_draw(panel, true);
Hisham Muhammad's avatar
Hisham Muhammad committed
724
               refresh();
725
               foreachProcess(panel, (ForeachProcessFn) Process_sendSignal, (size_t) sgn->key, NULL);
Hisham Muhammad's avatar
Hisham Muhammad committed
726
727
728
               napms(500);
            }
         }
729
         ProcessList_printHeader(pl, Panel_getHeader(panel));
730
         Panel_delete((Object*)signalsPanel);
Hisham Muhammad's avatar
Hisham Muhammad committed
731
732
733
         refreshTimeout = 0;
         break;
      }
734
#if (HAVE_LIBHWLOC || HAVE_NATIVE_AFFINITY)
735
736
      case 'a':
      {
737
         if (pl->cpuCount == 1)
738
739
            break;

740
741
742
         Process* p = (Process*) Panel_getSelected(panel);
         if (!p) break;
         Affinity* affinity = Process_getAffinity(p);
743
         if (!affinity) break;
744
745
         Panel* affinityPanel = AffinityPanel_new(pl, affinity);
         Affinity_delete(affinity);
746

Hisham Muhammad's avatar
Hisham Muhammad committed
747
         const char* fuFunctions[] = {"Set    ", "Cancel ", NULL};
748
         void* set = pickFromVector(panel, affinityPanel, 15, headerHeight, fuFunctions, defaultBar, header);
749
         if (set) {
750
            Affinity* affinity = AffinityPanel_getAffinity(affinityPanel);
751
752
            bool ok = foreachProcess(panel, (ForeachProcessFn) Process_setAffinity, (size_t) affinity, NULL);
            if (!ok) beep();
753
            Affinity_delete(affinity);
754
         }
755
         Panel_delete((Object*)affinityPanel);
756
         ProcessList_printHeader(pl, Panel_getHeader(panel));
757
758
759
         refreshTimeout = 0;
         break;
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
760
#endif
Hisham Muhammad's avatar
Hisham Muhammad committed
761
762
763
764
765
766
767
768
769
770
771
      case KEY_F(10):
      case 'q':
         quit = 1;
         break;
      case '<':
      case ',':
      case KEY_F(18):
      case '>':
      case '.':
      case KEY_F(6):
      {
772
         Panel* sortPanel = Panel_new(0, 0, 0, 0, true, Class(ListItem));
Hisham Muhammad's avatar
Hisham Muhammad committed
773
         Panel_setHeader(sortPanel, "Sort by");
Hisham Muhammad's avatar
Hisham Muhammad committed
774
         const char* fuFunctions[] = {"Sort  ", "Cancel ", NULL};
Hisham Muhammad's avatar
Hisham Muhammad committed
775
776
         ProcessField* fields = pl->fields;
         for (int i = 0; fields[i]; i++) {
777
            char* name = String_trim(Process_fieldNames[fields[i]]);
Hisham Muhammad's avatar
Hisham Muhammad committed
778
            Panel_add(sortPanel, (Object*) ListItem_new(name, fields[i]));
Hisham Muhammad's avatar
Hisham Muhammad committed
779
            if (fields[i] == pl->sortKey)
Hisham Muhammad's avatar
Hisham Muhammad committed
780
               Panel_setSelected(sortPanel, i);
Hisham Muhammad's avatar
Hisham Muhammad committed
781
782
            free(name);
         }
783
         ListItem* field = (ListItem*) pickFromVector(panel, sortPanel, 15, headerHeight, fuFunctions, defaultBar, header);
Hisham Muhammad's avatar
Hisham Muhammad committed
784
785
         if (field) {
            settings->changed = true;
786
787
            setSortKey(pl, field->key, panel, settings);
         } else {
788
            ProcessList_printHeader(pl, Panel_getHeader(panel));
Hisham Muhammad's avatar
Hisham Muhammad committed
789
         }
790
         Object_delete(sortPanel);
Hisham Muhammad's avatar
Hisham Muhammad committed
791
792
793
         refreshTimeout = 0;
         break;
      }
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
      case 'i':
      {
         Process* p = (Process*) Panel_getSelected(panel);
         if (!p) break;
         IOPriority ioprio = p->ioPriority;
         Panel* ioprioPanel = IOPriorityPanel_new(ioprio);
         const char* fuFunctions[] = {"Set    ", "Cancel ", NULL};
         void* set = pickFromVector(panel, ioprioPanel, 21, headerHeight, fuFunctions, defaultBar, header);
         if (set) {
            IOPriority ioprio = IOPriorityPanel_getIOPriority(ioprioPanel);
            bool ok = foreachProcess(panel, (ForeachProcessFn) Process_setIOPriority, (size_t) ioprio, NULL);
            if (!ok)
               beep();
         }
         Panel_delete((Object*)ioprioPanel);
         ProcessList_printHeader(pl, Panel_getHeader(panel));
         refreshTimeout = 0;
         break;
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
813
814
815
816
817
818
819
820
821
822
      case 'I':
      {
         refreshTimeout = 0;
         settings->changed = true;
         ProcessList_invertSortOrder(pl);
         break;
      }
      case KEY_F(8):
      case '[':
      {
Hisham Muhammad's avatar
Hisham Muhammad committed
823
         doRefresh = changePriority(panel, 1);
Hisham Muhammad's avatar
Hisham Muhammad committed
824
825
826
827
828
         break;
      }
      case KEY_F(7):
      case ']':
      {
Hisham Muhammad's avatar
Hisham Muhammad committed
829
         doRefresh = changePriority(panel, -1);
Hisham Muhammad's avatar
Hisham Muhammad committed
830
831
832
833
         break;
      }
      case KEY_F(3):
      case '/':
834
         IncSet_activate(inc, INC_SEARCH);
Hisham Muhammad's avatar
Hisham Muhammad committed
835
         break;
Hisham Muhammad's avatar
Hisham Muhammad committed
836
837
      case KEY_F(4):
      case '\\':
838
         IncSet_activate(inc, INC_FILTER);
Hisham Muhammad's avatar
Hisham Muhammad committed
839
840
841
         refreshTimeout = 0;
         doRefresh = true;
         continue;
Hisham Muhammad's avatar
Hisham Muhammad committed
842
843
844
845
      case 't':
      case KEY_F(5):
         refreshTimeout = 0;
         pl->treeView = !pl->treeView;
846
847
         if (pl->treeView) pl->direction = 1;
         ProcessList_printHeader(pl, Panel_getHeader(panel));
848
         ProcessList_expandTree(pl);
Hisham Muhammad's avatar
Hisham Muhammad committed
849
         settings->changed = true;
850
         if (following != -1) continue;
Hisham Muhammad's avatar
Hisham Muhammad committed
851
852
         break;
      case 'H':
Hisham Muhammad's avatar
Hisham Muhammad committed
853
         doRecalculate = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
854
         refreshTimeout = 0;
855
856
         pl->hideUserlandThreads = !pl->hideUserlandThreads;
         pl->hideThreads = pl->hideUserlandThreads;
Hisham Muhammad's avatar
Hisham Muhammad committed
857
858
859
         settings->changed = true;
         break;
      case 'K':
Hisham Muhammad's avatar
Hisham Muhammad committed
860
         doRecalculate = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
861
862
863
864
865
866
867
         refreshTimeout = 0;
         pl->hideKernelThreads = !pl->hideKernelThreads;
         settings->changed = true;
         break;
      default:
         doRefresh = false;
         refreshTimeout = resetRefreshTimeout;
Hisham Muhammad's avatar
Hisham Muhammad committed
868
         Panel_onKey(panel, ch);
Hisham Muhammad's avatar
Hisham Muhammad committed
869
870
871
872
873
874
875
876
877
878
879
880
881
882
         break;
      }
      follow = false;
   }
   attron(CRT_colors[RESET_COLOR]);
   mvhline(LINES-1, 0, ' ', COLS);
   attroff(CRT_colors[RESET_COLOR]);
   refresh();
   
   CRT_done();
   if (settings->changed)
      Settings_write(settings);
   Header_delete(header);
   ProcessList_delete(pl);
883
   IncSet_delete(inc);
Hisham Muhammad's avatar
Hisham Muhammad committed
884
   FunctionBar_delete((Object*)defaultBar);
Hisham Muhammad's avatar
Hisham Muhammad committed
885
   Panel_delete((Object*)panel);
Hisham Muhammad's avatar
Hisham Muhammad committed
886
887
   UsersTable_delete(ut);
   Settings_delete(settings);
888
889
890
   if(pidWhiteList) {
      Hashtable_delete(pidWhiteList);
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
891
892
   return 0;
}