ScreenManager.c 9.64 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 <stdlib.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
17
18
19
#include <stdbool.h>

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

typedef enum Orientation_ {
   VERTICAL,
   HORIZONTAL
} Orientation;

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

}*/

Hisham Muhammad's avatar
Hisham Muhammad committed
47
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
48
   ScreenManager* this;
Hisham's avatar
Hisham committed
49
   this = xMalloc(sizeof(ScreenManager));
Hisham Muhammad's avatar
Hisham Muhammad committed
50
51
52
53
54
   this->x1 = x1;
   this->y1 = y1;
   this->x2 = x2;
   this->y2 = y2;
   this->orientation = orientation;
55
   this->panels = Vector_new(Class(Panel), owner, DEFAULT_SIZE);
56
   this->panelCount = 0;
57
   this->header = header;
Hisham Muhammad's avatar
Hisham Muhammad committed
58
   this->settings = settings;
Hisham Muhammad's avatar
Hisham Muhammad committed
59
   this->owner = owner;
60
   this->allowFocusChange = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
61
62
63
64
   return this;
}

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

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

73
void ScreenManager_add(ScreenManager* this, Panel* item, int size) {
74
75
76
77
   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
78
79
   if (this->orientation == HORIZONTAL) {
      int lastX = 0;
80
81
      if (idx > 0) {
         Panel* last = (Panel*) Vector_get(this->panels, idx - 1);
Hisham Muhammad's avatar
Hisham Muhammad committed
82
83
         lastX = last->x + last->w + 1;
      }
84
      int height = LINES - this->y1 + this->y2;
85
86
      if (size <= 0) {
         size = COLS-this->x1+this->x2-lastX;
Hisham Muhammad's avatar
Hisham Muhammad committed
87
      }
88
      Panel_resize(item, size, height);
89
      Panel_move(item, lastX, this->y1);
90
91
92
93
94
95
      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
96
97
   }
   // TODO: VERTICAL
98
   Vector_insert(this->panels, idx, item);
Hisham Muhammad's avatar
Hisham Muhammad committed
99
   item->needsRedraw = true;
100
   this->panelCount++;
Hisham Muhammad's avatar
Hisham Muhammad committed
101
102
}

Hisham Muhammad's avatar
Hisham Muhammad committed
103
Panel* ScreenManager_remove(ScreenManager* this, int idx) {
104
   assert(this->panelCount > idx);
105
   int w = ((Panel*) Vector_get(this->panels, idx))->w;
106
107
   Panel* panel = (Panel*) Vector_remove(this->panels, idx);
   this->panelCount--;
108
109
110
111
112
113
   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
114
   return panel;
Hisham Muhammad's avatar
Hisham Muhammad committed
115
116
117
118
119
120
121
}

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;
122
   int panels = this->panelCount;
123
124
125
126
127
128
129
130
131
132
   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
133
      Panel_move(panel, lastX, y1);
Hisham Muhammad's avatar
Hisham Muhammad committed
134
   }
135
   // TODO: VERTICAL
Hisham Muhammad's avatar
Hisham Muhammad committed
136
137
}

138
139
140
141
142
143
144
145
146
147
148
149
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);
150
      if (*sortTimeout == 0 || this->settings->ss->treeView) {
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
         ProcessList_sort(pl);
         *sortTimeout = 1;
      }
      *redraw = true;
   }
   if (*redraw) {
      ProcessList_rebuildPanel(pl);
      Header_draw(this->header);
   }
   *rescan = false;
}

static void ScreenManager_drawPanels(ScreenManager* this, int focus) {
   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);
         }
      }
   }
}

176
177
static Panel* setCurrentPanel(ScreenManager* this, int focus) {
   Panel* panel = (Panel*) Vector_get(this->panels, focus);
178
179
180
181
   FunctionBar_draw(panel->currentBar, NULL);
   return panel;
}

182
void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
Hisham Muhammad's avatar
Hisham Muhammad committed
183
184
   bool quit = false;
   int focus = 0;
185
   
186
   Panel* panelFocus = setCurrentPanel(this, focus);
187

Hisham Muhammad's avatar
Hisham Muhammad committed
188
189
190
191
192
   double oldTime = 0.0;

   int ch = ERR;
   int closeTimeout = 0;

193
194
195
   bool timedOut = true;
   bool redraw = true;
   bool rescan = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
196
197
198
   int sortTimeout = 0;
   int resetSortTimeout = 5;

