libyui-ncurses  2.44.1
/usr/src/RPM/BUILD/libyui-ncurses-2.44.1/src/ncursesw.cc
00001 /*
00002   Copyright (C) 2000-2012 Novell, Inc
00003   This library is free software; you can redistribute it and/or modify
00004   it under the terms of the GNU Lesser General Public License as
00005   published by the Free Software Foundation; either version 2.1 of the
00006   License, or (at your option) version 3.0 of the License. This library
00007   is distributed in the hope that it will be useful, but WITHOUT ANY
00008   WARRANTY; without even the implied warranty of MERCHANTABILITY or
00009   FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
00010   License for more details. You should have received a copy of the GNU
00011   Lesser General Public License along with this library; if not, write
00012   to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
00013   Floor, Boston, MA 02110-1301 USA
00014 */
00015 
00016 
00017 /*-/
00018 
00019    File:       ncursesw.cc
00020 
00021    Author:     Michael Andres <ma@suse.de>
00022 
00023 /-*/
00024 
00025 /*
00026   Copyright (C) 1989 Free Software Foundation
00027   written by Eric Newton (newton@rocky.oswego.edu)
00028 
00029   This file is part of the GNU C++ Library.  This library is free
00030   software; you can redistribute it and/or modify it under the terms of
00031   the GNU Library General Public License as published by the Free
00032   Software Foundation; either version 2 of the License, or (at your
00033   option) any later version.  This library is distributed in the hope
00034   that it will be useful, but WITHOUT ANY WARRANTY; without even the
00035   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
00036   PURPOSE.  See the GNU Library General Public License for more details.
00037   You should have received a copy of the GNU Library General Public
00038   License along with this library; if not, write to the Free Software
00039   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
00040 
00041   modified by Ulrich Drepper  (drepper@karlsruhe.gmd.de)
00042           and Anatoly Ivasyuk (anatoly@nick.csh.rit.edu)
00043 
00044   modified by Juergen Pfeifer (Juergen.Pfeifer@T-Online.de)
00045 */
00046 
00047 #include <iostream>
00048 #include <stdlib.h>
00049 #include <string.h>
00050 #include <ncursesw/term.h>
00051 #undef line
00052 #undef columns
00053 
00054 #define  YUILogComponent "ncurses"
00055 #include <yui/YUILog.h>
00056 
00057 #include "ncursesw.h"
00058 #include "NCstring.h"
00059 
00060 
00061 #define COLORS_NEED_INITIALIZATION  -1
00062 #define COLORS_NOT_INITIALIZED       0
00063 #define COLORS_MONOCHROME            1
00064 #define COLORS_ARE_REALLY_THERE      2
00065 
00066 //
00067 // static class variables
00068 //
00069 long NCursesWindow::count = 0L;
00070 bool NCursesWindow::b_initialized = FALSE;
00071 
00072 
00073 
00074 int
00075 NCursesWindow::printw( const char * fmt, ... )
00076 {
00077     va_list args;
00078     va_start( args, fmt );
00079     char buf[BUFSIZ];
00080     vsprintf( buf, fmt, args );
00081     va_end( args );
00082     return waddstr( w, buf );
00083 }
00084 
00085 
00086 int
00087 NCursesWindow::printw( int y, int x, const char * fmt, ... )
00088 {
00089     va_list args;
00090     va_start( args, fmt );
00091     int result = wmove( w, y, x );
00092 
00093     if ( result == OK )
00094     {
00095         char buf[BUFSIZ];
00096         vsprintf( buf, fmt, args );
00097         result = waddstr( w, buf );
00098     }
00099 
00100     va_end( args );
00101 
00102     return result;
00103 }
00104 
00105 int
00106 NCursesWindow::addwstr( int y, int x, const wchar_t * str, int n )
00107 {
00108     const std::wstring wstr( str );
00109     std::string out;
00110 
00111     if ( NCstring::terminalEncoding() != "UTF-8" )
00112     {
00113         NCstring::RecodeFromWchar( wstr, NCstring::terminalEncoding(), &out );
00114         return ::mvwaddnstr( w, y, x, out.c_str(), n );
00115     }
00116     else
00117         return ::mvwaddnwstr( w, y, x, ( wchar_t* )str, n );
00118 
00119 }
00120 
00121 
00122 int
00123 NCursesWindow::addwstr( const wchar_t* str, int n )
00124 {
00125     const std::wstring wstr( str );
00126     std::string out;
00127 
00128     if ( NCstring::terminalEncoding() != "UTF-8" )
00129     {
00130         NCstring::RecodeFromWchar( wstr, NCstring::terminalEncoding(), &out );
00131         return ::waddnstr( w, out.c_str(), n );
00132     }
00133     else
00134         return ::waddnwstr( w, ( wchar_t* )str, n );
00135 }
00136 
00137 
00138 int
00139 NCursesWindow::in_wchar( int y, int x, cchar_t *combined )
00140 {
00141     int ret = mvwin_wch( w, y, x, combined );
00142     combined->attr = combined->attr & ( A_CHARTEXT | A_ALTCHARSET );
00143 
00144 // libncurses6 enables ext_color from struct cchar_t (see curses.h).
00145 // Set ext_color to 0 to respect the settings got from mvwin_wch (bnc#652240).
00146 #ifdef NCURSES_EXT_COLORS
00147     combined->ext_color = 0;
00148 #endif
00149     return ret;
00150 }
00151 
00152 int
00153 NCursesWindow::in_wchar( cchar_t *combined )
00154 {
00155     int ret = win_wch( w, combined );
00156     combined->attr = combined->attr & ( A_CHARTEXT | A_ALTCHARSET );
00157 // libncurses6 enables ext_color from struct cchar_t (see curses.h).
00158 // Set ext_color to 0 to respect the settings got from win_wch (bnc#652240).
00159 #ifdef NCURSES_EXT_COLORS
00160     combined->ext_color = 0;
00161 #endif
00162     return ret;
00163 }
00164 
00165 int
00166 NCursesWindow::add_attr_char( int y, int x )
00167 {
00168     int ret = ERR;
00169 
00170     if ( NCstring::terminalEncoding() != "UTF-8" )
00171     {
00172         ret = addch( inchar( y, x ) );
00173     }
00174     else
00175     {
00176         cchar_t combined;
00177         ret = in_wchar( y, x, &combined );
00178 
00179         if ( ret == OK )
00180         {
00181             ret = add_wch( &combined );
00182         }
00183     }
00184 
00185     return ret;
00186 }
00187 
00188 int
00189 NCursesWindow::add_attr_char( )
00190 {
00191     int ret = ERR;
00192 
00193     if ( NCstring::terminalEncoding() != "UTF-8" )
00194     {
00195         ret = addch( inchar() );
00196     }
00197     else
00198     {
00199         cchar_t combined;
00200         ret = in_wchar( &combined );
00201 
00202         if ( ret == OK )
00203         {
00204             ret = add_wch( &combined );
00205         }
00206     }
00207 
00208     return ret;
00209 }
00210 
00211 void
00212 NCursesWindow::init( void )
00213 {
00214     // Setting back_color_erase to FALSE was added because of bug #418613.
00215     // This isn't necessary any longer because the kernel patch which
00216     // has caused the bug was reverted (in SLES11-GM).
00217 #if 0
00218     static char * env;
00219     if (!env && (env = ::getenv("TERM"))) {
00220         if (::strncmp(env, "linux", 5) == 0)
00221             back_color_erase = FALSE;
00222     }
00223 #endif
00224     leaveok( 0 );
00225     keypad( 1 );
00226     meta( 1 );
00227 }
00228 
00229 void
00230 NCursesWindow::err_handler( const char *msg ) const THROWS( NCursesException )
00231 {
00232     THROW( new NCursesException( msg ) );
00233 }
00234 
00235 void
00236 NCursesWindow::initialize()
00237 {
00238     if ( !b_initialized )
00239     {
00240         //::initscr();
00241         b_initialized = TRUE;
00242 
00243         if ( colorInitialized == COLORS_NEED_INITIALIZATION )
00244         {
00245             colorInitialized = COLORS_NOT_INITIALIZED;
00246             useColors();
00247         }
00248 
00249         ::noecho();
00250 
00251         ::cbreak();
00252     }
00253 }
00254 
00255 NCursesWindow::NCursesWindow()
00256         : w(0), alloced(FALSE), par(0), subwins(0), sib(0)
00257 {
00258     if ( !b_initialized )
00259         initialize();
00260 
00261     w =  static_cast<WINDOW *>(0);
00262 
00263     init();
00264 
00265     count++;
00266 }
00267 
00268 NCursesWindow::NCursesWindow( int lines, int cols, int begin_y, int begin_x )
00269         : w(0), alloced(TRUE), par(0), subwins(0), sib(0)
00270 {
00271     if ( !b_initialized )
00272         initialize();
00273 
00274     if ( lines <= 0 )
00275         lines = 1;
00276 
00277     if ( cols <= 0 )
00278         cols = 1;
00279 
00280     if ( lines + begin_y > NCursesWindow::lines() )
00281         lines = NCursesWindow::lines() - begin_y;
00282 
00283     if ( cols + begin_x > NCursesWindow::cols() )
00284         cols = NCursesWindow::cols() - begin_x;
00285 
00286     yuiDebug() << "Lines: " << lines << " Cols: " << cols << " y: " << begin_y << " x: " << begin_x << std::endl;
00287 
00288     w = ::newwin( lines, cols, begin_y, begin_x );
00289 
00290     if ( w == 0 )
00291     {
00292         err_handler( "Cannot construct window" );
00293     }
00294 
00295     init();
00296 
00297     count++;
00298 }
00299 
00300 NCursesWindow::NCursesWindow( WINDOW* window )
00301         : w(0), alloced(FALSE), par(0), subwins(0), sib(0)
00302 {
00303     if ( !b_initialized )
00304         initialize();
00305 
00306     w = window ? window : ::stdscr;
00307 
00308     init();
00309 
00310     count++;
00311 }
00312 
00313 NCursesWindow::NCursesWindow( NCursesWindow& win, int l, int c,
00314                               int begin_y, int begin_x, char absrel )
00315         : w(0), alloced(TRUE), par(0), subwins(0), sib(0)
00316 {
00317     if ( l <= 0 )
00318         l = 1;
00319 
00320     if ( c <= 0 )
00321         c = 1;
00322 
00323     if ( begin_y < 0 )
00324         begin_y = 0;
00325 
00326     if ( begin_x < 0 )
00327         begin_x = 0;
00328 
00329     if ( absrel == 'a' ) // absolute origin
00330     {
00331         begin_y -= win.begy();
00332         begin_x -= win.begx();
00333     }
00334 
00335     if ( l + begin_y > win.height() )
00336         l = win.height() - begin_y;
00337 
00338     if ( c + begin_x > win.width() )
00339         c = win.width() - begin_x;
00340 
00341     // Even though we treat subwindows as a tree, the standard curses
00342     // library needs the `subwin' call to link to the parent in
00343     // order to correctly perform refreshes, etc.
00344     // Friendly enough, this also works for pads.
00345     w = ::derwin( win.w, l, c, begin_y, begin_x );
00346 
00347     if ( w == 0 )
00348     {
00349         yuiError() << "Throw " << wpos( begin_y, begin_x ) << wsze( l, c ) << std::endl;
00350         err_handler( "Cannot construct subwindow" );
00351     }
00352 
00353     //yuiMilestone() << "created " << wpos(begin_y, begin_x) << wsze(l, c) << std::endl;
00354 
00355     par = &win;
00356 
00357     sib = win.subwins;
00358 
00359     win.subwins = this;
00360 
00361     count++;
00362 }
00363 
00364 NCursesWindow NCursesWindow::Clone()
00365 {
00366     WINDOW *d = ::dupwin( w );
00367     NCursesWindow W( d );
00368     W.subwins = subwins;
00369     W.sib = sib;
00370     W.par = par;
00371     W.alloced = alloced;
00372     return W;
00373 }
00374 
00375 typedef int ( *RIPOFFINIT )( NCursesWindow& );
00376 static RIPOFFINIT R_INIT[5];       // There can't be more
00377 static int r_init_idx   = 0;
00378 static RIPOFFINIT* prip = R_INIT;
00379 
00380 extern "C" int _nc_ripoffline( int, int ( *init )( WINDOW*, int ) );
00381 
00382 NCursesWindow::NCursesWindow( WINDOW *win, int cols )
00383 {
00384     w = win;
00385     assert(( w->_maxx + 1 ) == cols );
00386     alloced = FALSE;
00387     subwins = par = sib = 0;
00388 }
00389 
00390 int NCursesWindow::ripoff_init( WINDOW *w, int cols )
00391 {
00392     int res = ERR;
00393 
00394     RIPOFFINIT init = *prip++;
00395 
00396     if ( init )
00397     {
00398         NCursesWindow* W = new NCursesWindow( w, cols );
00399         res = init( *W );
00400     }
00401 
00402     return res;
00403 }
00404 
00405 int NCursesWindow::ripoffline( int ripoff_lines,
00406                                int ( *init )( NCursesWindow& win ) )
00407 {
00408     int code = ::_nc_ripoffline( ripoff_lines, ripoff_init );
00409 
00410     if ( code == OK && init && ripoff_lines )
00411     {
00412         R_INIT[r_init_idx++] = init;
00413     }
00414 
00415     return code;
00416 }
00417 
00418 bool
00419 NCursesWindow::isDescendant( NCursesWindow& win )
00420 {
00421     for ( NCursesWindow* p = subwins; p != NULL; p = p->sib )
00422     {
00423         if ( p == &win )
00424             return TRUE;
00425         else
00426         {
00427             if ( p->isDescendant( win ) )
00428                 return TRUE;
00429         }
00430     }
00431 
00432     return FALSE;
00433 }
00434 
00435 void
00436 NCursesWindow::kill_subwindows()
00437 {
00438     for ( NCursesWindow* p = subwins; p != 0; p = p->sib )
00439     {
00440         p->kill_subwindows();
00441 
00442         if ( p->alloced )
00443         {
00444             if ( p->w != 0 )
00445                 ::delwin( p->w );
00446 
00447             p->alloced = FALSE;
00448         }
00449 
00450         p->w = 0; // cause a run-time error if anyone attempts to use...
00451     }
00452 }
00453 
00454 
00455 NCursesWindow::~NCursesWindow()
00456 {
00457     kill_subwindows();
00458 
00459     if ( par != 0 )  // Snip us from the parent's list of subwindows.
00460     {
00461         NCursesWindow * win = par->subwins;
00462         NCursesWindow * trail = 0;
00463 
00464         for ( ;; )
00465         {
00466             if ( win == 0 )
00467                 break;
00468             else if ( win == this )
00469             {
00470                 if ( trail != 0 )
00471                     trail->sib = win->sib;
00472                 else
00473                     par->subwins = win->sib;
00474 
00475                 break;
00476             }
00477             else
00478             {
00479                 trail = win;
00480                 win = win->sib;
00481             }
00482         }
00483     }
00484 
00485     if ( alloced && w != 0 )
00486         delwin( w );
00487 
00488     if ( alloced )
00489     {
00490         --count;
00491 
00492         if ( count == 0 )
00493         {
00494             ::endwin();
00495         }
00496         else if ( count < 0 ) // cannot happen!
00497         {
00498             err_handler( "Too many windows destroyed" );
00499         }
00500     }
00501 }
00502 
00503 // ---------------------------------------------------------------------
00504 // Color stuff
00505 int NCursesWindow::colorInitialized = COLORS_NOT_INITIALIZED;
00506 
00507 void
00508 NCursesWindow::useColors( void )
00509 {
00510     if ( colorInitialized == COLORS_NOT_INITIALIZED )
00511     {
00512         if ( b_initialized )
00513         {
00514             if ( ::has_colors() )
00515             {
00516                 ::start_color();
00517                 colorInitialized = COLORS_ARE_REALLY_THERE;
00518             }
00519             else
00520                 colorInitialized = COLORS_MONOCHROME;
00521         }
00522         else
00523             colorInitialized = COLORS_NEED_INITIALIZATION;
00524     }
00525 }
00526 
00527 short
00528 NCursesWindow::getcolor( int getback ) const
00529 {
00530     short fore, back;
00531 
00532     if ( colorInitialized == COLORS_ARE_REALLY_THERE )
00533     {
00534         if ( pair_content( PAIR_NUMBER( w->_attrs ), &fore, &back ) )
00535             err_handler( "Can't get color pair" );
00536     }
00537     else
00538     {
00539         // Monochrome means white on black
00540         back = COLOR_BLACK;
00541         fore = COLOR_WHITE;
00542     }
00543 
00544     return getback ? back : fore;
00545 }
00546 
00547 int NCursesWindow::NumberOfColors()
00548 {
00549     if ( colorInitialized == COLORS_ARE_REALLY_THERE )
00550         return COLORS;
00551     else
00552         return 1; // monochrome (actually there are two ;-)
00553 }
00554 
00555 short
00556 NCursesWindow::getcolor() const
00557 {
00558     if ( colorInitialized == COLORS_ARE_REALLY_THERE )
00559         return PAIR_NUMBER( w->_attrs );
00560     else
00561         return 0; // we only have pair zero
00562 }
00563 
00564 int
00565 NCursesWindow::setpalette( short fore, short back, short pair )
00566 {
00567     if ( colorInitialized == COLORS_ARE_REALLY_THERE )
00568         return init_pair( pair, fore, back );
00569     else
00570         return OK;
00571 }
00572 
00573 int
00574 NCursesWindow::setpalette( short fore, short back )
00575 {
00576     if ( colorInitialized == COLORS_ARE_REALLY_THERE )
00577         return setpalette( fore, back, PAIR_NUMBER( w->_attrs ) );
00578     else
00579         return OK;
00580 }
00581 
00582 
00583 int
00584 NCursesWindow::setcolor( short pair )
00585 {
00586     if ( colorInitialized == COLORS_ARE_REALLY_THERE )
00587     {
00588         if (( pair < 1 ) || ( pair > COLOR_PAIRS ) )
00589             err_handler( "Can't std::set color pair" );
00590 
00591         attroff( A_COLOR );
00592 
00593         attrset( COLOR_PAIR( pair ) );
00594     }
00595 
00596     return OK;
00597 }
00598 
00599 extern "C" int _nc_has_mouse( void );
00600 
00601 bool NCursesWindow::has_mouse() const
00602 {
00603     return (( ::has_key( KEY_MOUSE ) || ::_nc_has_mouse() )
00604             ? TRUE : FALSE );
00605 }
00606 
00607 NCursesPad::NCursesPad( int lines, int cols ) : NCursesWindow()
00608 {
00609     if ( lines <= 0 )
00610         lines = 1;
00611 
00612     if ( cols <= 0 )
00613         cols = 1;
00614 
00615     w = ::newpad( lines, cols );
00616 
00617     if ( w == ( WINDOW* )0 )
00618     {
00619         count--;
00620         err_handler( "Cannot construct window" );
00621     }
00622 
00623     alloced = TRUE;
00624 }
00625 
00626 
00627 
00628 int NCursesWindow::box( const wrect & dim )
00629 {
00630     wrect box_area( dim.intersectRelTo( area() ) );
00631 
00632     if ( box_area.Sze > 0 )
00633     {
00634         hline( box_area.Pos.L,              box_area.Pos.C, box_area.Sze.W );
00635         hline( box_area.Pos.L + box_area.Sze.H - 1, box_area.Pos.C, box_area.Sze.W );
00636         vline( box_area.Pos.L, box_area.Pos.C,              box_area.Sze.H );
00637         vline( box_area.Pos.L, box_area.Pos.C + box_area.Sze.W - 1, box_area.Sze.H );
00638 
00639         addch( box_area.Pos.L + box_area.Sze.H - 1, box_area.Pos.C, ACS_LLCORNER );
00640         addch( box_area.Pos.L, box_area.Pos.C + box_area.Sze.W - 1, ACS_URCORNER );
00641         addch( box_area.Pos.L + box_area.Sze.H - 1, box_area.Pos.C + box_area.Sze.W - 1, ACS_LRCORNER );
00642         addch( box_area.Pos.L,              box_area.Pos.C, ACS_ULCORNER );
00643     }
00644 
00645     return OK;
00646 }
00647 
00648 
00649 
00650 // move subwin tree inside parent
00651 int NCursesWindow::mvsubwin( NCursesWindow * sub, int begin_y, int begin_x )
00652 {
00653     int ret = ERR;
00654 
00655     if ( sub && sub->parent() )
00656     {
00657         sub->w->_parx = -1; // force ncurses to actually move the child
00658         ret = ::mvderwin( sub->w, begin_y, begin_x );
00659 
00660         for ( NCursesWindow * ch = sub->child(); ch && ret == OK; ch = ch->sibling() )
00661         {
00662             ret = mvsubwin( ch, ch->w->_pary, ch->w->_parx );
00663         }
00664     }
00665 
00666     return ret;
00667 }
00668 
00669 
00670 
00671 int NCursesWindow::resize( int lines, int columns )
00672 {
00673     if ( lines <= 0 )
00674         lines = 1;
00675 
00676     if ( columns <= 0 )
00677         columns = 1;
00678 
00679     return ::wresize( w, lines, columns );
00680 }
00681 
00682 
00683 std::ostream & operator<<( std::ostream & Stream, const NCursesWindow * Obj_Cv )
00684 {
00685     if ( Obj_Cv )
00686         return Stream << *Obj_Cv;
00687 
00688     return Stream << "(NoNCWin)";
00689 }
00690 
00691 
00692 std::ostream & operator<<( std::ostream & Stream, const NCursesWindow & Obj_Cv )
00693 {
00694     return Stream << "NCWin(" << Obj_Cv.w
00695            << wrect( wpos( Obj_Cv.begy(), Obj_Cv.begx() ),
00696                      wsze( Obj_Cv.height(), Obj_Cv.width() ) ) << ')';
00697 }
 All Classes Functions Variables