libyui-ncurses  2.50.1
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 #include "NCPopupTextEntry.h"
46 #include "NCi18n.h"
47 
48 extern std::string language2encoding( std::string lang );
49 
51 
52 
53 YUI * createUI( bool withThreads )
54 {
55  if ( ! YNCursesUI::ui() )
56  new YNCursesUI( withThreads );
57 
58  return YNCursesUI::ui();
59 }
60 
61 
62 YNCursesUI::YNCursesUI( bool withThreads )
63  : YUI( withThreads )
64 {
65  yuiMilestone() << "Start YNCursesUI" << std::endl;
66  _ui = this;
67 
68  if ( getenv( "LANG" ) != NULL )
69  {
70  setlocale ( LC_CTYPE, "" );
71  std::string language = getenv( "LANG" );
72  std::string encoding = nl_langinfo( CODESET );
73  yuiMilestone() << "getenv LANG: " << language << " encoding: " << encoding << std::endl;
74 
75  // Explicitly set LC_CTYPE so that it won't be changed if setenv( LANG ) is called elsewhere.
76  // (it's not enough to call setlocale( LC_CTYPE, .. ), set env. variable LC_CTYPE!)
77  std::string locale = setlocale( LC_CTYPE, NULL );
78  setenv( "LC_CTYPE", locale.c_str(), 1 );
79  yuiMilestone() << "setenv LC_CTYPE: " << locale << " encoding: " << encoding << std::endl;
80 
81  // The encoding of a terminal (xterm, konsole etc.) can never change; the encoding
82  // of the "real" console is changed in setConsoleFont().
83  NCstring::setTerminalEncoding( encoding );
84  app()->setLanguage( language, encoding );
85  }
86 
87  YButtonBoxMargins buttonBoxMargins;
88  buttonBoxMargins.left = 1;
89  buttonBoxMargins.right = 1;
90  buttonBoxMargins.top = 1;
91  buttonBoxMargins.bottom = 0;
92  buttonBoxMargins.spacing = 1;
93  buttonBoxMargins.helpButtonExtraSpacing = 3;
94  YButtonBox::setDefaultMargins( buttonBoxMargins );
95 
96  try
97  {
98  NCurses::init();
99  }
100  catch ( NCursesError & err )
101  {
102  yuiMilestone() << err << std::endl;
103  ::endwin();
104  abort();
105  }
106 
107  topmostConstructorHasFinished();
108 }
109 
110 
112 {
113  //delete left-over dialogs (if any)
114  YDialog::deleteAllDialogs();
115  yuiMilestone() << "Stop YNCursesUI" << std::endl;
116 }
117 
118 
119 YWidgetFactory *
121 {
122  NCWidgetFactory * factory = new NCWidgetFactory();
123  YUI_CHECK_NEW( factory );
124 
125  return factory;
126 }
127 
128 
129 YOptionalWidgetFactory *
131 {
133  YUI_CHECK_NEW( factory );
134 
135  return factory;
136 }
137 
138 
139 YApplication *
140 YNCursesUI::createApplication()
141 {
142  NCApplication * app = new NCApplication();
143  YUI_CHECK_NEW( app );
144 
145  return app;
146 }
147 
148 
149 void YNCursesUI::idleLoop( int fd_ycp )
150 {
151 
152  int timeout = 5;
153 
154  struct timeval tv;
155  fd_set fdset;
156  int retval;
157 
158  do
159  {
160  tv.tv_sec = timeout;
161  tv.tv_usec = 0;
162 
163  FD_ZERO( &fdset );
164  FD_SET( 0, &fdset );
165  FD_SET( fd_ycp, &fdset );
166 
167  retval = select( fd_ycp + 1, &fdset, 0, 0, &tv );
168 
169  if ( retval < 0 )
170  {
171  if ( errno != EINTR )
172  yuiError() << "idleLoop error in select() (" << errno << ')' << std::endl;
173  }
174  else if ( retval != 0 )
175  {
176  //do not throw here, as current dialog may not necessarily exist yet
177  //if we have threads
178  YDialog *currentDialog = YDialog::currentDialog( false );
179 
180  if ( currentDialog )
181  {
182  NCDialog * ncd = static_cast<NCDialog *>( currentDialog );
183 
184  if ( ncd )
185  {
186  extern NCBusyIndicator* NCBusyIndicatorObject;
187 
188  if ( NCBusyIndicatorObject )
189  NCBusyIndicatorObject->handler( 0 );
190 
191  ncd->idleInput();
192  }
193  }
194  } // else no input within timeout sec.
195  }
196  while ( !FD_ISSET( fd_ycp, &fdset ) );
197 }
198 
199 
200 /**
201  * Create the package selector plugin
202  **/
204 {
205  static NCPackageSelectorPluginStub * plugin = 0;
206 
207  if ( ! plugin )
208  {
209  plugin = new NCPackageSelectorPluginStub();
210 
211  // This is a deliberate memory leak: If an application requires a
212  // PackageSelector, it is a package selection application by
213  // definition. In this case, the ncurses_pkg plugin is intentionally
214  // kept open to avoid repeated start-up cost of the plugin and libzypp.
215  }
216 
217  return plugin;
218 }
219 
220 
221 YEvent * YNCursesUI::runPkgSelection( YWidget * selector )
222 {
223  YEvent * event = 0;
224 
225  YDialog *dialog = YDialog::currentDialog();
227 
228  if ( !dialog )
229  {
230  yuiError() << "ERROR package selection: No dialog rexisting." << std::endl;
231  return 0;
232  }
233 
234  if ( !selector )
235  {
236  yuiError() << "ERROR package selection: No package selector existing." << std::endl;
237  return 0;
238  }
239 
240  // debug: dump the widget tree
241  dialog->dumpDialogWidgetTree();
242 
243  if ( plugin )
244  {
245  event = plugin->runPkgSelection( dialog, selector );
246  }
247 
248  return event;
249 }
250 
251 
252 void YNCursesUI::init_title()
253 {
254  // Fetch command line args
255  YCommandLine cmdline;
256 
257  //
258  // Retrieve program name from command line
259  //
260 
261  std::string progName = YUILog::basename( cmdline[0] );
262 
263  if ( progName == "y2base" )
264  {
265  progName = "YaST2";
266 
267  // Special case for YaST2: argv[1] is the module name -
268  // this is what we want to display in the window title
269  //
270  // '/usr/lib/whatever/y2base' 'module_name' 'selected_ui'
271  // (e.g. 'y2base' 'lan' 'ncurses') -> we need 'lan'
272 
273  if ( cmdline.size() > 1 )
274  progName += " - " + cmdline[1];
275  }
276 
277  if ( progName.find( "lt-" ) == 0 ) // progName starts with "lt-"
278  {
279  // Remove leading "lt-" from libtool-generated binaries
280  progName = progName.substr( sizeof( "lt-" ) - 1 );
281  }
282 
283 
284  //
285  // Retrieve host name (if set)
286  //
287 
288  std::string hostName;
289 
290  char hostNameBuffer[ 256 ];
291 
292  if ( gethostname( hostNameBuffer, sizeof( hostNameBuffer ) - 1 ) != -1 )
293  {
294  // gethostname() might have messed up - yet another POSIX standard that
295  // transfers the burden of doing things right to the application
296  // programmer: Possibly no null byte
297 
298  hostNameBuffer[ sizeof( hostNameBuffer ) -1 ] = '\0';
299  hostName = hostNameBuffer;
300  }
301 
302  if ( hostName == "(none)" )
303  hostName = "";
304 
305  //
306  // Build and set window title
307  //
308 
309  std::string windowTitle = progName;
310 
311  if ( ! hostName.empty() )
312  windowTitle += " @ " + hostName;
313 
314  NCurses::SetTitle( windowTitle );
315 }
316 
317 
318 bool YNCursesUI::want_colors()
319 {
320  if ( getenv( "Y2NCURSES_BW" ) != NULL )
321  {
322  yuiMilestone() << "Y2NCURSES_BW is std::set - won't use colors" << std::endl;
323  return false;
324  }
325 
326  return true;
327 }
328 
329 
330 /**
331  * Set the console font, encoding etc.
332  * This is called from Console.ycp.
333  * The terminal encoding must be std::set correctly.
334  *
335  * This doesn't belong here, but it is so utterly entangled with member
336  * variables that are not exported at all (sic!) that it's not really feasible
337  * to extract the relevant parts.
338  **/
339 void YNCursesUI::setConsoleFont( const std::string & console_magic,
340  const std::string & font,
341  const std::string & screen_map,
342  const std::string & unicode_map,
343  const std::string & lang )
344 {
345  std::string cmd( "setfont" );
346  cmd += " -C " + myTerm;
347  cmd += " " + font;
348 
349  if ( !screen_map.empty() )
350  cmd += " -m " + screen_map;
351 
352  if ( !unicode_map.empty() )
353  cmd += " -u " + unicode_map;
354 
355  yuiMilestone() << cmd << std::endl;
356 
357  int ret = system(( cmd + " >/dev/null 2>&1" ).c_str() );
358 
359  // setfont returns error if called e.g. on a xterm -> return
360  if ( ret )
361  {
362  yuiError() << cmd.c_str() << " returned " << ret << std::endl;
363  Refresh();
364  return;
365  }
366 
367  // go on in case of a "real" console
368  cmd = "(echo -en \"\\033";
369 
370  if ( console_magic.length() )
371  cmd += console_magic;
372  else
373  cmd += "(B";
374 
375  cmd += "\" >" + myTerm + ")";
376 
377  yuiMilestone() << cmd << std::endl;
378 
379  ret = system(( cmd + " >/dev/null 2>&1" ).c_str() );
380 
381  if ( ret )
382  {
383  yuiError() << cmd.c_str() << " returned " << ret << std::endl;
384  }
385 
386  // set terminal encoding for console
387  // (setConsoleFont() in Console.ycp has passed the encoding as last
388  // argument but this encoding was not correct; now Console.ycp passes the
389  // language) if the encoding is NOT UTF-8 set the console encoding
390  // according to the language
391 
392  if ( NCstring::terminalEncoding() != "UTF-8" )
393  {
394  std::string language = lang;
395  std::string::size_type pos = language.find( '.' );
396 
397  if ( pos != std::string::npos )
398  {
399  language.erase( pos );
400  }
401 
402  pos = language.find( '_' );
403 
404  if ( pos != std::string::npos )
405  {
406  language.erase( pos );
407  }
408 
409  std::string code = language2encoding( language );
410 
411  yuiMilestone() << "setConsoleFont( ENCODING: " << code << " )" << std::endl;
412 
413  if ( NCstring::setTerminalEncoding( code ) )
414  {
415  Redraw();
416  }
417  else
418  {
419  Refresh();
420  }
421  }
422  else
423  {
424  Refresh();
425  }
426 }
427 
428 
430 {
431  std::string id = NCPopupTextEntry::askForText( wpos( 0, 0 ),
432  _("Enter Widget ID:"), // label
433  "" ); // initial text
434 
435  if ( ! id.empty() )
436  {
437  try
438  {
439  return sendWidgetID( id );
440  }
441  catch ( YUIWidgetNotFoundException & ex )
442  {
443  YUI_CAUGHT( ex );
444  }
445  }
446 
447  return 0;
448 }
static YNCursesUI * _ui
Global reference to the UI.
Definition: YNCursesUI.h:84
virtual YWidgetFactory * createWidgetFactory()
Create the widget factory that provides all the createXY() methods for standard (mandatory, i.e.
Definition: YNCursesUI.cc:120
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)
Set the (text) console font according to the current encoding etc.
Definition: YNCursesUI.cc:339
Widget factory for optional ("special") widgets.
virtual YOptionalWidgetFactory * createOptionalWidgetFactory()
Create the widget factory that provides all the createXY() methods for optional ("special") widgets a...
Definition: YNCursesUI.cc:130
YWidget * askSendWidgetID()
Open a pop-up dialog to ask the user for a widget ID and then send it with sendWidgetID().
Definition: YNCursesUI.cc:429
Concrete widget factory for mandatory widgets.
static YNCursesUI * ui()
Access the global Y2NCursesUI.
Definition: YNCursesUI.h:91
Definition: position.h:109
void handler(int sig_num)
handler, called by NCBusyIndicatorHandlerWrapper
virtual void idleLoop(int fd_ycp)
Idle around until fd_ycp is readable.
Definition: YNCursesUI.cc:149
virtual YEvent * runPkgSelection(YDialog *currentDialog, YWidget *packageSelector)
Fills the PackageSelector widget (runs the package selection).
NCPackageSelectorPluginStub * packageSelectorPlugin()
Returns the package selector plugin singleton of this UI or creates it (including loading the plugin ...
Definition: YNCursesUI.cc:203
virtual YEvent * runPkgSelection(YWidget *packageSelector)
Fills the PackageSelector widget and runs package selection.
Definition: YNCursesUI.cc:221
~YNCursesUI()
Destructor.
Definition: YNCursesUI.cc:111
YNCursesUI(bool withThreads)
Constructor.
Definition: YNCursesUI.cc:62