libyui  3.3.1
YUILoader.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: 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;
46  const char * envDisplay;
47  const char * envPreset;
48  std::string wantedGUI;
49 
50  if( getenv( "DISPLAY" ) )
51  envDisplay = getenv( "DISPLAY" );
52  else
53  envDisplay = "";
54 
55  if( getenv( "XDG_CURRENT_DESKTOP" ) )
56  envDesktop = getenv( "XDG_CURRENT_DESKTOP" );
57  else
58  envDesktop = "";
59 
60  if( getenv( "YUI_PREFERED_BACKEND" ) )
61  envPreset = getenv( "YUI_PREFERED_BACKEND" );
62  else
63  envPreset = "";
64 
65  yuiMilestone () << "DISPLAY: \"" << envDisplay << "\"" << std::endl;
66  yuiMilestone () << "XDG_CURRENT_DESKTOP: \"" << envDesktop << "\"" << std::endl;
67  yuiMilestone () << "YUI_PREFERED_BACKEND: \"" << envPreset << "\"" << std::endl;
68 
69  // Taken from: https://specifications.freedesktop.org/menu-spec/menu-spec-1.1.html#onlyshowin-registry
70  isGtk = ( ( strstr( envDesktop, "Cinnamon" ) != NULL ) || isGtk );
71  isGtk = ( ( strstr( envDesktop, "GNOME" ) != NULL ) || isGtk );
72  isGtk = ( ( strstr( envDesktop, "LXDE" ) != NULL ) || isGtk );
73  isGtk = ( ( strstr( envDesktop, "MATE" ) != NULL ) || isGtk );
74  isGtk = ( ( strstr( envDesktop, "Pantheon" ) != NULL ) || isGtk );
75  isGtk = ( ( strstr( envDesktop, "ROX" ) != NULL ) || isGtk );
76  isGtk = ( ( strstr( envDesktop, "Unity" ) != NULL ) || isGtk );
77  isGtk = ( ( strstr( envDesktop, "XFCE" ) != NULL ) || isGtk );
78 
79  if( isGtk ) yuiMilestone () << "Detected a Gtk-based desktop environment." << std::endl
80  << "Prefering Gtk-UI if available and no" << std::endl
81  << "user-selected override is present." << std::endl;
82 
83  YCommandLine cmdline;
84 
85  bool wantGtk = ( cmdline.find( "--gtk" ) != -1 );
86  bool wantNcurses = ( cmdline.find( "--ncurses" ) != -1 );
87  bool wantQt = ( cmdline.find( "--qt" ) != -1 );
88  wantGtk = ( wantGtk || ( strcmp( envPreset, YUIPlugin_Gtk ) == 0 ) ) && !( wantNcurses || wantQt );
89  wantNcurses = ( wantNcurses || ( strcmp( envPreset, YUIPlugin_NCurses ) == 0 ) ) && !( wantGtk || wantQt );
90  wantQt = ( wantQt || ( strcmp( envPreset, YUIPlugin_Qt ) == 0 ) ) && !( wantGtk || wantNcurses );
91 
92  if( wantGtk ) wantedGUI = YUIPlugin_Gtk;
93  if( wantNcurses ) wantedGUI = YUIPlugin_NCurses;
94  if( wantQt ) wantedGUI = YUIPlugin_Qt;
95 
96  yuiMilestone () << "User-selected UI-plugin: \"" << wantedGUI << "\"" << std::endl;
97 
98  bool haveGtk = pluginExists( YUIPlugin_Gtk );
99  bool haveNcurses = pluginExists( YUIPlugin_NCurses );
100  bool haveQt = pluginExists( YUIPlugin_Qt );
101 
102  wantedGUI="";
103 
104  // Set the UI-Plugin
105  if ( ( haveGtk || haveQt ) && strcmp ( envDisplay, "" ) &&
106  ( !wantNcurses || !isatty( STDOUT_FILENO ) ) )
107  {
108  // Qt is default if available.
109  if ( haveQt )
110  wantedGUI = YUIPlugin_Qt;
111 
112  // Do we want to use Gtk instead?
113  if ( haveGtk && ( ( ( isGtk || wantGtk ) && !wantQt ) || !haveQt ) )
114  wantedGUI = YUIPlugin_Gtk;
115  }
116 
117  else if ( haveNcurses && isatty( STDOUT_FILENO ) )
118  {
119  // We use NCurses.
120  wantedGUI = YUIPlugin_NCurses;
121  }
122 
123  // Load the wanted UI-plugin.
124  if( wantedGUI != "" )
125  {
126  yuiMilestone () << "Using UI-plugin: \"" << wantedGUI << "\""<< std::endl;
127  YSettings::loadedUI( wantedGUI, true );
128 
129  try
130  {
131  loadPlugin( wantedGUI, withThreads );
132  return;
133  }
134 
135  catch ( YUIException & ex )
136  {
137  YUI_CAUGHT( ex );
138 
139  // Default to NCurses, if possible.
140  if( wantedGUI != YUIPlugin_NCurses && haveNcurses && isatty( STDOUT_FILENO ) )
141  {
142  yuiWarning () << "Defaulting to: \"" << YUIPlugin_NCurses << "\""<< std::endl;
143  YSettings::loadedUI( YUIPlugin_NCurses, true );
144 
145  try
146  {
147  loadPlugin( YUIPlugin_NCurses, withThreads );
148  return;
149  }
150 
151  catch ( YUIException & ex )
152  {
153  YUI_CAUGHT( ex );
154  }
155  }
156 
157  YUI_RETHROW( ex ); // what else to do here?
158  }
159  }
160 
161  else
162  {
163  YUI_THROW( YUICantLoadAnyUIException() );
164  }
165 }
166 
168 {
169  if ( YUI::_ui )
170  {
171  yuiMilestone() << "Shutting down UI" << std::endl;
172  delete YUI::_ui;
173 
174  YUI::_ui = 0;
175  }
176 }
177 
178 void YUILoader::loadPlugin( const std::string & name, bool withThreads )
179 {
180  YUIPlugin uiPlugin( name.c_str() );
181 
182  if ( uiPlugin.success() )
183  {
184  createUIFunction_t createUI = (createUIFunction_t) uiPlugin.locateSymbol( "_Z8createUIb" ); // createUI(bool)
185 
186  if ( createUI )
187  {
188  YUI * ui = createUI( withThreads ); // no threads
189 
190  // At this point the concrete UI will have loaded its own
191  // internal plugins and registered their destructors.
192  // Our destructor must get called before those get dlclose'd.
193  //
194  // Formerly ~YUI was called quite late, which called ~YQUI
195  // and that ran code in the already unloaded Qt internal plugins.
196  atexit(deleteUI);
197 
198  if ( ui )
199  return;
200  }
201  }
202 
203  YUI_THROW( YUIPluginException( name ) );
204 }
205 
206 void YUILoader::loadExternalWidgetsPlugin ( const std::string& name, const std::string& plugin_name, const std::string& symbol )
207 {
208  YUIPlugin uiPlugin ( plugin_name.c_str() );
209 
210  if ( uiPlugin.success() )
211  {
212  createEWFunction_t createEW = ( createEWFunction_t ) uiPlugin.locateSymbol ( symbol.c_str() );
213 
214  if ( createEW )
215  {
216  YExternalWidgets * we = createEW ( name.c_str() );
217 
218  if ( we )
219  return;
220  }
221  }
222 
223  YUI_THROW ( YUIPluginException ( plugin_name ) );
224 }
225 
226 void YUILoader::loadExternalWidgets ( const std::string& name, const std::string& symbol )
227 {
228  std::string wantedGUI = name;
229  wantedGUI.append( "-" );
230  wantedGUI.append( YSettings::loadedUI() );
231 
232  bool haveExternal = pluginExists( wantedGUI );
233 
234  if( haveExternal )
235  {
236  try
237  {
238  loadExternalWidgetsPlugin(name, wantedGUI, symbol );
239  return;
240  }
241  catch ( YUIException & ex )
242  {
243  YUI_CAUGHT( ex );
244  YUI_RETHROW( ex ); // what else to do here?
245  }
246  }
247 
248  else
249  {
250  YUI_THROW( YUICantLoadAnyUIException() );
251  }
252 }
253 
254 bool YUILoader::pluginExists( const std::string & pluginBaseName )
255 {
256  struct stat fileinfo;
257  std::string pluginName = PLUGIN_PREFIX;
258 
259  pluginName.append( pluginBaseName );
260  pluginName.append( PLUGIN_SUFFIX );
261 
262  YPath plugin ( PLUGINDIR, pluginName );
263 
264  return stat( plugin.path().c_str(), &fileinfo) == 0;
265 
266 }
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:178
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:226
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:167
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