libyui-ncurses  2.44.1
/usr/src/RPM/BUILD/libyui-ncurses-2.44.1/src/YNCursesUI.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:       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 
 All Classes Functions Variables