2 // LauncherQueryable.cs
4 // Copyright (C) 2004 Joe Gasiorek
5 // Copyright (C) 2004 Novell, Inc.
9 // Permission is hereby granted, free of charge, to any person obtaining a
10 // copy of this software and associated documentation files (the "Software"),
11 // to deal in the Software without restriction, including without limitation
12 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 // and/or sell copies of the Software, and to permit persons to whom the
14 // Software is furnished to do so, subject to the following conditions:
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 // DEALINGS IN THE SOFTWARE.
29 using System
.Collections
;
32 using System
.Diagnostics
;
37 namespace Beagle
.Daemon
.LauncherQueryable
{
39 [QueryableFlavor (Name
="Launcher", Domain
=QueryDomain
.Local
, RequireInotify
=false)]
40 public class LauncherQueryable
: LuceneQueryable
{
42 private static Logger log
= Logger
.Get ("LauncherQueryable");
44 int polling_interval_in_hours
= 1;
46 public LauncherQueryable () : base ("LauncherIndex")
48 Dirs
= new ArrayList ();
50 string path
= Path
.Combine (ExternalStringsHack
.GnomePrefix
, "share");
51 Dirs
.Add (Path
.Combine (path
, "applications"));
52 Dirs
.Add (Path
.Combine (path
, "gnome/apps"));
53 Dirs
.Add (Path
.Combine (path
, "control-center-2.0"));
54 Dirs
.Add (Path
.Combine (path
, "control-center"));
55 Dirs
.Add (Path
.Combine (PathFinder
.HomeDir
, ".gnome2/panel2.d/default/launchers"));
58 foreach (string kde_dir
in KdeUtils
.KdeLocations
) {
59 if (kde_dir
== null || kde_dir
== String
.Empty
)
62 string share_dir
= Path
.Combine (kde_dir
, "share");
63 Dirs
.Add (Path
.Combine(share_dir
, "applications"));
65 Dirs
.Add (Path
.Combine (PathFinder
.HomeDir
, ".local/share/applications"));
68 override protected IFileAttributesStore
BuildFileAttributesStore (string index_fingerprint
)
70 return new FileAttributesStore_Mixed (IndexDirectory
, Driver
.Fingerprint
);
73 public override void Start ()
77 log
.Info ("Starting launcher backend");
78 Stopwatch timer
= new Stopwatch ();
83 if (!Inotify
.Enabled
) {
84 Scheduler
.Task task
= Scheduler
.TaskFromHook (new Scheduler
.TaskHook (CrawlHook
));
85 task
.Tag
= "Crawling system launchers";
86 ThisScheduler
.Add (task
);
90 log
.Info ("Launcher backend worker thread done in {0}", timer
);
95 log
.Info ("Scanning Launchers");
96 Stopwatch timer
= new Stopwatch ();
97 int launchers_found
= 0;
98 foreach (String dir
in Dirs
)
99 launchers_found
+= CrawlLaunchers (dir
);
101 log
.Info ("Found {0} Launchers in {1}", launchers_found
, timer
);
104 private void CrawlHook (Scheduler
.Task task
)
107 task
.Reschedule
= true;
108 task
.TriggerTime
= DateTime
.Now
.AddHours (this.polling_interval_in_hours
);
111 // Crawl the specified directory and all subdirectories, indexing all
112 // discovered launchers. If Inotify is available, every directory
113 // scanned will be watched.
114 private int CrawlLaunchers (string path
)
116 DirectoryInfo root
= new DirectoryInfo (path
);
121 Queue queue
= new Queue ();
122 queue
.Enqueue (root
);
124 while (queue
.Count
> 0) {
125 DirectoryInfo dir
= queue
.Dequeue () as DirectoryInfo
;
127 if (Inotify
.Enabled
) {
128 Inotify
.Subscribe (dir
.FullName
, OnInotifyEvent
, Inotify
.EventType
.Create
| Inotify
.EventType
.Modify
);
131 foreach (FileInfo file
in dir
.GetFiles ()) {
132 IndexLauncher (file
, Scheduler
.Priority
.Delayed
);
136 foreach (DirectoryInfo subdir
in dir
.GetDirectories ())
137 queue
.Enqueue (subdir
);
143 private void OnInotifyEvent (Inotify
.Watch watch
,
147 Inotify
.EventType type
)
152 string fullPath
= Path
.Combine (path
, subitem
);
154 if ((type
& Inotify
.EventType
.Create
) != 0 && (type
& Inotify
.EventType
.IsDirectory
) != 0) {
155 CrawlLaunchers (fullPath
);
158 if ((type
& Inotify
.EventType
.Modify
) != 0) {
159 IndexLauncher (new FileInfo (fullPath
), Scheduler
.Priority
.Immediate
);
164 private void IndexLauncher (FileInfo file
, Scheduler
.Priority priority
)
167 || (this.FileAttributesStore
.IsUpToDate (file
.FullName
)))
170 /* Check to see if file is a launcher */
171 if (Beagle
.Util
.VFS
.Mime
.GetMimeType (file
.FullName
) != "application/x-desktop")
177 reader
= new StreamReader (file
.Open (FileMode
.Open
, FileAccess
.Read
, FileShare
.Read
));
178 } catch (Exception e
) {
179 log
.Warn ("Could not open '{0}': {1}", file
.FullName
, e
.Message
);
183 if (reader
.ReadLine () != "[Desktop Entry]") {
188 /* I'm convinced it is a launcher */
189 Indexable indexable
= new Indexable (UriFu
.PathToFileUri (file
.FullName
));
191 indexable
.Timestamp
= file
.LastWriteTime
;
192 indexable
.Type
= "Launcher";
193 indexable
.MimeType
= "application/x-desktop";
195 // desktop files must have a name
196 bool have_name
= false;
199 while ((line
= reader
.ReadLine ()) != null) {
200 string [] sline
= line
.Split ('=');
201 if (sline
.Length
!= 2)
204 // FIXME: We shouldnt really search fields that are in other locales than the current should we?
206 if (sline
[0].Equals ("Icon") || sline
[0].Equals ("Exec")) {
207 indexable
.AddProperty (Beagle
.Property
.NewUnsearched ("fixme:" + sline
[0], sline
[1]));
208 } else if (sline
[0].StartsWith ("Name")) {
209 if (sline
[0] == "Name")
211 indexable
.AddProperty (Beagle
.Property
.NewUnsearched ("fixme:" + sline
[0], sline
[1]));
212 } else if (sline
[0].StartsWith ("Comment")) {
213 indexable
.AddProperty (Beagle
.Property
.New ("fixme:" + sline
[0], sline
[1]));
219 Scheduler
.Task task
= NewAddTask (indexable
);
220 task
.Priority
= priority
;
221 ThisScheduler
.Add (task
);