ScreenManager.c 11.1 KB
Newer Older
Hisham Muhammad's avatar
Hisham Muhammad committed
1
/*
Hisham Muhammad's avatar
Hisham Muhammad committed
2
htop - ScreenManager.c
Hisham Muhammad's avatar
Hisham Muhammad committed
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 "ScreenManager.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
9
#include "ProcessList.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
10

Hisham Muhammad's avatar
Hisham Muhammad committed
11
#include "Object.h"
12
#include "CRT.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
13

Hisham Muhammad's avatar
Hisham Muhammad committed
14
#include <assert.h>
15
#include <time.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
16
#include <string.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
17
#include <stdlib.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
18
19
20
#include <stdbool.h>

/*{
Hisham Muhammad's avatar
Hisham Muhammad committed
21
22
23
#include "FunctionBar.h"
#include "Vector.h"
#include "Header.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
24
25
#include "Settings.h"
#include "Panel.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
26
27
28
29
30
31
32
33
34
35
36
37

typedef enum Orientation_ {
   VERTICAL,
   HORIZONTAL
} Orientation;

typedef struct ScreenManager_ {
   int x1;
   int y1;
   int x2;
   int y2;
   Orientation orientation;
38
   Vector* panels;
Hisham Muhammad's avatar
Hisham Muhammad committed
39
   const char* name;
40
   int panelCount;
41
   const Header* header;
Hisham Muhammad's avatar
Hisham Muhammad committed
42
   const Settings* settings;
Hisham Muhammad's avatar
Hisham Muhammad committed
43
   bool owner;
44
   bool allowFocusChange;
Hisham Muhammad's avatar
Hisham Muhammad committed
45
46
47
48
} ScreenManager;

}*/

Hisham Muhammad's avatar
Hisham Muhammad committed
49
ScreenManager* ScreenManager_new(int x1, int y1, int x2, int y2, Orientation orientation, const Header* header, const Settings* settings, bool owner) {
Hisham Muhammad's avatar
Hisham Muhammad committed
50
   ScreenManager* this;
Hisham's avatar
Hisham committed
51
   this = xMalloc(sizeof(ScreenManager));
Hisham Muhammad's avatar
Hisham Muhammad committed
52
53
54
55
56
   this->x1 = x1;
   this->y1 = y1;
   this->x2 = x2;
   this->y2 = y2;
   this->orientation = orientation;
57
   this->panels = Vector_new(Class(Panel), owner, DEFAULT_SIZE);
58
   this->panelCount = 0;
59
   this->header = header;
Hisham Muhammad's avatar
Hisham Muhammad committed
60
   this->settings = settings;
Hisham Muhammad's avatar
Hisham Muhammad committed
61
   this->owner = owner;
62
   this->allowFocusChange = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
63
64
65
66
   return this;
}

void ScreenManager_delete(ScreenManager* this) {
67
   Vector_delete(this->panels);
Hisham Muhammad's avatar
Hisham Muhammad committed
68
69
70
71
   free(this);
}

inline int ScreenManager_size(ScreenManager* this) {
72
   return this->panelCount;
Hisham Muhammad's avatar
Hisham Muhammad committed
73
74
}

75
void ScreenManager_add(ScreenManager* this, Panel* item, int size) {
76
77
78
79
   ScreenManager_insert(this, item, size, Vector_size(this->panels));
}

