htop.c 32.2 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
#include "htop.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
28

Hisham Muhammad's avatar
Hisham Muhammad committed
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
#include <time.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
41

Hisham Muhammad's avatar
Hisham Muhammad committed
42
43
//#link m

Hisham Muhammad's avatar
Hisham Muhammad committed
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#define COPYRIGHT "(C) 2004-2014 Hisham Muhammad"

/*{

typedef enum {
   HTOP_OK = 0x00,
   HTOP_REFRESH = 0x01,
   HTOP_RECALCULATE = 0x03, // implies HTOP_REFRESH
   HTOP_SAVE_SETTINGS = 0x04,
   HTOP_KEEP_FOLLOWING = 0x08,
   HTOP_QUIT = 0x10,
   HTOP_REDRAW_BAR = 0x20,
   HTOP_UPDATE_PANELHDR = 0x41, // implies HTOP_REFRESH
} Htop_Reaction;

typedef Htop_Reaction (*Htop_Action)();

typedef struct State_ {
   IncSet* inc;
   Settings* settings;
   UsersTable* ut;
} State;

typedef bool(*ForeachProcessFn)(Process*, size_t);

}*/
70

71
static void printVersionFlag() {
72
73
74
   fputs("htop " VERSION " - " COPYRIGHT "\n"
         "Released under the GNU GPL.\n\n",
         stdout);
Hisham Muhammad's avatar
Hisham Muhammad committed
75
76
77
   exit(0);
}

78
79
static const char* defaultFunctions[]  = {"Help  ", "Setup ", "Search", "Filter", "Tree  ", "SortBy", "Nice -", "Nice +", "Kill  ", "Quit  ", NULL};
 
80
static void printHelpFlag() {
81
82
   fputs("htop " VERSION " - " COPYRIGHT "\n"
         "Released under the GNU GPL.\n\n"
83
84
85
86
87
88
         "-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"
89
90
91
92
93
94
         "-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
95
96
97
   exit(0);
}

98
99
100
101
102
103
104
105
106
107
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" },
108
   { .key = " F6 + -: ", .info = "expand/collapse tree" },
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
   { .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 }
};

135
static void showHelp(ProcessList* pl) {
Hisham Muhammad's avatar
Hisham Muhammad committed
136
137
   clear();
   attrset(CRT_colors[HELP_BOLD]);
138
139
140
141

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

142
   mvaddstr(0, 0, "htop " VERSION " - " COPYRIGHT);
Hisham Muhammad's avatar
Hisham Muhammad committed
143
144
145
146
147
148
   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], "[");
149
   if (pl->detailedCPUTime) {
150
      addattrstr(CRT_colors[CPU_NICE_TEXT], "low"); addstr("/");
151
152
153
      addattrstr(CRT_colors[CPU_NORMAL], "normal"); addstr("/");
      addattrstr(CRT_colors[CPU_KERNEL], "kernel"); addstr("/");
      addattrstr(CRT_colors[CPU_IRQ], "irq"); addstr("/");
154
      addattrstr(CRT_colors[CPU_SOFTIRQ], "soft-irq"); addstr("/");
155
      addattrstr(CRT_colors[CPU_STEAL], "steal"); addstr("/");
156
157
      addattrstr(CRT_colors[CPU_GUEST], "guest"); addstr("/");
      addattrstr(CRT_colors[CPU_IOWAIT], "io-wait");
158
159
      addattrstr(CRT_colors[BAR_SHADOW], " used%");
   } else {
160
      addattrstr(CRT_colors[CPU_NICE_TEXT], "low-priority"); addstr("/");
161
      addattrstr(CRT_colors[CPU_NORMAL], "normal"); addstr("/");
162
163
164
      addattrstr(CRT_colors[CPU_KERNEL], "kernel"); addstr("/");
      addattrstr(CRT_colors[CPU_STEAL], "virtualiz");
      addattrstr(CRT_colors[BAR_SHADOW], "               used%");
165
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
166
167
168
169
170
   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("/");
171
   addattrstr(CRT_colors[MEMORY_BUFFERS_TEXT], "buffers"); addstr("/");
Hisham Muhammad's avatar
Hisham Muhammad committed
172
   addattrstr(CRT_colors[MEMORY_CACHE], "cache");
173
   addattrstr(CRT_colors[BAR_SHADOW], "                            used/total");
Hisham Muhammad's avatar
Hisham Muhammad committed
174
175
176
177
178
   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");
179
   addattrstr(CRT_colors[BAR_SHADOW], "                                          used/total");
Hisham Muhammad's avatar
Hisham Muhammad committed
180
181
   addattrstr(CRT_colors[BAR_BORDER], "]");
   attrset(CRT_colors[DEFAULT_COLOR]);
182
   mvaddstr(6,0, "Type and layout of header meters are configurable in the setup screen.");
183
184
185
186
   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");
187
188
   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
189
   attrset(CRT_colors[HELP_BOLD]);
190
191
   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
192
193
194
195
196
197
198
199
200

   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
201
static const char* CategoriesFunctions[] = {"      ", "      ", "      ", "      ", "      ", "      ", "      ", "      ", "      ", "Done  ", NULL};
202

203
204
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
205
   CategoriesPanel* panelCategories = CategoriesPanel_new(settings, scr);
Hisham Muhammad's avatar
Hisham Muhammad committed
206
   ScreenManager_add(scr, (Panel*) panelCategories, FunctionBar_new(CategoriesFunctions, NULL, NULL), 16);
Hisham Muhammad's avatar
Hisham Muhammad committed
207
208
   CategoriesPanel_makeMetersPage(panelCategories);
   Panel* panelFocus;
Hisham Muhammad's avatar
Hisham Muhammad committed
209
   int ch;
Hisham Muhammad's avatar
Hisham Muhammad committed
210
   ScreenManager_run(scr, &panelFocus, &ch);
Hisham Muhammad's avatar
Hisham Muhammad committed
211
212
213
   ScreenManager_delete(scr);
}

