ScreenManager.c 8.89 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;
192
      ESCDELAY = 25;
Hisham Muhammad's avatar
Hisham Muhammad committed
193
      ch = getch();
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
215
                           if (panel == panelFocus || this->allowFocusChange) {
                              focus = i;
                              panelFocus = setCurrentPanel(panel);
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
      case KEY_CTRLB:
283
284
         if (!this->allowFocusChange)
            break;
Hisham Muhammad's avatar
Hisham Muhammad committed
285
286
287
         tryLeft:
         if (focus > 0)
            focus--;
288
         panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus));
Hisham Muhammad's avatar
Hisham Muhammad committed
289
         if (Panel_size(panelFocus) == 0 && focus > 0)
Hisham Muhammad's avatar
Hisham Muhammad committed
290
291
292
            goto tryLeft;
         break;
      case KEY_RIGHT:
293
      case KEY_CTRLF:
Hisham Muhammad's avatar
Hisham Muhammad committed
294
      case 9:
295
296
         if (!this->allowFocusChange)
            break;
Hisham Muhammad's avatar
Hisham Muhammad committed
297
         tryRight:
298
         if (focus < this->panelCount - 1)
Hisham Muhammad's avatar
Hisham Muhammad committed
299
            focus++;
300
         panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus));
301
         if (Panel_size(panelFocus) == 0 && focus < this->panelCount - 1)
Hisham Muhammad's avatar
Hisham Muhammad committed
302
303
304
305
306
307
308
309
            goto tryRight;
         break;
      case KEY_F(10):
      case 'q':
      case 27:
         quit = true;
         continue;
      default:
310
         sortTimeout = resetSortTimeout;
Hisham Muhammad's avatar
Hisham Muhammad committed
311
         Panel_onKey(panelFocus, ch);
Hisham Muhammad's avatar
Hisham Muhammad committed
312
313
314
315
         break;
      }
   }

Hisham Muhammad's avatar
Hisham Muhammad committed
316
317
318
319
   if (lastFocus)
      *lastFocus = panelFocus;
   if (lastKey)
      *lastKey = ch;
Hisham Muhammad's avatar
Hisham Muhammad committed
320
}