void ScreenManager_insert(ScreenManager* this, Panel* item, int size, int idx) {
Hisham Muhammad's avatar
Hisham Muhammad committed
80
81
   if (this->orientation == HORIZONTAL) {
      int lastX = 0;
82
83
      if (idx > 0) {
         Panel* last = (Panel*) Vector_get(this->panels, idx - 1);
Hisham Muhammad's avatar
Hisham Muhammad committed
84
85
         lastX = last->x + last->w + 1;
      }
86
      int height = LINES - this->y1 + this->y2;
87
88
      if (size <= 0) {
         size = COLS-this->x1+this->x2-lastX;
Hisham Muhammad's avatar
Hisham Muhammad committed
89
      }
90
      Panel_resize(item, size, height);
91
      Panel_move(item, lastX, this->y1);
92
93
94
95
96
97
      if (idx < this->panelCount) {
         for (int i = idx + 1; i <= this->panelCount; i++) {
            Panel* p = (Panel*) Vector_get(this->panels, i);
            Panel_move(p, p->x + size, p->y);
         }
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
98
99
   }
   // TODO: VERTICAL
100
   Vector_insert(this->panels, idx, item);
Hisham Muhammad's avatar
Hisham Muhammad committed
101
   item->needsRedraw = true;
102
   this->panelCount++;
Hisham Muhammad's avatar
Hisham Muhammad committed
103
104
}

Hisham Muhammad's avatar
Hisham Muhammad committed
105
Panel* ScreenManager_remove(ScreenManager* this, int idx) {
106
   assert(this->panelCount > idx);
107
   int w = ((Panel*) Vector_get(this->panels, idx))->w;
108
109
   Panel* panel = (Panel*) Vector_remove(this->panels, idx);
   this->panelCount--;
110
111
112
113
114
115
   if (idx < this->panelCount) {
      for (int i = idx; i < this->panelCount; i++) {
         Panel* p = (Panel*) Vector_get(this->panels, i);
         Panel_move(p, p->x - w, p->y);
      }
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
116
   return panel;
Hisham Muhammad's avatar
Hisham Muhammad committed
117
118
119
120
121
122
123
}

void ScreenManager_resize(ScreenManager* this, int x1, int y1, int x2, int y2) {
   this->x1 = x1;
   this->y1 = y1;
   this->x2 = x2;
   this->y2 = y2;
124
   int panels = this->panelCount;
125
126
127
128
129
130
131
132
133
134
   if (this->orientation == HORIZONTAL) {
      int lastX = 0;
      for (int i = 0; i < panels - 1; i++) {
         Panel* panel = (Panel*) Vector_get(this->panels, i);
         Panel_resize(panel, panel->w, LINES-y1+y2);
         Panel_move(panel, lastX, y1);
         lastX = panel->x + panel->w + 1;
      }
      Panel* panel = (Panel*) Vector_get(this->panels, panels-1);
      Panel_resize(panel, COLS-x1+x2-lastX, LINES-y1+y2);
Hisham Muhammad's avatar
Hisham Muhammad committed
135
      Panel_move(panel, lastX, y1);
Hisham Muhammad's avatar
Hisham Muhammad committed
136
   }
137
   // TODO: VERTICAL
Hisham Muhammad's avatar
Hisham Muhammad committed
138
139
}

140
141
142
143
144
145
146
147
148
149
150
151
static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTimeout, bool* redraw, bool *rescan, bool *timedOut) {
   ProcessList* pl = this->header->pl;

   struct timeval tv;
   gettimeofday(&tv, NULL);
   double newTime = ((double)tv.tv_sec * 10) + ((double)tv.tv_usec / 100000);
   *timedOut = (newTime - *oldTime > this->settings->delay);
   *rescan = *rescan || *timedOut;
   if (newTime < *oldTime) *rescan = true; // clock was adjusted?
   if (*rescan) {
      *oldTime = newTime;
      ProcessList_scan(pl);
152
      if (*sortTimeout == 0 || this->settings->ss->treeView) {
153
154
155
156
157
158
159
160
161
162
163
164
         ProcessList_sort(pl);
         *sortTimeout = 1;
      }
      *redraw = true;
   }
   if (*redraw) {
      ProcessList_rebuildPanel(pl);
      Header_draw(this->header);
   }
   *rescan = false;
}

Hisham Muhammad's avatar
Hisham Muhammad committed
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
static inline bool drawTab(int* y, int* x, int l, const char* name, bool cur) {
   attrset(CRT_colors[cur ? SCREENS_CUR_BORDER : SCREENS_OTH_BORDER]);
   mvaddch(*y, *x, '[');
   (*x)++;
   if (*x >= l) return false;
   int nameLen = strlen(name);
   int n = MIN(l - *x, nameLen);
   attrset(CRT_colors[cur ? SCREENS_CUR_TEXT : SCREENS_OTH_TEXT]);
   mvaddnstr(*y, *x, name, n);
   *x += n;
   if (*x >= l) return false;
   attrset(CRT_colors[cur ? SCREENS_CUR_BORDER : SCREENS_OTH_BORDER]);
   mvaddch(*y, *x, ']');
   *x += 2;
   if (*x >= l) return false;
   return true;
}

static void ScreenManager_drawScreenTabs(ScreenManager* this) {
   ScreenSettings** screens = this->settings->screens;
   int cur = this->settings->ssIndex;
   int l = COLS;
   Panel* panel = (Panel*) Vector_get(this->panels, 0);
   int y = panel->y - 1;
   int x = 2;
   
   if (this->name) {
      drawTab(&y, &x, l, this->name, true);
      return;
   }
   
   for (int s = 0; screens[s]; s++) {
      bool ok = drawTab(&y, &x, l, screens[s]->name, s == cur);
      if (!ok) {
         break;
      }
   }
   attrset(CRT_colors[RESET_COLOR]);
}

205
static void ScreenManager_drawPanels(ScreenManager* this, int focus) {
Hisham Muhammad's avatar
Hisham Muhammad committed
206
207
208
   if (this->settings->screenTabs) {
      ScreenManager_drawScreenTabs(this);
   }
209
210
211
212
213
214
215
216
217
218
219
220
   int nPanels = this->panelCount;
   for (int i = 0; i < nPanels; i++) {
      Panel* panel = (Panel*) Vector_get(this->panels, i);
      Panel_draw(panel, i == focus);
      if (i < nPanels) {
         if (this->orientation == HORIZONTAL) {
            mvvline(panel->y, panel->x+panel->w, ' ', panel->h+1);
         }
      }
   }
}

221
222
static Panel* setCurrentPanel(ScreenManager* this, int focus) {
   Panel* panel = (Panel*) Vector_get(this->panels, focus);
223
224
225
226
   FunctionBar_draw(panel->currentBar, NULL);
   return panel;
}

Hisham Muhammad's avatar
Hisham Muhammad committed
227
void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey, char* name) {
Hisham Muhammad's avatar
Hisham Muhammad committed
228
229
   bool quit = false;
   int focus = 0;
230
   
231
   Panel* panelFocus = setCurrentPanel(this, focus);
232

Hisham Muhammad's avatar
Hisham Muhammad committed
233
234
235
236
237
   double oldTime = 0.0;

   int ch = ERR;
   int closeTimeout = 0;

238
239
240
   bool timedOut = true;
   bool redraw = true;
   bool rescan = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
241
242
   int sortTimeout = 0;
   int resetSortTimeout = 5;
Hisham Muhammad's avatar
Hisham Muhammad committed
243
244
   
   this->name = name;
Hisham Muhammad's avatar
Hisham Muhammad committed
245

Hisham Muhammad's avatar
Hisham Muhammad committed
246
   while (!quit) {
247
      if (this->header) {
248
         checkRecalculation(this, &oldTime, &sortTimeout, &redraw, &rescan, &timedOut);
249
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
250
      
251
252
      if (redraw) {
         ScreenManager_drawPanels(this, focus);
Hisham Muhammad's avatar
Hisham Muhammad committed
253
254
      }

Hisham Muhammad's avatar
Hisham Muhammad committed
255
      int prevCh = ch;
256
      ch = Panel_getCh(panelFocus);
257

258
      HandlerResult result = IGNORED;
Hisham Muhammad's avatar
Hisham Muhammad committed
259
      if (ch == KEY_MOUSE) {
260
         ch = ERR;
Hisham Muhammad's avatar
Hisham Muhammad committed
261
262
263
         MEVENT mevent;
         int ok = getmouse(&mevent);
         if (ok == OK) {
264
265
266
267
268
269
270
271
272
273
            if (mevent.bstate & BUTTON1_RELEASED) {
               if (mevent.y == LINES - 1) {
                  ch = FunctionBar_synthesizeEvent(panelFocus->currentBar, mevent.x);
               } else {
                  for (int i = 0; i < this->panelCount; i++) {
                     Panel* panel = (Panel*) Vector_get(this->panels, i);
                     if (mevent.x >= panel->x && mevent.x <= panel->x+panel->w) {
                        if (mevent.y == panel->y) {
                           ch = EVENT_HEADER_CLICK(mevent.x - panel->x);
                           break;
Hisham Muhammad's avatar
Hisham Muhammad committed
274
275
276
                        } else if (this->settings->screenTabs && mevent.y == panel->y - 1) {
                           ch = EVENT_SCREEN_TAB_CLICK(mevent.x);
                           break;
277
                        } else if (mevent.y > panel->y && mevent.y <= panel->y+panel->h) {
278
                           ch = KEY_MOUSE;
279
280
                           if (panel == panelFocus || this->allowFocusChange) {
                              focus = i;
281
                              panelFocus = setCurrentPanel(this, i);
282
                              Object* oldSelection = Panel_getSelected(panel);
283
                              Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1);
284
285
286
                              if (Panel_getSelected(panel) == oldSelection) {
                                 ch = KEY_RECLICK;
                              }
287
288
                           }
                           break;
289
290
                        }
                     }
Hisham Muhammad's avatar
Hisham Muhammad committed
291
292
                  }
               }
293
294
295
296
297
298
            #if NCURSES_MOUSE_VERSION > 1
            } else if (mevent.bstate & BUTTON4_PRESSED) {
               ch = KEY_WHEELUP;
            } else if (mevent.bstate & BUTTON5_PRESSED) {
               ch = KEY_WHEELDOWN;
            #endif
Hisham Muhammad's avatar
Hisham Muhammad committed
299
300
301
            }
         }
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
302
      if (ch == ERR) {
303
         sortTimeout--;
304
         if (prevCh == ch && !timedOut) {
Hisham Muhammad's avatar
Hisham Muhammad committed
305
306
307
308
309
310
            closeTimeout++;
            if (closeTimeout == 100) {
               break;
            }
         } else
            closeTimeout = 0;
311
         redraw = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
312
         continue;
Hisham Muhammad's avatar
Hisham Muhammad committed
313
      }
314
315
316
317
318
      switch (ch) {
         case KEY_ALT('H'): ch = KEY_LEFT; break;
         case KEY_ALT('J'): ch = KEY_DOWN; break;
         case KEY_ALT('K'): ch = KEY_UP; break;
         case KEY_ALT('L'): ch = KEY_RIGHT; break;
319
      }
320
      redraw = true;
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
      if (Panel_eventHandlerFn(panelFocus)) {
         result = Panel_eventHandler(panelFocus, ch);
      }
      if (result & SYNTH_KEY) {
         ch = result >> 16;
      }
      if (result & REDRAW) {
         sortTimeout = 0;
      }
      if (result & RESCAN) {
         rescan = true;
         sortTimeout = 0;
      }
      if (result & HANDLED) {
         continue;
      } else if (result & BREAK_LOOP) {
         quit = true;
         continue;
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
340
341
      
      switch (ch) {
Hisham Muhammad's avatar
Hisham Muhammad committed
342
343
344
345
346
347
      case KEY_RESIZE:
      {
         ScreenManager_resize(this, this->x1, this->y1, this->x2, this->y2);
         continue;
      }
      case KEY_LEFT:
348
349
350
351
      case KEY_CTRL('B'):
         if (this->panelCount < 2) {
            goto defaultHandler;
         }
352
353
         if (!this->allowFocusChange)
            break;
Hisham Muhammad's avatar
Hisham Muhammad committed
354
355
356
         tryLeft:
         if (focus > 0)
            focus--;
357
         panelFocus = setCurrentPanel(this, focus);
Hisham Muhammad's avatar
Hisham Muhammad committed
358
         if (Panel_size(panelFocus) == 0 && focus > 0)
Hisham Muhammad's avatar
Hisham Muhammad committed
359
360
361
            goto tryLeft;
         break;
      case KEY_RIGHT:
362
      case KEY_CTRL('F'):
Hisham Muhammad's avatar
Hisham Muhammad committed
363
      case 9:
364
365
366
         if (this->panelCount < 2) {
            goto defaultHandler;
         }
367
368
         if (!this->allowFocusChange)
            break;
Hisham Muhammad's avatar
Hisham Muhammad committed
369
         tryRight:
370
         if (focus < this->panelCount - 1)
Hisham Muhammad's avatar
Hisham Muhammad committed
371
            focus++;
372
         panelFocus = setCurrentPanel(this, focus);
373
         if (Panel_size(panelFocus) == 0 && focus < this->panelCount - 1)
Hisham Muhammad's avatar
Hisham Muhammad committed
374
375
376
377
378
379
380
381
            goto tryRight;
         break;
      case KEY_F(10):
      case 'q':
      case 27:
         quit = true;
         continue;
      default:
382
         defaultHandler:
383
         sortTimeout = resetSortTimeout;
Hisham Muhammad's avatar
Hisham Muhammad committed
384
         Panel_onKey(panelFocus, ch);
Hisham Muhammad's avatar
Hisham Muhammad committed
385
386
387
388
         break;
      }
   }

Hisham Muhammad's avatar
Hisham Muhammad committed
389
390
391
392
   if (lastFocus)
      *lastFocus = panelFocus;
   if (lastKey)
      *lastKey = ch;
Hisham Muhammad's avatar
Hisham Muhammad committed
393
}