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