libyui  3.3.2
YUILoader.cc
1 /*
2  Copyright (C) 2000-2017 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: YUILoader.cc
20 
21  Author: Stefan Hundhammer <sh@suse.de>
22 
23 /-*/
24 
25 #include <stdlib.h> // getenv()
26 #include <unistd.h> // isatty()a
27 #include <sys/stat.h>
28 #include <string.h>
29 
30 #define YUILogComponent "ui"
31 #include "YUILog.h"
32 #include "YCommandLine.h"
33 #include "YUILoader.h"
34 #include "YUIPlugin.h"
35 #include "YUIException.h"
36 #include "YPath.h"
37 #include "YSettings.h"
38 
39 #include "Libyui_config.h"
40 
41 
42 void YUILoader::loadUI( bool withThreads )
43 {
44  bool isGtk = false;
45  const char * envDesktop = getenv( "XDG_CURRENT_DESKTOP" ) ?: "";
46  const char * envDisplay = getenv( "DISPLAY" ) ?: "";
47  const char * envPreset = getenv( "YUI_PREFERED_BACKEND" ) ?: "";
48  std::string wantedGUI;
49 
50  yuiMilestone () << "DISPLAY: \"" << envDisplay << "\"" << std::endl;
51  yuiMilestone () << "XDG_CURRENT_DESKTOP: \"" << envDesktop << "\"" << std::endl;
52  yuiMilestone () << "YUI_PREFERED_BACKEND: \"" << envPreset << "\"" << std::endl;
53 
54  // Taken from: https://specifications.freedesktop.org/menu-spec/menu-spec-1.1.html#onlyshowin-registry
55  isGtk = ( ( strstr( envDesktop, "Cinnamon" ) != NULL ) || isGtk );
56  isGtk = ( ( strstr( envDesktop, "GNOME" ) != NULL ) || isGtk );
57  isGtk = ( ( strstr( envDesktop, "LXDE" ) != NULL ) || isGtk );
58  isGtk = ( ( strstr( envDesktop, "MATE" ) != NULL ) || isGtk );
59  isGtk = ( ( strstr( envDesktop, "Pantheon" ) != NULL ) || isGtk );
60  isGtk = ( ( strstr( envDesktop, "ROX" ) != NULL ) || isGtk );
61  isGtk = ( ( strstr( envDesktop, "Unity" ) != NULL ) || isGtk );
62  isGtk = ( ( strstr( envDesktop, "XFCE" ) != NULL ) || isGtk );
63 
64  if( isGtk ) yuiMilestone () << "Detected a Gtk-based desktop environment." << std::endl
65  << "Prefering Gtk-UI if available and no" << std::endl
66  << "user-selected override is present." << std::endl;
67 
68  YCommandLine cmdline;
69 
70  bool wantGtk = ( cmdline.find( "--gtk" ) != -1 );
71  bool wantNcurses = ( cmdline.find( "--ncurses" ) != -1 );
72  bool wantQt = ( cmdline.find( "--qt" ) != -1 );
73  bool haveUIPreset = ( wantGtk || wantNcurses || wantQt );
74 
75  if( !haveUIPreset )
76  {
77  wantGtk = ( strcmp( envPreset, YUIPlugin_Gtk ) == 0 );
78  wantNcurses = ( strcmp( envPreset, YUIPlugin_NCurses ) == 0 );
79  wantQt = ( strcmp( envPreset, YUIPlugin_Qt ) == 0 );
80  }
81 
82  if( wantGtk ) wantedGUI = YUIPlugin_Gtk;
83  if( wantNcurses ) wantedGUI = YUIPlugin_NCurses;
84  if( wantQt ) wantedGUI = YUIPlugin_Qt;
85 
86  yuiMilestone () << "User-selected UI-plugin: \"" << wantedGUI << "\"" << std::endl;
87 
88  bool haveGtk = pluginExists( YUIPlugin_Gtk );
89  bool haveNcurses = pluginExists( YUIPlugin_NCurses );
90  bool haveQt = pluginExists( YUIPlugin_Qt );
91 
92  // This reset is intentional, so the loader can work it's magic
93  // selecting an UI-plugin as described in the documentation.
94  wantedGUI="";
95 
96  // Set the UI-Plugin
97  if ( ( haveGtk || haveQt ) && strcmp ( envDisplay, "" ) &&
98  ( !wantNcurses || !isatty( STDOUT_FILENO ) ) )
99  {
100  // Qt is default if available.
101  if ( haveQt )
102  wantedGUI = YUIPlugin_Qt;
103 
104  // Do we want to use Gtk instead?
105  if ( haveGtk && ( ( ( isGtk || wantGtk ) && !wantQt ) || !haveQt ) )
106  wantedGUI = YUIPlugin_Gtk;
107  }
108 
109  else if ( haveNcurses && isatty( STDOUT_FILENO ) )
110  {
111  // We use NCurses.
112  wantedGUI = YUIPlugin_NCurses;
113  }
114 
115  // Load the wanted UI-plugin.
116  if( wantedGUI != "" )
117  {
118  yuiMilestone () << "Using UI-plugin: \"" << wantedGUI << "\""<< std::endl;
119  YSettings::loadedUI( wantedGUI, true );
120 
121  try
122  {
123  loadPlugin( wantedGUI, withThreads );
124  return;
125  }
126 
127  catch ( YUIException & ex )
128  {
129  YUI_CAUGHT( ex );
130 
131  // Default to NCurses, if possible.
132  if( wantedGUI != YUIPlugin_NCurses && haveNcurses && isatty( STDOUT_FILENO ) )
133  {
134  yuiWarning () << "Defaulting to: \"" << YUIPlugin_NCurses << "\""<< std::endl;
135  YSettings::loadedUI( YUIPlugin_NCurses, true );
136 
137  try
138  {
139  loadPlugin( YUIPlugin_NCurses, withThreads );
140  return;
141  }
142 
143  catch ( YUIException & ex )
144  {
145  YUI_CAUGHT( ex );
146  }
147  }
148 
149  YUI_RETHROW( ex ); // what else to do here?
150  }
151  }
152 
153  else
154  {
155  YUI_THROW( YUICantLoadAnyUIException() );
156  }
157 }
158 
160 {
161  if ( YUI::_ui )
162  {
163  yuiMilestone() << "Shutting down UI" << std::endl;
164  delete YUI::_ui;
165 
166  YUI::_ui = 0;
167  }
168 }
169 
170 void YUILoader::loadPlugin( const std::string & name, bool withThreads )
171 {
172  YUIPlugin uiPlugin( name.c_str() );
173 
174  if ( uiPlugin.success() )
175  {
176  createUIFunction_t createUI = (createUIFunction_t) uiPlugin.locateSymbol( "_Z8createUIb" ); // createUI(bool)
177 
178  if ( createUI )
179  {
180  YUI * ui = createUI( withThreads ); // no threads
181 
182  // At this point the concrete UI will have loaded its own
183  // internal plugins and registered their destructors.
184  // Our destructor must get called before those get dlclose'd.
185  //
186  // Formerly ~YUI was called quite late, which called ~YQUI
187  // and that ran code in the already unloaded Qt internal plugins.
188  atexit(deleteUI);
189 
190  if ( ui )
191  return;
192  }
193  }
194 
195  YUI_THROW( YUIPluginException( name ) );
196 }
197 
198 void YUILoader::loadExternalWidgetsPlugin ( const std::string& name, const std::string& plugin_name, const std::string& symbol )
199 {
200  YUIPlugin uiPlugin ( plugin_name.c_str() );
201 
202  if ( uiPlugin.success() )
203  {
204  createEWFunction_t createEW = ( createEWFunction_t ) uiPlugin.locateSymbol ( symbol.c_str() );
205 
206  if ( createEW )
207  {
208  YExternalWidgets * we = createEW ( name.c_str() );
209 
210  if ( we )
211  return;
212  }
213  }
214 
215  YUI_THROW ( YUIPluginException ( plugin_name ) );
216 }
217 
218 void YUILoader::loadExternalWidgets ( const std::string& name, const std::string& symbol )
219 {
220  std::string wantedGUI = name;
221  wantedGUI.append( "-" );
222  wantedGUI.append( YSettings::loadedUI() );
223 
224  bool haveExternal = pluginExists( wantedGUI );
225 
226  if( haveExternal )
227  {
228  try
229  {
230  loadExternalWidgetsPlugin(name, wantedGUI, symbol );
231  return;
232  }
233  catch ( YUIException & ex )
234  {
235  YUI_CAUGHT( ex );
236  YUI_RETHROW( ex ); // what else to do here?
237  }
238  }
239 
240  else
241  {
242  YUI_THROW( YUICantLoadAnyUIException() );
243  }
244 }
245 
246 bool YUILoader::pluginExists( const std::string & pluginBaseName )
247 {
248  struct stat fileinfo;
249  std::string pluginName = PLUGIN_PREFIX;
250 
251  pluginName.append( pluginBaseName );
252  pluginName.append( PLUGIN_SUFFIX );
253 
254  YPath plugin ( PLUGINDIR, pluginName );
255 
256  return stat( plugin.path().c_str(), &fileinfo) == 0;
257 
258 }
std::string path()
Returns the full path of the file if found; if not found just the filename given in constructor...
Definition: YPath.cc:171
int find(const std::string &argName) const
Find a command line argument &#39;argName&#39; ("-display" etc.).
static std::string loadedUI()
Returns the value of the loaded UI-backend.
Definition: YSettings.cc:195
Abstract base class of a libYUI user interface.
Definition: YUI.h:48
static void loadPlugin(const std::string &name, bool withThreads=false)
Load a UI plug-in.
Definition: YUILoader.cc:170
static void loadExternalWidgets(const std::string &name, const std::string &symbol="_Z21createExternalWidgetsPKc")
Load the given External Widgets plugin followed by its graphical extension implementation in the foll...
Definition: YUILoader.cc:218
Exception class for plugin load failure.
Definition: YUIException.h:875
static void deleteUI()
This will make sure the UI singleton is deleted.
Definition: YUILoader.cc:159
Finds files (e.g.
Definition: YPath.h:43
Abstract base class of a libYUI Widget Extension interface.
Utility class to access /proc/<pid>/cmdline to retrieve argc and argv.
Definition: YCommandLine.h:37
Exception class for UI plugin load failure.
Definition: YUIException.h:890
Wrapper class for dlopen() and related.
Definition: YUIPlugin.h:35
Base class for UI Exceptions.
Definition: YUIException.h:297
static void loadUI(bool withThreads=false)
Load any of the available UI-plugins by this order and criteria:
Definition: YUILoader.cc:42