1 /* s_curses.c --
2
3 This file is part of the lzop file compressor.
4
5 Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer
6 All Rights Reserved.
7
8 lzop and the LZO library are free software; you can redistribute them
9 and/or modify them under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of
11 the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; see the file COPYING.
20 If not, write to the Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22
23 Markus F.X.J. Oberhumer
24 <markus@oberhumer.com>
25 http://www.oberhumer.com/opensource/lzop/
26 */
27
28
29 #include "conf.h"
30
31 #if defined(USE_SCREEN) && defined(USE_SCREEN_CURSES)
32
33 #include "screen.h"
34
35 #define this local_this
36
37 #define mask_fg 0x0f
38 #define mask_bg 0xf0
39
40
41 /*************************************************************************
42 // direct screen access
43 **************************************************************************/
44
45 #include <termios.h>
46 #include <ncurses.h>
47 #undef refresh
48 #undef clear
49
50
51 struct screen_data_t
52 {
53 WINDOW *w;
54 int mode;
55 int page;
56 int cols;
57 int rows;
58 int cursor_x;
59 int cursor_y;
60 unsigned char attr;
61 unsigned char init_attr;
62 chtype empty_cell;
63 };
64
65
66
s_refresh(screen_t * this)67 static void s_refresh(screen_t *this)
68 {
69 wrefresh(this->data->w);
70 }
71
72
73 static __inline__
make_cell(screen_t * this,int ch,int attr)74 chtype make_cell(screen_t *this, int ch, int attr)
75 {
76 int fg = attr & mask_fg;
77 chtype c = ch & 0xff;
78 if (fg < 8)
79 c |= COLOR_PAIR((fg + 0));
80 else
81 c |= COLOR_PAIR(((fg & 7) + 0)) | A_BOLD;
82 return c;
83 }
84
85
getMode(const screen_t * this)86 static int getMode(const screen_t *this)
87 {
88 return this->data->mode;
89 }
90
91
getPage(const screen_t * this)92 static int getPage(const screen_t *this)
93 {
94 return this->data->page;
95 }
96
97
getRows(const screen_t * this)98 static int getRows(const screen_t *this)
99 {
100 return this->data->rows;
101 }
102
103
getCols(const screen_t * this)104 static int getCols(const screen_t *this)
105 {
106 return this->data->cols;
107 }
108
109
getFg(const screen_t * this)110 static int getFg(const screen_t *this)
111 {
112 return this->data->attr & mask_fg;
113 }
114
115
getBg(const screen_t * this)116 static int getBg(const screen_t *this)
117 {
118 return this->data->attr & mask_bg;
119 }
120
121
setFg(screen_t * this,int fg)122 static void setFg(screen_t *this, int fg)
123 {
124 this->data->attr = (this->data->attr & mask_bg) | (fg & mask_fg);
125 }
126
127
setBg(screen_t * this,int bg)128 static void setBg(screen_t *this, int bg)
129 {
130 this->data->attr = (this->data->attr & mask_fg) | (bg & mask_bg);
131 }
132
133
134 /* private */
gotoxy(screen_t * this,int x,int y)135 static __inline__ int gotoxy(screen_t *this, int x, int y)
136 {
137 if (wmove(this->data->w, this->data->w->_begy+y,
138 this->data->w->_begx+x) != ERR)
139 return 0;
140 return -1;
141 }
142
143
setCursor(screen_t * this,int x,int y)144 static void setCursor(screen_t *this, int x, int y)
145 {
146 if (gotoxy(this,x,y) == 0)
147 {
148 this->data->cursor_x = x;
149 this->data->cursor_y = y;
150 }
151 }
152
153
getCursor(const screen_t * this,int * x,int * y)154 static void getCursor(const screen_t *this, int *x, int *y)
155 {
156 if (x)
157 *x = this->data->cursor_x;
158 if (y)
159 *y = this->data->cursor_y;
160 }
161
162
putCharAttr(screen_t * this,int ch,int attr,int x,int y)163 static void putCharAttr(screen_t *this, int ch, int attr, int x, int y)
164 {
165 if (gotoxy(this,x,y) == 0)
166 waddch(this->data->w,make_cell(this,ch,attr));
167 }
168
169
putChar(screen_t * this,int ch,int x,int y)170 static void putChar(screen_t *this, int ch, int x, int y)
171 {
172 putCharAttr(this,ch,this->data->attr,x,y);
173 }
174
175
putStringAttr(screen_t * this,const char * s,int attr,int x,int y)176 static void putStringAttr(screen_t *this, const char *s, int attr, int x, int y)
177 {
178 while (*s)
179 putCharAttr(this,*s++,attr,x++,y);
180 }
181
182
putString(screen_t * this,const char * s,int x,int y)183 static void putString(screen_t *this, const char *s, int x, int y)
184 {
185 putStringAttr(this,s,this->data->attr,x,y);
186 }
187
188
init(screen_t * this,int fd)189 static int init(screen_t *this, int fd)
190 {
191 int fg, bg;
192
193 if (!this || !this->data)
194 return -1;
195
196 this->data->mode = -1;
197 this->data->page = 0;
198
199 if (fd < 0 || !acc_isatty(fd))
200 return -1;
201
202 this->data->w = initscr();
203 if (!this->data->w)
204 return -1;
205 (void) noecho();
206
207 this->data->cols = this->data->w->_maxx - this->data->w->_begx + 1;
208 this->data->rows = this->data->w->_maxy - this->data->w->_begy + 1;
209 this->data->cursor_x = this->data->w->_curx;
210 this->data->cursor_y = this->data->w->_cury;
211
212 this->data->empty_cell = ' ';
213
214 if (has_colors())
215 start_color();
216 fg = (this->data->w->_attrs);
217 bg = (this->data->w->_bkgd);
218 fg = PAIR_NUMBER(this->data->w->_attrs);
219 bg = PAIR_NUMBER(this->data->w->_bkgd);
220 if (has_colors() && COLORS >= 8 && COLOR_PAIRS >= 8)
221 this->data->mode = 3;
222 else
223 this->data->mode = 7;
224
225 if (this->data->mode == 3)
226 {
227 int i = 0;
228 init_pair(i++, COLOR_BLACK, bg);
229 init_pair(i++, COLOR_BLUE, bg);
230 init_pair(i++, COLOR_GREEN, bg);
231 init_pair(i++, COLOR_CYAN, bg);
232 init_pair(i++, COLOR_RED, bg);
233 init_pair(i++, COLOR_MAGENTA, bg);
234 init_pair(i++, COLOR_YELLOW, bg);
235 init_pair(i++, COLOR_WHITE, bg);
236 }
237
238 this->data->attr = (bg << 4) | fg;
239 this->data->attr = 0x07;
240
241 return 0;
242 }
243
244
finalize(screen_t * this)245 static void finalize(screen_t *this)
246 {
247 #if 0
248 if (this->data->w)
249 (void) endwin();
250 #endif
251 UNUSED(this);
252 }
253
254
updateLineN(screen_t * this,const void * line,int y,int len)255 static void updateLineN(screen_t *this, const void *line, int y, int len)
256 {
257 if (len > 0 && len <= 2*this->data->cols)
258 {
259 int x;
260 const unsigned char *l = line;
261
262 for (x = 0; x < len / 2; x++, l += 2)
263 {
264 #if 1
265 if ((l[1] & mask_bg) != BG_BLACK)
266 putCharAttr(this,'#',l[1] >> 4,x,y);
267 else
268 putCharAttr(this,l[0],l[1],x,y);
269 #else
270 putCharAttr(this,l[0],l[1],x,y);
271 #endif
272 }
273 }
274 }
275
276
clearLine(screen_t * this,int y)277 static void clearLine(screen_t *this, int y)
278 {
279 int x;
280
281 for (x = 0; x < this->data->cols; x++)
282 if (gotoxy(this,x,y) == 0)
283 waddch(this->data->w,this->data->empty_cell);
284 }
285
286
s_clear(screen_t * this)287 static void s_clear(screen_t *this)
288 {
289 int y;
290
291 for (y = 0; y < this->data->rows; y++)
292 clearLine(this,y);
293 }
294
295
scrollUp(screen_t * this,int lines)296 static int scrollUp(screen_t *this, int lines)
297 {
298 if (lines <= 0)
299 return 0;
300 if (lines >= this->data->rows)
301 s_clear(this);
302 else
303 wscrl(this->data->w,lines);
304 return lines;
305 }
306
307
getCursorShape(const screen_t * this)308 static int getCursorShape(const screen_t *this)
309 {
310 UNUSED(this);
311 return 0;
312 }
313
314
setCursorShape(screen_t * this,int shape)315 static void setCursorShape(screen_t *this, int shape)
316 {
317 UNUSED(this);
318 UNUSED(shape);
319 }
320
321
kbhit(screen_t * this)322 static int kbhit(screen_t *this)
323 {
324 const int fd = STDIN_FILENO;
325 const unsigned long usec = 0;
326 struct timeval tv;
327 fd_set fds;
328
329 UNUSED(this);
330 FD_ZERO(&fds);
331 FD_SET(fd, &fds);
332 tv.tv_sec = usec / 1000000;
333 tv.tv_usec = usec % 1000000;
334 return (select(fd + 1, &fds, NULL, NULL, &tv) > 0);
335 }
336
337
intro(screen_t * this,void (* show_frames)(screen_t *))338 static int intro(screen_t *this, void (*show_frames)(screen_t *) )
339 {
340 int shape;
341 struct termios term_old, term_new;
342 int term_r;
343
344 term_r = tcgetattr(STDIN_FILENO, &term_old);
345 if (term_r == 0)
346 {
347 term_new = term_old;
348 term_new.c_lflag &= ~(ISIG | ICANON | ECHO);
349 tcsetattr(STDIN_FILENO, TCSANOW, &term_new);
350 }
351
352 shape = getCursorShape(this);
353 setCursorShape(this,0x2000);
354 show_frames(this);
355 if (this->data->rows > 24)
356 setCursor(this,this->data->cursor_x,this->data->cursor_y+1);
357 setCursorShape(this,shape);
358 s_refresh(this);
359
360 if (term_r == 0)
361 tcsetattr(STDIN_FILENO, TCSANOW, &term_old);
362
363 return 1;
364 }
365
366
367 static const screen_t driver =
368 {
369 sobject_destroy,
370 finalize,
371 init,
372 s_refresh,
373 getMode,
374 getPage,
375 getRows,
376 getCols,
377 getFg,
378 getBg,
379 getCursor,
380 getCursorShape,
381 setFg,
382 setBg,
383 setCursor,
384 setCursorShape,
385 putChar,
386 putCharAttr,
387 putString,
388 putStringAttr,
389 s_clear,
390 clearLine,
391 updateLineN,
392 scrollUp,
393 kbhit,
394 intro,
395 (struct screen_data_t *) 0
396 };
397
398
399 /* public constructor */
screen_curses_construct(void)400 screen_t *screen_curses_construct(void)
401 {
402 return sobject_construct(&driver,sizeof(*driver.data));
403 }
404
405
406 #endif /* defined(USE_SCREEN) && defined(USE_SCREEN_CURSES) */
407
408
409 /* vim:set ts=4 sw=4 et: */
410