1 /* 2 * this file is part of the oxygen gtk engine 3 * Copyright (c) 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr> 4 * 5 * inspired notably from kdelibs/kdeui/color/kcolorutils.h 6 * Copyright (C) 2007 Matthew Woehlke <mw_triad@users.sourceforge.net> 7 * Copyright (C) 2007 Thomas Zander <zander@kde.org> 8 * Copyright (C) 2007 Zack Rusin <zack@kde.org> 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Lesser General Public 12 * License as published by the Free Software Foundation; either 13 * version 2 of the License, or( at your option ) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Lesser General Public License for more details. 19 * 20 * You should have received a copy of the GNU Lesser General Public 21 * License along with this library; if not, write to the Free 22 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, 23 * MA 02110-1301, USA. 24 */ 25 26 #include "oxygengtkicons.h" 27 #include "config.h" 28 29 #include <algorithm> 30 #include <fstream> 31 #include <iostream> 32 #include <sstream> 33 34 #include <gtk/gtk.h> 35 36 namespace Oxygen 37 { 38 39 //_________________________________________ GtkIcons(void)40 GtkIcons::GtkIcons( void ): 41 _factory( 0L ), 42 _dirty( true ) 43 { 44 45 // initialize sizes 46 _sizes.push_back( std::make_pair( "panel-menu", 16 ) ); 47 _sizes.push_back( std::make_pair( "panel", 32 ) ); 48 _sizes.push_back( std::make_pair( "gtk-small-toolbar", 22 ) ); 49 _sizes.push_back( std::make_pair( "gtk-large-toolbar", 22 ) ); 50 _sizes.push_back( std::make_pair( "gtk-dnd", 48 ) ); 51 _sizes.push_back( std::make_pair( "gtk-button", 16 ) ); 52 _sizes.push_back( std::make_pair( "gtk-menu", 16 ) ); 53 _sizes.push_back( std::make_pair( "gtk-dialog", 32 ) ); 54 _sizes.push_back( std::make_pair( "", 16 ) ); 55 56 } 57 58 //_________________________________________ ~GtkIcons(void)59 GtkIcons::~GtkIcons( void ) 60 { 61 if( _factory ) 62 { gtk_icon_factory_remove_default( _factory ); } 63 } 64 65 //_________________________________________ setIconSize(const std::string & tag,unsigned int value)66 void GtkIcons::setIconSize( const std::string& tag, unsigned int value ) 67 { 68 SizeMap::iterator iter( std::find_if( _sizes.begin(), _sizes.end(), SameTagFTor( tag ) ) ); 69 if( iter == _sizes.end() ) { 70 71 std::cerr << "GtkIcons::setIconSize - no match for" << tag << "," << value << std::endl; 72 73 } else if( iter->second != value ) { 74 75 iter->second = value; 76 _dirty = true; 77 78 } 79 80 } 81 82 //_________________________________________ loadTranslations(const std::string & filename)83 void GtkIcons::loadTranslations( const std::string& filename ) 84 { 85 86 if( filename == _filename ) 87 { return; } 88 89 _filename = filename; 90 _dirty = true; 91 _icons.clear(); 92 93 std::ifstream in( filename.c_str() ); 94 if( !in ) 95 { 96 std::cerr << "Oxygen::GtkIcons::loadTranslations - could not open " << filename << std::endl; 97 return; 98 } 99 100 std::string line; 101 while( std::getline( in, line, '\n' ) ) 102 { 103 104 if( line.empty() ) continue; 105 106 IconPair iconPair; 107 std::istringstream stream( line.c_str() ); 108 stream >> iconPair.first >> iconPair.second; 109 if( ( stream.rdstate() & std::ios::failbit ) != 0 ) 110 { continue; } 111 112 _icons.insert( iconPair ); 113 114 } 115 116 } 117 118 //_________________________________________ generate(const PathList & pathList)119 Gtk::RC GtkIcons::generate( const PathList& pathList ) 120 { 121 122 if( (!_dirty) && _pathList == pathList ) return _rc; 123 124 #if OXYGEN_DEBUG 125 std::cerr << "Oxygen::GtkIcons::generate - regenerating translation tables" << std::endl; 126 #endif 127 128 _pathList = pathList; 129 _rc.clear(); 130 131 // reset factory 132 if( _factory ) 133 { 134 gtk_icon_factory_remove_default( _factory ); 135 g_object_unref( G_OBJECT( _factory ) ); 136 } 137 138 // create new 139 _factory = gtk_icon_factory_new(); 140 141 // generate icon size string 142 std::ostringstream iconSizesStr; 143 for( SizeMap::const_iterator iter = _sizes.begin(); iter != _sizes.end(); ++iter ) 144 { 145 if( iter->first.empty() ) continue; 146 if( iter != _sizes.begin() ) iconSizesStr << ": "; 147 iconSizesStr << iter->first << " = " << iter->second << "," << iter->second; 148 } 149 150 // pass to settings 151 GtkSettings* settings( gtk_settings_get_default() ); 152 gtk_settings_set_string_property( settings, "gtk-icon-sizes", iconSizesStr.str().c_str(), "oxygen-gtk" ); 153 154 // generate pixmap path 155 // this must be passed to gtk before any icon settings, otherwise 156 // other icons are not recognized 157 std::ostringstream pixmapPathStr; 158 pixmapPathStr << "pixmap_path \""; 159 for( PathList::const_iterator iter = pathList.begin(); iter != pathList.end(); ++iter ) 160 { 161 #if OXYGEN_DEBUG 162 std::cerr << "Oxygen::GtkIcons::generate - adding path: " << *iter << std::endl; 163 #endif 164 165 if( iter != pathList.begin() ) pixmapPathStr << ":"; 166 pixmapPathStr << *iter; 167 } 168 pixmapPathStr << "\""; 169 _rc.addToHeaderSection( pixmapPathStr.str() ); 170 171 // loop over icons 172 bool empty( true ); 173 for( IconMap::const_iterator iconIter = _icons.begin(); iconIter != _icons.end(); ++iconIter ) 174 { 175 176 GtkIconSet* iconSet( generate( iconIter->first, iconIter->second, pathList ) ); 177 if( iconSet ) 178 { 179 gtk_icon_factory_add( _factory, iconIter->first.c_str(), iconSet ); 180 gtk_icon_set_unref( iconSet ); 181 empty = false; 182 } 183 184 } 185 186 if( empty ) 187 { 188 189 g_object_unref( G_OBJECT( _factory ) ); 190 _factory = 0L; 191 192 } else gtk_icon_factory_add_default( _factory ); 193 194 // extra settings for entries 195 std::string stock( generateString( "gtk-clear", "actions/edit-clear-locationbar-rtl.png", pathList ) ); 196 if( !stock.empty() ) 197 { 198 _rc.addSection( "oxygen-icons-editor", Gtk::RC::defaultSection() ); 199 _rc.addToCurrentSection( stock ); 200 _rc.addToRootSection( "class \"*Entry*\" style \"oxygen-icons-editor\"" ); 201 } 202 203 _dirty = false; 204 return _rc; 205 206 } 207 208 //__________________________________________________________________ generate(const std::string & gtkIconName,const std::string & kdeIconName,const PathList & pathList) const209 GtkIconSet* GtkIcons::generate( 210 const std::string& gtkIconName, 211 const std::string& kdeIconName, 212 const PathList& pathList ) const 213 { 214 215 216 if( kdeIconName == "NONE" ) return 0L; 217 218 bool empty( true ); 219 220 // create iconSet 221 GtkIconSet* iconSet = gtk_icon_set_new(); 222 223 // loop over iconSizes 224 for( SizeMap::const_iterator sizeIter = _sizes.begin(); sizeIter != _sizes.end(); ++sizeIter ) 225 { 226 227 // generate full icon name 228 std::ostringstream iconFileStream; 229 iconFileStream << sizeIter->second << "x" << sizeIter->second << "/" << kdeIconName; 230 231 // loop over provided path to see if at least one icon is found 232 for( PathList::const_iterator pathIter = pathList.begin(); pathIter != pathList.end(); ++pathIter ) 233 { 234 std::string filename( *pathIter + '/' + iconFileStream.str() ); 235 if( !std::ifstream( filename.c_str() ) ) continue; 236 237 empty = false; 238 GtkIconSource* iconSource( gtk_icon_source_new() ); 239 240 // set name 241 gtk_icon_source_set_filename( iconSource, filename.c_str() ); 242 243 // set direction and state wildcarded 244 gtk_icon_source_set_direction_wildcarded( iconSource, TRUE ); 245 gtk_icon_source_set_state_wildcarded( iconSource, TRUE ); 246 247 // set size 248 if( sizeIter->first.empty() ) gtk_icon_source_set_size_wildcarded( iconSource, TRUE ); 249 else { 250 251 GtkIconSize size = gtk_icon_size_from_name( sizeIter->first.c_str() ); 252 if (size != GTK_ICON_SIZE_INVALID) 253 { 254 gtk_icon_source_set_size_wildcarded( iconSource, FALSE ); 255 gtk_icon_source_set_size( iconSource, size ); 256 } 257 } 258 259 // add source to iconSet 260 gtk_icon_set_add_source( iconSet, iconSource ); 261 gtk_icon_source_free( iconSource ); 262 break; 263 264 } 265 266 } 267 268 // if nothing found, return; 269 if( empty ) 270 { 271 272 gtk_icon_set_unref( iconSet ); 273 return 0L; 274 275 } else return iconSet; 276 277 } 278 279 //__________________________________________________________________ generateString(const std::string & gtkIconName,const std::string & kdeIconName,const PathList & pathList) const280 std::string GtkIcons::generateString( 281 const std::string& gtkIconName, 282 const std::string& kdeIconName, 283 const PathList& pathList ) const 284 { 285 286 287 if( kdeIconName == "NONE" ) return std::string(); 288 289 bool empty( true ); 290 std::ostringstream stockOut; 291 292 // new stock 293 stockOut << " stock[\"" << gtkIconName << "\"]={" << std::endl; 294 295 // loop over iconSizes 296 for( SizeMap::const_iterator sizeIter = _sizes.begin(); sizeIter != _sizes.end(); ++sizeIter ) 297 { 298 299 // generate full icon name 300 std::ostringstream iconFileStream; 301 iconFileStream << sizeIter->second << "x" << sizeIter->second << "/" << kdeIconName; 302 303 // loop over provided path to see if at least one icon is found 304 bool found( false ); 305 for( PathList::const_iterator pathIter = pathList.begin(); pathIter != pathList.end(); ++pathIter ) 306 { 307 std::string filename( *pathIter + '/' + iconFileStream.str() ); 308 if( !std::ifstream( filename.c_str() ) ) continue; 309 found = true; 310 break; 311 } 312 313 if( !found ) continue; 314 empty = false; 315 if( sizeIter->first.empty() ) stockOut << " { \"" << iconFileStream.str() << "\" }" << std::endl; 316 else stockOut << " { \"" << iconFileStream.str() << "\", *, *, \"" << sizeIter->first << "\" }," << std::endl; 317 318 319 } 320 321 stockOut << " }" << std::endl; 322 323 return empty ? std::string() : stockOut.str(); 324 325 } 326 327 328 329 } 330