File indexing completed on 2024-04-28 05:32:13

0001 /*
0002     this file is part of the oxygen gtk engine
0003     SPDX-FileCopyrightText: 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
0004     SPDX-FileCopyrightText: 2010 Ruslan Kabatsayev <b7.10110111@gmail.com>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include "oxygenqtsettings.h"
0010 #include "oxygencoloreffect.h"
0011 #include "oxygencolorutils.h"
0012 #include "oxygenfontinfo.h"
0013 #include "oxygengtkicons.h"
0014 #include "oxygengtkrc.h"
0015 #include "oxygenshadowhelper.h"
0016 #include "oxygentimeline.h"
0017 #include "config.h"
0018 
0019 #include <glib.h>
0020 #include <glib/gstdio.h>
0021 #include <gtk/gtk.h>
0022 
0023 #include <algorithm>
0024 #include <cstdio>
0025 #include <cstdlib>
0026 #include <cstring>
0027 #include <sys/stat.h>
0028 #include <fstream>
0029 #include <iostream>
0030 #include <sstream>
0031 
0032 #ifdef GDK_WINDOWING_X11
0033 #include <gdk/gdkx.h>
0034 #include <X11/Xatom.h>
0035 #endif
0036 
0037 namespace Oxygen
0038 {
0039 
0040     //_________________________________________________________
0041     const std::string QtSettings::_defaultKdeIconPath = "/usr/share/icons/";
0042 
0043     //_________________________________________________________
0044     /*
0045     Note: the default values set in the constructor are actually ignored.
0046     Real default values are set via Oxygen::QtSettings::loadKdeGlobalsOptions,
0047     from the oxygenrc file provided with oxygen-gtk
0048     */
0049     QtSettings::QtSettings( void ):
0050         _wmShadowsSupported( false ),
0051         _kdeIconTheme( "oxygen" ),
0052         _kdeFallbackIconTheme( "gnome" ),
0053         _inactiveChangeSelectionColor( false ),
0054         _useIconEffect( true ),
0055         _useBackgroundGradient( true ),
0056         _checkBoxStyle( CS_CHECK ),
0057         _tabStyle( TS_SINGLE ),
0058         _scrollBarAddLineButtons( 2 ),
0059         _scrollBarSubLineButtons( 1 ),
0060         _toolBarDrawItemSeparator( true ),
0061         _tooltipTransparent( true ),
0062         _tooltipDrawStyledFrames( true ),
0063         _viewDrawFocusIndicator( true ),
0064         _viewDrawTreeBranchLines( true ),
0065         _viewDrawTriangularExpander( true ),
0066         _viewTriangularExpanderSize( ArrowSmall ),
0067         _viewInvertSortIndicator( false ),
0068         _menuHighlightMode( MM_DARK ),
0069         _windowDragEnabled( true ),
0070         _windowDragMode( WD_FULL ),
0071         _useWMMoveResize( true ),
0072         _startDragDist( 4 ),
0073         _startDragTime( 500 ),
0074         _animationsEnabled( true ),
0075         _genericAnimationsEnabled( true ),
0076         _menuBarAnimationType( Fade ),
0077         _menuAnimationType( Fade ),
0078         _toolBarAnimationType( Fade ),
0079         _genericAnimationsDuration( 150 ),
0080         _menuBarAnimationsDuration( 150 ),
0081         _menuBarFollowMouseAnimationsDuration( 80 ),
0082         _menuAnimationsDuration( 150 ),
0083         _menuFollowMouseAnimationsDuration( 40 ),
0084         _toolBarAnimationsDuration( 50 ),
0085         _buttonSize( ButtonDefault ),
0086         _frameBorder( BorderDefault ),
0087         _windecoBlendType( FollowStyleHint ),
0088         _activeShadowConfiguration( Palette::Active ),
0089         _inactiveShadowConfiguration( Palette::Inactive ),
0090         _backgroundOpacity( 255 ),
0091         _argbEnabled( true ),
0092         _widgetExplorerEnabled( true ),
0093         _initialized( false ),
0094         _kdeColorsInitialized( false ),
0095         _gtkColorsInitialized( false ),
0096         _KDESession( false )
0097     {}
0098 
0099     //_________________________________________________________
0100     bool QtSettings::initialize( unsigned int flags )
0101     {
0102 
0103         const bool forced( flags&Forced );
0104 
0105         // no attempt at initializing if gtk settings is not yet set
0106         if( !gtk_settings_get_default() ) return false;
0107 
0108         if( _initialized && !forced ) return false;
0109         else if( !forced ) _initialized = true;
0110 
0111         if( g_getenv( "KDE_FULL_SESSION" ) )
0112         { _KDESession = true; }
0113 
0114         // init application name
0115         if( flags & AppName )
0116         {
0117             initUserConfigDir();
0118             initApplicationName();
0119             initArgb();
0120         }
0121 
0122         // keep track of whats changed
0123         bool changed( false );
0124 
0125         // support for wm shadows
0126         {
0127             const bool wmShadowsSupported( isAtomSupported( ShadowHelper::netWMShadowAtomName ) );
0128             if( wmShadowsSupported != _wmShadowsSupported )
0129             {
0130                 _wmShadowsSupported = wmShadowsSupported;
0131                 changed |= true;
0132             }
0133         }
0134 
0135         // configuration path
0136         {
0137             const PathList old( _kdeConfigPathList );
0138             _kdeConfigPathList = kdeConfigPathList();
0139             changed |= (old != _kdeConfigPathList );
0140         }
0141 
0142         // icon path
0143         {
0144             const PathList old( _kdeIconPathList );
0145             _kdeIconPathList = kdeIconPathList();
0146             changed |= (old != _kdeIconPathList );
0147         }
0148 
0149         // load kdeglobals and oxygen option maps
0150         const bool kdeGlobalsChanged = loadKdeGlobals();
0151         const bool oxygenChanged = loadOxygen();
0152 
0153         // do nothing if settings not changed
0154         if( forced && !(changed||kdeGlobalsChanged||oxygenChanged) ) return false;
0155 
0156         // dialog button ordering
0157         /* TODO: in principle this should be needed only once */
0158         if( flags & Extra )
0159         {
0160             GtkSettings* settings( gtk_settings_get_default() );
0161             gtk_settings_set_long_property( settings, "gtk-alternative-button-order", 1, "oxygen-gtk" );
0162         }
0163 
0164         // clear gtkrc
0165         _rc.clear();
0166 
0167         // kde globals options
0168         if( flags & KdeGlobals )
0169         { loadKdeGlobalsOptions(); }
0170 
0171         // oxygen options
0172         if( flags & Oxygen )
0173         { loadOxygenOptions(); }
0174 
0175         #if !OXYGEN_FORCE_KDE_ICONS_AND_FONTS
0176         // TODO: Add support for gtk schemes when not _KDESession
0177         if( _KDESession )
0178         #endif
0179         {
0180 
0181             // reload fonts
0182             if( flags & Fonts )
0183             { loadKdeFonts(); }
0184 
0185             // reload icons
0186             #if OXYGEN_ICON_HACK
0187             if( flags & Icons )
0188             { loadKdeIcons(); }
0189             #endif
0190 
0191         }
0192 
0193         // color palette
0194         if( flags & Colors )
0195         {
0196             loadKdePalette( forced );
0197             generateGtkColors();
0198         }
0199 
0200         // apply extra programatically set metrics metrics
0201         if( flags & Extra )
0202         { loadExtraOptions(); }
0203 
0204         // print generated Gtkrc and commit
0205         #if OXYGEN_DEBUG
0206         std::cerr << "Oxygen::QtSettings::initialize - Gtkrc: " << std::endl;
0207         std::cerr << _rc << std::endl;
0208         #endif
0209 
0210         // pass all resources to gtk and clear
0211         _rc.commit();
0212 
0213         #if OXYGEN_DEBUG
0214         std::cerr << "Oxygen::QtSettings::initialize - done. " << std::endl;
0215         #endif
0216 
0217         return true;
0218 
0219     }
0220 
0221     //_________________________________________________________
0222     bool QtSettings::runCommand( const std::string& command, char*& result ) const
0223     { return g_spawn_command_line_sync( command.c_str(), &result, 0L, 0L, 0L ) && result; }
0224 
0225     //_________________________________________________________
0226     bool QtSettings::loadKdeGlobals( void )
0227     {
0228 
0229         // save backup
0230         OptionMap old = _kdeGlobals;
0231 
0232         // clear and reload
0233         _kdeGlobals.clear();
0234         for( PathList::const_reverse_iterator iter = _kdeConfigPathList.rbegin(); iter != _kdeConfigPathList.rend(); ++iter )
0235         {
0236             const std::string filename( sanitizePath( *iter + "/kdeglobals" ) );
0237             _kdeGlobals.merge( OptionMap( filename ) );
0238             monitorFile( filename );
0239         }
0240 
0241         #if OXYGEN_DEBUG
0242         std::cerr << "Oxygen::QtSettings::loadKdeGlobals - kdeglobals: " << std::endl;
0243         std::cerr << _kdeGlobals << std::endl;
0244         #endif
0245 
0246         // check change
0247         return old != _kdeGlobals;
0248 
0249     }
0250 
0251     //_______________________________________________________
0252     bool QtSettings::isAtomSupported( const std::string& atomNameQuery ) const
0253     {
0254 
0255         // create atom
0256         #ifdef GDK_WINDOWING_X11
0257 
0258         // get screen and check
0259         GdkScreen* screen = gdk_screen_get_default();
0260         if( !screen ) return false;
0261 
0262         // get display and check
0263         GdkDisplay *gdkDisplay( gdk_screen_get_display( screen ) );
0264         Display* display( GDK_DISPLAY_XDISPLAY( gdkDisplay ) );
0265 
0266         // create atom
0267         Atom netSupportedAtom( XInternAtom( display, "_NET_SUPPORTED", False) );
0268         if( !netSupportedAtom ) return false;
0269 
0270         // root window
0271         Window root( GDK_WINDOW_XID( gdk_screen_get_root_window( screen ) ) );
0272         if( !root ) return false;
0273 
0274         Atom type;
0275         int format;
0276         unsigned char *data;
0277         unsigned long count;
0278         unsigned long after;
0279         int length = 32768;
0280 
0281         while( true )
0282         {
0283 
0284             // get atom property on root window
0285             // length is incremented until after is zero
0286             if( XGetWindowProperty(
0287                 display, root,
0288                 netSupportedAtom, 0l, length,
0289                 false, XA_ATOM, &type,
0290                 &format, &count, &after, &data) != Success ) return false;
0291 
0292             if( after == 0 ) break;
0293 
0294             // free data, increase length
0295             XFree( data );
0296             length *= 2;
0297             continue;
0298 
0299         }
0300 
0301         Atom* atoms = reinterpret_cast<Atom*>( data );
0302         bool found( false );
0303         for( unsigned long i = 0; i<count && !found; i++ )
0304         {
0305             char* atomName = XGetAtomName( display, atoms[i]);
0306             if( strcmp( atomName, atomNameQuery.c_str() ) == 0 ) found = true;
0307             XFree( atomName );
0308         }
0309 
0310         return found;
0311 
0312         #else
0313         return false;
0314         #endif
0315 
0316     }
0317 
0318     //_________________________________________________________
0319     bool QtSettings::loadOxygen( void )
0320     {
0321 
0322         // save backup
0323         OptionMap old = _oxygen;
0324 
0325         // clear and reload
0326         _oxygen.clear();
0327         for( PathList::const_reverse_iterator iter = _kdeConfigPathList.rbegin(); iter != _kdeConfigPathList.rend(); ++iter )
0328         {
0329             const std::string filename( sanitizePath( *iter + "/oxygenrc" ) );
0330             _oxygen.merge( filename );
0331             monitorFile( filename );
0332         }
0333 
0334         #if OXYGEN_DEBUG
0335         std::cerr << "Oxygen::QtSettings::loadOxygen - Oxygenrc: " << std::endl;
0336         std::cerr << _oxygen << std::endl;
0337         #endif
0338 
0339         // check change
0340         return old != _oxygen;
0341 
0342     }
0343 
0344     //_________________________________________________________
0345     PathList QtSettings::kdeConfigPathList( void ) const
0346     {
0347 
0348         PathList out;
0349 
0350         // load icon install prefix
0351         gchar* path = 0L;
0352         if( runCommand( "kde4-config --path config", path ) && path )
0353         {
0354 
0355             out.split( path );
0356             g_free( path );
0357 
0358         } else {
0359 
0360             out.push_back( userConfigDir() );
0361 
0362         }
0363 
0364         out.push_back( GTK_THEME_DIR );
0365 
0366         #if OXYGEN_DEBUG
0367         std::cerr << "Oxygen::QtSettings::kdeConfigPathList - loading configuration from path: " << std::endl;
0368         std::cerr << out << std::endl;
0369         #endif
0370 
0371         return out;
0372 
0373     }
0374 
0375     //_________________________________________________________
0376     PathList QtSettings::kdeIconPathList( void ) const
0377     {
0378 
0379         // load icon install prefix
0380         PathList out;
0381         char* path = 0L;
0382         if( runCommand( "kde4-config --path icon", path ) && path )
0383         {
0384             out.split( path );
0385             g_free( path );
0386         }
0387 
0388         // make sure defaultKdeIconPath is included in the list
0389         if( std::find( out.begin(), out.end(), _defaultKdeIconPath ) == out.end() )
0390         { out.push_back( _defaultKdeIconPath ); }
0391 
0392         return out;
0393 
0394     }
0395 
0396     //_________________________________________________________
0397     void QtSettings::initUserConfigDir( void )
0398     {
0399 
0400         // create directory name
0401         _userConfigDir = std::string( g_get_user_config_dir() ) + "/oxygen-gtk";
0402 
0403         // make sure that corresponding directory does exist
0404         struct stat st;
0405         if( stat( _userConfigDir.c_str(), &st ) != 0 )
0406         {
0407             #ifdef G_OS_WIN32
0408             // S_IRWXG and S_IRWXO are undefined on Windows, and g_mkdir()
0409             // ignores its second parameter on Windows anyway.
0410             g_mkdir( _userConfigDir.c_str(), 0 );
0411             #else
0412             g_mkdir( _userConfigDir.c_str(), S_IRWXU|S_IRWXG|S_IRWXO );
0413             #endif
0414         }
0415 
0416         // note: in some cases, the target might exist and not be a directory
0417         // nothing we can do about it. We won't overwrite the file to prevent dataloss
0418 
0419     }
0420 
0421     //_________________________________________________________
0422     void QtSettings::initArgb( void )
0423     {
0424         // get program name
0425         const char* appName = g_get_prgname();
0426         if( !appName ) return;
0427 
0428         // user-defined configuration file
0429         const std::string userConfig( userConfigDir() + "/argb-apps.conf");
0430 
0431         // make sure user configuration file exists
0432         std::ofstream newConfig( userConfig.c_str(), std::ios::app );
0433         if( newConfig )
0434         {
0435             // if the file is empty (newly created), put a hint there
0436             if( !newConfig.tellp() )
0437             { newConfig << "# argb-apps.conf\n# Put your user-specific ARGB app settings here\n\n"; }
0438             newConfig.close();
0439 
0440         }
0441 
0442         // check for ARGB hack being disabled
0443         if(g_getenv("OXYGEN_DISABLE_ARGB_HACK"))
0444         {
0445             std::cerr << "Oxygen::QtSettings::initArgb - ARGB hack is disabled; program name: " << appName << std::endl;
0446             std::cerr << "Oxygen::QtSettings::initArgb - if disabling ARGB hack helps, please add this string:\n\ndisable:" << appName << "\n\nto ~/.config/oxygen-gtk/argb-apps.conf\nand report it here: https://bugs.kde.org/show_bug.cgi?id=260640" << std::endl;
0447             _argbEnabled = false;
0448             return;
0449         }
0450 
0451         // get debug flag from environement
0452         const bool OXYGEN_ARGB_DEBUG = g_getenv("OXYGEN_ARGB_DEBUG");
0453 
0454         // read blacklist
0455         // system-wide configuration file
0456         const std::string configFile( std::string( GTK_THEME_DIR ) + "/argb-apps.conf" );
0457         std::ifstream systemIn( configFile.c_str() );
0458         if( !systemIn )
0459         {
0460 
0461             if( G_UNLIKELY(OXYGEN_DEBUG||OXYGEN_ARGB_DEBUG) )
0462             { std::cerr << "Oxygen::QtSettings::initArgb - ARGB config file \"" << configFile << "\" not found" << std::endl; }
0463 
0464         }
0465 
0466         // load options into a string
0467         std::string contents;
0468         std::vector<std::string> lines;
0469         while( std::getline( systemIn, contents, '\n' ) )
0470         {
0471             if( contents.empty() || contents[0] == '#' ) continue;
0472             lines.push_back( contents );
0473         }
0474 
0475         // user specific blacklist
0476         std::ifstream userIn( userConfig.c_str() );
0477         if( !userIn )
0478         {
0479 
0480             if( G_UNLIKELY(OXYGEN_DEBUG||OXYGEN_ARGB_DEBUG) )
0481             { std::cerr << "Oxygen::QtSettings::initArgb - user-defined ARGB config file \"" << userConfig << "\" not found - only system-wide one will be used" << std::endl; }
0482 
0483         }
0484 
0485         // load options into a string
0486         while( std::getline( userIn, contents, '\n' ) )
0487         {
0488             if( contents.empty() || contents[0] == '#' ) continue;
0489             lines.push_back( contents );
0490         }
0491 
0492         // true if application was found in one of the lines
0493         bool found( false );
0494         for( std::vector<std::string>::const_reverse_iterator iter = lines.rbegin(); iter != lines.rend() && !found; ++iter )
0495         {
0496 
0497             // store line locally
0498             std::string contents( *iter );
0499 
0500             // split string using ":" as a delimiter
0501             std::vector<std::string> appNames;
0502             size_t position( std::string::npos );
0503             while( ( position = contents.find( ':' ) ) != std::string::npos )
0504             {
0505                 std::string appName( contents.substr(0, position ) );
0506                 if( !appName.empty() ) { appNames.push_back( appName ); }
0507                 contents = contents.substr( position+1 );
0508             }
0509 
0510             if( !contents.empty() ) appNames.push_back( contents );
0511             if( appNames.empty() ) continue;
0512 
0513             // check line type
0514             bool enabled( true );
0515             if( appNames[0] == "enable" ) enabled = true;
0516             else if( appNames[0] == "disable" ) enabled = false;
0517             else continue;
0518 
0519             // compare application names to this application
0520             for( unsigned int i = 1; i < appNames.size(); i++ )
0521             {
0522                 if( appNames[i] == "all" || appNames[i] == appName )
0523                 {
0524                     found = true;
0525                     _argbEnabled = enabled;
0526                     break;
0527                 }
0528             }
0529 
0530         }
0531 
0532     }
0533 
0534     //_________________________________________________________
0535     void QtSettings::addIconTheme( PathList& pathList, const std::string& theme )
0536     {
0537 
0538         // do nothing if theme have already been included in the loop
0539         if( _iconThemes.find( theme ) != _iconThemes.end() ) return;
0540         _iconThemes.insert( theme );
0541 
0542         #if OXYGEN_DEBUG
0543         std::cerr << "Oxygen::QtSettings::addIconTheme - adding " << theme << std::endl;
0544         #endif
0545 
0546         // add all possible path (based on _kdeIconPathList) and look for possible parent
0547         std::string parentTheme;
0548         for( PathList::const_iterator iter = _kdeIconPathList.begin(); iter != _kdeIconPathList.end(); ++iter )
0549         {
0550 
0551             // create path and check for existence
0552             std::string path( sanitizePath( *iter + '/' + theme ) );
0553             struct stat st;
0554             if( stat( path.c_str(), &st ) != 0 ) continue;
0555 
0556             // add to path list
0557             pathList.push_back( path );
0558             if( parentTheme.empty() )
0559             {
0560                 const std::string index( sanitizePath( *iter + '/' + theme + "/index.theme" ) );
0561                 OptionMap themeOptions( index );
0562                 parentTheme = themeOptions.getValue( "[Icon Theme]", "Inherits" );
0563             }
0564 
0565         }
0566 
0567         // add parent if needed
0568         if( !parentTheme.empty() )
0569         {
0570             // split using "," as a separator
0571             PathList parentThemes( parentTheme, "," );
0572             for( PathList::const_iterator iter = parentThemes.begin(); iter != parentThemes.end(); ++iter )
0573             { addIconTheme( pathList, *iter ); }
0574         }
0575 
0576         return;
0577 
0578     }
0579 
0580     //_________________________________________________________
0581     void QtSettings::loadKdeIcons( void )
0582     {
0583 
0584         // update icon search path
0585         // put existing default path in a set
0586         PathSet searchPath( defaultIconSearchPath() );
0587 
0588         // add kde's path. Loop is reversed because added path must be prepended.
0589         for( PathList::const_reverse_iterator iter = _kdeIconPathList.rbegin(); iter != _kdeIconPathList.rend(); ++iter )
0590         {
0591 
0592             // remove trailing backslash, if any
0593             std::string path( *iter );
0594             if( path.empty() ) continue;
0595             if( path[path.size()-1] == '/' ) path = path.substr( 0, path.size()-1 );
0596 
0597             // check if already present and prepend if not
0598             if( searchPath.find( path ) == searchPath.end() )
0599             { gtk_icon_theme_prepend_search_path(gtk_icon_theme_get_default(), path.c_str() ); }
0600         }
0601 
0602         // load icon theme and path to gtk
0603         _iconThemes.clear();
0604         _kdeIconTheme = _kdeGlobals.getValue( "[Icons]", "Theme", "oxygen" );
0605 
0606         // store to settings
0607         GtkSettings* settings( gtk_settings_get_default() );
0608 
0609         gtk_settings_set_string_property( settings, "gtk-icon-theme-name", _kdeIconTheme.c_str(), "oxygen-gtk" );
0610         gtk_settings_set_string_property( settings, "gtk-fallback-icon-theme-name", _kdeFallbackIconTheme.c_str(), "oxygen-gtk" );
0611 
0612         // load icon sizes from kde
0613         // const int desktopIconSize( _kdeGlobals.getOption( "[DesktopIcons]", "Size" ).toInt( 48 ) );
0614         const int dialogIconSize( _kdeGlobals.getOption( "[DialogIcons]", "Size" ).toInt( 32 ) );
0615         const int panelIconSize( _kdeGlobals.getOption( "[PanelIcons]", "Size" ).toInt( 32 ) );
0616         const int mainToolbarIconSize( _kdeGlobals.getOption( "[MainToolbarIcons]", "Size" ).toInt( 22 ) );
0617         const int smallIconSize( _kdeGlobals.getOption( "[SmallIcons]", "Size" ).toInt( 16 ) );
0618         const int toolbarIconSize( _kdeGlobals.getOption( "[ToolbarIcons]", "Size" ).toInt( 22 ) );
0619 
0620         // set gtk icon sizes
0621         _icons.setIconSize( "panel-menu", smallIconSize );
0622         _icons.setIconSize( "panel", panelIconSize );
0623         _icons.setIconSize( "gtk-small-toolbar", toolbarIconSize );
0624         _icons.setIconSize( "gtk-large-toolbar", mainToolbarIconSize );
0625         _icons.setIconSize( "gtk-dnd", mainToolbarIconSize );
0626         _icons.setIconSize( "gtk-button", smallIconSize );
0627         _icons.setIconSize( "gtk-menu", smallIconSize );
0628         _icons.setIconSize( "gtk-dialog", dialogIconSize );
0629         _icons.setIconSize( "", smallIconSize );
0630 
0631         // load translation table, generate full translation list, and path to gtk
0632         _icons.loadTranslations( sanitizePath( std::string( GTK_THEME_DIR ) + "/icons4" ) );
0633 
0634         // generate full path list
0635         PathList iconThemeList;
0636         addIconTheme( iconThemeList, _kdeIconTheme );
0637         addIconTheme( iconThemeList, _kdeFallbackIconTheme );
0638 
0639         _rc.merge( _icons.generate( iconThemeList ) );
0640 
0641     }
0642 
0643     //_________________________________________________________
0644     PathSet QtSettings::defaultIconSearchPath( void ) const
0645     {
0646         PathSet searchPath;
0647 
0648         // load icon theme
0649         GtkIconTheme* theme( gtk_icon_theme_get_default() );
0650         if( !GTK_IS_ICON_THEME( theme ) ) return searchPath;
0651 
0652         // get default
0653         gchar** gtkSearchPath;
0654         int nElements;
0655 
0656         gtk_icon_theme_get_search_path( theme, &gtkSearchPath, &nElements );
0657         for( int i=0; i<nElements; i++ )
0658         { searchPath.insert( gtkSearchPath[i] ); }
0659 
0660         // free
0661         g_strfreev( gtkSearchPath );
0662 
0663         return searchPath;
0664     }
0665 
0666     //_________________________________________________________
0667     void QtSettings::loadKdePalette( bool forced )
0668     {
0669 
0670         if( _kdeColorsInitialized && !forced ) return;
0671         _kdeColorsInitialized = true;
0672 
0673         // contrast
0674         ColorUtils::setContrast( _kdeGlobals.getOption( "[KDE]", "contrast" ).toVariant<double>( 7 ) / 10 );
0675 
0676         // palette
0677         _palette.clear();
0678         _palette.setColor( Palette::Active, Palette::Window, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:Window]", "BackgroundNormal" ) ) );
0679         _palette.setColor( Palette::Active, Palette::WindowText, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:Window]", "ForegroundNormal" ) ) );
0680 
0681         _palette.setColor( Palette::Active, Palette::Button, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:Button]", "BackgroundNormal" ) ) );
0682         _palette.setColor( Palette::Active, Palette::ButtonText, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:Button]", "ForegroundNormal" ) ) );
0683 
0684         _palette.setColor( Palette::Active, Palette::Selected, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:Selection]", "BackgroundNormal" ) ) );
0685         _palette.setColor( Palette::Active, Palette::SelectedText, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:Selection]", "ForegroundNormal" ) ) );
0686 
0687         _palette.setColor( Palette::Active, Palette::Tooltip, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:Tooltip]", "BackgroundNormal" ) ) );
0688         _palette.setColor( Palette::Active, Palette::TooltipText, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:Tooltip]", "ForegroundNormal" ) ) );
0689 
0690         _palette.setColor( Palette::Active, Palette::Focus, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:View]", "DecorationFocus" ) ) );
0691         _palette.setColor( Palette::Active, Palette::Hover, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:View]", "DecorationHover" ) ) );
0692 
0693         _palette.setColor( Palette::Active, Palette::Base, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:View]", "BackgroundNormal" ) ) );
0694         _palette.setColor( Palette::Active, Palette::BaseAlternate, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:View]", "BackgroundAlternate" ) ) );
0695         _palette.setColor( Palette::Active, Palette::Text, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:View]", "ForegroundNormal" ) ) );
0696         _palette.setColor( Palette::Active, Palette::NegativeText, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:View]", "ForegroundNegative" ) ) );
0697 
0698         _palette.setColor( Palette::Active, Palette::ActiveWindowBackground, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[WM]", "activeBackground" ) ) );
0699         _palette.setColor( Palette::Active, Palette::InactiveWindowBackground, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[WM]", "inactiveBackground" ) ) );
0700 
0701         // load effects
0702         const ColorUtils::Effect disabledEffect( Palette::Disabled, _kdeGlobals );
0703         const ColorUtils::Effect inactiveEffect( Palette::Inactive, _kdeGlobals );
0704 
0705         // generate inactive and disabled palette from active, applying effects from kdeglobals
0706         _inactiveChangeSelectionColor = ( _kdeGlobals.getOption( "[ColorEffects:Inactive]", "ChangeSelectionColor" ).toVariant<std::string>( "false" ) == "true" );
0707         _palette.generate( Palette::Active, Palette::Inactive, inactiveEffect, _inactiveChangeSelectionColor );
0708         _palette.generate( Palette::Active, Palette::Disabled, disabledEffect );
0709 
0710         #if OXYGEN_DEBUG
0711         std::cerr << "Oxygen::QtSettings::loadKdePalette - disabled effect: " << std::endl;
0712         std::cerr << disabledEffect << std::endl;
0713 
0714         std::cerr << "Oxygen::QtSettings::loadKdePalette - inactive effect: " << std::endl;
0715         std::cerr << inactiveEffect << std::endl;
0716 
0717         std::cerr << "Oxygen::QtSettings::loadKdePalette - palette: " << std::endl;
0718         std::cerr << _palette << std::endl;
0719         #endif
0720 
0721     }
0722 
0723     //_________________________________________________________
0724     void QtSettings::generateGtkColors( void )
0725     {
0726 
0727         #if OXYGEN_DEBUG
0728         std::cerr << "Oxygen::QtSettings::generateGtkColors" << std::endl;
0729         #endif
0730 
0731         // customize gtk palette
0732         _palette.setGroup( Palette::Active );
0733 
0734         // default colors
0735         _rc.setCurrentSection( Gtk::RC::defaultSection() );
0736         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[NORMAL]", _palette.color( Palette::Window ) ) );
0737         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[PRELIGHT]", _palette.color( Palette::Window ) ) );
0738         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[ACTIVE]", _palette.color( Palette::Window ) ) );
0739 
0740         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[SELECTED]", _palette.color( Palette::Selected ) ) );
0741         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[INSENSITIVE]", _palette.color( Palette::Window ) ) );
0742 
0743         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[NORMAL]", _palette.color( Palette::WindowText ) ) );
0744         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[ACTIVE]", _palette.color( Palette::WindowText ) ) );
0745         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[PRELIGHT]", _palette.color( Palette::WindowText ) ) );
0746         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[SELECTED]", _palette.color( Palette::WindowText ) ) );
0747         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[INSENSITIVE]", _palette.color( Palette::Disabled, Palette::WindowText ) ) );
0748 
0749         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  base[NORMAL]", _palette.color( Palette::Base ) ) );
0750 
0751         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  base[ACTIVE]", _palette.color( Palette::Inactive, Palette::Selected ) ) );
0752         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  base[PRELIGHT]", _palette.color( Palette::Base ) ) );
0753         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  base[SELECTED]", _palette.color( Palette::Selected ) ) );
0754         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  base[INSENSITIVE]", _palette.color( Palette::Disabled, Palette::Base ) ) );
0755 
0756         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[NORMAL]", _palette.color( Palette::Text ) ) );
0757 
0758         if( _inactiveChangeSelectionColor ) _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[ACTIVE]", _palette.color( Palette::Text ) ) );
0759         else _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[ACTIVE]", _palette.color( Palette::SelectedText ) ) );
0760 
0761         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[PRELIGHT]", _palette.color( Palette::Text ) ) );
0762         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[SELECTED]", _palette.color( Palette::SelectedText ) ) );
0763         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[INSENSITIVE]", _palette.color( Palette::Disabled, Palette::Text ) ) );
0764         addLinkColors( "[Colors:Window]" );
0765 
0766         // buttons
0767         _rc.addSection( "oxygen-buttons-internal", Gtk::RC::defaultSection() );
0768         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[NORMAL]", _palette.color( Palette::Button ) ) );
0769         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[ACTIVE]", _palette.color( Palette::Button ) ) );
0770         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[PRELIGHT]", _palette.color( Palette::Button ) ) );
0771         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[INSENSITIVE]", _palette.color( Palette::Disabled, Palette::Button ) ) );
0772         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[NORMAL]", _palette.color( Palette::ButtonText ) ) );
0773         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[ACTIVE]", _palette.color( Palette::ButtonText ) ) );
0774         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[PRELIGHT]", _palette.color( Palette::ButtonText ) ) );
0775         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[INSENSITIVE]", _palette.color( Palette::Disabled, Palette::ButtonText ) ) );
0776         addLinkColors( "[Colors:Button]" );
0777 
0778         _rc.matchClassToSection( "*Button", "oxygen-buttons-internal" );
0779         _rc.matchClassToSection( "GtkOptionMenu", "oxygen-buttons-internal" );
0780         _rc.matchWidgetClassToSection( "*<GtkButton>.<GtkLabel>", "oxygen-buttons-internal" );
0781         _rc.matchWidgetClassToSection( "*<GtkButton>.<GtkAlignment>.<GtkBox>.<GtkLabel>", "oxygen-buttons-internal" );
0782 
0783         // combobox
0784         _rc.addSection( "oxygen-combobox-internal", "oxygen-buttons-internal" );
0785         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[NORMAL]", _palette.color( Palette::ButtonText ) ) );
0786         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[ACTIVE]", _palette.color( Palette::ButtonText ) ) );
0787         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[PRELIGHT]", _palette.color( Palette::ButtonText ) ) );
0788         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[INSENSITIVE]", _palette.color( Palette::Disabled, Palette::ButtonText ) ) );
0789         _rc.matchWidgetClassToSection( "*<GtkComboBox>.*<GtkCellView>", "oxygen-combobox-internal" );
0790 
0791         // checkboxes and radio buttons
0792         _rc.addSection( "oxygen-checkbox-buttons-internal", "oxygen-buttons-internal" );
0793         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[NORMAL]", _palette.color( Palette::WindowText ) ) );
0794         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[ACTIVE]", _palette.color( Palette::WindowText ) ) );
0795         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[PRELIGHT]", _palette.color( Palette::WindowText ) ) );
0796         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[INSENSITIVE]", _palette.color( Palette::Disabled, Palette::WindowText ) ) );
0797         _rc.matchWidgetClassToSection( "*<GtkCheckButton>.<GtkLabel>", "oxygen-checkbox-buttons-internal" );
0798 
0799         // progressbar labels
0800         _rc.addSection( "oxygen-progressbar-internal", Gtk::RC::defaultSection() );
0801         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[NORMAL]", _palette.color( Palette::WindowText ) ) );
0802         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[ACTIVE]", _palette.color( Palette::WindowText ) ) );
0803         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[PRELIGHT]", _palette.color( Palette::WindowText ) ) );
0804         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[INSENSITIVE]", _palette.color( Palette::Disabled, Palette::WindowText ) ) );
0805 
0806         _rc.matchClassToSection( "GtkProgressBar", "oxygen-progressbar-internal" );
0807 
0808         // menu items
0809         _rc.addSection( "oxygen-menubar-item-internal", "oxygen-menu-font-internal" );
0810         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[NORMAL]", _palette.color( Palette::Text ) ) );
0811         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[NORMAL]", _palette.color( Palette::WindowText ) ) );
0812 
0813         if( _menuHighlightMode == MM_STRONG )
0814         {
0815 
0816             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[PRELIGHT]", _palette.color( Palette::Text ) ) );
0817             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[SELECTED]", _palette.color( Palette::SelectedText ) ) );
0818             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[ACTIVE]", _palette.color( Palette::SelectedText ) ) );
0819             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[PRELIGHT]", _palette.color( Palette::WindowText ) ) );
0820             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[SELECTED]", _palette.color( Palette::SelectedText ) ) );
0821             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[ACTIVE]", _palette.color( Palette::SelectedText ) ) );
0822 
0823         } else {
0824 
0825             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[PRELIGHT]", _palette.color( Palette::Text ) ) );
0826             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[SELECTED]", _palette.color( Palette::Text ) ) );
0827             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[ACTIVE]", _palette.color( Palette::Text ) ) );
0828             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[PRELIGHT]", _palette.color( Palette::WindowText ) ) );
0829             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[SELECTED]", _palette.color( Palette::WindowText ) ) );
0830             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[ACTIVE]", _palette.color( Palette::WindowText ) ) );
0831 
0832         }
0833         _rc.matchWidgetClassToSection( "*<GtkMenuItem>.<GtkLabel>", "oxygen-menubar-item-internal" );
0834 
0835 
0836         if( _menuHighlightMode == MM_STRONG )
0837         {
0838             _rc.addSection( "oxygen-menu-item-internal", "oxygen-menubar-item-internal" );
0839             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[PRELIGHT]", _palette.color( Palette::SelectedText ) ) );
0840             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[PRELIGHT]", _palette.color( Palette::SelectedText ) ) );
0841             _rc.matchWidgetClassToSection( "*<GtkMenu>.<GtkMenuItem>.<GtkLabel>", "oxygen-menu-item-internal" );
0842         }
0843 
0844         // text entries
0845         _rc.addSection( "oxygen-entry-internal", Gtk::RC::defaultSection() );
0846         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[NORMAL]", _palette.color( Palette::Base ) ) );
0847         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[INSENSITIVE]", _palette.color( Palette::Disabled, Palette::Base ) ) );
0848         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  base[INSENSITIVE]", _palette.color( Palette::Disabled, Palette::Base ) ) );
0849         addLinkColors( "[Colors:View]" );
0850         _rc.matchClassToSection( "GtkSpinButton", "oxygen-entry-internal" );
0851         _rc.matchClassToSection( "GtkEntry", "oxygen-entry-internal" );
0852         _rc.matchClassToSection( "GtkTextView", "oxygen-entry-internal" );
0853         _rc.matchWidgetClassToSection( "*<GtkComboBoxEntry>.<GtkButton>", "oxygen-entry-internal" );
0854         _rc.matchWidgetClassToSection( "*<GtkCombo>.<GtkButton>", "oxygen-entry-internal" );
0855 
0856         // tooltips
0857         _rc.addSection( "oxygen-tooltips-internal", Gtk::RC::defaultSection() );
0858         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[NORMAL]", _palette.color( Palette::Tooltip ) ) );
0859         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[NORMAL]", _palette.color( Palette::TooltipText ) ) );
0860         _rc.addToCurrentSection( Gtk::RCOption<int>( "  xthickness", 3 ) );
0861         _rc.addToCurrentSection( Gtk::RCOption<int>( "  ythickness", 3 ) );
0862         addLinkColors( "[Colors:Tooltip]" );
0863 
0864         _rc.matchWidgetToSection( "gtk-tooltip*", "oxygen-tooltips-internal" );
0865 
0866         // special case for google chrome
0867         /* based on http://code.google.com/p/chromium/wiki/LinuxGtkThemeIntegration */
0868         _rc.addSection( "oxygen-chrome-gtk-frame-internal", Gtk::RC::defaultSection() );
0869         _rc.addToCurrentSection( Gtk::RCOption<std::string>( " ChromeGtkFrame::frame-color", _palette.color( Palette::Window ) ) );
0870         _rc.addToCurrentSection( Gtk::RCOption<std::string>( " ChromeGtkFrame::inactive-frame-color", _palette.color( Palette::Window ) ) );
0871         _rc.matchClassToSection( "ChromeGtkFrame", "oxygen-chrome-gtk-frame-internal" );
0872 
0873     }
0874 
0875 
0876     //_________________________________________________________
0877     void QtSettings::addLinkColors( const std::string& section )
0878     {
0879 
0880         {
0881             // link colors
0882             // from http://ubuntuforums.org/showthread.php?p=7009302
0883             const ColorUtils::Rgba linkColor( ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( section, "ForegroundLink" ) ) );
0884             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  GtkWidget::link-color", linkColor ) );
0885             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  GtkHTML::alink_color", linkColor ) );
0886             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  GtkHTML::link_color", linkColor ) );
0887             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  GnomeHref::link-color", linkColor ) );
0888             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  GtkIMHtml::hyperlink-color", linkColor ) );
0889             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  GtkIMHtml::hyperlink-prelight-color", linkColor ) );
0890         }
0891 
0892         {
0893             // visited link colors
0894             // from http://ubuntuforums.org/showthread.php?p=7009302
0895             const ColorUtils::Rgba visitedLinkColor( ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( section, "ForegroundVisited" ) ) );
0896             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  GtkWidget::visited-link-color", visitedLinkColor ) );
0897             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  GtkHTML::vlink_color", visitedLinkColor ) );
0898         }
0899 
0900     }
0901 
0902     //_________________________________________________________
0903     void QtSettings::loadKdeFonts( void )
0904     {
0905 
0906         // try load default font
0907         FontInfo::Map fonts;
0908         FontInfo defaultFont;
0909         if( _kdeGlobals.hasOption( "[General]", "font" ) )
0910         {
0911 
0912             defaultFont = FontInfo::fromKdeOption( _kdeGlobals.getValue( "[General]", "font", "" ) );
0913 
0914         } else {
0915 
0916             #if OXYGEN_DEBUG
0917             std::cerr << "Oxygen::QtSettings::loadKdeFonts - cannot load default font" << std::endl;
0918             #endif
0919 
0920         }
0921 
0922         fonts[FontInfo::Default] = defaultFont;
0923 
0924         // load extra fonts
0925         typedef std::map<FontInfo::FontType, std::string> FontNameMap;
0926         FontNameMap optionNames;
0927         optionNames.insert( std::make_pair( FontInfo::Desktop, "desktopFont" ) );
0928         optionNames.insert( std::make_pair( FontInfo::Fixed, "fixed" ) );
0929         optionNames.insert( std::make_pair( FontInfo::Menu, "menuFont" ) );
0930         optionNames.insert( std::make_pair( FontInfo::ToolBar, "toolBarFont" ) );
0931         for( FontNameMap::const_iterator iter = optionNames.begin(); iter != optionNames.end(); ++iter )
0932         {
0933             FontInfo local;
0934             if( _kdeGlobals.hasOption( "[General]", iter->second ) )
0935             {
0936 
0937                 local = FontInfo::fromKdeOption( _kdeGlobals.getValue( "[General]", iter->second, "" ) );
0938 
0939             } else {
0940 
0941                 #if OXYGEN_DEBUG
0942                 std::cerr << "Oxygen::QtSettings::loadKdeFonts - cannot load font named " << iter->second << std::endl;
0943                 #endif
0944                 local = defaultFont;
0945 
0946             }
0947 
0948             // store in map
0949             fonts[iter->first] = local;
0950 
0951         }
0952 
0953         // pass fonts to RC
0954         if( fonts[FontInfo::Default].isValid() )
0955         {
0956             // pass to settings
0957             GtkSettings* settings( gtk_settings_get_default() );
0958             gtk_settings_set_string_property( settings, "gtk-font-name", fonts[FontInfo::Default].toString( false ).c_str(), "oxygen-gtk" );
0959 
0960             _rc.setCurrentSection( Gtk::RC::defaultSection() );
0961             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  font_name", fonts[FontInfo::Default].toString() ) );
0962         }
0963 
0964         if( fonts[FontInfo::Menu].isValid() )
0965         {
0966             _rc.addSection( "oxygen-menu-font-internal", Gtk::RC::defaultSection() );
0967             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  font_name", fonts[FontInfo::Menu].toString() ) );
0968             _rc.matchWidgetClassToSection( "*<GtkMenuItem>.<GtkLabel>", "oxygen-menu-font-internal" );
0969         }
0970 
0971         if( fonts[FontInfo::ToolBar].isValid() )
0972         {
0973             _rc.addSection( "oxygen-toolbar-font-internal", Gtk::RC::defaultSection() );
0974             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  font_name", fonts[FontInfo::ToolBar].toString() ) );
0975             _rc.matchWidgetClassToSection( "*<GtkToolbar>.*", "oxygen-toolbar-font-internal" );
0976         }
0977 
0978         // don't check for section and tag presence - use default font if not present
0979         _WMFont=FontInfo::fromKdeOption( _kdeGlobals.getValue( "[WM]", "activeFont", "Sans Serif,8,-1,5,50,0,0,0,0,0" ) );
0980 
0981     }
0982 
0983     //_________________________________________________________
0984     void QtSettings::loadKdeGlobalsOptions( void )
0985     {
0986 
0987         #if OXYGEN_DEBUG
0988         std::cerr << "Oxygen::QtSettings::loadKdeGlobalsOptions" << std::endl;
0989         #endif
0990 
0991         // toolbar style
0992         const std::string toolbarTextPosition( _kdeGlobals.getOption( "[Toolbar style]", "ToolButtonStyle" ).toVariant<std::string>( "TextBelowIcon" ) );
0993         GtkToolbarStyle toolbarStyle( GTK_TOOLBAR_BOTH );
0994         if( toolbarTextPosition == "TextOnly" ) toolbarStyle = GTK_TOOLBAR_TEXT;
0995         else if( toolbarTextPosition == "TextBesideIcon" ) toolbarStyle = GTK_TOOLBAR_BOTH_HORIZ;
0996         else if( toolbarTextPosition == "NoText" ) toolbarStyle = GTK_TOOLBAR_ICONS;
0997 
0998         GtkSettings* settings( gtk_settings_get_default() );
0999         gtk_settings_set_long_property( settings, "gtk-toolbar-style", toolbarStyle, "oxygen-gtk" );
1000 
1001         // icons on buttons
1002         if( _kdeGlobals.getValue( "[KDE]", "ShowIconsOnPushButtons", "true" ) == "false" )
1003         { gtk_settings_set_long_property( settings, "gtk-button-images", 0, "oxygen-gtk" ); }
1004 
1005         // active icon effects
1006         _useIconEffect = _kdeGlobals.getOption( "[MainToolbarIcons]", "ActiveEffect" ).toVariant<std::string>( "gamma" ) != "none";
1007 
1008         // start drag time and distance
1009         _startDragDist = _kdeGlobals.getOption( "[KDE]", "StartDragDist" ).toVariant<int>( 4 );
1010         _startDragTime = _kdeGlobals.getOption( "[KDE]", "StartDragTime" ).toVariant<int>( 500 );
1011 
1012     }
1013 
1014     //_________________________________________________________
1015     void QtSettings::loadOxygenOptions( void )
1016     {
1017 
1018         // background pixmap
1019         _backgroundPixmap = _oxygen.getValue( "[Common]", "BackgroundPixmap", "" );
1020 
1021         // background gradient
1022         _useBackgroundGradient = ( _oxygen.getValue( "[Common]", "UseBackgroundGradient", "true" ) == "true" );
1023 
1024         // checkbox style
1025         _checkBoxStyle = (_oxygen.getValue( "[Style]", "CheckBoxStyle", "CS_CHECK" ) == "CS_CHECK") ? CS_CHECK:CS_X;
1026 
1027         // checkbox style
1028         _tabStyle = (_oxygen.getValue( "[Style]", "TabStyle", "TS_SINGLE" ) == "TS_SINGLE") ? TS_SINGLE:TS_PLAIN;
1029 
1030         // scrollbar buttons
1031         _scrollBarAddLineButtons = _oxygen.getOption( "[Style]", "ScrollBarAddLineButtons" ).toVariant<int>( 2 );
1032         _scrollBarSubLineButtons = _oxygen.getOption( "[Style]", "ScrollBarSubLineButtons" ).toVariant<int>( 1 );
1033 
1034         // toolbar separators
1035         _toolBarDrawItemSeparator = _oxygen.getOption( "[Style]", "ToolBarDrawItemSeparator" ).toVariant<std::string>("true") == "true";
1036 
1037         // tooltips
1038         _tooltipTransparent = _oxygen.getOption( "[Style]", "ToolTipTransparent" ).toVariant<std::string>("true") == "true";
1039         _tooltipDrawStyledFrames = _oxygen.getOption( "[Style]", "ToolTipDrawStyledFrames" ).toVariant<std::string>("true") == "true";
1040 
1041         // focus indicator in views
1042         _viewDrawFocusIndicator = _oxygen.getOption( "[Style]", "ViewDrawFocusIndicator" ).toVariant<std::string>("true") == "true";
1043 
1044         // tree branch lines
1045         _viewDrawTreeBranchLines = _oxygen.getOption( "[Style]", "ViewDrawTreeBranchLines" ).toVariant<std::string>("true") == "true";
1046 
1047         // triangular expanders
1048         _viewDrawTriangularExpander = _oxygen.getOption( "[Style]", "ViewDrawTriangularExpander" ).toVariant<std::string>("true") == "true";
1049 
1050         // triangular expander (arrow) size
1051         std::string expanderSize( _oxygen.getOption( "[Style]", "ViewTriangularExpanderSize" ).toVariant<std::string>("TE_SMALL") );
1052         if( expanderSize == "TE_NORMAL" ) _viewTriangularExpanderSize = ArrowNormal;
1053         else if( expanderSize == "TE_TINY" ) _viewTriangularExpanderSize = ArrowTiny;
1054         else _viewTriangularExpanderSize = ArrowSmall;
1055 
1056         // invert view sort indicators
1057         _viewInvertSortIndicator = _oxygen.getOption( "[Style]", "ViewInvertSortIndicator" ).toVariant<std::string>("false") == "true";
1058 
1059         // menu highlight mode
1060         std::string highlightMode( _oxygen.getOption( "[Style]", "MenuHighlightMode" ).toVariant<std::string>("MM_DARK") );
1061         if( highlightMode == "MM_SUBTLE" ) _menuHighlightMode = MM_SUBTLE;
1062         else if( highlightMode == "MM_STRONG" ) _menuHighlightMode = MM_STRONG;
1063         else _menuHighlightMode = MM_DARK;
1064 
1065         // window drag mode
1066         _windowDragEnabled = _oxygen.getOption( "[Style]", "WindowDragEnabled" ).toVariant<std::string>("true") == "true";
1067 
1068         std::string windowDragMode( _oxygen.getOption( "[Style]", "WindowDragMode" ).toVariant<std::string>("WD_FULL") );
1069         if( windowDragMode == "WD_MINIMAL" ) _windowDragMode = WD_MINIMAL;
1070         else _windowDragMode = WD_FULL;
1071 
1072         // use window manager to handle window drag
1073         _useWMMoveResize = _oxygen.getOption( "[Style]", "UseWMMoveResize" ).toVariant<std::string>("true") == "true";
1074 
1075         // animations
1076         _animationsEnabled = ( _oxygen.getOption( "[Style]", "AnimationsEnabled" ).toVariant<std::string>("true") == "true" );
1077         _genericAnimationsEnabled = ( _oxygen.getOption( "[Style]", "GenericAnimationsEnabled" ).toVariant<std::string>("true") == "true" );
1078 
1079         // menubar animation type
1080         std::string menuBarAnimationType( _oxygen.getValue( "[Style]", "MenuBarAnimationType", "MB_FADE") );
1081         if( menuBarAnimationType == "MB_NONE" ) _menuBarAnimationType = NoAnimation;
1082         else if( menuBarAnimationType == "MB_FADE" ) _menuBarAnimationType = Fade;
1083         else if( menuBarAnimationType == "MB_FOLLOW_MOUSE" ) _menuBarAnimationType = FollowMouse;
1084 
1085         // menubar animation type
1086         std::string menuAnimationType( _oxygen.getValue( "[Style]", "MenuAnimationType", "ME_FADE") );
1087         if( menuAnimationType == "ME_NONE" ) _menuAnimationType = NoAnimation;
1088         else if( menuAnimationType == "ME_FADE" ) _menuAnimationType = Fade;
1089         else if( menuAnimationType == "ME_FOLLOW_MOUSE" ) _menuAnimationType = FollowMouse;
1090 
1091         // toolbar animation type
1092         std::string toolBarAnimationType( _oxygen.getValue( "[Style]", "ToolBarAnimationType", "TB_FADE") );
1093         if( toolBarAnimationType == "TB_NONE" ) _toolBarAnimationType = NoAnimation;
1094         else if( toolBarAnimationType == "TB_FADE" ) _toolBarAnimationType = Fade;
1095         else if( toolBarAnimationType == "TB_FOLLOW_MOUSE" ) _toolBarAnimationType = FollowMouse;
1096 
1097         // animations duration
1098         _genericAnimationsDuration = _oxygen.getOption( "[Style]", "GenericAnimationsDuration" ).toVariant<int>(150);
1099         _menuBarAnimationsDuration = _oxygen.getOption( "[Style]", "MenuBarAnimationsDuration" ).toVariant<int>(150);
1100         _menuBarFollowMouseAnimationsDuration = _oxygen.getOption( "[Style]", "MenuBarFollowMouseAnimationsDuration" ).toVariant<int>(80);
1101         _menuAnimationsDuration = _oxygen.getOption( "[Style]", "MenuAnimationsDuration" ).toVariant<int>(150);
1102         _menuFollowMouseAnimationsDuration = _oxygen.getOption( "[Style]", "MenuFollowMouseAnimationsDuration" ).toVariant<int>(40);
1103         _toolBarAnimationsDuration = _oxygen.getOption( "[Style]", "ToolBarAnimationsDuration" ).toVariant<int>(50);
1104 
1105         // animation steps
1106         TimeLine::setSteps( _oxygen.getOption( "[Style]", "AnimationSteps" ).toVariant<int>( 10 ) );
1107 
1108         // widget explorer
1109         _widgetExplorerEnabled =
1110             _oxygen.getOption( "[Style]", "WidgetExplorerEnabled" ).toVariant<std::string>("false") == "true" ||
1111             _oxygen.getOption( "[Style]", "WidgetExplorerGtkEnabled" ).toVariant<std::string>("false") == "true";
1112 
1113         // window decoration button size
1114         std::string buttonSize( _oxygen.getValue( "[Windeco]", "ButtonSize", "Normal") );
1115         if( buttonSize == "Small" ) _buttonSize = ButtonSmall;
1116         else if( buttonSize == "Large" ) _buttonSize = ButtonLarge;
1117         else if( buttonSize == "Very Large" ) _buttonSize = ButtonVeryLarge;
1118         else if( buttonSize == "Huge" ) _buttonSize = ButtonHuge;
1119         else _buttonSize = ButtonDefault;
1120 
1121         // window decoration frame border size
1122         std::string frameBorder(  _oxygen.getValue( "[Windeco]", "FrameBorder", "Normal") );
1123         if( frameBorder == "No Border" ) _frameBorder = BorderNone;
1124         else if( frameBorder == "No Side Border" ) _frameBorder = BorderNoSide;
1125         else if( frameBorder == "Tiny" ) _frameBorder = BorderTiny;
1126         else if( frameBorder == "Large" ) _frameBorder = BorderLarge;
1127         else if( frameBorder == "Very Large" ) _frameBorder = BorderVeryLarge;
1128         else if( frameBorder == "Huge" ) _frameBorder = BorderHuge;
1129         else if( frameBorder == "Very Huge" ) _frameBorder = BorderVeryHuge;
1130         else if( frameBorder == "Oversized" ) _frameBorder = BorderOversized;
1131         else _frameBorder = BorderDefault;
1132 
1133         // window decoration title alignment
1134         std::string titleAlign( _oxygen.getValue( "[Windeco]", "TitleAlignment", "Center" ) );
1135         if( titleAlign == "Left" ) _titleAlignment = PANGO_ALIGN_LEFT;
1136         else if( titleAlign == "Center" ) _titleAlignment = PANGO_ALIGN_CENTER;
1137         else if( titleAlign == "Right" ) _titleAlignment = PANGO_ALIGN_RIGHT;
1138         else _titleAlignment = PANGO_ALIGN_CENTER;
1139 
1140         // window decoration radial gradient enable option
1141         std::string wdBlendType( _oxygen.getValue( "[Windeco]", "BlendColor", "Follow Style Hint" ) );
1142         if( wdBlendType == "Follow Style Hint" ) _windecoBlendType=FollowStyleHint;
1143         else if( wdBlendType == "Radial Gradient" ) _windecoBlendType=RadialGradient;
1144         else if( wdBlendType == "Solid Color" ) _windecoBlendType=SolidColor;
1145         else _windecoBlendType=FollowStyleHint;
1146 
1147         // shadow configurations
1148         _activeShadowConfiguration.initialize( _oxygen );
1149         _inactiveShadowConfiguration.initialize( _oxygen );
1150 
1151         if(_kdeGlobals.getOption( "[General]", "widgetStyle" ).toVariant<std::string>("oxygen") == "oxygen transparent")
1152         {
1153             _backgroundOpacity = _oxygen.getOption( "[Common]", "BackgroundOpacity" ).toVariant<int>(255);
1154 
1155         } else {
1156 
1157             _backgroundOpacity = 255;
1158 
1159         }
1160 
1161         #if OXYGEN_DEBUG
1162         std::cerr << _activeShadowConfiguration << std::endl;
1163         std::cerr << _inactiveShadowConfiguration << std::endl;
1164         #endif
1165 
1166         // copy relevant options to to gtk
1167         // scrollbar width
1168         _rc.setCurrentSection( Gtk::RC::defaultSection() );
1169         _rc.addToCurrentSection( Gtk::RCOption<int>(
1170             "  GtkScrollbar::slider-width",
1171             _oxygen.getOption( "[Style]", "ScrollBarWidth" ).toVariant<int>(15) + 1 ) );
1172 
1173         _rc.addToCurrentSection( Gtk::RCOption<bool>("  GtkScrollbar::has-backward-stepper", _scrollBarSubLineButtons > 0 ) );
1174         _rc.addToCurrentSection( Gtk::RCOption<bool>("  GtkScrollbar::has-forward-stepper", _scrollBarAddLineButtons > 0 ) );
1175 
1176         // note the inversion for add and sub, due to the fact that kde options refer to the button location, and not its direction
1177         _rc.addToCurrentSection( Gtk::RCOption<bool>("  GtkScrollbar::has-secondary-backward-stepper", _scrollBarAddLineButtons > 1 ) );
1178         _rc.addToCurrentSection( Gtk::RCOption<bool>("  GtkScrollbar::has-secondary-forward-stepper", _scrollBarSubLineButtons > 1 ) );
1179 
1180         // mnemonics
1181         GtkSettings* settings( gtk_settings_get_default() );
1182         if( _oxygen.hasOption( "[Style]", "MnemonicsMode" ) )
1183         {
1184 
1185             const std::string mnemonicsMode( _oxygen.getOption( "[Style]", "MnemonicsMode" ).toVariant<std::string>("MN_ALWAYS") );
1186             if( mnemonicsMode == "MN_NEVER" )
1187             {
1188 
1189                 gtk_settings_set_long_property( settings, "gtk-enable-mnemonics", false, "oxygen-gtk" );
1190                 gtk_settings_set_long_property( settings, "gtk-auto-mnemonics", false, "oxygen-gtk" );
1191 
1192             } else if( mnemonicsMode == "MN_AUTO" ) {
1193 
1194                 gtk_settings_set_long_property( settings, "gtk-enable-mnemonics", true, "oxygen-gtk" );
1195                 gtk_settings_set_long_property( settings, "gtk-auto-mnemonics", true, "oxygen-gtk" );
1196 
1197             } else {
1198 
1199                 gtk_settings_set_long_property( settings, "gtk-enable-mnemonics", true, "oxygen-gtk" );
1200                 gtk_settings_set_long_property( settings, "gtk-auto-mnemonics", false, "oxygen-gtk" );
1201 
1202             }
1203 
1204         } else {
1205 
1206             // for backward compatibility
1207             const bool showMnemonics( _oxygen.getOption( "[Style]", "ShowMnemonics" ).toVariant<std::string>("true") == "true" );
1208             if( showMnemonics )
1209             {
1210 
1211                 gtk_settings_set_long_property( settings, "gtk-enable-mnemonics", true, "oxygen-gtk" );
1212                 gtk_settings_set_long_property( settings, "gtk-auto-mnemonics", false, "oxygen-gtk" );
1213 
1214             } else {
1215 
1216                 gtk_settings_set_long_property( settings, "gtk-enable-mnemonics", false, "oxygen-gtk" );
1217                 gtk_settings_set_long_property( settings, "gtk-auto-mnemonics", false, "oxygen-gtk" );
1218 
1219             }
1220 
1221         }
1222 
1223     }
1224 
1225     //_________________________________________________________
1226     void QtSettings::loadExtraOptions( void )
1227     {
1228 
1229         // deal with pathbar button margins
1230         // this needs to be done programatically in order to properly account for RTL locales
1231         _rc.addSection( "oxygen-pathbutton-internal", Gtk::RC::defaultSection() );
1232         _rc.addToCurrentSection( "  GtkButton::inner-border = { 2, 2, 1, 0 }" );
1233 
1234         if( gtk_widget_get_default_direction() == GTK_TEXT_DIR_RTL )
1235         {
1236 
1237             _rc.addToCurrentSection( "  GtkToggleButton::inner-border={ 10, 0, 1, 0 }" );
1238 
1239         } else {
1240 
1241             _rc.addToCurrentSection( "  GtkToggleButton::inner-border={ 0, 10, 1, 0 }" );
1242 
1243         }
1244 
1245         _rc.matchWidgetClassToSection( "*PathBar.GtkToggleButton", "oxygen-pathbutton-internal" );
1246 
1247         // entry margins
1248         _rc.addSection( "oxygen-entry-margins-internal", Gtk::RC::defaultSection() );
1249         _rc.addToCurrentSection( Gtk::RCOption<int>( "  xthickness", 5 ) );
1250         _rc.addToCurrentSection( Gtk::RCOption<int>( "  ythickness", applicationName().isXul() ? 2:1 ) );
1251         _rc.matchClassToSection( "GtkEntry", "oxygen-entry-margins-internal" );
1252 
1253         // combobox buttons
1254         _rc.addSection( "oxygen-combobox-button-internal", Gtk::RC::defaultSection() );
1255         _rc.addToCurrentSection( Gtk::RCOption<int>( "  xthickness", 2 ) );
1256         _rc.addToCurrentSection( Gtk::RCOption<int>( "  ythickness", applicationName().isXul() ? 2:0 ) );
1257         _rc.matchWidgetClassToSection( "*<GtkComboBox>.<GtkButton>", "oxygen-combobox-button-internal" );
1258 
1259     }
1260 
1261     //_________________________________________________________
1262     std::string QtSettings::sanitizePath( const std::string& path ) const
1263     {
1264 
1265         std::string out( path );
1266         size_t position( std::string::npos );
1267         while( ( position = out.find( "//" ) ) != std::string::npos )
1268         { out.replace( position, 2, "/" ); }
1269 
1270         return out;
1271     }
1272 
1273     //_________________________________________________________
1274     void QtSettings::monitorFile( const std::string& filename )
1275     {
1276 
1277         // check if file was already added
1278         if( _monitoredFiles.find( filename ) != _monitoredFiles.end() )
1279         { return; }
1280 
1281         // check file existence
1282         if( !std::ifstream( filename.c_str() ) )
1283         { return; }
1284 
1285         // create FileMonitor
1286         FileMonitor monitor;
1287         monitor.file = g_file_new_for_path( filename.c_str() );
1288         if( ( monitor.monitor = g_file_monitor( monitor.file, G_FILE_MONITOR_NONE, 0L, 0L ) ) )
1289         {
1290 
1291             // insert in map
1292             _monitoredFiles.insert( std::make_pair( filename, monitor ) );
1293 
1294         } else {
1295 
1296             // clear file and return
1297             g_object_unref( monitor.file );
1298             return;
1299 
1300         }
1301 
1302     }
1303 
1304     //_________________________________________________________
1305     void QtSettings::clearMonitoredFiles( void )
1306     {
1307         for( FileMap::iterator iter = _monitoredFiles.begin(); iter != _monitoredFiles.end(); iter++ )
1308         {
1309             iter->second.signal.disconnect();
1310             g_object_unref( iter->second.file );
1311             g_object_unref( iter->second.monitor );
1312         }
1313 
1314         _monitoredFiles.clear();
1315     }
1316 
1317 }