214
static bool foreachProcess(Panel* panel, ForeachProcessFn fn, int arg, bool* wasAnyTagged) {
215
   bool ok = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
216
   bool anyTagged = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
217
   for (int i = 0; i < Panel_size(panel); i++) {
Hisham Muhammad's avatar
Hisham Muhammad committed
218
      Process* p = (Process*) Panel_get(panel, i);
Hisham Muhammad's avatar
Hisham Muhammad committed
219
      if (p->tag) {
220
         ok = fn(p, arg) && ok;
Hisham Muhammad's avatar
Hisham Muhammad committed
221
222
223
224
         anyTagged = true;
      }
   }
   if (!anyTagged) {
Hisham Muhammad's avatar
Hisham Muhammad committed
225
      Process* p = (Process*) Panel_getSelected(panel);
226
      if (p) ok = fn(p, arg) && ok;
Hisham Muhammad's avatar
Hisham Muhammad committed
227
   }
228
229
230
231
232
233
234
235
   if (wasAnyTagged)
      *wasAnyTagged = anyTagged;
   return ok;
}

static bool changePriority(Panel* panel, int delta) {
   bool anyTagged;
   bool ok = foreachProcess(panel, (ForeachProcessFn) Process_changePriorityBy, delta, &anyTagged);
236
237
   if (!ok)
      beep();
Hisham Muhammad's avatar
Hisham Muhammad committed
238
239
240
   return anyTagged;
}

241
242
243
244
245
246
247
248
static int selectedPid(Panel* panel) {
   Process* p = (Process*) Panel_getSelected(panel);
   if (p) {
      return p->pid;
   }
   return -1;
}

Hisham Muhammad's avatar
Hisham Muhammad committed
249
250
static Object* pickFromVector(Panel* panel, Panel* list, int x, const char** keyLabels, Header* header) {
   int y = panel->y;
Hisham Muhammad's avatar
Hisham Muhammad committed
251
   const char* fuKeys[] = {"Enter", "Esc", NULL};
252
   int fuEvents[] = {13, 27};
253
   ScreenManager* scr = ScreenManager_new(0, y, 0, -1, HORIZONTAL, header, false);
254
   scr->allowFocusChange = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
255
   ScreenManager_add(scr, list, FunctionBar_new(keyLabels, fuKeys, fuEvents), x - 1);
Hisham Muhammad's avatar
Hisham Muhammad committed
256
257
   ScreenManager_add(scr, panel, NULL, -1);
   Panel* panelFocus;
Hisham Muhammad's avatar
Hisham Muhammad committed
258
   int ch;
259
   bool unfollow = false;
260
   int pid = selectedPid(panel);
261
   if (header->pl->following == -1) {
262
      header->pl->following = pid;
263
264
      unfollow = true;
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
265
   ScreenManager_run(scr, &panelFocus, &ch);
266
267
268
   if (unfollow) {
      header->pl->following = -1;
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
269
   ScreenManager_delete(scr);
Hisham Muhammad's avatar
Hisham Muhammad committed
270
271
272
   Panel_move(panel, 0, y);
   Panel_resize(panel, COLS, LINES-y-1);
   if (panelFocus == list && ch == 13) {
273
      Process* selected = (Process*)Panel_getSelected(panel);
274
      if (selected && selected->pid == pid)
275
276
277
         return Panel_getSelected(list);
      else
         beep();
Hisham Muhammad's avatar
Hisham Muhammad committed
278
279
280
281
   }
   return NULL;
}

Hisham Muhammad's avatar
Hisham Muhammad committed
282
static void addUserToVector(int key, void* userCast, void* panelCast) {
Hisham Muhammad's avatar
Hisham Muhammad committed
283
   char* user = (char*) userCast;
Hisham Muhammad's avatar
Hisham Muhammad committed
284
285
   Panel* panel = (Panel*) panelCast;
   Panel_add(panel, (Object*) ListItem_new(user, key));
Hisham Muhammad's avatar
Hisham Muhammad committed
286
287
}

288
static bool setUserOnly(const char* userName, bool* userOnly, uid_t* userId) {
Hisham Muhammad's avatar
Hisham Muhammad committed
289
290
291
292
   struct passwd* user = getpwnam(userName);
   if (user) {
      *userOnly = true;
      *userId = user->pw_uid;
293
      return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
294
   }
295
   return false;
Hisham Muhammad's avatar
Hisham Muhammad committed
296
297
}

298
299
300
301
302
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
303
304
}

305
306
307
308
309
310
311
312
313
314
315
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);
      }
   }
}

