ncurses 6.1 - patch 20180127
[ncurses.git] / c++ / cursesw.cc
index d1354425666537994e5fb9343a86d983f4361f4b..16438770d47aaf178a92b0d52ddbb956efb7d407 100644 (file)
 // * this is for making emacs happy: -*-Mode: C++;-*-
+/****************************************************************************
+ * Copyright (c) 2007-2012,2014 Free Software Foundation, Inc.              *
+ *                                                                          *
+ * Permission is hereby granted, free of charge, to any person obtaining a  *
+ * copy of this software and associated documentation files (the            *
+ * "Software"), to deal in the Software without restriction, including      *
+ * without limitation the rights to use, copy, modify, merge, publish,      *
+ * distribute, distribute with modifications, sublicense, and/or sell       *
+ * copies of the Software, and to permit persons to whom the Software is    *
+ * furnished to do so, subject to the following conditions:                 *
+ *                                                                          *
+ * The above copyright notice and this permission notice shall be included  *
+ * in all copies or substantial portions of the Software.                   *
+ *                                                                          *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
+ *                                                                          *
+ * Except as contained in this notice, the name(s) of the above copyright   *
+ * holders shall not be used in advertising or otherwise to promote the     *
+ * sale, use or other dealings in this Software without prior written       *
+ * authorization.                                                           *
+ ****************************************************************************/
 
 /*
-  Copyright (C) 1989 Free Software Foundation
-  written by Eric Newton (newton@rocky.oswego.edu)
-
-  This file is part of the GNU C++ Library.  This library is free
-  software; you can redistribute it and/or modify it under the terms of
-  the GNU Library General Public License as published by the Free
-  Software Foundation; either version 2 of the License, or (at your
-  option) any later version.  This library is distributed in the hope
-  that it will be useful, but WITHOUT ANY WARRANTY; without even the
-  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the GNU Library General Public License for more details.
-  You should have received a copy of the GNU Library General Public
-  License along with this library; if not, write to the Free Software
-  Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
-  modified by Ulrich Drepper  (drepper@karlsruhe.gmd.de)
-          and Anatoly Ivasyuk (anatoly@nick.csh.rit.edu)
-
-  modified by Juergen Pfeifer (Juergen.Pfeifer@T-Online.de)      
-*/
+ * Authors:
+ *     Thomas E. Dickey
+ *     Juergen Pfeifer
+ *
+ * The NCursesWindow class was originally based on a file written by
+ * Eric Newton, later modified by Ulrich Drepper and Anatoly Ivasyuk.
+ * However, aside from the compatible interface definition, no trace
+ * of the original code remains in this version: it consists only of
+ * changes introduced since 1995.
+ */
 
 #include "internal.h"
-
-MODULE_ID("$Id: cursesw.cc,v 1.5 1997/05/05 20:04:59 tom Exp $")
-
-#pragma implementation
-
 #include "cursesw.h"
 
+MODULE_ID("$Id: cursesw.cc,v 1.54 2014/02/01 22:10:42 tom Exp $")
+
 #define COLORS_NEED_INITIALIZATION  -1
 #define COLORS_NOT_INITIALIZED       0
 #define COLORS_MONOCHROME            1
 #define COLORS_ARE_REALLY_THERE      2
 
+#define HaveColors() (colorInitialized == COLORS_ARE_REALLY_THERE)
 
 // declare static variables for the class
