25 #include "kservice_p.h"
27 #include <sys/types.h>
40 #include <ksimpleconfig.h>
41 #include <kapplication.h>
43 #include <kdesktopfile.h>
45 #include <kiconloader.h>
47 #include <kconfigbase.h>
48 #include <kstandarddirs.h>
49 #include <dcopclient.h>
51 #include "kservicefactory.h"
52 #include "kservicetypefactory.h"
53 #include "kservicetype.h"
54 #include "kuserprofile.h"
57 class KService::KServicePrivate
65 : KSycocaEntry( TQString::null)
67 d =
new KServicePrivate;
70 m_strType =
"Application";
75 m_bAllowAsDefault =
true;
76 m_initialPreference = 10;
81 : KSycocaEntry( _fullpath)
83 KDesktopFile config( _fullpath );
89 : KSycocaEntry( config->fileName())
97 d =
new KServicePrivate;
100 bool absPath = !TQDir::isRelativePath(entryPath());
101 bool kde4application = config->fileName().contains(
"/share/applications/kde4/");
102 TQString kde4applicationprefix;
103 if (kde4application) {
105 kde4applicationprefix = config->fileName();
106 int pos = kde4applicationprefix.find(
"/share/applications/kde4/");
107 kde4applicationprefix.truncate(pos);
110 config->setDesktopGroup();
112 TQMap<TQString, TQString> entryMap = config->entryMap(config->group());
114 entryMap.remove(
"Encoding");
115 entryMap.remove(
"Version");
117 m_bDeleted = config->readBoolEntry(
"Hidden",
false );
118 entryMap.remove(
"Hidden");
126 m_strName = config->readName();
127 entryMap.remove(
"Name");
128 if ( m_strName.isEmpty() )
130 if (config->readEntry(
"Exec" ).isEmpty())
138 m_strName = entryPath();
139 int i = m_strName.findRev(
'/');
140 m_strName = m_strName.mid(i+1);
141 i = m_strName.findRev(
'.');
143 m_strName = m_strName.left(i);
146 m_strType = config->readType();
147 entryMap.remove(
"Type");
148 if ( m_strType.isEmpty() )
155 m_strType =
"Application";
156 }
else if ( m_strType !=
"Application" && m_strType !=
"Service" )
158 kdWarning(7012) <<
"The desktop entry file " << entryPath()
159 <<
" has Type=" << m_strType
160 <<
" instead of \"Application\" or \"Service\"" << endl;
166 if (!config->tryExec()) {
173 TQString resource = config->resource();
175 if ( (m_strType ==
"Application") &&
176 (!resource.isEmpty()) &&
177 (resource !=
"apps") &&
180 kdWarning(7012) <<
"The desktop entry file " << entryPath()
181 <<
" has Type=" << m_strType <<
" but is located under \"" << resource
182 <<
"\" instead of \"apps\"" << endl;
187 if ( (m_strType ==
"Service") &&
188 (!resource.isEmpty()) &&
189 (resource !=
"services") &&
192 kdWarning(7012) <<
"The desktop entry file " << entryPath()
193 <<
" has Type=" << m_strType <<
" but is located under \"" << resource
194 <<
"\" instead of \"services\"" << endl;
199 TQString
name = entryPath();
200 int pos = name.findRev(
'/');
202 name = name.mid(pos+1);
203 pos = name.find(
'.');
205 name = name.left(pos);
207 m_strExec = config->readPathEntry(
"Exec" );
208 if (kde4application && !m_strExec.startsWith(
"/")) {
209 m_strExec =
"KDEHOME=$HOME/" KDE4_DEFAULT_HOME
" KDEDIRS=" + kde4applicationprefix +
"/ XDG_DATA_DIRS=" + kde4applicationprefix +
"/share XDG_CONFIG_DIRS=/etc/xdg/ PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:$PATH "+m_strExec;
211 else if (config->readBoolEntry(
"X-KDE-SubstituteUID")) {
212 TQString
path = TQString::fromLocal8Bit(getenv(
"PATH"));
215 int space = m_strExec.find(
" ");
220 command = m_strExec.left(space);
221 params = m_strExec.mid(space);
223 path.replace(TQRegExp(
"(^|:)(/usr/local|/usr)/bin($|:)"),
"\\1\\2/sbin:\\2/bin\\3");
224 path.replace(TQRegExp(
"(^|:)/bin($|:)"),
"\\1/sbin:/bin\\2");
225 m_strExec = KStandardDirs::findExe(command, path);
226 if (!m_strExec.isEmpty() && !params.isEmpty()) {
231 entryMap.remove(
"Exec");
233 m_strIcon = config->readEntry(
"Icon",
"unknown" );
234 if (kde4application) {
235 if (TQFile::exists(kde4applicationprefix +
"/share/icons/oxygen/22x22/apps/" + m_strIcon +
".png")) {
236 m_strIcon = kde4applicationprefix +
"/share/icons/oxygen/22x22/apps/" + m_strIcon +
".png";
237 }
else if (TQFile::exists(kde4applicationprefix +
"/share/icons/hicolor/22x22/apps/" + m_strIcon +
".png")) {
238 m_strIcon = kde4applicationprefix +
"/share/icons/hicolor/22x22/apps/" + m_strIcon +
".png";
241 entryMap.remove(
"Icon");
242 m_bTerminal = (config->readBoolEntry(
"Terminal" ));
243 entryMap.remove(
"Terminal");
244 m_strTerminalOptions = config->readEntry(
"TerminalOptions" );
245 entryMap.remove(
"TerminalOptions");
246 m_strPath = config->readPath();
247 entryMap.remove(
"Path");
248 m_strComment = config->readComment();
249 entryMap.remove(
"Comment");
250 m_strGenName = config->readGenericName();
251 if (kde4application) {
252 m_strGenName +=
" [KDE4]";
254 entryMap.remove(
"GenericName");
256 if (!untranslatedGenericName.isEmpty())
257 entryMap.insert(
"UntranslatedGenericName", untranslatedGenericName);
259 m_lstKeywords = config->readListEntry(
"Keywords");
260 entryMap.remove(
"Keywords");
261 d->categories = config->readListEntry(
"Categories",
';');
262 entryMap.remove(
"Categories");
263 m_strLibrary = config->readEntry(
"X-KDE-Library" );
264 entryMap.remove(
"X-KDE-Library");
265 m_strInit = config->readEntry(
"X-KDE-Init" );
266 entryMap.remove(
"X-KDE-Init");
268 m_lstServiceTypes = config->readListEntry(
"ServiceTypes" );
269 entryMap.remove(
"ServiceTypes");
271 if (!kde4application)
272 m_lstServiceTypes += config->readListEntry(
"MimeType",
';' );
273 entryMap.remove(
"MimeType");
275 if ( m_strType ==
"Application" && !m_lstServiceTypes.contains(
"Application") )
277 m_lstServiceTypes +=
"Application";
279 TQString dcopServiceType = config->readEntry(
"X-DCOP-ServiceType").lower();
280 entryMap.remove(
"X-DCOP-ServiceType");
281 if (dcopServiceType ==
"unique")
282 m_DCOPServiceType = DCOP_Unique;
283 else if (dcopServiceType ==
"multi")
284 m_DCOPServiceType = DCOP_Multi;
285 else if (dcopServiceType ==
"wait")
286 m_DCOPServiceType = DCOP_Wait;
288 m_DCOPServiceType = DCOP_None;
290 m_strDesktopEntryName = name.lower();
292 m_strDesktopEntryName =
"kde4-" + m_strDesktopEntryName;
294 m_bAllowAsDefault = config->readBoolEntry(
"AllowDefault",
true );
295 entryMap.remove(
"AllowDefault");
297 m_initialPreference = config->readNumEntry(
"X-KDE-InitialPreference", 1 );
298 entryMap.remove(
"X-KDE-InitialPreference");
299 if ( m_initialPreference == 1 )
300 m_initialPreference = config->readNumEntry(
"InitialPreference", 1 );
301 entryMap.remove(
"InitialPreference");
307 TQMap<TQString,TQString>::ConstIterator it = entryMap.begin();
308 for( ; it != entryMap.end();++it)
311 TQString key = it.key();
312 if (kde4application && key==
"OnlyShowIn" && it.data()==
"KDE;")
314 m_mapProps.insert( key, TQVariant( it.data()));
320 d =
new KServicePrivate;
324 KService::~KService()
330 TQPixmap
KService::pixmap( KIcon::Group _group,
int _force_size,
int _state, TQString * _path )
const
332 KIconLoader *iconLoader=KGlobal::iconLoader();
333 if (!iconLoader->extraDesktopThemesAdded())
335 TQPixmap
pixmap=iconLoader->loadIcon( m_strIcon, _group, _force_size, _state, _path,
true );
336 if (!pixmap.isNull() )
return pixmap;
338 iconLoader->addExtraDesktopThemes();
341 return iconLoader->loadIcon( m_strIcon, _group, _force_size, _state, _path );
344 void KService::load( TQDataStream& s )
349 TQ_INT8 def, term, dummy1, dummy2;
350 TQ_INT8 dst, initpref;
351 TQString dummyStr1, dummyStr2;
352 int dummyI1, dummyI2;
359 s >> m_strType >> m_strName >> m_strExec >> m_strIcon
360 >> term >> m_strTerminalOptions
361 >> m_strPath >> m_strComment >> m_lstServiceTypes >> def >> m_mapProps
362 >> m_strLibrary >> dummyI1 >> dummyI2
364 >> m_strDesktopEntryName
365 >> dummy1 >> dummyStr1 >> initpref >> dummyStr2 >> dummy2
366 >> m_lstKeywords >> m_strInit >> dummyUI32 >> m_strGenName
367 >> d->categories >> d->menuId;
369 m_bAllowAsDefault = def;
372 m_initialPreference = initpref;
377 void KService::save( TQDataStream& s )
379 KSycocaEntry::save( s );
380 TQ_INT8 def = m_bAllowAsDefault, initpref = m_initialPreference;
381 TQ_INT8 term = m_bTerminal;
382 TQ_INT8 dst = (TQ_INT8) m_DCOPServiceType;
383 TQ_INT8 dummy1 = 0, dummy2 = 0;
384 TQString dummyStr1, dummyStr2;
385 int dummyI1 = 0, dummyI2 = 0;
386 TQ_UINT32 dummyUI32 = 0;
392 s << m_strType << m_strName << m_strExec << m_strIcon
393 << term << m_strTerminalOptions
394 << m_strPath << m_strComment << m_lstServiceTypes << def << m_mapProps
395 << m_strLibrary << dummyI1 << dummyI2
397 << m_strDesktopEntryName
398 << dummy1 << dummyStr1 << initpref << dummyStr2 << dummy2
399 << m_lstKeywords << m_strInit << dummyUI32 << m_strGenName
400 << d->categories << d->menuId;
405 if (!m_bValid)
return false;
416 TQStringList::ConstIterator it = m_lstServiceTypes.begin();
417 for( ; it != m_lstServiceTypes.end(); ++it )
419 (*it).toInt(&isNumber);
424 if ( ptr && ptr->inherits( _servicetype ) )
430 if ( mimePtr && mimePtr->is( *it ) )
438 if (!m_bValid)
return 0;
443 TQStringList::ConstIterator it = m_lstServiceTypes.begin();
444 for( ; it != m_lstServiceTypes.end(); ++it )
446 (*it).toInt(&isNumber);
451 if ( !ptr || !ptr->inherits( mimeType ) )
454 int initalPreference = m_initialPreference;
456 if (it != m_lstServiceTypes.end())
458 int i = (*it).toInt(&isNumber);
460 initalPreference = i;
462 return initalPreference;
470 it = m_lstServiceTypes.begin();
471 for( ; it != m_lstServiceTypes.end(); ++it )
473 (*it).toInt(&isNumber);
480 if ( !mimePtr || !mimePtr->is( *it ) )
483 int initalPreference = m_initialPreference;
485 if (it != m_lstServiceTypes.end())
487 int i = (*it).toInt(&isNumber);
489 initalPreference = i;
491 return initalPreference;
496 class KServiceReadProperty :
public KConfigBase
499 KServiceReadProperty(
const TQString &_key,
const TQCString &_value)
500 : key(_key), value(_value) { }
502 bool internalHasGroup(
const TQCString &)
const {
return false; }
504 TQStringList groupList()
const {
return TQStringList(); }
506 TQMap<TQString,TQString> entryMap(
const TQString &group)
const
507 { Q_UNUSED(group);
return TQMap<TQString,TQString>(); }
509 void reparseConfiguration() { }
511 KEntryMap internalEntryMap(
const TQString &pGroup)
const
512 { Q_UNUSED(pGroup);
return KEntryMap(); }
514 KEntryMap internalEntryMap()
const {
return KEntryMap(); }
516 void putData(
const KEntryKey &_key,
const KEntry& _data,
bool _checkGroup)
517 { Q_UNUSED(_key); Q_UNUSED(_data); Q_UNUSED(_checkGroup); }
519 KEntry lookupData(
const KEntryKey &_key)
const
520 { Q_UNUSED(_key); KEntry entry; entry.mValue = value;
return entry; }
528 return property( _name, TQVariant::Invalid);
534 static TQVariant makeStringVariant(
const TQString&
string )
538 return string.isNull() ? TQVariant() : TQVariant( string );
543 if ( _name ==
"Type" )
544 return TQVariant( m_strType );
545 else if ( _name ==
"Name" )
546 return TQVariant( m_strName );
547 else if ( _name ==
"Exec" )
548 return makeStringVariant( m_strExec );
549 else if ( _name ==
"Icon" )
550 return makeStringVariant( m_strIcon );
551 else if ( _name ==
"Terminal" )
552 return TQVariant( static_cast<int>(m_bTerminal) );
553 else if ( _name ==
"TerminalOptions" )
554 return makeStringVariant( m_strTerminalOptions );
555 else if ( _name ==
"Path" )
556 return makeStringVariant( m_strPath );
557 else if ( _name ==
"Comment" )
558 return makeStringVariant( m_strComment );
559 else if ( _name ==
"GenericName" )
560 return makeStringVariant( m_strGenName );
561 else if ( _name ==
"ServiceTypes" )
562 return TQVariant( m_lstServiceTypes );
563 else if ( _name ==
"AllowAsDefault" )
564 return TQVariant( static_cast<int>(m_bAllowAsDefault) );
565 else if ( _name ==
"InitialPreference" )
566 return TQVariant( m_initialPreference );
567 else if ( _name ==
"Library" )
568 return makeStringVariant( m_strLibrary );
569 else if ( _name ==
"DesktopEntryPath" )
570 return TQVariant( entryPath() );
571 else if ( _name ==
"DesktopEntryName")
572 return TQVariant( m_strDesktopEntryName );
573 else if ( _name ==
"Categories")
574 return TQVariant( d->categories );
575 else if ( _name ==
"Keywords")
576 return TQVariant( m_lstKeywords );
580 if (t == TQVariant::Invalid)
584 t = KServiceTypeFactory::self()->findPropertyTypeByName(_name);
585 if (t == TQVariant::Invalid)
587 kdDebug(7012) <<
"Request for unknown property '" << _name <<
"'\n";
594 TQMap<TQString,TQVariant>::ConstIterator it = m_mapProps.find( _name );
595 if ( (it == m_mapProps.end()) || (!it.data().isValid()))
603 case TQVariant::String:
605 case TQVariant::Bool:
608 TQString aValue = it.data().toString();
610 if (aValue ==
"true" || aValue ==
"on" || aValue ==
"yes")
615 val = aValue.toInt( &bOK );
619 if (t == TQVariant::Bool)
621 return TQVariant((
bool)val, 1);
623 return TQVariant(val);
627 KServiceReadProperty ksrp(_name, it.data().toString().utf8());
628 return ksrp.readPropertyEntry(_name, t);
636 TQMap<TQString,TQVariant>::ConstIterator it = m_mapProps.begin();
637 for( ; it != m_mapProps.end(); ++it )
638 res.append( it.key() );
640 res.append(
"Type" );
641 res.append(
"Name" );
642 res.append(
"Comment" );
643 res.append(
"GenericName" );
644 res.append(
"Icon" );
645 res.append(
"Exec" );
646 res.append(
"Terminal" );
647 res.append(
"TerminalOptions" );
648 res.append(
"Path" );
649 res.append(
"ServiceTypes" );
650 res.append(
"AllowAsDefault" );
651 res.append(
"InitialPreference" );
652 res.append(
"Library" );
653 res.append(
"DesktopEntryPath" );
654 res.append(
"DesktopEntryName" );
655 res.append(
"Keywords" );
656 res.append(
"Categories" );
663 return KServiceFactory::self()->allServices();
668 KService * s = KServiceFactory::self()->findServiceByName( _name );
669 return KService::Ptr( s );
674 KService * s = KServiceFactory::self()->findServiceByDesktopPath( _name );
675 return KService::Ptr( s );
680 KService * s = KServiceFactory::self()->findServiceByDesktopName( _name.lower() );
681 if (!s && !_name.startsWith(
"kde-"))
682 s = KServiceFactory::self()->findServiceByDesktopName(
"kde-"+_name.lower() );
683 return KService::Ptr( s );
688 KService * s = KServiceFactory::self()->findServiceByMenuId( _name );
689 return KService::Ptr( s );
702 if (!TQDir::isRelativePath(_storageId) && TQFile::exists(_storageId))
705 TQString tmp = _storageId;
706 tmp = tmp.mid(tmp.findRev(
'/')+1);
708 if (tmp.endsWith(
".desktop"))
709 tmp.truncate(tmp.length()-8);
711 if (tmp.endsWith(
".kdelnk"))
712 tmp.truncate(tmp.length()-7);
721 return KServiceFactory::self()->allInitServices();
725 TQVariant v =
property(
"X-KDE-SubstituteUID", TQVariant::Bool);
726 return v.isValid() && v.toBool();
732 TQVariant v =
property(
"X-KDE-Username", TQVariant::String);
733 user = v.isValid() ? v.toString() : TQString::null;
735 user = ::getenv(
"ADMIN_ACCOUNT");
742 TQMap<TQString,TQVariant>::ConstIterator it = m_mapProps.find(
"NoDisplay" );
743 if ( (it != m_mapProps.end()) && (it.data().isValid()))
745 TQString aValue = it.data().toString().lower();
746 if (aValue ==
"true" || aValue ==
"on" || aValue ==
"yes")
750 it = m_mapProps.find(
"OnlyShowIn" );
751 if ( (it != m_mapProps.end()) && (it.data().isValid()))
753 TQString aValue = it.data().toString();
754 TQStringList aList = TQStringList::split(
';', aValue);
755 if ((!aList.contains(
"TDE")) && (!aList.contains(
"KDE")))
759 it = m_mapProps.find(
"NotShowIn" );
760 if ( (it != m_mapProps.end()) && (it.data().isValid()))
762 TQString aValue = it.data().toString();
763 TQStringList aList = TQStringList::split(
';', aValue);
764 if ((aList.contains(
"TDE")) || (aList.contains(
"KDE")))
768 if (!kapp->authorizeControlModule(d->menuId))
775 TQVariant v =
property(
"UntranslatedGenericName", TQVariant::String);
776 return v.isValid() ? v.toString() : TQString::null;
780 TQMap<TQString,TQVariant>::ConstIterator it = m_mapProps.find(
"X-SuSE-Unimportant" );
781 if ( (it == m_mapProps.end()) || (!it.data().isValid()))
786 TQString aValue = it.data().toString();
787 if (aValue ==
"true" || aValue ==
"on" || aValue ==
"yes")
794 TQMap<TQString,TQVariant>::ConstIterator it = m_mapProps.find(
"X-KDE-ParentApp" );
795 if ( (it == m_mapProps.end()) || (!it.data().isValid()))
797 return TQString::null;
800 return it.data().toString();
805 if ( m_strExec.find(
"%F" ) != -1 || m_strExec.find(
"%U" ) != -1 ||
806 m_strExec.find(
"%N" ) != -1 || m_strExec.find(
"%D" ) != -1 )
814 return d->categories;
822 void KService::setMenuId(
const TQString &menuId)
829 if (!d->menuId.isEmpty())
844 TQString *menuId,
const TQStringList *reservedMenuIds)
846 TQString base = suggestedName;
848 base.prepend(
"kde-");
851 for(
int i = 1;
true; i++)
854 result = base +
".desktop";
856 result = base + TQString(
"-%1.desktop").arg(i);
858 if (reservedMenuIds && reservedMenuIds->contains(result))
868 if (!locate(
"xdgdata-apps", result).isEmpty())
873 TQString file = result.mid(4);
874 if (!locate(
"apps",
".hidden/"+file).isEmpty())
889 TQString file = result.mid(4);
895 void KService::virtual_hook(
int id,
void* data )
896 { KSycocaEntry::virtual_hook(
id, data ); }
901 KServiceProgressDialog dlg(parent,
"ksycoca_progress",
902 i18n(
"Updating System Configuration"),
903 i18n(
"Updating system configuration."));
906 DCOPClient *client = kapp->dcopClient();
908 int result = client->callAsync(
"kded",
"kbuildsycoca",
"recreate()",
909 data, TQT_TQOBJECT(&dlg), TQT_SLOT(slotFinished()));
917 KServiceProgressDialog::KServiceProgressDialog(TQWidget *parent,
const char *name,
918 const TQString &caption,
const TQString &text)
919 : KProgressDialog(parent, name, caption, text, true)
921 connect(&m_timer, TQT_SIGNAL(timeout()),
this, TQT_SLOT(slotProgress()));
922 progressBar()->setTotalSteps(20);
924 m_timer.start(m_timeStep);
929 KServiceProgressDialog::slotProgress()
931 int p = progressBar()->progress();
934 progressBar()->reset();
935 progressBar()->setProgress(1);
936 m_timeStep = m_timeStep * 2;
937 m_timer.start(m_timeStep);
941 progressBar()->setProgress(p+1);
946 KServiceProgressDialog::slotFinished()
948 progressBar()->setProgress(20);
950 TQTimer::singleShot(1000,
this, TQT_SLOT(close()));
953 #include "kservice_p.moc"