316
317
318
319
320
321
322
static bool expandCollapse(Panel* panel) {
   Process* p = (Process*) Panel_getSelected(panel);
   if (!p) return false;
   p->showChildren = !p->showChildren;
   return true;
}

Hisham Muhammad's avatar
Hisham Muhammad committed
323
324
325
326
327
328
329
330
331
static inline Htop_Reaction setSortKey(ProcessList* pl, ProcessField sortKey) {
   pl->sortKey = sortKey;
   pl->direction = 1;
   pl->treeView = false;
   return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_UPDATE_PANELHDR;
}

static Htop_Reaction sortBy(Panel* panel, ProcessList* pl, Header* header) {
   Htop_Reaction reaction = HTOP_OK;
332
333
334
335
336
337
338
339
340
341
342
   Panel* sortPanel = Panel_new(0, 0, 0, 0, true, Class(ListItem));
   Panel_setHeader(sortPanel, "Sort by");
   const char* fuFunctions[] = {"Sort  ", "Cancel ", NULL};
   ProcessField* fields = pl->fields;
   for (int i = 0; fields[i]; i++) {
      char* name = String_trim(Process_fieldNames[fields[i]]);
      Panel_add(sortPanel, (Object*) ListItem_new(name, fields[i]));
      if (fields[i] == pl->sortKey)
         Panel_setSelected(sortPanel, i);
      free(name);
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
343
   ListItem* field = (ListItem*) pickFromVector(panel, sortPanel, 15, fuFunctions, header);
344
   if (field) {
Hisham Muhammad's avatar
Hisham Muhammad committed
345
      reaction |= setSortKey(pl, field->key);
346
347
   }
   Object_delete(sortPanel);
Hisham Muhammad's avatar
Hisham Muhammad committed
348
   return reaction | HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
349
350
}

Hisham Muhammad's avatar
Hisham Muhammad committed
351
static void millisleep(unsigned long millisec) {
352
353
354
355
356
357
358
359
360
   struct timespec req = {
      .tv_sec = 0,
      .tv_nsec = millisec * 1000000L
   };
   while(nanosleep(&req,&req)==-1) {
      continue;
   }
}

Hisham Muhammad's avatar
Hisham Muhammad committed
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
// ----------------------------------------

static Htop_Reaction actionResize(Panel* panel) {
   Panel_resize(panel, COLS, LINES-(panel->y)-1);
   return HTOP_REDRAW_BAR;
}

static Htop_Reaction actionSortByMemory(Panel* panel, ProcessList* pl) {
   (void) panel;
   return setSortKey(pl, PERCENT_MEM);
}

static Htop_Reaction actionSortByCPU(Panel* panel, ProcessList* pl) {
   (void) panel;
   return setSortKey(pl, PERCENT_CPU);
}

static Htop_Reaction actionSortByTime(Panel* panel, ProcessList* pl) {
   (void) panel;
   return setSortKey(pl, TIME);
}

static Htop_Reaction actionToggleKernelThreads(Panel* panel, ProcessList* pl) {
   (void) panel;
   pl->hideKernelThreads = !pl->hideKernelThreads;
   return HTOP_RECALCULATE | HTOP_SAVE_SETTINGS;
}

static Htop_Reaction actionToggleUserlandThreads(Panel* panel, ProcessList* pl) {
   (void) panel;
   pl->hideUserlandThreads = !pl->hideUserlandThreads;
   pl->hideThreads = pl->hideUserlandThreads;
   return HTOP_RECALCULATE | HTOP_SAVE_SETTINGS;
}

static Htop_Reaction actionToggleTreeView(Panel* panel, ProcessList* pl) {
   (void) panel;
   pl->treeView = !pl->treeView;
   if (pl->treeView) pl->direction = 1;
   ProcessList_expandTree(pl);
   return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_KEEP_FOLLOWING | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}

static Htop_Reaction actionIncFilter(Panel* panel, ProcessList* pl, Header* header, State* state) {
   (void) panel, (void) pl, (void) header;
   IncSet_activate(state->inc, INC_FILTER);
   return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
}

static Htop_Reaction actionIncSearch(Panel* panel, ProcessList* pl, Header* header, State* state) {
   (void) panel, (void) pl, (void) header;
   IncSet_activate(state->inc, INC_SEARCH);
   return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
}

static Htop_Reaction actionHigherPriority(Panel* panel) {
   bool changed = changePriority(panel, -1);
   return changed ? HTOP_REFRESH : HTOP_OK;
}

static Htop_Reaction actionLowerPriority(Panel* panel) {
   bool changed = changePriority(panel, 1);
   return changed ? HTOP_REFRESH : HTOP_OK;
}

static Htop_Reaction actionInvertSortOrder(Panel* panel, ProcessList* pl) {
   (void) panel;
   ProcessList_invertSortOrder(pl);
   return HTOP_REFRESH | HTOP_SAVE_SETTINGS;
}

static Htop_Reaction actionSetIOPriority(Panel* panel, ProcessList* pl, Header* header) {
   (void) panel, (void) pl;
   Process* p = (Process*) Panel_getSelected(panel);
   if (!p) return HTOP_OK;
   IOPriority ioprio = p->ioPriority;
   Panel* ioprioPanel = IOPriorityPanel_new(ioprio);
   const char* fuFunctions[] = {"Set    ", "Cancel ", NULL};
   void* set = pickFromVector(panel, ioprioPanel, 21, fuFunctions, 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);
   return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}

static Htop_Reaction actionSetSortColumn(Panel* panel, ProcessList* pl, Header* header) {
   return sortBy(panel, pl, header);
}

static Htop_Reaction actionExpandOrCollapse(Panel* panel) {
   bool changed = expandCollapse(panel);
   return changed ? HTOP_RECALCULATE : HTOP_OK;
}

static Htop_Reaction actionExpandCollapseOrSortColumn(Panel* panel, ProcessList* pl, Header* header) {
   return pl->treeView ? actionExpandOrCollapse(panel) : actionSetSortColumn(panel, pl, header);
}

static Htop_Reaction actionQuit() {
   return HTOP_QUIT;
}

static Htop_Reaction actionSetAffinity(Panel* panel, ProcessList* pl, Header* header) {
   if (pl->cpuCount == 1)
      return HTOP_OK;
#if (HAVE_LIBHWLOC || HAVE_NATIVE_AFFINITY)
   Process* p = (Process*) Panel_getSelected(panel);
   if (!p) return HTOP_OK;
   Affinity* affinity = Process_getAffinity(p);
   if (!affinity) return HTOP_OK;
   Panel* affinityPanel = AffinityPanel_new(pl, affinity);
   Affinity_delete(affinity);

   const char* fuFunctions[] = {"Set    ", "Cancel ", NULL};
   void* set = pickFromVector(panel, affinityPanel, 15, fuFunctions, header);
   if (set) {
      Affinity* affinity = AffinityPanel_getAffinity(affinityPanel);
      bool ok = foreachProcess(panel, (ForeachProcessFn) Process_setAffinity, (size_t) affinity, NULL);
      if (!ok) beep();
      Affinity_delete(affinity);
   }
   Panel_delete((Object*)affinityPanel);
#endif
   return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}

static Htop_Reaction actionKill(Panel* panel, ProcessList* pl, Header* header) {
   (void) pl;
   Panel* signalsPanel = (Panel*) SignalsPanel_new();
   const char* fuFunctions[] = {"Send  ", "Cancel ", NULL};
   ListItem* sgn = (ListItem*) pickFromVector(panel, signalsPanel, 15, fuFunctions, header);
   if (sgn) {
      if (sgn->key != 0) {
         Panel_setHeader(panel, "Sending...");
         Panel_draw(panel, true);
         refresh();
         foreachProcess(panel, (ForeachProcessFn) Process_sendSignal, (size_t) sgn->key, NULL);
         napms(500);
      }
   }
   Panel_delete((Object*)signalsPanel);
   return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}

static Htop_Reaction actionFilterByUser(Panel* panel, ProcessList* pl, Header* header, State* state) {
   Panel* usersPanel = Panel_new(0, 0, 0, 0, true, Class(ListItem));
   Panel_setHeader(usersPanel, "Show processes of:");
   UsersTable_foreach(state->ut, addUserToVector, usersPanel);
   Vector_insertionSort(usersPanel->items);
   ListItem* allUsers = ListItem_new("All users", -1);
   Panel_insert(usersPanel, 0, (Object*) allUsers);
   const char* fuFunctions[] = {"Show    ", "Cancel ", NULL};
   ListItem* picked = (ListItem*) pickFromVector(panel, usersPanel, 20, fuFunctions, header);
   if (picked) {
      if (picked == allUsers) {
         pl->userOnly = false;
      } else {
         setUserOnly(ListItem_getRef(picked), &(pl->userOnly), &(pl->userId));
      }
   }
   Panel_delete((Object*)usersPanel);
   return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}

static Htop_Reaction actionFollow() {
   return HTOP_KEEP_FOLLOWING;
}

static Htop_Reaction actionSetup(Panel* panel, ProcessList* pl, Header* header, State* state) {
   (void) pl;
   Setup_run(state->settings, header);
   // TODO: shouldn't need this, colors should be dynamic
   int headerHeight = Header_calculateHeight(header);
   Panel_move(panel, 0, headerHeight);
   Panel_resize(panel, COLS, LINES-headerHeight-1);
   return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}

static Htop_Reaction actionLsof(Panel* panel) {
   Process* p = (Process*) Panel_getSelected(panel);
   if (!p) return HTOP_OK;
   OpenFilesScreen* ts = OpenFilesScreen_new(p);
   OpenFilesScreen_run(ts);
   OpenFilesScreen_delete(ts);
   clear();
   CRT_enableDelay();
   return HTOP_REFRESH | HTOP_REDRAW_BAR;
}

static Htop_Reaction actionStrace(Panel* panel) {
   Process* p = (Process*) Panel_getSelected(panel);
   if (!p) return HTOP_OK;
   TraceScreen* ts = TraceScreen_new(p);
   TraceScreen_run(ts);
   TraceScreen_delete(ts);
   clear();
   CRT_enableDelay();
   return HTOP_REFRESH | HTOP_REDRAW_BAR;
}

static Htop_Reaction actionTag(Panel* panel) {
   Process* p = (Process*) Panel_getSelected(panel);
   if (!p) return HTOP_OK;
   Process_toggleTag(p);
   Panel_onKey(panel, KEY_DOWN);
   return HTOP_OK;
}

static Htop_Reaction actionRedraw() {
   clear();
   return HTOP_REFRESH | HTOP_REDRAW_BAR;
}

static Htop_Reaction actionHelp(Panel* panel, ProcessList* pl) {
   (void) panel;
   showHelp(pl);
   return HTOP_RECALCULATE | HTOP_REDRAW_BAR;
}

static Htop_Reaction actionUntagAll(Panel* panel) {
   for (int i = 0; i < Panel_size(panel); i++) {
      Process* p = (Process*) Panel_get(panel, i);
      p->tag = false;
   }
   return HTOP_REFRESH;
}

static Htop_Reaction actionTagAllChildren(Panel* panel) {
   Process* p = (Process*) Panel_getSelected(panel);
   if (!p) return HTOP_OK;
   tagAllChildren(panel, p);
   return HTOP_OK;
}

void setBindings(Htop_Action* keys) {
   keys[KEY_RESIZE] = actionResize;
   keys['M'] = actionSortByMemory;
   keys['T'] = actionSortByTime;
   keys['P'] = actionSortByCPU;
   keys['H'] = actionToggleUserlandThreads;
   keys['K'] = actionToggleKernelThreads;
   keys['t'] = actionToggleTreeView;
   keys[KEY_F(5)] = actionToggleTreeView;
   keys[KEY_F(4)] = actionIncFilter;
   keys['\\'] = actionIncFilter;
   keys[KEY_F(3)] = actionIncSearch;
   keys['/'] = actionIncSearch;

   keys[']'] = actionHigherPriority;
   keys[KEY_F(7)] = actionHigherPriority;
   keys['['] = actionLowerPriority;
   keys[KEY_F(8)] = actionLowerPriority;
   keys['I'] = actionInvertSortOrder;
   keys['i'] = actionSetIOPriority;
   keys[KEY_F(6)] = actionExpandCollapseOrSortColumn;
   keys[KEY_F(18)] = actionExpandCollapseOrSortColumn;
   keys['<'] = actionSetSortColumn;
   keys[','] = actionSetSortColumn;
   keys['>'] = actionSetSortColumn;
   keys['.'] = actionSetSortColumn;
   keys[KEY_F(10)] = actionQuit;
   keys['q'] = actionQuit;
   keys['a'] = actionSetAffinity;
   keys[KEY_F(9)] = actionKill;
   keys['k'] = actionKill;
   keys['+'] = actionExpandOrCollapse;
   keys['='] = actionExpandOrCollapse;
   keys['-'] = actionExpandOrCollapse;
   keys['u'] = actionFilterByUser;
   keys['F'] = actionFollow;
   keys['S'] = actionSetup;
   keys['C'] = actionSetup;
   keys[KEY_F(2)] = actionSetup;
   keys['l'] = actionLsof;
   keys['s'] = actionStrace;
   keys[' '] = actionTag;
   keys['\014'] = actionRedraw; // Ctrl+L
   keys[KEY_F(1)] = actionHelp;
   keys['h'] = actionHelp;
   keys['?'] = actionHelp;
   keys['U'] = actionUntagAll;
   keys['c'] = actionTagAllChildren;
}

// ----------------------------------------


static void updateTreeFunctions(FunctionBar* fuBar, bool mode) {
   if (mode) {
      FunctionBar_setLabel(fuBar, KEY_F(5), "Sorted");
      FunctionBar_setLabel(fuBar, KEY_F(6), "Collap");
   } else {
      FunctionBar_setLabel(fuBar, KEY_F(5), "Tree  ");
      FunctionBar_setLabel(fuBar, KEY_F(6), "SortBy");
   }
}

Hisham Muhammad's avatar
Hisham Muhammad committed
662
663
664
665
666
int main(int argc, char** argv) {

   int delay = -1;
   bool userOnly = false;
   uid_t userId = 0;
667
   int usecolors = 1;
668
669
670
   char *argCopy;
   char *pid;
   Hashtable *pidWhiteList = NULL;
671
672
673
674
675
676
677
678
679
680
681

   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'},
682
      {"pid",      required_argument,   0, 'p'},
683
684
      {0,0,0,0}
   };
685
   int sortKey = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
686

687
688
689
   char *lc_ctype = getenv("LC_CTYPE");
   if(lc_ctype != NULL)
      setlocale(LC_CTYPE, lc_ctype);
690
691
   else if ((lc_ctype = getenv("LC_ALL")))
      setlocale(LC_CTYPE, lc_ctype);
692
   else
693
      setlocale(LC_CTYPE, "");
694

695
   /* Parse arguments */
696
   while ((opt = getopt_long(argc, argv, "hvCs:d:u:p:", long_opts, &opti))) {
697
698
699
700
701
702
703
704
705
      if (opt == EOF) break;
      switch (opt) {
         case 'h':
            printHelpFlag();
            break;
         case 'v':
            printVersionFlag();
            break;
         case 's':
Hisham Muhammad's avatar
Hisham Muhammad committed
706
            if (strcmp(optarg, "help") == 0) {
707
708
709
710
711
712
713
714
715
716
717
718
               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':
719
            if (sscanf(optarg, "%16d", &delay) == 1) {
720
721
722
723
724
725
               if (delay < 1) delay = 1;
               if (delay > 100) delay = 100;
            } else {
               fprintf(stderr, "Error: invalid delay value \"%s\".\n", optarg);
               exit(1);
            }
726
727
            break;
         case 'u':
728
729
730
731
            if (!setUserOnly(optarg, &userOnly, &userId)) {
               fprintf(stderr, "Error: invalid user \"%s\".\n", optarg);
               exit(1);
            }
732
733
734
            break;
         case 'C':
            usecolors=0;
735
            break;
736
        case 'p': {
737
            argCopy = strdup(optarg);
738
739
            char* saveptr;
            pid = strtok_r(argCopy, ",", &saveptr);
740
741
742
743
744
745
746
747

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

            while( pid ) {
                unsigned int num_pid = atoi(pid);
                Hashtable_put(pidWhiteList, num_pid, (void *) 1);
748
                pid = strtok_r(NULL, ",", &saveptr);
749
750
751
            }
            free(argCopy);

752
            break;
753
         }
754
755
         default:
            exit(1);
Hisham Muhammad's avatar
Hisham Muhammad committed
756
757
      }
   }
758
759


760
761
762
763
   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
764

Hisham Muhammad's avatar
Hisham Muhammad committed
765
766
767
   bool quit = false;
   int sortTimeout = 0;
   int resetSortTimeout = 5;
Hisham Muhammad's avatar
Hisham Muhammad committed
768
   bool doRefresh = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
769
   bool forceRecalculate = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
770
771
772
773
774
   Settings* settings;
   
   ProcessList* pl = NULL;
   UsersTable* ut = UsersTable_new();

775
776
777
778
779
780
781
782
783
784
785
786
787
788
#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

789
   pl = ProcessList_new(ut, pidWhiteList);
Hisham Muhammad's avatar
Hisham Muhammad committed
790
791
   pl->userOnly = userOnly;
   pl->userId = userId;
792
   Process_getMaxPid();
Hisham Muhammad's avatar
Hisham Muhammad committed
793
794
   
   Header* header = Header_new(pl);
795
   settings = Settings_new(pl, header, pl->cpuCount);
Hisham Muhammad's avatar
Hisham Muhammad committed
796
797
798
799
800
   int headerHeight = Header_calculateHeight(header);

   // FIXME: move delay code to settings
   if (delay != -1)
      settings->delay = delay;
801
802
   if (!usecolors) 
      settings->colorScheme = COLORSCHEME_MONOCHROME;
803

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

806
   Panel* panel = Panel_new(0, headerHeight, COLS, LINES - headerHeight - 2, false, &Process_class);
807
   ProcessList_setPanel(pl, panel);
Hisham Muhammad's avatar
Hisham Muhammad committed
808
   
809
   FunctionBar* defaultBar = FunctionBar_new(defaultFunctions, NULL, NULL);
Hisham Muhammad's avatar
Hisham Muhammad committed
810
   updateTreeFunctions(defaultBar, pl->treeView);
811
   
812
813
   if (sortKey > 0) {
      pl->sortKey = sortKey;
Hisham Muhammad's avatar
Hisham Muhammad committed
814
      pl->treeView = false;
815
816
      pl->direction = 1;
   }
817
   ProcessList_printHeader(pl, Panel_getHeader(panel));
Hisham Muhammad's avatar
Hisham Muhammad committed
818

819
820
   IncSet* inc = IncSet_new(defaultBar);

Hisham Muhammad's avatar
Hisham Muhammad committed
821
   ProcessList_scan(pl);
822
   millisleep(75);
823
   ProcessList_scan(pl);
Hisham Muhammad's avatar
Hisham Muhammad committed
824
825
826
827
828
829
830
831
832
   
   FunctionBar_draw(defaultBar, NULL);
   
   int acc = 0;
   bool follow = false;
 
   struct timeval tv;
   double oldTime = 0.0;

833
   int ch = ERR;
Hisham Muhammad's avatar
Hisham Muhammad committed
834
835
   int closeTimeout = 0;

Hisham Muhammad's avatar
Hisham Muhammad committed
836
   bool drawPanel = true;
837
   
838
839
   bool collapsed = false;
   
Hisham Muhammad's avatar
Hisham Muhammad committed
840
841
842
843
844
845
846
847
848
   Htop_Action keys[KEY_MAX] = { NULL };
   setBindings(keys);
   
   State state = {
      .inc = inc,
      .settings = settings,
      .ut = ut,
   };
   
Hisham Muhammad's avatar
Hisham Muhammad committed
849
850
   while (!quit) {
      gettimeofday(&tv, NULL);
851
      double newTime = ((double)tv.tv_sec * 10) + ((double)tv.tv_usec / 100000);
Hisham Muhammad's avatar
Hisham Muhammad committed
852
853
      bool timeToRecalculate = (newTime - oldTime > settings->delay);
      if (newTime < oldTime) timeToRecalculate = true; // clock was adjusted?
854
      int following = follow ? selectedPid(panel) : -1;
Hisham Muhammad's avatar
Hisham Muhammad committed
855
      if (timeToRecalculate) {
856
         Header_draw(header);
Hisham Muhammad's avatar
Hisham Muhammad committed
857
         oldTime = newTime;
858
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
859
      if (doRefresh) {
Hisham Muhammad's avatar
Hisham Muhammad committed
860
         if (timeToRecalculate || forceRecalculate) {
Hisham Muhammad's avatar
Hisham Muhammad committed
861
            ProcessList_scan(pl);
Hisham Muhammad's avatar
Hisham Muhammad committed
862
            forceRecalculate = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
863
         }
Hisham Muhammad's avatar
Hisham Muhammad committed
864
         if (sortTimeout == 0 || pl->treeView) {
Hisham Muhammad's avatar
Hisham Muhammad committed
865
            ProcessList_sort(pl);
Hisham Muhammad's avatar
Hisham Muhammad committed
866
            sortTimeout = 1;
Hisham Muhammad's avatar
Hisham Muhammad committed
867
         }
Hisham Muhammad's avatar
Hisham Muhammad committed
868
869
         ProcessList_rebuildPanel(pl, true, following, IncSet_filter(inc));
         drawPanel = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
870
871
      }
      doRefresh = true;
872
873
874
875
876
877
878
879
880
881
882
883
884
      
      if (pl->treeView) {
         Process* p = (Process*) Panel_getSelected(panel);
         if (p) {
            if (!p->showChildren && !collapsed) {
               FunctionBar_setLabel(defaultBar, KEY_F(6), "Expand");
               FunctionBar_draw(defaultBar, NULL);
            } else if (p->showChildren && collapsed) {
               FunctionBar_setLabel(defaultBar, KEY_F(6), "Collap");
               FunctionBar_draw(defaultBar, NULL);
            }
            collapsed = !p->showChildren;
         }
Hisham Muhammad's avatar
Hisham Muhammad committed
885
886
      } else {
         collapsed = false;
887
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
888

Hisham Muhammad's avatar
Hisham Muhammad committed
889
      if (drawPanel) {
890
         Panel_draw(panel, true);
891
      }
892
      
Hisham Muhammad's avatar
Hisham Muhammad committed
893
      int prev = ch;
894
      if (inc->active)
895
         move(LINES-1, CRT_cursorX);
Hisham Muhammad's avatar
Hisham Muhammad committed
896
897
898
      ch = getch();

      if (ch == ERR) {
899
         if (!inc->active)
Hisham Muhammad's avatar
Hisham Muhammad committed
900
901
            sortTimeout--;
         if (prev == ch && !timeToRecalculate) {
Hisham Muhammad's avatar
Hisham Muhammad committed
902
            closeTimeout++;
903
            if (closeTimeout == 100) {
Hisham Muhammad's avatar
Hisham Muhammad committed
904
               break;
905
            }
Hisham Muhammad's avatar
Hisham Muhammad committed
906
907
         } else
            closeTimeout = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
908
         drawPanel = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
909
910
         continue;
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
911
912
913
      drawPanel = true;

      Htop_Reaction reaction = HTOP_OK;
Hisham Muhammad's avatar
Hisham Muhammad committed
914
915
916
917
918

      if (ch == KEY_MOUSE) {
         MEVENT mevent;
         int ok = getmouse(&mevent);
         if (ok == OK) {
919
920
921
922
923
924
            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);
Hisham Muhammad's avatar
Hisham Muhammad committed
925
926
                     pl->treeView = false;
                     reaction |= HTOP_REDRAW_BAR;
927
                  } else {
Hisham Muhammad's avatar
Hisham Muhammad committed
928
                     reaction |= setSortKey(pl, field);
929
                  }
Hisham Muhammad's avatar
Hisham Muhammad committed
930
931
                  sortTimeout = 0;
                  ch = ERR;
932
933
934
               } else if (mevent.y >= panel->y + 1 && mevent.y < LINES - 1) {
                  Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1);
                  follow = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
935
                  ch = ERR;
936
               } if (mevent.y == LINES - 1) {
937
                  ch = FunctionBar_synthesizeEvent(inc->bar, mevent.x);
938
               }
939
940
941
942
943
944
            } 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
945
946
947
948
            }
         }
      }

