1 /*
2 * this file is part of the oxygen gtk engine
3 * Copyright (c) 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
4 * Copyright (c) 2010 Ruslan Kabatsayev <b7.10110111@gmail.com>
5 *
6 * This  library is free  software; you can  redistribute it and/or
7 * modify it  under  the terms  of the  GNU Lesser  General  Public
8 * License  as published  by the Free  Software  Foundation; either
9 * version 2 of the License, or( at your option ) any later version.
10 *
11 * This library is distributed  in the hope that it will be useful,
12 * but  WITHOUT ANY WARRANTY; without even  the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License  along  with  this library;  if not,  write to  the Free
18 * Software Foundation, Inc., 51  Franklin St, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21 
22 #include "oxygenqtsettings.h"
23 #include "oxygencoloreffect.h"
24 #include "oxygencolorutils.h"
25 #include "oxygenfontinfo.h"
26 #include "oxygengtkicons.h"
27 #include "oxygengtkrc.h"
28 #include "oxygentimeline.h"
29 #include "config.h"
30 
31 #include <glib.h>
32 #include <glib/gstdio.h>
33 #include <gtk/gtk.h>
34 
35 #include <algorithm>
36 #include <cstdio>
37 #include <cstdlib>
38 #include <cstring>
39 #include <sys/stat.h>
40 #include <fstream>
41 #include <iostream>
42 #include <sstream>
43 
44 namespace Oxygen
45 {
46 
47     //_________________________________________________________
48     const std::string QtSettings::_defaultKdeIconPath = "/usr/share/icons/";
49 
50     //_________________________________________________________
51     /*
52     Note: the default values set in the constructor are actually ignored.
53     Real default values are set via Oxygen::QtSettings::loadKdeGlobalsOptions,
54     from the oxygenrc file provided with oxygen-gtk
55     */
QtSettings(void)56     QtSettings::QtSettings( void ):
57         _kdeIconTheme( "oxygen" ),
58         _kdeFallbackIconTheme( "gnome" ),
59         _inactiveChangeSelectionColor( false ),
60         _useIconEffect( true ),
61         _useBackgroundGradient( true ),
62         _checkBoxStyle( CS_CHECK ),
63         _tabStyle( TS_SINGLE ),
64         _scrollBarAddLineButtons( 2 ),
65         _scrollBarSubLineButtons( 1 ),
66         _toolBarDrawItemSeparator( true ),
67         _tooltipTransparent( true ),
68         _tooltipDrawStyledFrames( true ),
69         _viewDrawFocusIndicator( true ),
70         _viewDrawTreeBranchLines( true ),
71         _viewDrawTriangularExpander( true ),
72         _viewTriangularExpanderSize( ArrowSmall ),
73         _viewInvertSortIndicator( false ),
74         _menuHighlightMode( MM_DARK ),
75         _windowDragEnabled( true ),
76         _windowDragMode( WD_FULL ),
77         _useWMMoveResize( true ),
78         _startDragDist( 4 ),
79         _startDragTime( 500 ),
80         _animationsEnabled( true ),
81         _genericAnimationsEnabled( true ),
82         _menuBarAnimationType( Fade ),
83         _menuAnimationType( Fade ),
84         _toolBarAnimationType( Fade ),
85         _genericAnimationsDuration( 150 ),
86         _menuBarAnimationsDuration( 150 ),
87         _menuBarFollowMouseAnimationsDuration( 80 ),
88         _menuAnimationsDuration( 150 ),
89         _menuFollowMouseAnimationsDuration( 40 ),
90         _toolBarAnimationsDuration( 50 ),
91         _buttonSize( ButtonDefault ),
92         _frameBorder( BorderDefault ),
93         _windecoBlendType( FollowStyleHint ),
94         _activeShadowConfiguration( Palette::Active ),
95         _inactiveShadowConfiguration( Palette::Inactive ),
96         _backgroundOpacity( 255 ),
97         _argbEnabled( true ),
98         _initialized( false ),
99         _kdeColorsInitialized( false ),
100         _gtkColorsInitialized( false ),
101         _KDESession( false )
102     {}
103 
104     //_________________________________________________________
initialize(unsigned int flags)105     bool QtSettings::initialize( unsigned int flags )
106     {
107 
108         const bool forced( flags&Forced );
109 
110         // no attempt at initializing if gtk settings is not yet set
111         if( !gtk_settings_get_default() ) return false;
112 
113         if( _initialized && !forced ) return false;
114         else if( !forced ) _initialized = true;
115 
116         if( g_getenv( "KDE_FULL_SESSION" ) )
117         { _KDESession = true; }
118 
119         // init application name
120         if( flags & AppName )
121         {
122             initUserConfigDir();
123             initApplicationName();
124             initArgb();
125         }
126 
127         // keep track of whats changed
128         bool changed( false );
129 
130         // configuration path
131         {
132             const PathList old( _kdeConfigPathList );
133             _kdeConfigPathList = kdeConfigPathList();
134             changed |= (old != _kdeConfigPathList );
135         }
136 
137         // icon path
138         {
139             const PathList old( _kdeIconPathList );
140             _kdeIconPathList = kdeIconPathList();
141             changed |= (old != _kdeIconPathList );
142         }
143 
144         // load kdeglobals and oxygen option maps
145         const bool kdeGlobalsChanged = loadKdeGlobals();
146         const bool oxygenChanged = loadOxygen();
147 
148         // do nothing if settings not changed
149         if( forced && !(changed||kdeGlobalsChanged||oxygenChanged) ) return false;
150 
151         // dialog button ordering
152         /* TODO: in principle this should be needed only once */
153         if( flags & Extra )
154         {
155             GtkSettings* settings( gtk_settings_get_default() );
156             gtk_settings_set_long_property( settings, "gtk-alternative-button-order", 1, "oxygen-gtk" );
157         }
158 
159         // clear gtkrc
160         _rc.clear();
161 
162         // kde globals options
163         if( flags & KdeGlobals )
164         { loadKdeGlobalsOptions(); }
165 
166         // oxygen options
167         if( flags & Oxygen )
168         { loadOxygenOptions(); }
169 
170         #if !OXYGEN_FORCE_KDE_ICONS_AND_FONTS
171         // TODO: Add support for gtk schemes when not _KDESession
172         if( _KDESession )
173         #endif
174         {
175 
176             // reload fonts
177             if( flags & Fonts )
178             { loadKdeFonts(); }
179 
180             // reload icons
181             #if OXYGEN_ICON_HACK
182             if( flags & Icons )
183             { loadKdeIcons(); }
184             #endif
185 
186         }
187 
188         // color palette
189         if( flags & Colors )
190         {
191             loadKdePalette( forced );
192             generateGtkColors();
193         }
194 
195         // apply extra programatically set metrics metrics
196         if( flags & Extra )
197         { loadExtraOptions(); }
198 
199         // print generated Gtkrc and commit
200         #if OXYGEN_DEBUG
201         std::cerr << "Oxygen::QtSettings::initialize - Gtkrc: " << std::endl;
202         std::cerr << _rc << std::endl;
203         #endif
204 
205         // pass all resources to gtk and clear
206         _rc.commit();
207 
208         #if OXYGEN_DEBUG
209         std::cerr << "Oxygen::QtSettings::initialize - done. " << std::endl;
210         #endif
211 
212         return true;
213 
214     }
215 
216     //_________________________________________________________
runCommand(const std::string & command,char * & result) const217     bool QtSettings::runCommand( const std::string& command, char*& result ) const
218     { return g_spawn_command_line_sync( command.c_str(), &result, 0L, 0L, 0L ) && result; }
219 
220     //_________________________________________________________
loadKdeGlobals(void)221     bool QtSettings::loadKdeGlobals( void )
222     {
223 
224         // save backup
225         OptionMap old = _kdeGlobals;
226 
227         // clear and reload
228         _kdeGlobals.clear();
229         for( PathList::const_reverse_iterator iter = _kdeConfigPathList.rbegin(); iter != _kdeConfigPathList.rend(); ++iter )
230         {
231             const std::string filename( sanitizePath( *iter + "/kdeglobals" ) );
232             _kdeGlobals.merge( OptionMap( filename ) );
233             monitorFile( filename );
234         }
235 
236         #if OXYGEN_DEBUG
237         std::cerr << "Oxygen::QtSettings::loadKdeGlobals - kdeglobals: " << std::endl;
238         std::cerr << _kdeGlobals << std::endl;
239         #endif
240 
241         // check change
242         return old != _kdeGlobals;
243 
244     }
245 
246     //_________________________________________________________
loadOxygen(void)247     bool QtSettings::loadOxygen( void )
248     {
249 
250         // save backup
251         OptionMap old = _oxygen;
252 
253         // clear and reload
254         _oxygen.clear();
255         for( PathList::const_reverse_iterator iter = _kdeConfigPathList.rbegin(); iter != _kdeConfigPathList.rend(); ++iter )
256         {
257             const std::string filename( sanitizePath( *iter + "/oxygenrc" ) );
258             _oxygen.merge( filename );
259             monitorFile( filename );
260         }
261 
262         #if OXYGEN_DEBUG
263         std::cerr << "Oxygen::QtSettings::loadOxygen - Oxygenrc: " << std::endl;
264         std::cerr << _oxygen << std::endl;
265         #endif
266 
267         // check change
268         return old != _oxygen;
269 
270     }
271 
272     //_________________________________________________________
kdeConfigPathList(void) const273     PathList QtSettings::kdeConfigPathList( void ) const
274     {
275 
276         PathList out;
277 
278         // load icon install prefix
279         gchar* path = 0L;
280         if( runCommand( "kde4-config --path config", path ) && path )
281         {
282 
283             out.split( path );
284             g_free( path );
285 
286         } else {
287 
288             out.push_back( userConfigDir() );
289 
290         }
291 
292         out.push_back( GTK_THEME_DIR );
293 
294         #if OXYGEN_DEBUG
295         std::cerr << "Oxygen::QtSettings::kdeConfigPathList - loading configuration from path: " << std::endl;
296         std::cerr << out << std::endl;
297         #endif
298 
299         return out;
300 
301     }
302 
303     //_________________________________________________________
kdeIconPathList(void) const304     PathList QtSettings::kdeIconPathList( void ) const
305     {
306 
307         // load icon install prefix
308         PathList out;
309         char* path = 0L;
310         if( runCommand( "kde4-config --path icon", path ) && path )
311         {
312             out.split( path );
313             g_free( path );
314         }
315 
316         // make sure defaultKdeIconPath is included in the list
317         if( std::find( out.begin(), out.end(), _defaultKdeIconPath ) == out.end() )
318         { out.push_back( _defaultKdeIconPath ); }
319 
320         return out;
321 
322     }
323 
324     //_________________________________________________________
initUserConfigDir(void)325     void QtSettings::initUserConfigDir( void )
326     {
327 
328         // create directory name
329         _userConfigDir = std::string( g_get_user_config_dir() ) + "/oxygen-gtk";
330 
331         // make sure that corresponding directory does exist
332         struct stat st;
333         if( stat( _userConfigDir.c_str(), &st ) != 0 )
334         {
335             #ifdef G_OS_WIN32
336             // S_IRWXG and S_IRWXO are undefined on Windows, and g_mkdir()
337             // ignores its second parameter on Windows anyway.
338             g_mkdir( _userConfigDir.c_str(), 0 );
339             #else
340             g_mkdir( _userConfigDir.c_str(), S_IRWXU|S_IRWXG|S_IRWXO );
341             #endif
342         }
343 
344         // note: in some cases, the target might exist and not be a directory
345         // nothing we can do about it. We won't overwrite the file to prevent dataloss
346 
347     }
348 
349     //_________________________________________________________
initArgb(void)350     void QtSettings::initArgb( void )
351     {
352         // get program name
353         const char* appName = g_get_prgname();
354         if( !appName ) return;
355 
356         // user-defined configuration file
357         const std::string userConfig( userConfigDir() + "/argb-apps.conf");
358 
359         // make sure user configuration file exists
360         std::ofstream newConfig( userConfig.c_str(), std::ios::app );
361         if( newConfig )
362         {
363             // if the file is empty (newly created), put a hint there
364             if( !newConfig.tellp() )
365             { newConfig << "# argb-apps.conf\n# Put your user-specific ARGB app settings here\n\n"; }
366             newConfig.close();
367 
368         }
369 
370         // check for ARGB hack being disabled
371         if(g_getenv("OXYGEN_DISABLE_ARGB_HACK"))
372         {
373             std::cerr << "Oxygen::QtSettings::initArgb - ARGB hack is disabled; program name: " << appName << std::endl;
374             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;
375             _argbEnabled = false;
376             return;
377         }
378 
379         // get debug flag from environement
380         const bool OXYGEN_ARGB_DEBUG = g_getenv("OXYGEN_ARGB_DEBUG");
381 
382         // read blacklist
383         // system-wide configuration file
384         const std::string configFile( std::string( GTK_THEME_DIR ) + "/argb-apps.conf" );
385         std::ifstream systemIn( configFile.c_str() );
386         if( !systemIn )
387         {
388 
389             if( G_UNLIKELY(OXYGEN_DEBUG||OXYGEN_ARGB_DEBUG) )
390             { std::cerr << "Oxygen::QtSettings::initArgb - ARGB config file \"" << configFile << "\" not found" << std::endl; }
391 
392         }
393 
394         // load options into a string
395         std::string contents;
396         std::vector<std::string> lines;
397         while( std::getline( systemIn, contents, '\n' ) )
398         {
399             if( contents.empty() || contents[0] == '#' ) continue;
400             lines.push_back( contents );
401         }
402 
403         // user specific blacklist
404         std::ifstream userIn( userConfig.c_str() );
405         if( !userIn )
406         {
407 
408             if( G_UNLIKELY(OXYGEN_DEBUG||OXYGEN_ARGB_DEBUG) )
409             { std::cerr << "Oxygen::QtSettings::initArgb - user-defined ARGB config file \"" << userConfig << "\" not found - only system-wide one will be used" << std::endl; }
410 
411         }
412 
413         // load options into a string
414         while( std::getline( userIn, contents, '\n' ) )
415         {
416             if( contents.empty() || contents[0] == '#' ) continue;
417             lines.push_back( contents );
418         }
419 
420         // true if application was found in one of the lines
421         bool found( false );
422         for( std::vector<std::string>::const_reverse_iterator iter = lines.rbegin(); iter != lines.rend() && !found; ++iter )
423         {
424 
425             // store line locally
426             std::string contents( *iter );
427 
428             // split string using ":" as a delimiter
429             std::vector<std::string> appNames;
430             size_t position( std::string::npos );
431             while( ( position = contents.find( ':' ) ) != std::string::npos )
432             {
433                 std::string appName( contents.substr(0, position ) );
434                 if( !appName.empty() ) { appNames.push_back( appName ); }
435                 contents = contents.substr( position+1 );
436             }
437 
438             if( !contents.empty() ) appNames.push_back( contents );
439             if( appNames.empty() ) continue;
440 
441             // check line type
442             bool enabled( true );
443             if( appNames[0] == "enable" ) enabled = true;
444             else if( appNames[0] == "disable" ) enabled = false;
445             else continue;
446 
447             // compare application names to this application
448             for( unsigned int i = 1; i < appNames.size(); i++ )
449             {
450                 if( appNames[i] == "all" || appNames[i] == appName )
451                 {
452                     found = true;
453                     _argbEnabled = enabled;
454                     break;
455                 }
456             }
457 
458         }
459 
460     }
461 
462     //_________________________________________________________
addIconTheme(PathList & pathList,const std::string & theme)463     void QtSettings::addIconTheme( PathList& pathList, const std::string& theme )
464     {
465 
466         // do nothing if theme have already been included in the loop
467         if( _iconThemes.find( theme ) != _iconThemes.end() ) return;
468         _iconThemes.insert( theme );
469 
470         #if OXYGEN_DEBUG
471         std::cerr << "Oxygen::QtSettings::addIconTheme - adding " << theme << std::endl;
472         #endif
473 
474         // add all possible path (based on _kdeIconPathList) and look for possible parent
475         std::string parentTheme;
476         for( PathList::const_iterator iter = _kdeIconPathList.begin(); iter != _kdeIconPathList.end(); ++iter )
477         {
478 
479             // create path and check for existence
480             std::string path( sanitizePath( *iter + '/' + theme ) );
481             struct stat st;
482             if( stat( path.c_str(), &st ) != 0 ) continue;
483 
484             // add to path list
485             pathList.push_back( path );
486             if( parentTheme.empty() )
487             {
488                 const std::string index( sanitizePath( *iter + '/' + theme + "/index.theme" ) );
489                 OptionMap themeOptions( index );
490                 parentTheme = themeOptions.getValue( "[Icon Theme]", "Inherits" );
491             }
492 
493         }
494 
495         // add parent if needed
496         if( !parentTheme.empty() )
497         {
498             // split using "," as a separator
499             PathList parentThemes( parentTheme, "," );
500             for( PathList::const_iterator iter = parentThemes.begin(); iter != parentThemes.end(); ++iter )
501             { addIconTheme( pathList, *iter ); }
502         }
503 
504         return;
505 
506     }
507 
508     //_________________________________________________________
loadKdeIcons(void)509     void QtSettings::loadKdeIcons( void )
510     {
511 
512         // update icon search path
513         // put existing default path in a set
514         PathSet searchPath( defaultIconSearchPath() );
515 
516         // add kde's path. Loop is reversed because added path must be prepended.
517         for( PathList::const_reverse_iterator iter = _kdeIconPathList.rbegin(); iter != _kdeIconPathList.rend(); ++iter )
518         {
519 
520             // remove trailing backslash, if any
521             std::string path( *iter );
522             if( path.empty() ) continue;
523             if( path[path.size()-1] == '/' ) path = path.substr( 0, path.size()-1 );
524 
525             // check if already present and prepend if not
526             if( searchPath.find( path ) == searchPath.end() )
527             { gtk_icon_theme_prepend_search_path(gtk_icon_theme_get_default(), path.c_str() ); }
528         }
529 
530         // load icon theme and path to gtk
531         _iconThemes.clear();
532         _kdeIconTheme = _kdeGlobals.getValue( "[Icons]", "Theme", "oxygen" );
533 
534         // store to settings
535         GtkSettings* settings( gtk_settings_get_default() );
536 
537         gtk_settings_set_string_property( settings, "gtk-icon-theme-name", _kdeIconTheme.c_str(), "oxygen-gtk" );
538         gtk_settings_set_string_property( settings, "gtk-fallback-icon-theme-name", _kdeFallbackIconTheme.c_str(), "oxygen-gtk" );
539 
540         // load icon sizes from kde
541         // const int desktopIconSize( _kdeGlobals.getOption( "[DesktopIcons]", "Size" ).toInt( 48 ) );
542         const int dialogIconSize( _kdeGlobals.getOption( "[DialogIcons]", "Size" ).toInt( 32 ) );
543         const int panelIconSize( _kdeGlobals.getOption( "[PanelIcons]", "Size" ).toInt( 32 ) );
544         const int mainToolbarIconSize( _kdeGlobals.getOption( "[MainToolbarIcons]", "Size" ).toInt( 22 ) );
545         const int smallIconSize( _kdeGlobals.getOption( "[SmallIcons]", "Size" ).toInt( 16 ) );
546         const int toolbarIconSize( _kdeGlobals.getOption( "[ToolbarIcons]", "Size" ).toInt( 22 ) );
547 
548         // set gtk icon sizes
549         _icons.setIconSize( "panel-menu", smallIconSize );
550         _icons.setIconSize( "panel", panelIconSize );
551         _icons.setIconSize( "gtk-small-toolbar", toolbarIconSize );
552         _icons.setIconSize( "gtk-large-toolbar", mainToolbarIconSize );
553         _icons.setIconSize( "gtk-dnd", mainToolbarIconSize );
554         _icons.setIconSize( "gtk-button", smallIconSize );
555         _icons.setIconSize( "gtk-menu", smallIconSize );
556         _icons.setIconSize( "gtk-dialog", dialogIconSize );
557         _icons.setIconSize( "", smallIconSize );
558 
559         // load translation table, generate full translation list, and path to gtk
560         _icons.loadTranslations( sanitizePath( std::string( GTK_THEME_DIR ) + "/icons4" ) );
561 
562         // generate full path list
563         PathList iconThemeList;
564         addIconTheme( iconThemeList, _kdeIconTheme );
565         addIconTheme( iconThemeList, _kdeFallbackIconTheme );
566 
567         _rc.merge( _icons.generate( iconThemeList ) );
568 
569     }
570 
571     //_________________________________________________________
defaultIconSearchPath(void) const572     PathSet QtSettings::defaultIconSearchPath( void ) const
573     {
574         PathSet searchPath;
575 
576         // load icon theme
577         GtkIconTheme* theme( gtk_icon_theme_get_default() );
578         if( !GTK_IS_ICON_THEME( theme ) ) return searchPath;
579 
580         // get default
581         gchar** gtkSearchPath;
582         int nElements;
583 
584         gtk_icon_theme_get_search_path( theme, &gtkSearchPath, &nElements );
585         for( int i=0; i<nElements; i++ )
586         { searchPath.insert( gtkSearchPath[i] ); }
587 
588         // free
589         g_strfreev( gtkSearchPath );
590 
591         return searchPath;
592     }
593 
594     //_________________________________________________________
loadKdePalette(bool forced)595     void QtSettings::loadKdePalette( bool forced )
596     {
597 
598         if( _kdeColorsInitialized && !forced ) return;
599         _kdeColorsInitialized = true;
600 
601         // contrast
602         ColorUtils::setContrast( _kdeGlobals.getOption( "[KDE]", "contrast" ).toVariant<double>( 7 ) / 10 );
603 
604         // palette
605         _palette.clear();
606         _palette.setColor( Palette::Active, Palette::Window, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:Window]", "BackgroundNormal" ) ) );
607         _palette.setColor( Palette::Active, Palette::WindowText, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:Window]", "ForegroundNormal" ) ) );
608 
609         _palette.setColor( Palette::Active, Palette::Button, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:Button]", "BackgroundNormal" ) ) );
610         _palette.setColor( Palette::Active, Palette::ButtonText, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:Button]", "ForegroundNormal" ) ) );
611 
612         _palette.setColor( Palette::Active, Palette::Selected, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:Selection]", "BackgroundNormal" ) ) );
613         _palette.setColor( Palette::Active, Palette::SelectedText, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:Selection]", "ForegroundNormal" ) ) );
614 
615         _palette.setColor( Palette::Active, Palette::Tooltip, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:Tooltip]", "BackgroundNormal" ) ) );
616         _palette.setColor( Palette::Active, Palette::TooltipText, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:Tooltip]", "ForegroundNormal" ) ) );
617 
618         _palette.setColor( Palette::Active, Palette::Focus, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:View]", "DecorationFocus" ) ) );
619         _palette.setColor( Palette::Active, Palette::Hover, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:View]", "DecorationHover" ) ) );
620 
621         _palette.setColor( Palette::Active, Palette::Base, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:View]", "BackgroundNormal" ) ) );
622         _palette.setColor( Palette::Active, Palette::BaseAlternate, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:View]", "BackgroundAlternate" ) ) );
623         _palette.setColor( Palette::Active, Palette::Text, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:View]", "ForegroundNormal" ) ) );
624         _palette.setColor( Palette::Active, Palette::NegativeText, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[Colors:View]", "ForegroundNegative" ) ) );
625 
626         _palette.setColor( Palette::Active, Palette::ActiveWindowBackground, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[WM]", "activeBackground" ) ) );
627         _palette.setColor( Palette::Active, Palette::InactiveWindowBackground, ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( "[WM]", "inactiveBackground" ) ) );
628 
629         // load effects
630         const ColorUtils::Effect disabledEffect( Palette::Disabled, _kdeGlobals );
631         const ColorUtils::Effect inactiveEffect( Palette::Inactive, _kdeGlobals );
632 
633         // generate inactive and disabled palette from active, applying effects from kdeglobals
634         _inactiveChangeSelectionColor = ( _kdeGlobals.getOption( "[ColorEffects:Inactive]", "ChangeSelectionColor" ).toVariant<std::string>( "false" ) == "true" );
635         _palette.generate( Palette::Active, Palette::Inactive, inactiveEffect, _inactiveChangeSelectionColor );
636         _palette.generate( Palette::Active, Palette::Disabled, disabledEffect );
637 
638         #if OXYGEN_DEBUG
639         std::cerr << "Oxygen::QtSettings::loadKdePalette - disabled effect: " << std::endl;
640         std::cerr << disabledEffect << std::endl;
641 
642         std::cerr << "Oxygen::QtSettings::loadKdePalette - inactive effect: " << std::endl;
643         std::cerr << inactiveEffect << std::endl;
644 
645         std::cerr << "Oxygen::QtSettings::loadKdePalette - palette: " << std::endl;
646         std::cerr << _palette << std::endl;
647         #endif
648 
649     }
650 
651     //_________________________________________________________
generateGtkColors(void)652     void QtSettings::generateGtkColors( void )
653     {
654 
655         #if OXYGEN_DEBUG
656         std::cerr << "Oxygen::QtSettings::generateGtkColors" << std::endl;
657         #endif
658 
659         // customize gtk palette
660         _palette.setGroup( Palette::Active );
661 
662         // default colors
663         _rc.setCurrentSection( Gtk::RC::defaultSection() );
664         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[NORMAL]", _palette.color( Palette::Window ) ) );
665         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[PRELIGHT]", _palette.color( Palette::Window ) ) );
666         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[ACTIVE]", _palette.color( Palette::Window ) ) );
667 
668         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[SELECTED]", _palette.color( Palette::Selected ) ) );
669         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[INSENSITIVE]", _palette.color( Palette::Window ) ) );
670 
671         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[NORMAL]", _palette.color( Palette::WindowText ) ) );
672         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[ACTIVE]", _palette.color( Palette::WindowText ) ) );
673         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[PRELIGHT]", _palette.color( Palette::WindowText ) ) );
674         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[SELECTED]", _palette.color( Palette::WindowText ) ) );
675         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[INSENSITIVE]", _palette.color( Palette::Disabled, Palette::WindowText ) ) );
676 
677         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  base[NORMAL]", _palette.color( Palette::Base ) ) );
678 
679         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  base[ACTIVE]", _palette.color( Palette::Inactive, Palette::Selected ) ) );
680         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  base[PRELIGHT]", _palette.color( Palette::Base ) ) );
681         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  base[SELECTED]", _palette.color( Palette::Selected ) ) );
682         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  base[INSENSITIVE]", _palette.color( Palette::Disabled, Palette::Base ) ) );
683 
684         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[NORMAL]", _palette.color( Palette::Text ) ) );
685 
686         if( _inactiveChangeSelectionColor ) _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[ACTIVE]", _palette.color( Palette::Text ) ) );
687         else _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[ACTIVE]", _palette.color( Palette::SelectedText ) ) );
688 
689         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[PRELIGHT]", _palette.color( Palette::Text ) ) );
690         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[SELECTED]", _palette.color( Palette::SelectedText ) ) );
691         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[INSENSITIVE]", _palette.color( Palette::Disabled, Palette::Text ) ) );
692         addLinkColors( "[Colors:Window]" );
693 
694         // buttons
695         _rc.addSection( "oxygen-buttons-internal", Gtk::RC::defaultSection() );
696         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[NORMAL]", _palette.color( Palette::Button ) ) );
697         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[ACTIVE]", _palette.color( Palette::Button ) ) );
698         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[PRELIGHT]", _palette.color( Palette::Button ) ) );
699         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[INSENSITIVE]", _palette.color( Palette::Disabled, Palette::Button ) ) );
700         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[NORMAL]", _palette.color( Palette::ButtonText ) ) );
701         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[ACTIVE]", _palette.color( Palette::ButtonText ) ) );
702         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[PRELIGHT]", _palette.color( Palette::ButtonText ) ) );
703         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[INSENSITIVE]", _palette.color( Palette::Disabled, Palette::ButtonText ) ) );
704         addLinkColors( "[Colors:Button]" );
705 
706         _rc.matchClassToSection( "*Button", "oxygen-buttons-internal" );
707         _rc.matchClassToSection( "GtkOptionMenu", "oxygen-buttons-internal" );
708         _rc.matchWidgetClassToSection( "*<GtkButton>.<GtkLabel>", "oxygen-buttons-internal" );
709         _rc.matchWidgetClassToSection( "*<GtkButton>.<GtkAlignment>.<GtkBox>.<GtkLabel>", "oxygen-buttons-internal" );
710 
711         // combobox
712         _rc.addSection( "oxygen-combobox-internal", "oxygen-buttons-internal" );
713         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[NORMAL]", _palette.color( Palette::ButtonText ) ) );
714         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[ACTIVE]", _palette.color( Palette::ButtonText ) ) );
715         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[PRELIGHT]", _palette.color( Palette::ButtonText ) ) );
716         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[INSENSITIVE]", _palette.color( Palette::Disabled, Palette::ButtonText ) ) );
717         _rc.matchWidgetClassToSection( "*<GtkComboBox>.*<GtkCellView>", "oxygen-combobox-internal" );
718 
719         // checkboxes and radio buttons
720         _rc.addSection( "oxygen-checkbox-buttons-internal", "oxygen-buttons-internal" );
721         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[NORMAL]", _palette.color( Palette::WindowText ) ) );
722         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[ACTIVE]", _palette.color( Palette::WindowText ) ) );
723         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[PRELIGHT]", _palette.color( Palette::WindowText ) ) );
724         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[INSENSITIVE]", _palette.color( Palette::Disabled, Palette::WindowText ) ) );
725         _rc.matchWidgetClassToSection( "*<GtkCheckButton>.<GtkLabel>", "oxygen-checkbox-buttons-internal" );
726 
727         // progressbar labels
728         _rc.addSection( "oxygen-progressbar-internal", Gtk::RC::defaultSection() );
729         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[NORMAL]", _palette.color( Palette::WindowText ) ) );
730         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[ACTIVE]", _palette.color( Palette::WindowText ) ) );
731         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[PRELIGHT]", _palette.color( Palette::WindowText ) ) );
732         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[INSENSITIVE]", _palette.color( Palette::Disabled, Palette::WindowText ) ) );
733 
734         _rc.matchClassToSection( "GtkProgressBar", "oxygen-progressbar-internal" );
735 
736         // menu items
737         _rc.addSection( "oxygen-menubar-item-internal", "oxygen-menu-font-internal" );
738         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[NORMAL]", _palette.color( Palette::Text ) ) );
739         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[NORMAL]", _palette.color( Palette::WindowText ) ) );
740 
741         if( _menuHighlightMode == MM_STRONG )
742         {
743 
744             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[PRELIGHT]", _palette.color( Palette::Text ) ) );
745             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[SELECTED]", _palette.color( Palette::SelectedText ) ) );
746             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[ACTIVE]", _palette.color( Palette::SelectedText ) ) );
747             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[PRELIGHT]", _palette.color( Palette::WindowText ) ) );
748             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[SELECTED]", _palette.color( Palette::SelectedText ) ) );
749             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[ACTIVE]", _palette.color( Palette::SelectedText ) ) );
750 
751         } else {
752 
753             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[PRELIGHT]", _palette.color( Palette::Text ) ) );
754             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[SELECTED]", _palette.color( Palette::Text ) ) );
755             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[ACTIVE]", _palette.color( Palette::Text ) ) );
756             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[PRELIGHT]", _palette.color( Palette::WindowText ) ) );
757             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[SELECTED]", _palette.color( Palette::WindowText ) ) );
758             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[ACTIVE]", _palette.color( Palette::WindowText ) ) );
759 
760         }
761         _rc.matchWidgetClassToSection( "*<GtkMenuItem>.<GtkLabel>", "oxygen-menubar-item-internal" );
762 
763 
764         if( _menuHighlightMode == MM_STRONG )
765         {
766             _rc.addSection( "oxygen-menu-item-internal", "oxygen-menubar-item-internal" );
767             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  text[PRELIGHT]", _palette.color( Palette::SelectedText ) ) );
768             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[PRELIGHT]", _palette.color( Palette::SelectedText ) ) );
769             _rc.matchWidgetClassToSection( "*<GtkMenu>.<GtkMenuItem>.<GtkLabel>", "oxygen-menu-item-internal" );
770         }
771 
772         // text entries
773         _rc.addSection( "oxygen-entry-internal", Gtk::RC::defaultSection() );
774         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[NORMAL]", _palette.color( Palette::Base ) ) );
775         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[INSENSITIVE]", _palette.color( Palette::Disabled, Palette::Base ) ) );
776         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  base[INSENSITIVE]", _palette.color( Palette::Disabled, Palette::Base ) ) );
777         addLinkColors( "[Colors:View]" );
778         _rc.matchClassToSection( "GtkSpinButton", "oxygen-entry-internal" );
779         _rc.matchClassToSection( "GtkEntry", "oxygen-entry-internal" );
780         _rc.matchClassToSection( "GtkTextView", "oxygen-entry-internal" );
781         _rc.matchWidgetClassToSection( "*<GtkComboBoxEntry>.<GtkButton>", "oxygen-entry-internal" );
782         _rc.matchWidgetClassToSection( "*<GtkCombo>.<GtkButton>", "oxygen-entry-internal" );
783 
784         // tooltips
785         _rc.addSection( "oxygen-tooltips-internal", Gtk::RC::defaultSection() );
786         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  bg[NORMAL]", _palette.color( Palette::Tooltip ) ) );
787         _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  fg[NORMAL]", _palette.color( Palette::TooltipText ) ) );
788         _rc.addToCurrentSection( Gtk::RCOption<int>( "  xthickness", 3 ) );
789         _rc.addToCurrentSection( Gtk::RCOption<int>( "  ythickness", 3 ) );
790         addLinkColors( "[Colors:Tooltip]" );
791 
792         _rc.matchWidgetToSection( "gtk-tooltip*", "oxygen-tooltips-internal" );
793 
794         // special case for google chrome
795         /* based on http://code.google.com/p/chromium/wiki/LinuxGtkThemeIntegration */
796         _rc.addSection( "oxygen-chrome-gtk-frame-internal", Gtk::RC::defaultSection() );
797         _rc.addToCurrentSection( Gtk::RCOption<std::string>( " ChromeGtkFrame::frame-color", _palette.color( Palette::Window ) ) );
798         _rc.addToCurrentSection( Gtk::RCOption<std::string>( " ChromeGtkFrame::inactive-frame-color", _palette.color( Palette::Window ) ) );
799         _rc.matchClassToSection( "ChromeGtkFrame", "oxygen-chrome-gtk-frame-internal" );
800 
801     }
802 
803 
804     //_________________________________________________________
addLinkColors(const std::string & section)805     void QtSettings::addLinkColors( const std::string& section )
806     {
807 
808         {
809             // link colors
810             // from http://ubuntuforums.org/showthread.php?p=7009302
811             const ColorUtils::Rgba linkColor( ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( section, "ForegroundLink" ) ) );
812             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  GtkWidget::link-color", linkColor ) );
813             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  GtkHTML::alink_color", linkColor ) );
814             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  GtkHTML::link_color", linkColor ) );
815             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  GnomeHref::link-color", linkColor ) );
816             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  GtkIMHtml::hyperlink-color", linkColor ) );
817             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  GtkIMHtml::hyperlink-prelight-color", linkColor ) );
818         }
819 
820         {
821             // visited link colors
822             // from http://ubuntuforums.org/showthread.php?p=7009302
823             const ColorUtils::Rgba visitedLinkColor( ColorUtils::Rgba::fromKdeOption( _kdeGlobals.getValue( section, "ForegroundVisited" ) ) );
824             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  GtkWidget::visited-link-color", visitedLinkColor ) );
825             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  GtkHTML::vlink_color", visitedLinkColor ) );
826         }
827 
828     }
829 
830     //_________________________________________________________
loadKdeFonts(void)831     void QtSettings::loadKdeFonts( void )
832     {
833 
834         // try load default font
835         FontInfo::Map fonts;
836         FontInfo defaultFont;
837         if( _kdeGlobals.hasOption( "[General]", "font" ) )
838         {
839 
840             defaultFont = FontInfo::fromKdeOption( _kdeGlobals.getValue( "[General]", "font", "" ) );
841 
842         } else {
843 
844             #if OXYGEN_DEBUG
845             std::cerr << "Oxygen::QtSettings::loadKdeFonts - cannot load default font" << std::endl;
846             #endif
847 
848         }
849 
850         fonts[FontInfo::Default] = defaultFont;
851 
852         // load extra fonts
853         typedef std::map<FontInfo::FontType, std::string> FontNameMap;
854         FontNameMap optionNames;
855         optionNames.insert( std::make_pair( FontInfo::Desktop, "desktopFont" ) );
856         optionNames.insert( std::make_pair( FontInfo::Fixed, "fixed" ) );
857         optionNames.insert( std::make_pair( FontInfo::Menu, "menuFont" ) );
858         optionNames.insert( std::make_pair( FontInfo::ToolBar, "toolBarFont" ) );
859         for( FontNameMap::const_iterator iter = optionNames.begin(); iter != optionNames.end(); ++iter )
860         {
861             FontInfo local;
862             if( _kdeGlobals.hasOption( "[General]", iter->second ) )
863             {
864 
865                 local = FontInfo::fromKdeOption( _kdeGlobals.getValue( "[General]", iter->second, "" ) );
866 
867             } else {
868 
869                 #if OXYGEN_DEBUG
870                 std::cerr << "Oxygen::QtSettings::loadKdeFonts - cannot load font named " << iter->second << std::endl;
871                 #endif
872                 local = defaultFont;
873 
874             }
875 
876             // store in map
877             fonts[iter->first] = local;
878 
879         }
880 
881         // pass fonts to RC
882         if( fonts[FontInfo::Default].isValid() )
883         {
884             // pass to settings
885             GtkSettings* settings( gtk_settings_get_default() );
886             gtk_settings_set_string_property( settings, "gtk-font-name", fonts[FontInfo::Default].toString( false ).c_str(), "oxygen-gtk" );
887 
888             _rc.setCurrentSection( Gtk::RC::defaultSection() );
889             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  font_name", fonts[FontInfo::Default].toString() ) );
890         }
891 
892         if( fonts[FontInfo::Menu].isValid() )
893         {
894             _rc.addSection( "oxygen-menu-font-internal", Gtk::RC::defaultSection() );
895             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  font_name", fonts[FontInfo::Menu].toString() ) );
896             _rc.matchWidgetClassToSection( "*<GtkMenuItem>.<GtkLabel>", "oxygen-menu-font-internal" );
897         }
898 
899         if( fonts[FontInfo::ToolBar].isValid() )
900         {
901             _rc.addSection( "oxygen-toolbar-font-internal", Gtk::RC::defaultSection() );
902             _rc.addToCurrentSection( Gtk::RCOption<std::string>( "  font_name", fonts[FontInfo::ToolBar].toString() ) );
903             _rc.matchWidgetClassToSection( "*<GtkToolbar>.*", "oxygen-toolbar-font-internal" );
904         }
905 
906         // don't check for section and tag presence - use default font if not present
907         _WMFont=FontInfo::fromKdeOption( _kdeGlobals.getValue( "[WM]", "activeFont", "Sans Serif,8,-1,5,50,0,0,0,0,0" ) );
908 
909     }
910 
911     //_________________________________________________________
loadKdeGlobalsOptions(void)912     void QtSettings::loadKdeGlobalsOptions( void )
913     {
914 
915         #if OXYGEN_DEBUG
916         std::cerr << "Oxygen::QtSettings::loadKdeGlobalsOptions" << std::endl;
917         #endif
918 
919         // toolbar style
920         const std::string toolbarTextPosition( _kdeGlobals.getOption( "[Toolbar style]", "ToolButtonStyle" ).toVariant<std::string>( "TextBelowIcon" ) );
921         GtkToolbarStyle toolbarStyle( GTK_TOOLBAR_BOTH );
922         if( toolbarTextPosition == "TextOnly" ) toolbarStyle = GTK_TOOLBAR_TEXT;
923         else if( toolbarTextPosition == "TextBesideIcon" ) toolbarStyle = GTK_TOOLBAR_BOTH_HORIZ;
924         else if( toolbarTextPosition == "NoText" ) toolbarStyle = GTK_TOOLBAR_ICONS;
925 
926         GtkSettings* settings( gtk_settings_get_default() );
927         gtk_settings_set_long_property( settings, "gtk-toolbar-style", toolbarStyle, "oxygen-gtk" );
928 
929         // icons on buttons
930         if( _kdeGlobals.getValue( "[KDE]", "ShowIconsOnPushButtons", "true" ) == "false" )
931         { gtk_settings_set_long_property( settings, "gtk-button-images", 0, "oxygen-gtk" ); }
932 
933         // active icon effects
934         _useIconEffect = _kdeGlobals.getOption( "[MainToolbarIcons]", "ActiveEffect" ).toVariant<std::string>( "gamma" ) != "none";
935 
936         // start drag time and distance
937         _startDragDist = _kdeGlobals.getOption( "[KDE]", "StartDragDist" ).toVariant<int>( 4 );
938         _startDragTime = _kdeGlobals.getOption( "[KDE]", "StartDragTime" ).toVariant<int>( 500 );
939 
940     }
941 
942     //_________________________________________________________
loadOxygenOptions(void)943     void QtSettings::loadOxygenOptions( void )
944     {
945 
946         // background pixmap
947         _backgroundPixmap = _oxygen.getValue( "[Common]", "BackgroundPixmap", "" );
948 
949         // background gradient
950         _useBackgroundGradient = ( _oxygen.getValue( "[Common]", "UseBackgroundGradient", "true" ) == "true" );
951 
952         // checkbox style
953         _checkBoxStyle = (_oxygen.getValue( "[Style]", "CheckBoxStyle", "CS_CHECK" ) == "CS_CHECK") ? CS_CHECK:CS_X;
954 
955         // checkbox style
956         _tabStyle = (_oxygen.getValue( "[Style]", "TabStyle", "TS_SINGLE" ) == "TS_SINGLE") ? TS_SINGLE:TS_PLAIN;
957 
958         // scrollbar buttons
959         _scrollBarAddLineButtons = _oxygen.getOption( "[Style]", "ScrollBarAddLineButtons" ).toVariant<int>( 2 );
960         _scrollBarSubLineButtons = _oxygen.getOption( "[Style]", "ScrollBarSubLineButtons" ).toVariant<int>( 1 );
961 
962         // toolbar separators
963         _toolBarDrawItemSeparator = _oxygen.getOption( "[Style]", "ToolBarDrawItemSeparator" ).toVariant<std::string>("true") == "true";
964 
965         // tooltips
966         _tooltipTransparent = _oxygen.getOption( "[Style]", "ToolTipTransparent" ).toVariant<std::string>("true") == "true";
967         _tooltipDrawStyledFrames = _oxygen.getOption( "[Style]", "ToolTipDrawStyledFrames" ).toVariant<std::string>("true") == "true";
968 
969         // focus indicator in views
970         _viewDrawFocusIndicator = _oxygen.getOption( "[Style]", "ViewDrawFocusIndicator" ).toVariant<std::string>("true") == "true";
971 
972         // tree branch lines
973         _viewDrawTreeBranchLines = _oxygen.getOption( "[Style]", "ViewDrawTreeBranchLines" ).toVariant<std::string>("true") == "true";
974 
975         // triangular expanders
976         _viewDrawTriangularExpander = _oxygen.getOption( "[Style]", "ViewDrawTriangularExpander" ).toVariant<std::string>("true") == "true";
977 
978         // triangular expander (arrow) size
979         std::string expanderSize( _oxygen.getOption( "[Style]", "ViewTriangularExpanderSize" ).toVariant<std::string>("TE_SMALL") );
980         if( expanderSize == "TE_NORMAL" ) _viewTriangularExpanderSize = ArrowNormal;
981         else if( expanderSize == "TE_TINY" ) _viewTriangularExpanderSize = ArrowTiny;
982         else _viewTriangularExpanderSize = ArrowSmall;
983 
984         // invert view sort indicators
985         _viewInvertSortIndicator = _oxygen.getOption( "[Style]", "ViewInvertSortIndicator" ).toVariant<std::string>("false") == "true";
986 
987         // menu highlight mode
988         std::string highlightMode( _oxygen.getOption( "[Style]", "MenuHighlightMode" ).toVariant<std::string>("MM_DARK") );
989         if( highlightMode == "MM_SUBTLE" ) _menuHighlightMode = MM_SUBTLE;
990         else if( highlightMode == "MM_STRONG" ) _menuHighlightMode = MM_STRONG;
991         else _menuHighlightMode = MM_DARK;
992 
993         // window drag mode
994         _windowDragEnabled = _oxygen.getOption( "[Style]", "WindowDragEnabled" ).toVariant<std::string>("true") == "true";
995 
996         std::string windowDragMode( _oxygen.getOption( "[Style]", "WindowDragMode" ).toVariant<std::string>("WD_FULL") );
997         if( windowDragMode == "WD_MINIMAL" ) _windowDragMode = WD_MINIMAL;
998         else _windowDragMode = WD_FULL;
999 
1000         // use window manager to handle window drag
1001         _useWMMoveResize = _oxygen.getOption( "[Style]", "UseWMMoveResize" ).toVariant<std::string>("true") == "true";
1002 
1003         // animations
1004         _animationsEnabled = ( _oxygen.getOption( "[Style]", "AnimationsEnabled" ).toVariant<std::string>("true") == "true" );
1005         _genericAnimationsEnabled = ( _oxygen.getOption( "[Style]", "GenericAnimationsEnabled" ).toVariant<std::string>("true") == "true" );
1006 
1007         // menubar animation type
1008         std::string menuBarAnimationType( _oxygen.getValue( "[Style]", "MenuBarAnimationType", "MB_FADE") );
1009         if( menuBarAnimationType == "MB_NONE" ) _menuBarAnimationType = NoAnimation;
1010         else if( menuBarAnimationType == "MB_FADE" ) _menuBarAnimationType = Fade;
1011         else if( menuBarAnimationType == "MB_FOLLOW_MOUSE" ) _menuBarAnimationType = FollowMouse;
1012 
1013         // menubar animation type
1014         std::string menuAnimationType( _oxygen.getValue( "[Style]", "MenuAnimationType", "ME_FADE") );
1015         if( menuAnimationType == "ME_NONE" ) _menuAnimationType = NoAnimation;
1016         else if( menuAnimationType == "ME_FADE" ) _menuAnimationType = Fade;
1017         else if( menuAnimationType == "ME_FOLLOW_MOUSE" ) _menuAnimationType = FollowMouse;
1018 
1019         // toolbar animation type
1020         std::string toolBarAnimationType( _oxygen.getValue( "[Style]", "ToolBarAnimationType", "TB_FADE") );
1021         if( toolBarAnimationType == "TB_NONE" ) _toolBarAnimationType = NoAnimation;
1022         else if( toolBarAnimationType == "TB_FADE" ) _toolBarAnimationType = Fade;
1023         else if( toolBarAnimationType == "TB_FOLLOW_MOUSE" ) _toolBarAnimationType = FollowMouse;
1024 
1025         // animations duration
1026         _genericAnimationsDuration = _oxygen.getOption( "[Style]", "GenericAnimationsDuration" ).toVariant<int>(150);
1027         _menuBarAnimationsDuration = _oxygen.getOption( "[Style]", "MenuBarAnimationsDuration" ).toVariant<int>(150);
1028         _menuBarFollowMouseAnimationsDuration = _oxygen.getOption( "[Style]", "MenuBarFollowMouseAnimationsDuration" ).toVariant<int>(80);
1029         _menuAnimationsDuration = _oxygen.getOption( "[Style]", "MenuAnimationsDuration" ).toVariant<int>(150);
1030         _menuFollowMouseAnimationsDuration = _oxygen.getOption( "[Style]", "MenuFollowMouseAnimationsDuration" ).toVariant<int>(40);
1031         _toolBarAnimationsDuration = _oxygen.getOption( "[Style]", "ToolBarAnimationsDuration" ).toVariant<int>(50);
1032 
1033         // animation steps
1034         TimeLine::setSteps( _oxygen.getOption( "[Style]", "AnimationSteps" ).toVariant<int>( 10 ) );
1035 
1036         // window decoration button size
1037         std::string buttonSize( _oxygen.getValue( "[Windeco]", "ButtonSize", "Normal") );
1038         if( buttonSize == "Small" ) _buttonSize = ButtonSmall;
1039         else if( buttonSize == "Large" ) _buttonSize = ButtonLarge;
1040         else if( buttonSize == "Very Large" ) _buttonSize = ButtonVeryLarge;
1041         else if( buttonSize == "Huge" ) _buttonSize = ButtonHuge;
1042         else _buttonSize = ButtonDefault;
1043 
1044         // window decoration frame border size
1045         std::string frameBorder(  _oxygen.getValue( "[Windeco]", "FrameBorder", "Normal") );
1046         if( frameBorder == "No Border" ) _frameBorder = BorderNone;
1047         else if( frameBorder == "No Side Border" ) _frameBorder = BorderNoSide;
1048         else if( frameBorder == "Tiny" ) _frameBorder = BorderTiny;
1049         else if( frameBorder == "Large" ) _frameBorder = BorderLarge;
1050         else if( frameBorder == "Very Large" ) _frameBorder = BorderVeryLarge;
1051         else if( frameBorder == "Huge" ) _frameBorder = BorderHuge;
1052         else if( frameBorder == "Very Huge" ) _frameBorder = BorderVeryHuge;
1053         else if( frameBorder == "Oversized" ) _frameBorder = BorderOversized;
1054         else _frameBorder = BorderDefault;
1055 
1056         // window decoration title alignment
1057         std::string titleAlign( _oxygen.getValue( "[Windeco]", "TitleAlignment", "Center" ) );
1058         if( titleAlign == "Left" ) _titleAlignment = PANGO_ALIGN_LEFT;
1059         else if( titleAlign == "Center" ) _titleAlignment = PANGO_ALIGN_CENTER;
1060         else if( titleAlign == "Right" ) _titleAlignment = PANGO_ALIGN_RIGHT;
1061         else _titleAlignment = PANGO_ALIGN_CENTER;
1062 
1063         // Windeco radial gradient enable option
1064         std::string wdBlendType( _oxygen.getValue( "[Windeco]", "BlendColor", "Follow Style Hint" ) );
1065         if( wdBlendType == "Follow Style Hint" ) _windecoBlendType=FollowStyleHint;
1066         else if( wdBlendType == "Radial Gradient" ) _windecoBlendType=RadialGradient;
1067         else if( wdBlendType == "Solid Color" ) _windecoBlendType=SolidColor;
1068         else _windecoBlendType=FollowStyleHint;
1069 
1070         // shadow configurations
1071         _activeShadowConfiguration.initialize( _oxygen );
1072         _inactiveShadowConfiguration.initialize( _oxygen );
1073 
1074         if(_kdeGlobals.getOption( "[General]", "widgetStyle" ).toVariant<std::string>("oxygen") == "oxygen transparent")
1075             _backgroundOpacity = _oxygen.getOption( "[Common]", "BackgroundOpacity" ).toVariant<int>(255);
1076         else
1077             _backgroundOpacity = 255;
1078 
1079         #if OXYGEN_DEBUG
1080         std::cerr << _activeShadowConfiguration << std::endl;
1081         std::cerr << _inactiveShadowConfiguration << std::endl;
1082         #endif
1083 
1084         // copy relevant options to to gtk
1085         // scrollbar width
1086         _rc.setCurrentSection( Gtk::RC::defaultSection() );
1087         _rc.addToCurrentSection( Gtk::RCOption<int>(
1088             "  GtkScrollbar::slider-width",
1089             _oxygen.getOption( "[Style]", "ScrollBarWidth" ).toVariant<int>(15) + 1 ) );
1090 
1091         _rc.addToCurrentSection( Gtk::RCOption<bool>("  GtkScrollbar::has-backward-stepper", _scrollBarSubLineButtons > 0 ) );
1092         _rc.addToCurrentSection( Gtk::RCOption<bool>("  GtkScrollbar::has-forward-stepper", _scrollBarAddLineButtons > 0 ) );
1093 
1094         // note the inversion for add and sub, due to the fact that kde options refer to the button location, and not its direction
1095         _rc.addToCurrentSection( Gtk::RCOption<bool>("  GtkScrollbar::has-secondary-backward-stepper", _scrollBarAddLineButtons > 1 ) );
1096         _rc.addToCurrentSection( Gtk::RCOption<bool>("  GtkScrollbar::has-secondary-forward-stepper", _scrollBarSubLineButtons > 1 ) );
1097 
1098         // mnemonics
1099         GtkSettings* settings( gtk_settings_get_default() );
1100         if( _oxygen.hasOption( "[Style]", "MnemonicsMode" ) )
1101         {
1102 
1103             const std::string mnemonicsMode( _oxygen.getOption( "[Style]", "MnemonicsMode" ).toVariant<std::string>("MN_ALWAYS") );
1104             if( mnemonicsMode == "MN_NEVER" )
1105             {
1106 
1107                 gtk_settings_set_long_property( settings, "gtk-enable-mnemonics", false, "oxygen-gtk" );
1108                 gtk_settings_set_long_property( settings, "gtk-auto-mnemonics", false, "oxygen-gtk" );
1109 
1110             } else if( mnemonicsMode == "MN_AUTO" ) {
1111 
1112                 gtk_settings_set_long_property( settings, "gtk-enable-mnemonics", true, "oxygen-gtk" );
1113                 gtk_settings_set_long_property( settings, "gtk-auto-mnemonics", true, "oxygen-gtk" );
1114 
1115             } else {
1116 
1117                 gtk_settings_set_long_property( settings, "gtk-enable-mnemonics", true, "oxygen-gtk" );
1118                 gtk_settings_set_long_property( settings, "gtk-auto-mnemonics", false, "oxygen-gtk" );
1119 
1120             }
1121 
1122         } else {
1123 
1124             // for backward compatibility
1125             const bool showMnemonics( _oxygen.getOption( "[Style]", "ShowMnemonics" ).toVariant<std::string>("true") == "true" );
1126             if( showMnemonics )
1127             {
1128 
1129                 gtk_settings_set_long_property( settings, "gtk-enable-mnemonics", true, "oxygen-gtk" );
1130                 gtk_settings_set_long_property( settings, "gtk-auto-mnemonics", false, "oxygen-gtk" );
1131 
1132             } else {
1133 
1134                 gtk_settings_set_long_property( settings, "gtk-enable-mnemonics", false, "oxygen-gtk" );
1135                 gtk_settings_set_long_property( settings, "gtk-auto-mnemonics", false, "oxygen-gtk" );
1136 
1137             }
1138 
1139         }
1140 
1141     }
1142 
1143     //_________________________________________________________
loadExtraOptions(void)1144     void QtSettings::loadExtraOptions( void )
1145     {
1146 
1147         // deal with pathbar button margins
1148         // this needs to be done programatically in order to properly account for RTL locales
1149         _rc.addSection( "oxygen-pathbutton-internal", Gtk::RC::defaultSection() );
1150         _rc.addToCurrentSection( "  GtkButton::inner-border = { 2, 2, 1, 0 }" );
1151 
1152         if( gtk_widget_get_default_direction() == GTK_TEXT_DIR_RTL )
1153         {
1154 
1155             _rc.addToCurrentSection( "  GtkToggleButton::inner-border={ 10, 0, 1, 0 }" );
1156 
1157         } else {
1158 
1159             _rc.addToCurrentSection( "  GtkToggleButton::inner-border={ 0, 10, 1, 0 }" );
1160 
1161         }
1162 
1163         _rc.matchWidgetClassToSection( "*PathBar.GtkToggleButton", "oxygen-pathbutton-internal" );
1164 
1165         // entry margins
1166         _rc.addSection( "oxygen-entry-margins-internal", Gtk::RC::defaultSection() );
1167         _rc.addToCurrentSection( Gtk::RCOption<int>( "  xthickness", 5 ) );
1168         _rc.addToCurrentSection( Gtk::RCOption<int>( "  ythickness", applicationName().isXul() ? 2:1 ) );
1169         _rc.matchClassToSection( "GtkEntry", "oxygen-entry-margins-internal" );
1170 
1171         // combobox buttons
1172         _rc.addSection( "oxygen-combobox-button-internal", Gtk::RC::defaultSection() );
1173         _rc.addToCurrentSection( Gtk::RCOption<int>( "  xthickness", 2 ) );
1174         _rc.addToCurrentSection( Gtk::RCOption<int>( "  ythickness", applicationName().isXul() ? 2:0 ) );
1175         _rc.matchWidgetClassToSection( "*<GtkComboBox>.<GtkButton>", "oxygen-combobox-button-internal" );
1176 
1177     }
1178 
1179     //_________________________________________________________
sanitizePath(const std::string & path) const1180     std::string QtSettings::sanitizePath( const std::string& path ) const
1181     {
1182 
1183         std::string out( path );
1184         size_t position( std::string::npos );
1185         while( ( position = out.find( "//" ) ) != std::string::npos )
1186         { out.replace( position, 2, "/" ); }
1187 
1188         return out;
1189     }
1190 
1191     //_________________________________________________________
monitorFile(const std::string & filename)1192     void QtSettings::monitorFile( const std::string& filename )
1193     {
1194 
1195         // check if file was already added
1196         if( _monitoredFiles.find( filename ) != _monitoredFiles.end() )
1197         { return; }
1198 
1199         // check file existence
1200         if( !std::ifstream( filename.c_str() ) )
1201         { return; }
1202 
1203         // create FileMonitor
1204         FileMonitor monitor;
1205         monitor.file = g_file_new_for_path( filename.c_str() );
1206         if( ( monitor.monitor = g_file_monitor( monitor.file, G_FILE_MONITOR_NONE, 0L, 0L ) ) )
1207         {
1208 
1209             // insert in map
1210             _monitoredFiles.insert( std::make_pair( filename, monitor ) );
1211 
1212         } else {
1213 
1214             // clear file and return
1215             g_object_unref( monitor.file );
1216             return;
1217 
1218         }
1219 
1220     }
1221 
1222     //_________________________________________________________
clearMonitoredFiles(void)1223     void QtSettings::clearMonitoredFiles( void )
1224     {
1225         for( FileMap::iterator iter = _monitoredFiles.begin(); iter != _monitoredFiles.end(); iter++ )
1226         {
1227             iter->second.signal.disconnect();
1228             g_object_unref( iter->second.file );
1229             g_object_unref( iter->second.monitor );
1230         }
1231 
1232         _monitoredFiles.clear();
1233     }
1234 
1235 }
1236