File indexing completed on 2024-05-05 17:40:41
0001 /* 0002 this file is part of the oxygen gtk engine 0003 SPDX-FileCopyrightText: 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr> 0004 0005 inspired notably from kdelibs/kdeui/color/kcolorutils.h 0006 SPDX-FileCopyrightText: 2007 Matthew Woehlke <mw_triad@users.sourceforge.net> 0007 SPDX-FileCopyrightText: 2007 Thomas Zander <zander@kde.org> 0008 SPDX-FileCopyrightText: 2007 Zack Rusin <zack@kde.org> 0009 0010 SPDX-License-Identifier: LGPL-2.0-or-later 0011 */ 0012 0013 #include "oxygengtkicons.h" 0014 #include "config.h" 0015 0016 #include <algorithm> 0017 #include <fstream> 0018 #include <iostream> 0019 #include <sstream> 0020 0021 #include <gtk/gtk.h> 0022 0023 namespace Oxygen 0024 { 0025 0026 //_________________________________________ 0027 GtkIcons::GtkIcons( void ): 0028 _factory( 0L ), 0029 _dirty( true ) 0030 { 0031 0032 // initialize sizes 0033 _sizes.push_back( std::make_pair( "panel-menu", 16 ) ); 0034 _sizes.push_back( std::make_pair( "panel", 32 ) ); 0035 _sizes.push_back( std::make_pair( "gtk-small-toolbar", 22 ) ); 0036 _sizes.push_back( std::make_pair( "gtk-large-toolbar", 22 ) ); 0037 _sizes.push_back( std::make_pair( "gtk-dnd", 48 ) ); 0038 _sizes.push_back( std::make_pair( "gtk-button", 16 ) ); 0039 _sizes.push_back( std::make_pair( "gtk-menu", 16 ) ); 0040 _sizes.push_back( std::make_pair( "gtk-dialog", 32 ) ); 0041 _sizes.push_back( std::make_pair( "", 16 ) ); 0042 0043 } 0044 0045 //_________________________________________ 0046 GtkIcons::~GtkIcons( void ) 0047 { 0048 if( _factory ) 0049 { gtk_icon_factory_remove_default( _factory ); } 0050 } 0051 0052 //_________________________________________ 0053 void GtkIcons::setIconSize( const std::string& tag, unsigned int value ) 0054 { 0055 SizeMap::iterator iter( std::find_if( _sizes.begin(), _sizes.end(), SameTagFTor( tag ) ) ); 0056 if( iter == _sizes.end() ) { 0057 0058 std::cerr << "GtkIcons::setIconSize - no match for" << tag << "," << value << std::endl; 0059 0060 } else if( iter->second != value ) { 0061 0062 iter->second = value; 0063 _dirty = true; 0064 0065 } 0066 0067 } 0068 0069 //_________________________________________ 0070 void GtkIcons::loadTranslations( const std::string& filename ) 0071 { 0072 0073 if( filename == _filename ) 0074 { return; } 0075 0076 _filename = filename; 0077 _dirty = true; 0078 _icons.clear(); 0079 0080 std::ifstream in( filename.c_str() ); 0081 if( !in ) 0082 { 0083 std::cerr << "Oxygen::GtkIcons::loadTranslations - could not open " << filename << std::endl; 0084 return; 0085 } 0086 0087 std::string line; 0088 while( std::getline( in, line, '\n' ) ) 0089 { 0090 0091 if( line.empty() ) continue; 0092 0093 IconPair iconPair; 0094 std::istringstream stream( line.c_str() ); 0095 stream >> iconPair.first >> iconPair.second; 0096 if( ( stream.rdstate() & std::ios::failbit ) != 0 ) 0097 { continue; } 0098 0099 _icons.insert( iconPair ); 0100 0101 } 0102 0103 } 0104 0105 //_________________________________________ 0106 Gtk::RC GtkIcons::generate( const PathList& pathList ) 0107 { 0108 0109 if( (!_dirty) && _pathList == pathList ) return _rc; 0110 0111 #if OXYGEN_DEBUG 0112 std::cerr << "Oxygen::GtkIcons::generate - regenerating translation tables" << std::endl; 0113 #endif 0114 0115 _pathList = pathList; 0116 _rc.clear(); 0117 0118 // reset factory 0119 if( _factory ) 0120 { 0121 gtk_icon_factory_remove_default( _factory ); 0122 g_object_unref( G_OBJECT( _factory ) ); 0123 } 0124 0125 // create new 0126 _factory = gtk_icon_factory_new(); 0127 0128 // generate icon size string 0129 std::ostringstream iconSizesStr; 0130 for( SizeMap::const_iterator iter = _sizes.begin(); iter != _sizes.end(); ++iter ) 0131 { 0132 if( iter->first.empty() ) continue; 0133 if( iter != _sizes.begin() ) iconSizesStr << ": "; 0134 iconSizesStr << iter->first << " = " << iter->second << "," << iter->second; 0135 } 0136 0137 // pass to settings 0138 GtkSettings* settings( gtk_settings_get_default() ); 0139 gtk_settings_set_string_property( settings, "gtk-icon-sizes", iconSizesStr.str().c_str(), "oxygen-gtk" ); 0140 0141 // generate pixmap path 0142 // this must be passed to gtk before any icon settings, otherwise 0143 // other icons are not recognized 0144 std::ostringstream pixmapPathStr; 0145 pixmapPathStr << "pixmap_path \""; 0146 for( PathList::const_iterator iter = pathList.begin(); iter != pathList.end(); ++iter ) 0147 { 0148 #if OXYGEN_DEBUG 0149 std::cerr << "Oxygen::GtkIcons::generate - adding path: " << *iter << std::endl; 0150 #endif 0151 0152 if( iter != pathList.begin() ) pixmapPathStr << ":"; 0153 pixmapPathStr << *iter; 0154 } 0155 pixmapPathStr << "\""; 0156 _rc.addToHeaderSection( pixmapPathStr.str() ); 0157 0158 // loop over icons 0159 bool empty( true ); 0160 for( IconMap::const_iterator iconIter = _icons.begin(); iconIter != _icons.end(); ++iconIter ) 0161 { 0162 0163 GtkIconSet* iconSet( generate( iconIter->first, iconIter->second, pathList ) ); 0164 if( iconSet ) 0165 { 0166 gtk_icon_factory_add( _factory, iconIter->first.c_str(), iconSet ); 0167 gtk_icon_set_unref( iconSet ); 0168 empty = false; 0169 } 0170 0171 } 0172 0173 if( empty ) 0174 { 0175 0176 g_object_unref( G_OBJECT( _factory ) ); 0177 _factory = 0L; 0178 0179 } else gtk_icon_factory_add_default( _factory ); 0180 0181 // extra settings for entries 0182 std::string stock( generateString( "gtk-clear", "actions/edit-clear-locationbar-rtl.png", pathList ) ); 0183 if( !stock.empty() ) 0184 { 0185 _rc.addSection( "oxygen-icons-editor", Gtk::RC::defaultSection() ); 0186 _rc.addToCurrentSection( stock ); 0187 _rc.addToRootSection( "class \"*Entry*\" style \"oxygen-icons-editor\"" ); 0188 } 0189 0190 _dirty = false; 0191 return _rc; 0192 0193 } 0194 0195 //__________________________________________________________________ 0196 GtkIconSet* GtkIcons::generate( 0197 const std::string& gtkIconName, 0198 const std::string& kdeIconName, 0199 const PathList& pathList ) const 0200 { 0201 0202 0203 if( kdeIconName == "NONE" ) return 0L; 0204 0205 bool empty( true ); 0206 0207 // create iconSet 0208 GtkIconSet* iconSet = gtk_icon_set_new(); 0209 0210 // loop over iconSizes 0211 for( SizeMap::const_iterator sizeIter = _sizes.begin(); sizeIter != _sizes.end(); ++sizeIter ) 0212 { 0213 0214 // generate full icon name 0215 std::ostringstream iconFileStream; 0216 iconFileStream << sizeIter->second << "x" << sizeIter->second << "/" << kdeIconName; 0217 0218 // loop over provided path to see if at least one icon is found 0219 for( PathList::const_iterator pathIter = pathList.begin(); pathIter != pathList.end(); ++pathIter ) 0220 { 0221 std::string filename( *pathIter + '/' + iconFileStream.str() ); 0222 if( !std::ifstream( filename.c_str() ) ) continue; 0223 0224 empty = false; 0225 GtkIconSource* iconSource( gtk_icon_source_new() ); 0226 0227 // set name 0228 gtk_icon_source_set_filename( iconSource, filename.c_str() ); 0229 0230 // set direction and state wildcarded 0231 gtk_icon_source_set_direction_wildcarded( iconSource, TRUE ); 0232 gtk_icon_source_set_state_wildcarded( iconSource, TRUE ); 0233 0234 // set size 0235 if( sizeIter->first.empty() ) gtk_icon_source_set_size_wildcarded( iconSource, TRUE ); 0236 else { 0237 0238 GtkIconSize size = gtk_icon_size_from_name( sizeIter->first.c_str() ); 0239 if (size != GTK_ICON_SIZE_INVALID) 0240 { 0241 gtk_icon_source_set_size_wildcarded( iconSource, FALSE ); 0242 gtk_icon_source_set_size( iconSource, size ); 0243 } 0244 } 0245 0246 // add source to iconSet 0247 gtk_icon_set_add_source( iconSet, iconSource ); 0248 gtk_icon_source_free( iconSource ); 0249 break; 0250 0251 } 0252 0253 } 0254 0255 // if nothing found, return; 0256 if( empty ) 0257 { 0258 0259 gtk_icon_set_unref( iconSet ); 0260 return 0L; 0261 0262 } else return iconSet; 0263 0264 } 0265 0266 //__________________________________________________________________ 0267 std::string GtkIcons::generateString( 0268 const std::string& gtkIconName, 0269 const std::string& kdeIconName, 0270 const PathList& pathList ) const 0271 { 0272 0273 0274 if( kdeIconName == "NONE" ) return std::string(); 0275 0276 bool empty( true ); 0277 std::ostringstream stockOut; 0278 0279 // new stock 0280 stockOut << " stock[\"" << gtkIconName << "\"]={" << std::endl; 0281 0282 // loop over iconSizes 0283 for( SizeMap::const_iterator sizeIter = _sizes.begin(); sizeIter != _sizes.end(); ++sizeIter ) 0284 { 0285 0286 // generate full icon name 0287 std::ostringstream iconFileStream; 0288 iconFileStream << sizeIter->second << "x" << sizeIter->second << "/" << kdeIconName; 0289 0290 // loop over provided path to see if at least one icon is found 0291 bool found( false ); 0292 for( PathList::const_iterator pathIter = pathList.begin(); pathIter != pathList.end(); ++pathIter ) 0293 { 0294 std::string filename( *pathIter + '/' + iconFileStream.str() ); 0295 if( !std::ifstream( filename.c_str() ) ) continue; 0296 found = true; 0297 break; 0298 } 0299 0300 if( !found ) continue; 0301 empty = false; 0302 if( sizeIter->first.empty() ) stockOut << " { \"" << iconFileStream.str() << "\" }" << std::endl; 0303 else stockOut << " { \"" << iconFileStream.str() << "\", *, *, \"" << sizeIter->first << "\" }," << std::endl; 0304 0305 0306 } 0307 0308 stockOut << " }" << std::endl; 0309 0310 return empty ? std::string() : stockOut.str(); 0311 0312 } 0313 0314 0315 0316 }