-int NCursesWindow::count = 0;
+long NCursesWindow::count = 0L;
+bool NCursesWindow::b_initialized = FALSE;
 
 int
 NCursesWindow::scanw(const char* fmt, ...)
 {
-#if defined(__GNUG__)
+    int result = ERR;
+
     va_list args;
     va_start(args, fmt);
-    char buf[BUFSIZ];
-    int result = wgetstr(w, buf);
-    if (result == OK) {
-       strstreambuf ss(buf, BUFSIZ);
-       result = ss.vscan(fmt, args);
-    }
+    result = ::vw_scanw (w, const_cast<NCURSES_CONST char *>(fmt), args);
     va_end(args);
+
     return result;
-#else
-    return ERR;
-#endif
 }
 
 
 int
 NCursesWindow::scanw(int y, int x, const char* fmt, ...)
 {
-#if defined(__GNUG__)
-    va_list args;
-    va_start(args, fmt);
-    char buf[BUFSIZ];
-    int result = wmove(w, y, x);
-    if (result == OK) {
-       result = wgetstr(w, buf);
-       if (result == OK) {
-           strstreambuf ss(buf, BUFSIZ);
-           result = ss.vscan(fmt, args);
-       }
+    int result = ERR;
+
+    if (::wmove(w, y, x) != ERR) {
+       va_list args;
+       va_start(args, fmt);
+       result = ::vw_scanw (w, const_cast<NCURSES_CONST char *>(fmt), args);
+       va_end(args);
+    }
+    return result;
+}
+
+
+int
+NCursesWindow::scanw(const char* fmt, va_list args)
+{
+    int result = ERR;
+
+    result = ::vw_scanw (w, const_cast<NCURSES_CONST char *>(fmt), args);
+
+    return result;
+}
+
+
+int
+NCursesWindow::scanw(int y, int x, const char* fmt, va_list args)
+{
+    int result = ERR;
+
+    if (::wmove(w, y, x) != ERR) {
+       result = ::vw_scanw (w, const_cast<NCURSES_CONST char *>(fmt), args);
     }
-    va_end(args);
     return result;
-#else
-    return ERR;
-#endif
 }
 
 
@@ -87,10 +112,9 @@ NCursesWindow::printw(const char * fmt, ...)
 {
     va_list args;
     va_start(args, fmt);
-    char buf[BUFSIZ];
-    vsprintf(buf, fmt, args);
+    int result = ::vw_printw(w, fmt, args);
     va_end(args);
-    return waddstr(w, buf);
+    return result;
 }
 
 
@@ -99,24 +123,39 @@ NCursesWindow::printw(int y, int x, const char * fmt, ...)
 {
     va_list args;
     va_start(args, fmt);
-    int result = wmove(w, y, x);
+    int result = ::wmove(w, y, x);
     if (result == OK) {
-       char buf[BUFSIZ];
-       vsprintf(buf, fmt, args);
-       result = waddstr(w, buf);
+       result = ::vw_printw(w, fmt, args);
     }
     va_end(args);
     return result;
 }
 
 
+int
+NCursesWindow::printw(const char * fmt, va_list args)
+{
+    int result = ::vw_printw(w, fmt, args);
+    return result;
+}
+
+
+int
+NCursesWindow::printw(int y, int x, const char * fmt, va_list args)
+{
+    int result = ::wmove(w, y, x);
+    if (result == OK) {
+       result = ::vw_printw(w, fmt, args);
+    }
+    return result;
+}
+
+
 void
-NCursesWindow::init(void)
+NCursesWindow::set_keyboard(void)
 {
-    noecho();
-    cbreak();
-    leaveok(0);
-    keypad(1);
+    keypad(TRUE);
+    meta(TRUE);
 }
 
 void
@@ -126,61 +165,91 @@ NCursesWindow::err_handler(const char *msg) const THROWS(NCursesException)
 }
 
 void
