ScreenManager.c 9.16 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
162
163
164
static Panel* setCurrentPanel(Panel* panel) {
   FunctionBar_draw(panel->currentBar, NULL);
   return panel;
}

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

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

   int ch = ERR;
   int closeTimeout = 0;

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
191
      int prevCh = ch;
Hisham Muhammad's avatar
Hisham Muhammad committed
192
      ch = getch();
193

194
      HandlerResult result = IGNORED;
Hisham Muhammad's avatar
Hisham Muhammad committed
195
      if (ch == KEY_MOUSE) {
196
         ch = ERR;
Hisham Muhammad's avatar
Hisham Muhammad committed
197
198
199
         MEVENT mevent;
         int ok = getmouse(&mevent);
         if (ok == OK) {
200
201
202
203
204
205
206
207
208
209
210
            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) {
211
                           ch = KEY_MOUSE;
212
213
214
                           if (panel == panelFocus || this->allowFocusChange) {
                              focus = i;
                              panelFocus = setCurrentPanel(panel);
215
                              Object* oldSelection = Panel_getSelected(panel);
216
                              Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1);
217
218
219
                              if (Panel_getSelected(panel) == oldSelection) {
                                 ch = KEY_RECLICK;
                              }
220
221
                           }
                           break;
222
223
                        }
                     }
Hisham Muhammad's avatar
Hisham Muhammad committed
224
225
                  }
               }
226
227
228
229
230
231
            #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
232
233
234
            }
         }
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
235
      if (ch == ERR) {
236
         sortTimeout--;
237
         if (prevCh == ch && !timedOut) {
Hisham Muhammad's avatar
Hisham Muhammad committed
238
239
240
241
242
243
            closeTimeout++;
            if (closeTimeout == 100) {
               break;
            }
         } else
            closeTimeout = 0;
244
         redraw = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
245
         continue;
Hisham Muhammad's avatar
Hisham Muhammad committed
246
      }
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
      else if (ch == 27) {
         int ch2 = getch();
         if (ch2 != ERR) {
            switch(ch2)
            {
            case 'h':
               ch = KEY_LEFT;
               break;
            case 'j':
               ch = KEY_DOWN;
               break;
            case 'k':
               ch = KEY_UP;
               break;
            case 'l':
               ch = KEY_RIGHT;
               break;
            default:
               ungetch(ch2);
               break;
            }
         }
      }
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
      case KEY_CTRLB:
299
300
         if (!this->allowFocusChange)
            break;
Hisham Muhammad's avatar
Hisham Muhammad committed
301
302
303
         tryLeft:
         if (focus > 0)
            focus--;
304
         panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus));
Hisham Muhammad's avatar
Hisham Muhammad committed
305
         if (Panel_size(panelFocus) == 0 && focus > 0)
Hisham Muhammad's avatar
Hisham Muhammad committed
306
307
308
            goto tryLeft;
         break;
      case KEY_RIGHT:
309
      case KEY_CTRLF:
Hisham Muhammad's avatar
Hisham Muhammad committed
310
      case 9:
311
312
         if (!this->allowFocusChange)
            break;
Hisham Muhammad's avatar
Hisham Muhammad committed
313
         tryRight:
314
         if (focus < this->panelCount - 1)
Hisham Muhammad's avatar
Hisham Muhammad committed
315
            focus++;
316
         panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus));
317
         if (Panel_size(panelFocus) == 0 && focus < this->panelCount - 1)
Hisham Muhammad's avatar
Hisham Muhammad committed
318
319
320
321
322
323
324
325
            goto tryRight;
         break;
      case KEY_F(10):
      case 'q':
      case 27:
         quit = true;
         continue;
      default:
326
         sortTimeout = resetSortTimeout;
Hisham Muhammad's avatar
Hisham Muhammad committed
327
         Panel_onKey(panelFocus, ch);
Hisham Muhammad's avatar
Hisham Muhammad committed
328
329
330
331
         break;
      }
   }

Hisham Muhammad's avatar
Hisham Muhammad committed
332
333
334
335
   if (lastFocus)
      *lastFocus = panelFocus;
   if (lastKey)
      *lastKey = ch;
Hisham Muhammad's avatar
Hisham Muhammad committed
336
}