• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // * this is for making emacs happy: -*-Mode: C++;-*-
2 /****************************************************************************
3  * Copyright 2019,2020 Thomas E. Dickey                                     *
4  * Copyright 1998-2012,2014 Free Software Foundation, Inc.                  *
5  *                                                                          *
6  * Permission is hereby granted, free of charge, to any person obtaining a  *
7  * copy of this software and associated documentation files (the            *
8  * "Software"), to deal in the Software without restriction, including      *
9  * without limitation the rights to use, copy, modify, merge, publish,      *
10  * distribute, distribute with modifications, sublicense, and/or sell       *
11  * copies of the Software, and to permit persons to whom the Software is    *
12  * furnished to do so, subject to the following conditions:                 *
13  *                                                                          *
14  * The above copyright notice and this permission notice shall be included  *
15  * in all copies or substantial portions of the Software.                   *
16  *                                                                          *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
20  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
23  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
24  *                                                                          *
25  * Except as contained in this notice, the name(s) of the above copyright   *
26  * holders shall not be used in advertising or otherwise to promote the     *
27  * sale, use or other dealings in this Software without prior written       *
28  * authorization.                                                           *
29  ****************************************************************************/
30 
31 /*
32  * Authors:
33  *	Thomas E. Dickey
34  *	Juergen Pfeifer
35  *
36  * The NCursesWindow class was originally based on a file written by
37  * Eric Newton, later modified by Ulrich Drepper and Anatoly Ivasyuk.
38  * However, aside from the compatible interface definition, no trace
39  * of the original code remains in this version: it consists only of
40  * changes introduced since 1995.
41  */
42 
43 #include "internal.h"
44 #include "cursesw.h"
45 
46 MODULE_ID("$Id: cursesw.cc,v 1.56 2020/02/02 23:34:34 tom Exp $")
47 
48 #define COLORS_NEED_INITIALIZATION  -1
49 #define COLORS_NOT_INITIALIZED       0
50 #define COLORS_MONOCHROME            1
51 #define COLORS_ARE_REALLY_THERE      2
52 
53 #define HaveColors() (colorInitialized == COLORS_ARE_REALLY_THERE)
54 
55 // declare static variables for the class
56 long NCursesWindow::count = 0L;
57 bool NCursesWindow::b_initialized = FALSE;
58 
59 int
scanw(const char * fmt,...)60 NCursesWindow::scanw(const char* fmt, ...)
61 {
62     int result = ERR;
63 
64     va_list args;
65     va_start(args, fmt);
66     result = ::vw_scanw (w, const_cast<NCURSES_CONST char *>(fmt), args);
67     va_end(args);
68 
69     return result;
70 }
71 
72 
73 int
scanw(int y,int x,const char * fmt,...)74 NCursesWindow::scanw(int y, int x, const char* fmt, ...)
75 {
76     int result = ERR;
77 
78     if (::wmove(w, y, x) != ERR) {
79 	va_list args;
80 	va_start(args, fmt);
81 	result = ::vw_scanw (w, const_cast<NCURSES_CONST char *>(fmt), args);
82 	va_end(args);
83     }
84     return result;
85 }
86 
87 
88 int
scanw(const char * fmt,va_list args)89 NCursesWindow::scanw(const char* fmt, va_list args)
90 {
91     int result = ERR;
92 
93     result = ::vw_scanw (w, const_cast<NCURSES_CONST char *>(fmt), args);
94 
95     return result;
96 }
97 
98 
99 int
scanw(int y,int x,const char * fmt,va_list args)100 NCursesWindow::scanw(int y, int x, const char* fmt, va_list args)
101 {
102     int result = ERR;
103 
104     if (::wmove(w, y, x) != ERR) {
105 	result = ::vw_scanw (w, const_cast<NCURSES_CONST char *>(fmt), args);
106     }
107     return result;
108 }
109 
110 
111 int
printw(const char * fmt,...)112 NCursesWindow::printw(const char * fmt, ...)
113 {
114     va_list args;
115     va_start(args, fmt);
116     int result = ::vw_printw(w, fmt, args);
117     va_end(args);
118     return result;
119 }
120 
121 
122 int
printw(int y,int x,const char * fmt,...)123 NCursesWindow::printw(int y, int x, const char * fmt, ...)
124 {
125     va_list args;
126     va_start(args, fmt);
127     int result = ::wmove(w, y, x);
128     if (result == OK) {
129 	result = ::vw_printw(w, fmt, args);
130     }
131     va_end(args);
132     return result;
133 }
134 
135 
136 int
printw(const char * fmt,va_list args)137 NCursesWindow::printw(const char * fmt, va_list args)
138 {
139     int result = ::vw_printw(w, fmt, args);
140     return result;
141 }
142 
143 
144 int
printw(int y,int x,const char * fmt,va_list args)145 NCursesWindow::printw(int y, int x, const char * fmt, va_list args)
146 {
147     int result = ::wmove(w, y, x);
148     if (result == OK) {
149 	result = ::vw_printw(w, fmt, args);
150     }
151     return result;
152 }
153 
154 
155 void
set_keyboard(void)156 NCursesWindow::set_keyboard(void)
157 {
158     keypad(TRUE);
159     meta(TRUE);
160 }
161 
162 void
err_handler(const char * msg) const163 NCursesWindow::err_handler(const char *msg) const THROWS(NCursesException)
164 {
165   THROW(new NCursesException(msg));
166 }
167 
168 void
initialize()169 NCursesWindow::initialize()
170 {
171     if (!b_initialized) {
172 	::initscr();
173 	b_initialized = TRUE;
174 	if (colorInitialized == COLORS_NEED_INITIALIZATION) {
175 	    colorInitialized = COLORS_NOT_INITIALIZED;
176 	    useColors();
177 	}
178 	::noecho();
179 	::cbreak();
180     }
181 }
182 
183 void
constructing()184 NCursesWindow::constructing()
185 {
186     initialize();
187     ++count;
188 }
189 
NCursesWindow()190 NCursesWindow::NCursesWindow()
191   : w(0), alloced(FALSE), par(0), subwins(0), sib(0)
192 {
193     constructing();
194 
195     w = static_cast<WINDOW *>(0);
196 }
197 
NCursesWindow(int nlines,int ncols,int begin_y,int begin_x)198 NCursesWindow::NCursesWindow(int nlines, int ncols, int begin_y, int begin_x)
199   : w(0), alloced(TRUE), par(0), subwins(0), sib(0)
200 {
201     constructing();
202 
203     w = ::newwin(nlines, ncols, begin_y, begin_x);
204     if (w == 0) {
205 	err_handler("Cannot construct window");
206     }
207     set_keyboard();
208 }
209 
NCursesWindow(WINDOW * window)210 NCursesWindow::NCursesWindow(WINDOW* window)
211   : w(0), alloced(FALSE), par(0), subwins(0), sib(0)
212 {
213     constructing();
214 
215     // We used to use a reference on the "window" parameter, but we cannot do
216     // that with an opaque pointer (see NCURSES_OPAQUE).  If the parameter was
217     // "::stdscr", that is first set via the "constructing() call, and is null
218     // up to that point.  So we allow a null pointer here as meaning the "same"
219     // as "::stdscr".
220     w = window ? window : ::stdscr;
221     set_keyboard();
222 }
223 
NCursesWindow(NCursesWindow & win,int ny,int nx,int begin_y,int begin_x,char absrel)224 NCursesWindow::NCursesWindow(NCursesWindow& win, int ny, int nx,
225 			     int begin_y, int begin_x, char absrel)
226   : w(0), alloced(TRUE), par(0), subwins(0), sib(0)
227 {
228     constructing();
229     if (absrel == 'a') {	// absolute origin
230 	begin_y -= win.begy();
231 	begin_x -= win.begx();
232     }
233 
234     // Link this window into its parent's list of subwindows.
235     // We use derwin(), since this also works for pads.
236     w = ::derwin(win.w, ny, nx, begin_y, begin_x);
237     if (w == 0) {
238 	err_handler("Cannot construct subwindow");
239     }
240 
241     par = &win;
242     sib = win.subwins;
243     win.subwins = this;
244 }
245 
NCursesWindow(NCursesWindow & win,bool do_box NCURSES_PARAM_INIT (TRUE))246 NCursesWindow::NCursesWindow(NCursesWindow& win,
247 				bool do_box NCURSES_PARAM_INIT(TRUE))
248   : w(0), alloced(TRUE), par(0), subwins(0), sib(0)
249 {
250     constructing();
251     int myHeight = win.height();
252     int myWidth  = win.width();
253     w = :: derwin(win.w, myHeight - 2, myWidth - 2, 1, 1);
254     if (w == 0) {
255 	err_handler("Cannot construct subwindow");
256     }
257 
258     par = &win;
259     sib = win.subwins;
260     win.subwins = this;
261     subwins = 0;
262 
263     if (do_box) {
264 	win.box();
265 	win.touchwin();
266     }
267 }
268 
Clone()269 NCursesWindow NCursesWindow::Clone()
270 {
271     WINDOW *d = ::dupwin(w);
272     NCursesWindow W(d);
273     W.subwins = subwins;
274     W.sib = sib;
275     W.par = par;
276     W.alloced = alloced;
277     return W;
278 }
279 
280 typedef int (*RIPOFFINIT)(NCursesWindow&);
281 static RIPOFFINIT R_INIT[5];       // There can't be more
282 static int r_init_idx   = 0;
283 static RIPOFFINIT* prip = R_INIT;
284 
NCursesWindow(WINDOW * win,int ncols)285 NCursesWindow::NCursesWindow(WINDOW *win, int ncols)
286   : w(0), alloced(FALSE), par(0), subwins(0), sib(0)
287 {
288     (void) ncols;
289     initialize();
290     w = win;
291 }
292 
_nc_xx_ripoff_init(WINDOW * w,int ncols)293 int _nc_xx_ripoff_init(WINDOW *w, int ncols)
294 {
295     (void) ncols;
296     int res = ERR;
297 
298     RIPOFFINIT init = *prip++;
299     if (init) {
300 	res = init(*(new NCursesWindow(w,ncols)));
301     }
302     return res;
303 }
304 
ripoffline(int ripoff_lines,int (* init)(NCursesWindow & win))305 int NCursesWindow::ripoffline(int ripoff_lines,
306 			      int (*init)(NCursesWindow& win))
307 {
308     int code = ::_nc_ripoffline(ripoff_lines,_nc_xx_ripoff_init);
309     if (code == OK && init && ripoff_lines) {
310 	R_INIT[r_init_idx++] = init;
311     }
312     return code;
313 }
314 
315 bool
isDescendant(NCursesWindow & win)316 NCursesWindow::isDescendant(NCursesWindow& win)
317 {
318     bool result = FALSE;
319 
320     for (NCursesWindow* p = subwins; p != NULL; p = p->sib) {
321 	if (p == &win || p->isDescendant(win)) {
322 	    result = TRUE;
323 	    break;
324 	}
325     }
326     return result;
327 }
328 
329 void
kill_subwindows()330 NCursesWindow::kill_subwindows()
331 {
332     NCursesWindow* p = subwins;
333 
334     subwins = 0;
335     while (p != 0) {
336 	NCursesWindow* q = p->sib;
337 	p->kill_subwindows();
338 	if (p->alloced) {
339 	    if (p->w != 0)
340 		::delwin(p->w);
341 	}
342 	delete p;
343 	p = q;
344     }
345 }
346 
347 
~NCursesWindow()348 NCursesWindow::~NCursesWindow() THROWS(NCursesException)
349 {
350     kill_subwindows();
351 
352     if (par != 0) {
353 	// Remove this window from the parent's list of subwindows.
354 	NCursesWindow * next = par->subwins;
355 	NCursesWindow * prev = 0;
356 	while (next != 0) {
357 	    if (next == this) {
358 		if (prev != 0) {
359 		    prev->sib = next->sib;
360 		} else {
361 		    par->subwins = next->sib;
362 		}
363 		break;
364 	    }
365 	    prev = next;
366 	    next = next->sib;
367 	}
368     }
369 
370     if (alloced && w != 0)
371 	::delwin(w);
372 
373     if (alloced) {
374 	--count;
375 	if (count == 0) {
376 	    ::endwin();
377 	} else if (count < 0) { // cannot happen!
378 	    err_handler("Too many windows destroyed");
379 	}
380     }
381 }
382 
383 // ---------------------------------------------------------------------
384 // Color stuff
385 //
386 int NCursesWindow::colorInitialized = COLORS_NOT_INITIALIZED;
387 
388 void
useColors(void)389 NCursesWindow::useColors(void)
390 {
391     if (colorInitialized == COLORS_NOT_INITIALIZED) {
392 	if (b_initialized) {
393 	    if (::has_colors()) {
394 		::start_color();
395 		colorInitialized = COLORS_ARE_REALLY_THERE;
396 	    } else {
397 		colorInitialized = COLORS_MONOCHROME;
398 	    }
399 	} else {
400 	    colorInitialized = COLORS_NEED_INITIALIZATION;
401 	}
402     }
403 }
404 
405 NCURSES_PAIRS_T
getPair() const406 NCursesWindow::getPair() const
407 {
408     return static_cast<NCURSES_PAIRS_T>(PAIR_NUMBER(getattrs(w)));
409 }
410 
411 NCURSES_COLOR_T
getcolor(int getback) const412 NCursesWindow::getcolor(int getback) const
413 {
414     NCURSES_COLOR_T fore, back;
415 
416     if (HaveColors()) {
417 	if (::pair_content(getPair(), &fore, &back) == ERR)
418 	    err_handler("Can't get color pair");
419     } else {
420 	// Monochrome means white on black
421 	back = COLOR_BLACK;
422 	fore = COLOR_WHITE;
423     }
424     return getback ? back : fore;
425 }
426 
NumberOfColors()427 int NCursesWindow::NumberOfColors()
428 {
429     return (HaveColors()) ? COLORS : 1;
430 }
431 
432 NCURSES_PAIRS_T
getcolor() const433 NCursesWindow::getcolor() const
434 {
435     return (HaveColors()) ? getPair() : 0;
436 }
437 
438 int
setpalette(NCURSES_COLOR_T fore,NCURSES_COLOR_T back,NCURSES_PAIRS_T pair)439 NCursesWindow::setpalette(NCURSES_COLOR_T fore, NCURSES_COLOR_T back, NCURSES_PAIRS_T pair)
440 {
441     return (HaveColors()) ? ::init_pair(pair, fore, back) : OK;
442 }
443 
444 int
setpalette(NCURSES_COLOR_T fore,NCURSES_COLOR_T back)445 NCursesWindow::setpalette(NCURSES_COLOR_T fore, NCURSES_COLOR_T back)
446 {
447     return setpalette(fore, back, getPair());
448 }
449 
450 
451 int
setcolor(NCURSES_PAIRS_T pair)452 NCursesWindow::setcolor(NCURSES_PAIRS_T pair)
453 {
454     if (HaveColors()) {
455 	if ((pair < 1) || (pair > COLOR_PAIRS))
456 	    err_handler("Can't set color pair");
457 
458 	attroff(A_COLOR);
459 	attrset(COLOR_PAIR(pair));
460     }
461     return OK;
462 }
463 
464 #if HAVE_HAS_KEY
has_mouse() const465 bool NCursesWindow::has_mouse() const
466 {
467     return ((::has_key(KEY_MOUSE) || ::has_mouse())
468 	     ? TRUE : FALSE);
469 }
470 #endif
471