Hisham Muhammad's avatar
Hisham Muhammad committed
199
   while (!quit) {
200
      if (this->header) {
201
         checkRecalculation(this, &oldTime, &sortTimeout, &redraw, &rescan, &timedOut);
202
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
203
      
204
205
      if (redraw) {
         ScreenManager_drawPanels(this, focus);
Hisham Muhammad's avatar
Hisham Muhammad committed
206
207
      }

Hisham Muhammad's avatar
Hisham Muhammad committed
208
      int prevCh = ch;
209
      ch = Panel_getCh(panelFocus);
210

211
      HandlerResult result = IGNORED;
Hisham Muhammad's avatar
Hisham Muhammad committed
212
      if (ch == KEY_MOUSE) {
213
         ch = ERR;
Hisham Muhammad's avatar
Hisham Muhammad committed
214
215
216
         MEVENT mevent;
         int ok = getmouse(&mevent);
         if (ok == OK) {
217
218
219
220
221
222
223
224
225
226
227
            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;
                        } else if (mevent.y > panel->y && mevent.y <= panel->y+panel->h) {
228
                           ch = KEY_MOUSE;
229
230
                           if (panel == panelFocus || this->allowFocusChange) {
                              focus = i;
231
                              panelFocus = setCurrentPanel(this, i);
232
                              Object* oldSelection = Panel_getSelected(panel);
233
                              Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1);
234
235
236
                              if (Panel_getSelected(panel) == oldSelection) {
                                 ch = KEY_RECLICK;
                              }
237
238
                           }
                           break;
239
240
                        }
                     }
Hisham Muhammad's avatar
Hisham Muhammad committed
241
242
                  }
               }
243
244
245
246
247
248
            #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
249
250
251
            }
         }
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
252
      if (ch == ERR) {
253
         sortTimeout--;
254
         if (prevCh == ch && !timedOut) {
Hisham Muhammad's avatar
Hisham Muhammad committed
255
256
257
258
259
260
            closeTimeout++;
            if (closeTimeout == 100) {
               break;
            }
         } else
            closeTimeout = 0;
261
         redraw = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
262
         continue;
Hisham Muhammad's avatar
Hisham Muhammad committed
263
      }
264
265
266
267
268
      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;
269
      }
270
      redraw = true;
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
      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
290
291
      
      switch (ch) {
Hisham Muhammad's avatar
Hisham Muhammad committed
292
293
294
295
296
297
      case KEY_RESIZE:
      {
         ScreenManager_resize(this, this->x1, this->y1, this->x2, this->y2);
         continue;
      }
      case KEY_LEFT:
298
299
300
301
      case KEY_CTRL('B'):
         if (this->panelCount < 2) {
            goto defaultHandler;
         }
302
303
         if (!this->allowFocusChange)
            break;
Hisham Muhammad's avatar
Hisham Muhammad committed
304
305
306
         tryLeft:
         if (focus > 0)
            focus--;
307
         panelFocus = setCurrentPanel(this, focus);
Hisham Muhammad's avatar
Hisham Muhammad committed
308
         if (Panel_size(panelFocus) == 0 && focus > 0)
Hisham Muhammad's avatar
Hisham Muhammad committed
309
310
311
            goto tryLeft;
         break;
      case KEY_RIGHT:
312
      case KEY_CTRL('F'):
Hisham Muhammad's avatar
Hisham Muhammad committed
313
      case 9:
314
315
316
         if (this->panelCount < 2) {
            goto defaultHandler;
         }
317
318
         if (!this->allowFocusChange)
            break;
Hisham Muhammad's avatar
Hisham Muhammad committed
319
         tryRight:
320
         if (focus < this->panelCount - 1)
Hisham Muhammad's avatar
Hisham Muhammad committed
321
            focus++;
322
         panelFocus = setCurrentPanel(this, focus);
323
         if (Panel_size(panelFocus) == 0 && focus < this->panelCount - 1)
Hisham Muhammad's avatar
Hisham Muhammad committed
324
325
326
327
328
329
330
331
            goto tryRight;
         break;
      case KEY_F(10):
      case 'q':
      case 27:
         quit = true;
         continue;
      default:
332
         defaultHandler:
333
         sortTimeout = resetSortTimeout;
Hisham Muhammad's avatar
Hisham Muhammad committed
334
         Panel_onKey(panelFocus, ch);
Hisham Muhammad's avatar
Hisham Muhammad committed
335
336
337
338
         break;
      }
   }

Hisham Muhammad's avatar
Hisham Muhammad committed
339
340
341
342
   if (lastFocus)
      *lastFocus = panelFocus;
   if (lastKey)
      *lastKey = ch;
Hisham Muhammad's avatar
Hisham Muhammad committed
343
}