ScreenManager.c 9.05 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
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) {
Alan Barr's avatar
Alan Barr committed
148
   const int nPanels = this->panelCount;
149
150
151
   for (int i = 0; i < nPanels; i++) {
      Panel* panel = (Panel*) Vector_get(this->panels, i);
      Panel_draw(panel, i == focus);
Alan Barr's avatar
Alan Barr committed
152
153
      if (this->orientation == HORIZONTAL) {
         mvvline(panel->y, panel->x+panel->w, ' ', panel->h+1);
154
155
156
157
      }
   }
}

158
159
160
161
162
static Panel* setCurrentPanel(Panel* panel) {
   FunctionBar_draw(panel->currentBar, NULL);
   return panel;
}

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

Hisham Muhammad's avatar
Hisham Muhammad committed
169
170
171
172
173
   double oldTime = 0.0;

   int ch = ERR;
   int closeTimeout = 0;

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
189
      int prevCh = ch;
190
      set_escdelay(25);
Hisham Muhammad's avatar
Hisham Muhammad committed
191
      ch = getch();
192

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

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