-NCursesWindow::initialize() {
-  ::initscr();
-  if (colorInitialized==COLORS_NEED_INITIALIZATION) {
-    colorInitialized=COLORS_NOT_INITIALIZED;
-    count++;
-    useColors();
-    count--;
-  }
+NCursesWindow::initialize()
+{
+    if (!b_initialized) {
+       ::initscr();
+       b_initialized = TRUE;
+       if (colorInitialized == COLORS_NEED_INITIALIZATION) {
+           colorInitialized = COLORS_NOT_INITIALIZED;
+           useColors();
+       }
+       ::noecho();
+       ::cbreak();
+    }
+}
+
+void
+NCursesWindow::constructing()
+{
+    initialize();
+    ++count;
+}
+
+NCursesWindow::NCursesWindow()
+  : w(0), alloced(FALSE), par(0), subwins(0), sib(0)
+{
+    constructing();
+
+    w = static_cast<WINDOW *>(0);
 }
 
-NCursesWindow::NCursesWindow(int lines, int cols, int begin_y, int begin_x)
+NCursesWindow::NCursesWindow(int nlines, int ncols, int begin_y, int begin_x)
+  : w(0), alloced(TRUE), par(0), subwins(0), sib(0)
 {
-    if (count==0)
-      initialize();
+    constructing();
 
-    w = ::newwin(lines, cols, begin_y, begin_x);
+    w = ::newwin(nlines, ncols, begin_y, begin_x);
     if (w == 0) {
        err_handler("Cannot construct window");
     }
-    init();
-
-    alloced = 1;
-    subwins = par = sib = 0;
-    count++;
+    set_keyboard();
 }
 
-NCursesWindow::NCursesWindow(WINDOW* &window)
+NCursesWindow::NCursesWindow(WINDOW* window)
+  : w(0), alloced(FALSE), par(0), subwins(0), sib(0)
 {
-    if (count==0)
-      initialize();
-    
-    w = window;
-    init();
-    alloced = 0;
-    subwins = par = sib = 0;
-    count++;
+    constructing();
+
+    // We used to use a reference on the "window" parameter, but we cannot do
+    // that with an opaque pointer (see NCURSES_OPAQUE).  If the parameter was
+    // "::stdscr", that is first set via the "constructing() call, and is null
+    // up to that point.  So we allow a null pointer here as meaning the "same"
+    // as "::stdscr".
+    w = window ? window : ::stdscr;
+    set_keyboard();
 }
 
-
-NCursesWindow::NCursesWindow(NCursesWindow& win, int l, int c,
-                            int by, int bx, char absrel)
+NCursesWindow::NCursesWindow(NCursesWindow& win, int ny, int nx,
+                            int begin_y, int begin_x, char absrel)
+  : w(0), alloced(TRUE), par(0), subwins(0), sib(0)
 {
-    if (absrel == 'r') { // relative origin 
-       by += win.begy();
-       bx += win.begx();
+    constructing();
+    if (absrel == 'a') {       // absolute origin
+       begin_y -= win.begy();
+       begin_x -= win.begx();
     }
 
-    // Even though we treat subwindows as a tree, the standard curses
-    // library needs the `subwin' call to link to the root in
-    // order to correctly perform refreshes, etc.
+    // Link this window into its parent's list of subwindows.
+    // We use derwin(), since this also works for pads.
+    w = ::derwin(win.w, ny, nx, begin_y, begin_x);
+    if (w == 0) {
+       err_handler("Cannot construct subwindow");
+    }
 
-    NCursesWindow* root = &win;
-    while (root->par != 0) root = root->par;
+    par = &win;
+    sib = win.subwins;
+    win.subwins = this;
+}
 
-    w = subwin(root->w, l, c, by, bx);
+NCursesWindow::NCursesWindow(NCursesWindow& win,
+                               bool do_box NCURSES_PARAM_INIT(TRUE))
+  : w(0), alloced(TRUE), par(0), subwins(0), sib(0)
+{
+    constructing();
+    int myHeight = win.height();
+    int myWidth  = win.width();
+    w = :: derwin(win.w, myHeight - 2, myWidth - 2, 1, 1);
     if (w == 0) {
        err_handler("Cannot construct subwindow");
     }
@@ -189,34 +258,88 @@ NCursesWindow::NCursesWindow(NCursesWindow& win, int l, int c,
     sib = win.subwins;
     win.subwins = this;
     subwins = 0;
-    alloced = 1;
-    count++;
+
+    if (do_box) {
+       win.box();
+       win.touchwin();
+    }
+}
+
+NCursesWindow NCursesWindow::Clone()
+{
+    WINDOW *d = ::dupwin(w);
+    NCursesWindow W(d);
+    W.subwins = subwins;
+    W.sib = sib;
+    W.par = par;
+    W.alloced = alloced;
+    return W;
+}
+
+typedef int (*RIPOFFINIT)(NCursesWindow&);
+static RIPOFFINIT R_INIT[5];       // There can't be more
+static int r_init_idx   = 0;
+static RIPOFFINIT* prip = R_INIT;
+
+NCursesWindow::NCursesWindow(WINDOW *win, int ncols)
+  : w(0), alloced(FALSE), par(0), subwins(0), sib(0)
+{
+    (void) ncols;
+    initialize();
+    w = win;
+}
+
+int _nc_xx_ripoff_init(WINDOW *w, int ncols)
+{
+    (void) ncols;
+    int res = ERR;
+
+    RIPOFFINIT init = *prip++;
+    if (init) {
+       res = init(*(new NCursesWindow(w,ncols)));
+    }
+    return res;
+}
+
+int NCursesWindow::ripoffline(int ripoff_lines,
+                             int (*init)(NCursesWindow& win))
+{
+    int code = ::_nc_ripoffline(ripoff_lines,_nc_xx_ripoff_init);
+    if (code == OK && init && ripoff_lines) {
+       R_INIT[r_init_idx++] = init;
+    }
+    return code;
 }
 
 bool
-NCursesWindow::isDescendant(NCursesWindow& win) {
-  for (NCursesWindow* p = subwins; p != NULL; p = p->sib) {
-    if (p==&win)
-      return TRUE;
-    else {
-      if (p->isDescendant(win))
-       return TRUE;
+NCursesWindow::isDescendant(NCursesWindow& win)
+{
+    bool result = FALSE;
+
+    for (NCursesWindow* p = subwins; p != NULL; p = p->sib) {
+       if (p == &win || p->isDescendant(win)) {
+           result = TRUE;
+           break;
+       }
     }
-  }
-  return FALSE;
+    return result;
 }
 
 void
 NCursesWindow::kill_subwindows()
 {
-    for (NCursesWindow* p = subwins; p != 0; p = p->sib) {
+    NCursesWindow* p = subwins;
+
+    subwins = 0;
+    while (p != 0) {
+       NCursesWindow* q = p->sib;
        p->kill_subwindows();
        if (p->alloced) {
            if (p->w != 0)
                ::delwin(p->w);
-           p->alloced = 0;
        }
-       p->w = 0; // cause a run-time error if anyone attempts to use...
+       delete p;
+       p = q;
     }
 }
 
@@ -225,33 +348,34 @@ NCursesWindow::~NCursesWindow()
 {
     kill_subwindows();
 
-    if (par != 0) {  // Snip us from the parent's list of subwindows.
-       NCursesWindow * win = par->subwins;
-       NCursesWindow * trail = 0;
-       for (;;) {
-           if (win == 0)
+    if (par != 0) {
+       // Remove this window from the parent's list of subwindows.
+       NCursesWindow * next = par->subwins;
+       NCursesWindow * prev = 0;
+       while (next != 0) {
+           if (next == this) {
+               if (prev != 0) {
+                   prev->sib = next->sib;
+               } else {
+                   par->subwins = next->sib;
+               }
                break;
-           else if (win == this) {
-               if (trail != 0)
-                   trail->sib = win->sib;
-               else
-                   par->subwins = win->sib;
-               break;
-           } else {
-               trail = win;
-               win = win->sib;
            }
+           prev = next;
+           next = next->sib;
        }
     }
 
     if (alloced && w != 0)
-       delwin(w);
-
-    --count;
-    if (count == 0)
-       endwin();
-    else if (count < 0) { // cannot happen!
-       err_handler("Too many windows destroyed");
+       ::delwin(w);
+
+    if (alloced) {
+       --count;
+       if (count == 0) {
+           ::endwin();
+       } else if (count < 0) { // cannot happen!
+           err_handler("Too many windows destroyed");
+       }
     }
 }
 
@@ -263,82 +387,83 @@ int NCursesWindow::colorInitialized = COLORS_NOT_INITIALIZED;
 void
 NCursesWindow::useColors(void)
 {
-    if (colorInitialized == COLORS_NOT_INITIALIZED) {        
-      if (count>0) {
-       if (has_colors()) {
-         start_color();
-         colorInitialized = COLORS_ARE_REALLY_THERE;
+    if (colorInitialized == COLORS_NOT_INITIALIZED) {
+       if (b_initialized) {
+           if (::has_colors()) {
+               ::start_color();
+               colorInitialized = COLORS_ARE_REALLY_THERE;
+           } else {
+               colorInitialized = COLORS_MONOCHROME;
+           }
+       } else {
+           colorInitialized = COLORS_NEED_INITIALIZATION;
        }
-       else
-         colorInitialized = COLORS_MONOCHROME;
-      }
-      else
-       colorInitialized = COLORS_NEED_INITIALIZATION;
     }
 }
 
-short
-NCursesWindow::getcolor(int getback) const 
+NCURSES_PAIRS_T
+NCursesWindow::getPair() const
 {
-    short fore, back;
+    return static_cast<NCURSES_PAIRS_T>(PAIR_NUMBER(getattrs(w)));
+}
 
-    if (colorInitialized==COLORS_ARE_REALLY_THERE) {
-      if (pair_content(PAIR_NUMBER(w->_attrs), &fore, &back))
-       err_handler("Can't get color pair");
-    }
-    else {
-      // Monochrome means white on black
-      back = COLOR_BLACK;
-      fore = COLOR_WHITE;
+NCURSES_COLOR_T
+NCursesWindow::getcolor(int getback) const
+{
+    NCURSES_COLOR_T fore, back;
+
+    if (HaveColors()) {
+       if (::pair_content(getPair(), &fore, &back) == ERR)
+           err_handler("Can't get color pair");
+    } else {
+       // Monochrome means white on black
+       back = COLOR_BLACK;
+       fore = COLOR_WHITE;
     }
     return getback ? back : fore;
 }
 
 int NCursesWindow::NumberOfColors()
 {
-  if (colorInitialized==COLORS_ARE_REALLY_THERE)
-    return COLORS;
-  else
-    return 1; // monochrome (actually there are two ;-)
+    return (HaveColors()) ? COLORS : 1;
 }
 
-short
-NCursesWindow::getcolor() const 
+NCURSES_PAIRS_T
+NCursesWindow::getcolor() const
 {
-  if (colorInitialized==COLORS_ARE_REALLY_THERE)
-    return PAIR_NUMBER(w->_attrs);
-  else
-    return 0; // we only have pair zero
+    return (HaveColors()) ? getPair() : 0;
 }
 
 int
-NCursesWindow::setpalette(short fore, short back, short pair)
+NCursesWindow::setpalette(NCURSES_COLOR_T fore, NCURSES_COLOR_T back, NCURSES_PAIRS_T pair)
 {
-  if (colorInitialized==COLORS_ARE_REALLY_THERE)
-    return init_pair(pair, fore, back);
-  else
-    return OK;
+    return (HaveColors()) ? ::init_pair(pair, fore, back) : OK;
 }
 
 int
-NCursesWindow::setpalette(short fore, short back)
+NCursesWindow::setpalette(NCURSES_COLOR_T fore, NCURSES_COLOR_T back)
 {
-  if (colorInitialized==COLORS_ARE_REALLY_THERE)
-    return setpalette(fore, back, PAIR_NUMBER(w->_attrs));
-  else
-    return OK;
+    return setpalette(fore, back, getPair());
 }
 
 
 int
-NCursesWindow::setcolor(short pair)
+NCursesWindow::setcolor(NCURSES_PAIRS_T pair)
 {
-  if (colorInitialized==COLORS_ARE_REALLY_THERE) {
-    if ((pair < 1) || (pair > COLOR_PAIRS))
-      err_handler("Can't set color pair");
-    
-    attroff(A_COLOR);
-    attrset(COLOR_PAIR(pair));
-  }
-  return OK;
+    if (HaveColors()) {
+       if ((pair < 1) || (pair > COLOR_PAIRS))
+           err_handler("Can't set color pair");
+
+       attroff(A_COLOR);
+       attrset(COLOR_PAIR(pair));
+    }
+    return OK;
+}
+
+#if HAVE_HAS_KEY
+bool NCursesWindow::has_mouse() const
+{
+    return ((::has_key(KEY_MOUSE) || ::has_mouse())
+            ? TRUE : FALSE);
 }
+#endif