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