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