libyui-ncurses  2.44.1
 All Classes Functions Variables
YNCursesUI.cc
1 /*
2  Copyright (C) 2000-2012 Novell, Inc
3  This library is free software; you can redistribute it and/or modify
4  it under the terms of the GNU Lesser General Public License as
5  published by the Free Software Foundation; either version 2.1 of the
6  License, or (at your option) version 3.0 of the License. This library
7  is distributed in the hope that it will be useful, but WITHOUT ANY
8  WARRANTY; without even the implied warranty of MERCHANTABILITY or
9  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10  License for more details. You should have received a copy of the GNU
11  Lesser General Public License along with this library; if not, write
12  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
13  Floor, Boston, MA 02110-1301 USA
14 */
15 
16 
17 /*-/
18 
19  File: YNCursesUI.cc
20 
21  Author: Michael Andres <ma@suse.de>
22 
23 /-*/
24 
25 #include "YNCursesUI.h"
26 #include <string>
27 #include <sys/time.h>
28 #include <unistd.h>
29 #include <langinfo.h>
30 
31 #include <yui/YUI.h>
32 #include <yui/YEvent.h>
33 #include <yui/YDialog.h>
34 #include <yui/YCommandLine.h>
35 #include <yui/YButtonBox.h>
36 #include <yui/YMacro.h>
37 
38 #define YUILogComponent "ncurses"
39 #include <yui/YUILog.h>
40 
41 #include "NCstring.h"
42 #include "NCWidgetFactory.h"
43 #include "NCOptionalWidgetFactory.h"
44 #include "NCPackageSelectorPluginStub.h"
45 
46 extern std::string language2encoding( std::string lang );
47 
49 
50 
51 YUI * createUI( bool withThreads )
52 {
53  if ( ! YNCursesUI::ui() )
54  new YNCursesUI( withThreads );
55 
56  return YNCursesUI::ui();
57 }
58 
59 
60 YNCursesUI::YNCursesUI( bool withThreads )
61  : YUI( withThreads )
62 {
63  yuiMilestone() << "Start YNCursesUI" << std::endl;
64  _ui = this;
65 
66  if ( getenv( "LANG" ) != NULL )
67  {
68  setlocale ( LC_CTYPE, "" );
69  std::string language = getenv( "LANG" );
70  std::string encoding = nl_langinfo( CODESET );
71  yuiMilestone() << "getenv LANG: " << language << " encoding: " << encoding << std::endl;
72 
73  // Explicitly set LC_CTYPE so that it won't be changed if setenv( LANG ) is called elsewhere.
74  // (it's not enough to call setlocale( LC_CTYPE, .. ), set env. variable LC_CTYPE!)
75  std::string locale = setlocale( LC_CTYPE, NULL );
76  setenv( "LC_CTYPE", locale.c_str(), 1 );
77  yuiMilestone() << "setenv LC_CTYPE: " << locale << " encoding: " << encoding << std::endl;
78 
79  // The encoding of a terminal (xterm, konsole etc.) can never change; the encoding
80  // of the "real" console is changed in setConsoleFont().
81  NCstring::setTerminalEncoding( encoding );
82  app()->setLanguage( language, encoding );
83  }
84 
85  YButtonBoxMargins buttonBoxMargins;
86  buttonBoxMargins.left = 1;
87  buttonBoxMargins.right = 1;
88  buttonBoxMargins.top = 1;
89  buttonBoxMargins.bottom = 0;
90  buttonBoxMargins.spacing = 1;
91  buttonBoxMargins.helpButtonExtraSpacing = 3;
92  YButtonBox::setDefaultMargins( buttonBoxMargins );
93 
94  try
95  {
96  NCurses::init();
97  }
98  catch ( NCursesError & err )
99  {
100  yuiMilestone() << err << std::endl;
101  ::endwin();
102  abort();
103  }
104 
105  topmostConstructorHasFinished();
106 }
107 
108 
110 {
111  //delete left-over dialogs (if any)
112  YDialog::deleteAllDialogs();
113  yuiMilestone() << "Stop YNCursesUI" << std::endl;
114 }
115 
116 
117 YWidgetFactory *
119 {
120  NCWidgetFactory * factory = new NCWidgetFactory();
121  YUI_CHECK_NEW( factory );
122 
123  return factory;
124 }
125 
126 
127 YOptionalWidgetFactory *
129 {
131  YUI_CHECK_NEW( factory );
132 
133  return factory;
134 }
135 
136 
137 YApplication *
138 YNCursesUI::createApplication()
139 {
140  NCApplication * app = new NCApplication();
141  YUI_CHECK_NEW( app );
142 
143  return app;
144 }
145 
146 
147 void YNCursesUI::idleLoop( int fd_ycp )
148 {
149 
150  int timeout = 5;
151 
152  struct timeval tv;
153  fd_set fdset;
154  int retval;
155 
156  do
157  {
158  tv.tv_sec = timeout;
159  tv.tv_usec = 0;
160 
161  FD_ZERO( &fdset );
162  FD_SET( 0, &fdset );
163  FD_SET( fd_ycp, &fdset );
164 
165  retval = select( fd_ycp + 1, &fdset, 0, 0, &tv );
166 
167  if ( retval < 0 )
168  {
169  if ( errno != EINTR )
170  yuiError() << "idleLoop error in select() (" << errno << ')' << std::endl;
171  }
172  else if ( retval != 0 )
173  {
174  //do not throw here, as current dialog may not necessarily exist yet
175  //if we have threads
176  YDialog *currentDialog = YDialog::currentDialog( false );
177 
178  if ( currentDialog )
179  {
180  NCDialog * ncd = static_cast<NCDialog *>( currentDialog );
181 
182  if ( ncd )
183  {
184  extern NCBusyIndicator* NCBusyIndicatorObject;
185 
186  if ( NCBusyIndicatorObject )
187  NCBusyIndicatorObject->handler( 0 );
188 
189  ncd->idleInput();
190  }
191  }
192  } // else no input within timeout sec.
193  }
194  while ( !FD_ISSET( fd_ycp, &fdset ) );
195 }
196 
197 
198 /**
199  * Create the package selector plugin
200  **/
202 {
203  static NCPackageSelectorPluginStub * plugin = 0;
204 
205  if ( ! plugin )
206  {
207  plugin = new NCPackageSelectorPluginStub();
208 
209  // This is a deliberate memory leak: If an application requires a
210  // PackageSelector, it is a package selection application by
211  // definition. In this case, the ncurses_pkg plugin is intentionally
212  // kept open to avoid repeated start-up cost of the plugin and libzypp.
213  }
214 
215  return plugin;
216 }
217 
218 
219 YEvent * YNCursesUI::runPkgSelection( YWidget * selector )
220 {
221  YEvent * event = 0;
222 
223  YDialog *dialog = YDialog::currentDialog();
225 
226  if ( !dialog )
227  {
228  yuiError() << "ERROR package selection: No dialog rexisting." << std::endl;
229  return 0;
230  }
231 
232  if ( !selector )
233  {
234  yuiError() << "ERROR package selection: No package selector existing." << std::endl;
235  return 0;
236  }
237 
238  // debug: dump the widget tree
239  dialog->dumpDialogWidgetTree();
240 
241  if ( plugin )
242  {
243  event = plugin->runPkgSelection( dialog, selector );
244  }
245 
246  return event;
247 }
248 
249 
250 void YNCursesUI::init_title()
251 {
252  // Fetch command line args
253  YCommandLine cmdline;
254 
255  //
256  // Retrieve program name from command line
257  //
258 
259  std::string progName = YUILog::basename( cmdline[0] );
260 
261  if ( progName == "y2base" )
262  {
263  progName = "YaST2";
264 
265  // Special case for YaST2: argv[1] is the module name -
266  // this is what we want to display in the window title
267  //
268  // '/usr/lib/whatever/y2base' 'module_name' 'selected_ui'
269  // (e.g. 'y2base' 'lan' 'ncurses') -> we need 'lan'
270 
271  if ( cmdline.size() > 1 )
272  progName += " - " + cmdline[1];
273  }
274 
275  if ( progName.find( "lt-" ) == 0 ) // progName starts with "lt-"
276  {
277  // Remove leading "lt-" from libtool-generated binaries
278  progName = progName.substr( sizeof( "lt-" ) - 1 );
279  }
280 
281 
282  //
283  // Retrieve host name (if set)
284  //
285 
286  std::string hostName;
287 
288  char hostNameBuffer[ 256 ];
289 
290  if ( gethostname( hostNameBuffer, sizeof( hostNameBuffer ) - 1 ) != -1 )
291  {
292  // gethostname() might have messed up - yet another POSIX standard that
293  // transfers the burden of doing things right to the application
294  // programmer: Possibly no null byte
295 
296  hostNameBuffer[ sizeof( hostNameBuffer ) -1 ] = '\0';
297  hostName = hostNameBuffer;
298  }
299 
300  if ( hostName == "(none)" )
301  hostName = "";
302 
303  //
304  // Build and set window title
305  //
306 
307  std::string windowTitle = progName;
308 
309  if ( ! hostName.empty() )
310  windowTitle += " @ " + hostName;
311 
312  NCurses::SetTitle( windowTitle );
313 }
314 
315 
316 bool YNCursesUI::want_colors()
317 {
318  if ( getenv( "Y2NCURSES_BW" ) != NULL )
319  {
320  yuiMilestone() << "Y2NCURSES_BW is std::set - won't use colors" << std::endl;
321  return false;
322  }
323 
324  return true;
325 }
326 
327 
328 /**
329  * Set the console font, encoding etc.
330  * This is called from Console.ycp.
331  * The terminal encoding must be std::set correctly.
332  *
333  * This doesn't belong here, but it is so utterly entangled with member
334  * variables that are not exported at all (sic!) that it's not really feasible
335  * to extract the relevant parts.
336  **/
337 void YNCursesUI::setConsoleFont( const std::string & console_magic,
338  const std::string & font,
339  const std::string & screen_map,
340  const std::string & unicode_map,
341  const std::string & lang )
342 {
343  std::string cmd( "setfont" );
344  cmd += " -C " + myTerm;
345  cmd += " " + font;
346 
347  if ( !screen_map.empty() )
348  cmd += " -m " + screen_map;
349 
350  if ( !unicode_map.empty() )
351  cmd += " -u " + unicode_map;
352 
353  yuiMilestone() << cmd << std::endl;
354 
355  int ret = system(( cmd + " >/dev/null 2>&1" ).c_str() );
356 
357  // setfont returns error if called e.g. on a xterm -> return
358  if ( ret )
359  {
360  yuiError() << cmd.c_str() << " returned " << ret << std::endl;
361  Refresh();
362  return;
363  }
364 
365  // go on in case of a "real" console
366  cmd = "(echo -en \"\\033";
367 
368  if ( console_magic.length() )
369  cmd += console_magic;
370  else
371  cmd += "(B";
372 
373  cmd += "\" >" + myTerm + ")";
374 
375  yuiMilestone() << cmd << std::endl;
376 
377  ret = system(( cmd + " >/dev/null 2>&1" ).c_str() );
378 
379  if ( ret )
380  {
381  yuiError() << cmd.c_str() << " returned " << ret << std::endl;
382  }
383 
384  // set terminal encoding for console
385  // (setConsoleFont() in Console.ycp has passed the encoding as last
386  // argument but this encoding was not correct; now Console.ycp passes the
387  // language) if the encoding is NOT UTF-8 set the console encoding
388  // according to the language
389 
390  if ( NCstring::terminalEncoding() != "UTF-8" )
391  {
392  std::string language = lang;
393  std::string::size_type pos = language.find( '.' );
394 
395  if ( pos != std::string::npos )
396  {
397  language.erase( pos );
398  }
399 
400  pos = language.find( '_' );
401 
402  if ( pos != std::string::npos )
403  {
404  language.erase( pos );
405  }
406 
407  std::string code = language2encoding( language );
408 
409  yuiMilestone() << "setConsoleFont( ENCODING: " << code << " )" << std::endl;
410 
411  if ( NCstring::setTerminalEncoding( code ) )
412  {
413  Redraw();
414  }
415  else
416  {
417  Refresh();
418  }
419  }
420  else
421  {
422  Refresh();
423  }
424 }
425 
static YNCursesUI * _ui
Definition: YNCursesUI.h:84
virtual YWidgetFactory * createWidgetFactory()
Definition: YNCursesUI.cc:118
virtual void setConsoleFont(const std::string &console_magic, const std::string &font, const std::string &screen_map, const std::string &unicode_map, const std::string &lang)
Definition: YNCursesUI.cc:337
virtual YOptionalWidgetFactory * createOptionalWidgetFactory()
Definition: YNCursesUI.cc:128
static YNCursesUI * ui()
Definition: YNCursesUI.h:91
void handler(int sig_num)
virtual void idleLoop(int fd_ycp)
Definition: YNCursesUI.cc:147
virtual YEvent * runPkgSelection(YDialog *currentDialog, YWidget *packageSelector)
NCPackageSelectorPluginStub * packageSelectorPlugin()
Definition: YNCursesUI.cc:201
virtual YEvent * runPkgSelection(YWidget *packageSelector)
Definition: YNCursesUI.cc:219
YNCursesUI(bool withThreads)
Definition: YNCursesUI.cc:60