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: YNCursesUI.cc 00020 00021 Author: Michael Andres <ma@suse.de> 00022 00023 /-*/ 00024 00025 #include "YNCursesUI.h" 00026 #include <string> 00027 #include <sys/time.h> 00028 #include <unistd.h> 00029 #include <langinfo.h> 00030 00031 #include <yui/YUI.h> 00032 #include <yui/YEvent.h> 00033 #include <yui/YDialog.h> 00034 #include <yui/YCommandLine.h> 00035 #include <yui/YButtonBox.h> 00036 #include <yui/YMacro.h> 00037 00038 #define YUILogComponent "ncurses" 00039 #include <yui/YUILog.h> 00040 00041 #include "NCstring.h" 00042 #include "NCWidgetFactory.h" 00043 #include "NCOptionalWidgetFactory.h" 00044 #include "NCPackageSelectorPluginStub.h" 00045 00046 extern std::string language2encoding( std::string lang ); 00047 00048 YNCursesUI * YNCursesUI::_ui = 0; 00049 00050 00051 YUI * createUI( bool withThreads ) 00052 { 00053 if ( ! YNCursesUI::ui() ) 00054 new YNCursesUI( withThreads ); 00055 00056 return YNCursesUI::ui(); 00057 } 00058 00059 00060 YNCursesUI::YNCursesUI( bool withThreads ) 00061 : YUI( withThreads ) 00062 { 00063 yuiMilestone() << "Start YNCursesUI" << std::endl; 00064 _ui = this; 00065 00066 if ( getenv( "LANG" ) != NULL ) 00067 { 00068 setlocale ( LC_CTYPE, "" ); 00069 std::string language = getenv( "LANG" ); 00070 std::string encoding = nl_langinfo( CODESET ); 00071 yuiMilestone() << "getenv LANG: " << language << " encoding: " << encoding << std::endl; 00072 00073 // Explicitly set LC_CTYPE so that it won't be changed if setenv( LANG ) is called elsewhere. 00074 // (it's not enough to call setlocale( LC_CTYPE, .. ), set env. variable LC_CTYPE!) 00075 std::string locale = setlocale( LC_CTYPE, NULL ); 00076 setenv( "LC_CTYPE", locale.c_str(), 1 ); 00077 yuiMilestone() << "setenv LC_CTYPE: " << locale << " encoding: " << encoding << std::endl; 00078 00079 // The encoding of a terminal (xterm, konsole etc.) can never change; the encoding 00080 // of the "real" console is changed in setConsoleFont(). 00081 NCstring::setTerminalEncoding( encoding ); 00082 app()->setLanguage( language, encoding ); 00083 } 00084 00085 YButtonBoxMargins buttonBoxMargins; 00086 buttonBoxMargins.left = 1; 00087 buttonBoxMargins.right = 1; 00088 buttonBoxMargins.top = 1; 00089 buttonBoxMargins.bottom = 0; 00090 buttonBoxMargins.spacing = 1; 00091 buttonBoxMargins.helpButtonExtraSpacing = 3; 00092 YButtonBox::setDefaultMargins( buttonBoxMargins ); 00093 00094 try 00095 { 00096 NCurses::init(); 00097 } 00098 catch ( NCursesError & err ) 00099 { 00100 yuiMilestone() << err << std::endl; 00101 ::endwin(); 00102 abort(); 00103 } 00104 00105 topmostConstructorHasFinished(); 00106 } 00107 00108 00109 YNCursesUI::~YNCursesUI() 00110 { 00111 //delete left-over dialogs (if any) 00112 YDialog::deleteAllDialogs(); 00113 yuiMilestone() << "Stop YNCursesUI" << std::endl; 00114 } 00115 00116 00117 YWidgetFactory * 00118 YNCursesUI::createWidgetFactory() 00119 { 00120 NCWidgetFactory * factory = new NCWidgetFactory(); 00121 YUI_CHECK_NEW( factory ); 00122 00123 return factory; 00124 } 00125 00126 00127 YOptionalWidgetFactory * 00128 YNCursesUI::createOptionalWidgetFactory() 00129 { 00130 NCOptionalWidgetFactory * factory = new NCOptionalWidgetFactory(); 00131 YUI_CHECK_NEW( factory ); 00132 00133 return factory; 00134 } 00135 00136 00137 YApplication * 00138 YNCursesUI::createApplication() 00139 { 00140 NCApplication * app = new NCApplication(); 00141 YUI_CHECK_NEW( app ); 00142 00143 return app; 00144 } 00145 00146 00147 void YNCursesUI::idleLoop( int fd_ycp ) 00148 { 00149 00150 int timeout = 5; 00151 00152 struct timeval tv; 00153 fd_set fdset; 00154 int retval; 00155 00156 do 00157 { 00158 tv.tv_sec = timeout; 00159 tv.tv_usec = 0; 00160 00161 FD_ZERO( &fdset ); 00162 FD_SET( 0, &fdset ); 00163 FD_SET( fd_ycp, &fdset ); 00164 00165 retval = select( fd_ycp + 1, &fdset, 0, 0, &tv ); 00166 00167 if ( retval < 0 ) 00168 { 00169 if ( errno != EINTR ) 00170 yuiError() << "idleLoop error in select() (" << errno << ')' << std::endl; 00171 } 00172 else if ( retval != 0 ) 00173 { 00174 //do not throw here, as current dialog may not necessarily exist yet 00175 //if we have threads 00176 YDialog *currentDialog = YDialog::currentDialog( false ); 00177 00178 if ( currentDialog ) 00179 { 00180 NCDialog * ncd = static_cast<NCDialog *>( currentDialog ); 00181 00182 if ( ncd ) 00183 { 00184 extern NCBusyIndicator* NCBusyIndicatorObject; 00185 00186 if ( NCBusyIndicatorObject ) 00187 NCBusyIndicatorObject->handler( 0 ); 00188 00189 ncd->idleInput(); 00190 } 00191 } 00192 } // else no input within timeout sec. 00193 } 00194 while ( !FD_ISSET( fd_ycp, &fdset ) ); 00195 } 00196 00197 00198 /** 00199 * Create the package selector plugin 00200 **/ 00201 NCPackageSelectorPluginStub * YNCursesUI::packageSelectorPlugin() 00202 { 00203 static NCPackageSelectorPluginStub * plugin = 0; 00204 00205 if ( ! plugin ) 00206 { 00207 plugin = new NCPackageSelectorPluginStub(); 00208 00209 // This is a deliberate memory leak: If an application requires a 00210 // PackageSelector, it is a package selection application by 00211 // definition. In this case, the ncurses_pkg plugin is intentionally 00212 // kept open to avoid repeated start-up cost of the plugin and libzypp. 00213 } 00214 00215 return plugin; 00216 } 00217 00218 00219 YEvent * YNCursesUI::runPkgSelection( YWidget * selector ) 00220 { 00221 YEvent * event = 0; 00222 00223 YDialog *dialog = YDialog::currentDialog(); 00224 NCPackageSelectorPluginStub * plugin = packageSelectorPlugin(); 00225 00226 if ( !dialog ) 00227 { 00228 yuiError() << "ERROR package selection: No dialog rexisting." << std::endl; 00229 return 0; 00230 } 00231 00232 if ( !selector ) 00233 { 00234 yuiError() << "ERROR package selection: No package selector existing." << std::endl; 00235 return 0; 00236 } 00237 00238 // debug: dump the widget tree 00239 dialog->dumpDialogWidgetTree(); 00240 00241 if ( plugin ) 00242 { 00243 event = plugin->runPkgSelection( dialog, selector ); 00244 } 00245 00246 return event; 00247 } 00248 00249 00250 void YNCursesUI::init_title() 00251 { 00252 // Fetch command line args 00253 YCommandLine cmdline; 00254 00255 // 00256 // Retrieve program name from command line 00257 // 00258 00259 std::string progName = YUILog::basename( cmdline[0] ); 00260 00261 if ( progName == "y2base" ) 00262 { 00263 progName = "YaST2"; 00264 00265 // Special case for YaST2: argv[1] is the module name - 00266 // this is what we want to display in the window title 00267 // 00268 // '/usr/lib/whatever/y2base' 'module_name' 'selected_ui' 00269 // (e.g. 'y2base' 'lan' 'ncurses') -> we need 'lan' 00270 00271 if ( cmdline.size() > 1 ) 00272 progName += " - " + cmdline[1]; 00273 } 00274 00275 if ( progName.find( "lt-" ) == 0 ) // progName starts with "lt-" 00276 { 00277 // Remove leading "lt-" from libtool-generated binaries 00278 progName = progName.substr( sizeof( "lt-" ) - 1 ); 00279 } 00280 00281 00282 // 00283 // Retrieve host name (if set) 00284 // 00285 00286 std::string hostName; 00287 00288 char hostNameBuffer[ 256 ]; 00289 00290 if ( gethostname( hostNameBuffer, sizeof( hostNameBuffer ) - 1 ) != -1 ) 00291 { 00292 // gethostname() might have messed up - yet another POSIX standard that 00293 // transfers the burden of doing things right to the application 00294 // programmer: Possibly no null byte 00295 00296 hostNameBuffer[ sizeof( hostNameBuffer ) -1 ] = '\0'; 00297 hostName = hostNameBuffer; 00298 } 00299 00300 if ( hostName == "(none)" ) 00301 hostName = ""; 00302 00303 // 00304 // Build and set window title 00305 // 00306 00307 std::string windowTitle = progName; 00308 00309 if ( ! hostName.empty() ) 00310 windowTitle += " @ " + hostName; 00311 00312 NCurses::SetTitle( windowTitle ); 00313 } 00314 00315 00316 bool YNCursesUI::want_colors() 00317 { 00318 if ( getenv( "Y2NCURSES_BW" ) != NULL ) 00319 { 00320 yuiMilestone() << "Y2NCURSES_BW is std::set - won't use colors" << std::endl; 00321 return false; 00322 } 00323 00324 return true; 00325 } 00326 00327 00328 /** 00329 * Set the console font, encoding etc. 00330 * This is called from Console.ycp. 00331 * The terminal encoding must be std::set correctly. 00332 * 00333 * This doesn't belong here, but it is so utterly entangled with member 00334 * variables that are not exported at all (sic!) that it's not really feasible 00335 * to extract the relevant parts. 00336 **/ 00337 void YNCursesUI::setConsoleFont( const std::string & console_magic, 00338 const std::string & font, 00339 const std::string & screen_map, 00340 const std::string & unicode_map, 00341 const std::string & lang ) 00342 { 00343 std::string cmd( "setfont" ); 00344 cmd += " -C " + myTerm; 00345 cmd += " " + font; 00346 00347 if ( !screen_map.empty() ) 00348 cmd += " -m " + screen_map; 00349 00350 if ( !unicode_map.empty() ) 00351 cmd += " -u " + unicode_map; 00352 00353 yuiMilestone() << cmd << std::endl; 00354 00355 int ret = system(( cmd + " >/dev/null 2>&1" ).c_str() ); 00356 00357 // setfont returns error if called e.g. on a xterm -> return 00358 if ( ret ) 00359 { 00360 yuiError() << cmd.c_str() << " returned " << ret << std::endl; 00361 Refresh(); 00362 return; 00363 } 00364 00365 // go on in case of a "real" console 00366 cmd = "(echo -en \"\\033"; 00367 00368 if ( console_magic.length() ) 00369 cmd += console_magic; 00370 else 00371 cmd += "(B"; 00372 00373 cmd += "\" >" + myTerm + ")"; 00374 00375 yuiMilestone() << cmd << std::endl; 00376 00377 ret = system(( cmd + " >/dev/null 2>&1" ).c_str() ); 00378 00379 if ( ret ) 00380 { 00381 yuiError() << cmd.c_str() << " returned " << ret << std::endl; 00382 } 00383 00384 // set terminal encoding for console 00385 // (setConsoleFont() in Console.ycp has passed the encoding as last 00386 // argument but this encoding was not correct; now Console.ycp passes the 00387 // language) if the encoding is NOT UTF-8 set the console encoding 00388 // according to the language 00389 00390 if ( NCstring::terminalEncoding() != "UTF-8" ) 00391 { 00392 std::string language = lang; 00393 std::string::size_type pos = language.find( '.' ); 00394 00395 if ( pos != std::string::npos ) 00396 { 00397 language.erase( pos ); 00398 } 00399 00400 pos = language.find( '_' ); 00401 00402 if ( pos != std::string::npos ) 00403 { 00404 language.erase( pos ); 00405 } 00406 00407 std::string code = language2encoding( language ); 00408 00409 yuiMilestone() << "setConsoleFont( ENCODING: " << code << " )" << std::endl; 00410 00411 if ( NCstring::setTerminalEncoding( code ) ) 00412 { 00413 Redraw(); 00414 } 00415 else 00416 { 00417 Refresh(); 00418 } 00419 } 00420 else 00421 { 00422 Refresh(); 00423 } 00424 } 00425