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

Hisham Muhammad's avatar
Hisham Muhammad committed
94
Panel* ScreenManager_remove(ScreenManager* this, int idx) {
95
96
97
   assert(this->panelCount > idx);
   Panel* panel = (Panel*) Vector_remove(this->panels, idx);
   this->panelCount--;
Hisham Muhammad's avatar
Hisham Muhammad committed
98
   return panel;
Hisham Muhammad's avatar
Hisham Muhammad committed
99
100
101
102
103
104
105
}

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;
106
   int panels = this->panelCount;
107
108
109
110
111
112
113
114
115
116
   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
117
      Panel_move(panel, lastX, y1);
Hisham Muhammad's avatar
Hisham Muhammad committed
118
   }
119
   // TODO: VERTICAL
Hisham Muhammad's avatar
Hisham Muhammad committed
120
121
}

122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
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);
      if (*sortTimeout == 0 || this->settings->treeView) {
         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);
         }
      }
   }
}

160
161
static Panel* setCurrentPanel(ScreenManager* this, int focus) {
   Panel* panel = (Panel*) Vector_get(this->panels, focus);
162
163
164
165
   FunctionBar_draw(panel->currentBar, NULL);
   return panel;
}

166
void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
Hisham Muhammad's avatar
Hisham Muhammad committed
167
168
   bool quit = false;
   int focus = 0;
169
   
170
   Panel* panelFocus = setCurrentPanel(this, focus);
171

Hisham Muhammad's avatar
Hisham Muhammad committed
172
173
174
175
176
   double oldTime = 0.0;

   int ch = ERR;
   int closeTimeout = 0;

177
178
179
   bool timedOut = true;
   bool redraw = true;
   bool rescan = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
180
181
182
   int sortTimeout = 0;
   int resetSortTimeout = 5;

Hisham Muhammad's avatar
Hisham Muhammad committed
183
   while (!quit) {
184
      if (this->header) {
185
         checkRecalculation(this, &oldTime, &sortTimeout, &redraw, &rescan, &timedOut);
186
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
187
      
188
189
      if (redraw) {
         ScreenManager_drawPanels(this, focus);
Hisham Muhammad's avatar
Hisham Muhammad committed
190
191
      }

Hisham Muhammad's avatar
Hisham Muhammad committed
192
      int prevCh = ch;
193
      ch = Panel_getCh(panelFocus);
194

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

Hisham Muhammad's avatar
Hisham Muhammad committed
323
324
325
326
   if (lastFocus)
      *lastFocus = panelFocus;
   if (lastKey)
      *lastKey = ch;
Hisham Muhammad's avatar
Hisham Muhammad committed
327
}