949
950
      if (inc->active) {
         doRefresh = IncSet_handleKey(inc, ch, panel, getMainPanelValue, NULL);
951
952
953
         if (!inc->active) {
            follow = true;
         }
954
955
956
957
958
959
         continue;
      }
      
      if (isdigit((char)ch)) {
         if (Panel_size(panel) == 0) continue;
         pid_t pid = ch-48 + acc;
960
         for (int i = 0; i < ProcessList_size(pl); i++) {
961
            Panel_setSelected(panel, i);
962
963
964
965
966
            Process* p = (Process*) Panel_getSelected(panel);
            if (p && p->pid == pid) {
               break;
            }
         }
967
968
969
970
971
972
973
974
         acc = pid * 10;
         if (acc > 10000000)
            acc = 0;
         continue;
      } else {
         acc = 0;
      }

Hisham Muhammad's avatar
Hisham Muhammad committed
975
976
977
978
979
980
      if(ch != ERR && keys[ch]) {
         reaction |= (keys[ch])(panel, pl, header, &state);
      } else {
         doRefresh = false;
         sortTimeout = resetSortTimeout;
         Panel_onKey(panel, ch);
Hisham Muhammad's avatar
Hisham Muhammad committed
981
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
982
983
      
      // Reaction handlers:
984

Hisham Muhammad's avatar
Hisham Muhammad committed
985
986
987
      if (reaction & HTOP_REDRAW_BAR) {
         updateTreeFunctions(defaultBar, pl->treeView);
         IncSet_drawBar(inc);
Hisham Muhammad's avatar
Hisham Muhammad committed
988
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
989
      if (reaction & HTOP_UPDATE_PANELHDR) {
990
991
         ProcessList_printHeader(pl, Panel_getHeader(panel));
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
992
      if (reaction & HTOP_REFRESH) {
Hisham Muhammad's avatar
Hisham Muhammad committed
993
         doRefresh = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
994
995
996
997
998
999
1000
         sortTimeout = 0;
      }      
      if (reaction & HTOP_RECALCULATE) {
         forceRecalculate = true;
         sortTimeout = 0;
      }
      if (reaction & HTOP_SAVE_SETTINGS) {
Hisham Muhammad's avatar
Hisham Muhammad committed
1001
1002
         settings->changed = true;
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
1003
1004
1005
1006
      if (reaction & HTOP_QUIT) {
         quit = true;
      }
      follow = (reaction & HTOP_KEEP_FOLLOWING);
Hisham Muhammad's avatar
Hisham Muhammad committed
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
   }
   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);
Hisham Muhammad's avatar
Hisham Muhammad committed
1018
   
Hisham Muhammad's avatar
Hisham Muhammad committed
1019
   FunctionBar_delete((Object*)defaultBar);
Hisham Muhammad's avatar
Hisham Muhammad committed
1020
   Panel_delete((Object*)panel);
Hisham Muhammad's avatar
Hisham Muhammad committed
1021
1022
   
   IncSet_delete(inc);
Hisham Muhammad's avatar
Hisham Muhammad committed
1023
1024
   UsersTable_delete(ut);
   Settings_delete(settings);
Hisham Muhammad's avatar
Hisham Muhammad committed
1025
   
1026
1027
1028
   if(pidWhiteList) {
      Hashtable_delete(pidWhiteList);
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
1029
1030
   return 0;
}