libyui-ncurses
2.44.1
|
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 }