ScreenManager.c 7.82 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"
Hisham Muhammad's avatar
Hisham Muhammad committed
12

Hisham Muhammad's avatar
Hisham Muhammad committed
13
#include <assert.h>
14
#include <time.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
15
#include <stdlib.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
16
17
18
#include <stdbool.h>

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

typedef enum Orientation_ {
   VERTICAL,
   HORIZONTAL
} Orientation;

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

}*/

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

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

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

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

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

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

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

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

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

   int ch = ERR;
   int closeTimeout = 0;

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

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
193
194
195
196
197
      if (ch == KEY_MOUSE) {
         MEVENT mevent;
         int ok = getmouse(&mevent);
         if (ok == OK) {
            if (mevent.y == LINES - 1) {
198
               ch = FunctionBar_synthesizeEvent(panelFocus->currentBar, mevent.x);
Hisham Muhammad's avatar
Hisham Muhammad committed
199
            } else {
200
201
               for (int i = 0; i < this->panelCount; i++) {
                  Panel* panel = (Panel*) Vector_get(this->panels, i);
Hisham Muhammad's avatar
Hisham Muhammad committed
202
                  if (mevent.x > panel->x && mevent.x <= panel->x+panel->w &&
203
204
                     mevent.y > panel->y && mevent.y <= panel->y+panel->h &&
                     (this->allowFocusChange || panelFocus == panel) ) {
Hisham Muhammad's avatar
Hisham Muhammad committed
205
                     focus = i;
206
                     panelFocus = setCurrentPanel(panel);
Hisham Muhammad's avatar
Hisham Muhammad committed
207
                     Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1);
Hisham Muhammad's avatar
Hisham Muhammad committed
208
209
210
211
212
213
                     break;
                  }
               }
            }
         }
      }
214
215
      if (Panel_eventHandlerFn(panelFocus)) {
         HandlerResult result = Panel_eventHandler(panelFocus, ch);
216
217
218
         if (result & SYNTH_KEY) {
            ch = result >> 16;
         }
219
220
         if (result & REDRAW) {
            //redraw = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
221
222
            sortTimeout = 0;
         }
223
224
         if (result & RESCAN) {
            rescan = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
225
226
227
            sortTimeout = 0;
         }
         if (result & HANDLED) {
228
            redraw = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
229
            continue;
Hisham Muhammad's avatar
Hisham Muhammad committed
230
         } else if (result & BREAK_LOOP) {
Hisham Muhammad's avatar
Hisham Muhammad committed
231
232
233
234
            quit = true;
            continue;
         }
      }
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
      redraw = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
248
249
      
      switch (ch) {
Hisham Muhammad's avatar
Hisham Muhammad committed
250
251
252
253
254
255
      case KEY_RESIZE:
      {
         ScreenManager_resize(this, this->x1, this->y1, this->x2, this->y2);
         continue;
      }
      case KEY_LEFT:
256
      case KEY_CTRLB:
257
258
         if (!this->allowFocusChange)
            break;
Hisham Muhammad's avatar
Hisham Muhammad committed
259
260
261
         tryLeft:
         if (focus > 0)
            focus--;
262
         panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus));
Hisham Muhammad's avatar
Hisham Muhammad committed
263
         if (Panel_size(panelFocus) == 0 && focus > 0)
Hisham Muhammad's avatar
Hisham Muhammad committed
264
265
266
            goto tryLeft;
         break;
      case KEY_RIGHT:
267
      case KEY_CTRLF:
Hisham Muhammad's avatar
Hisham Muhammad committed
268
      case 9:
269
270
         if (!this->allowFocusChange)
            break;
Hisham Muhammad's avatar
Hisham Muhammad committed
271
         tryRight:
272
         if (focus < this->panelCount - 1)
Hisham Muhammad's avatar
Hisham Muhammad committed
273
            focus++;
274
         panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus));
275
         if (Panel_size(panelFocus) == 0 && focus < this->panelCount - 1)
Hisham Muhammad's avatar
Hisham Muhammad committed
276
277
278
279
280
281
282
283
            goto tryRight;
         break;
      case KEY_F(10):
      case 'q':
      case 27:
         quit = true;
         continue;
      default:
284
         sortTimeout = resetSortTimeout;
Hisham Muhammad's avatar
Hisham Muhammad committed
285
         Panel_onKey(panelFocus, ch);
Hisham Muhammad's avatar
Hisham Muhammad committed
286
287
288
289
         break;
      }
   }

Hisham Muhammad's avatar
Hisham Muhammad committed
290
291
292
293
   if (lastFocus)
      *lastFocus = panelFocus;
   if (lastKey)
      *lastKey = ch;
Hisham Muhammad's avatar
Hisham Muhammad committed
294
}