48
48
// Loads data from a Lens key-file in a usable form
49
LensDirectoryReader::LensFileData::LensFileData(GKeyFile* file,
51
: id(g_strdup(lens_id))
52
, domain(g_key_file_get_string(file, G_KEY_FILE_DESKTOP_GROUP, "X-Ubuntu-Gettext-Domain", NULL))
53
, dbus_name(g_key_file_get_string(file, GROUP, "DBusName", NULL))
54
, dbus_path(g_key_file_get_string(file, GROUP, "DBusPath", NULL))
55
, name(g_strdup(g_dgettext(domain.Value(), g_key_file_get_string(file, GROUP, "Name", NULL))))
56
, icon(g_key_file_get_string(file, GROUP, "Icon", NULL))
57
, description(g_key_file_get_locale_string(file, GROUP, "Description", NULL, NULL))
58
, search_hint(g_key_file_get_locale_string(file, GROUP, "SearchHint", NULL, NULL))
60
, shortcut(g_key_file_get_string(file, GROUP, "Shortcut", NULL))
51
LensFileData(GKeyFile* file)
52
: domain(g_key_file_get_string(file, G_KEY_FILE_DESKTOP_GROUP, "X-Ubuntu-Gettext-Domain", NULL))
53
, dbus_name(g_key_file_get_string(file, GROUP, "DBusName", NULL))
54
, dbus_path(g_key_file_get_string(file, GROUP, "DBusPath", NULL))
55
, name(g_strdup(g_dgettext(domain.Value(), g_key_file_get_string(file, GROUP, "Name", NULL))))
56
, icon(g_key_file_get_string(file, GROUP, "Icon", NULL))
57
, description(g_key_file_get_locale_string(file, GROUP, "Description", NULL, NULL))
58
, search_hint(g_key_file_get_locale_string(file, GROUP, "SearchHint", NULL, NULL))
59
, visible(g_key_file_get_boolean(file, GROUP, "Visible", NULL))
60
, shortcut(g_key_file_get_string(file, GROUP, "Shortcut", NULL))
63
static bool IsValid(GKeyFile* file, glib::Error& error)
62
if (g_key_file_has_key(file, GROUP, "Visible", NULL))
65
return (g_key_file_has_group(file, GROUP) &&
66
g_key_file_has_key(file, GROUP, "DBusName", &error) &&
67
g_key_file_has_key(file, GROUP, "DBusPath", &error) &&
68
g_key_file_has_key(file, GROUP, "Name", &error) &&
69
g_key_file_has_key(file, GROUP, "Icon", &error));
64
visible = g_key_file_get_boolean(file, GROUP, "Visible", NULL) != FALSE;
73
glib::String dbus_name;
74
glib::String dbus_path;
77
glib::String description;
78
glib::String search_hint;
80
glib::String shortcut;
68
bool LensDirectoryReader::LensFileData::IsValid(GKeyFile* file, glib::Error& error)
70
return (g_key_file_has_group(file, GROUP) &&
71
g_key_file_has_key(file, GROUP, "DBusName", &error) &&
72
g_key_file_has_key(file, GROUP, "DBusPath", &error) &&
73
g_key_file_has_key(file, GROUP, "Name", &error) &&
74
g_key_file_has_key(file, GROUP, "Icon", &error));
83
77
/* A quick guide to finding Lens files
103
97
* override those found system-wide. This is to ease development of Lenses.
106
class FilesystemLenses::Impl
101
class LensDirectoryReader::Impl
109
104
typedef std::map<GFile*, glib::Object<GCancellable>> CancellableMap;
111
Impl(FilesystemLenses* owner);
112
Impl(FilesystemLenses* owner, std::string const& lens_directory);
116
LensList GetLenses() const;
117
Lens::Ptr GetLens(std::string const& lens_id) const;
118
Lens::Ptr GetLensAtIndex(std::size_t index) const;
119
Lens::Ptr GetLensForShortcut(std::string const& lens_shortcut) const;
120
std::size_t count() const;
123
glib::Object<GFile> BuildLensPathFile(std::string const& directory);
106
Impl(LensDirectoryReader *owner, std::string const& directory)
108
, directory_(g_file_new_for_path(directory.c_str()))
109
, children_waiting_to_load_(0)
110
, enumeration_done_(false)
112
LOG_DEBUG(logger) << "Initialising lens reader for: " << directory;
114
glib::Object<GCancellable> cancellable(g_cancellable_new());
115
g_file_enumerate_children_async(directory_,
116
G_FILE_ATTRIBUTE_STANDARD_NAME,
117
G_FILE_QUERY_INFO_NONE,
120
(GAsyncReadyCallback)OnDirectoryEnumerated,
122
cancel_map_[directory_] = cancellable;
127
for (auto pair: cancel_map_)
129
g_cancellable_cancel(pair.second);
124
133
void EnumerateLensesDirectoryChildren(GFileEnumerator* enumerator);
125
134
void LoadLensFile(std::string const& lensfile_path);
126
void CreateLensFromKeyFileData(GFile* path, const char* data, gsize length);
127
void DecrementAndCheckChildrenWaiting();
135
void GetLensDataFromKeyFile(GFile* path, const char* data, gsize length);
136
DataList GetLensData() const;
129
139
static void OnDirectoryEnumerated(GFile* source, GAsyncResult* res, Impl* self);
130
140
static void LoadFileContentCallback(GObject* source, GAsyncResult* res, gpointer user_data);
132
FilesystemLenses* owner_;
142
LensDirectoryReader *owner_;
133
143
glib::Object<GFile> directory_;
144
DataList lenses_data_;
134
145
std::size_t children_waiting_to_load_;
146
bool enumeration_done_;
135
147
CancellableMap cancel_map_;
139
FilesystemLenses::Impl::Impl(FilesystemLenses* owner)
141
, children_waiting_to_load_(0)
143
LOG_DEBUG(logger) << "Initialising in standard lens directory mode: " << LENSES_DIR;
145
directory_ = BuildLensPathFile(LENSES_DIR);
150
FilesystemLenses::Impl::Impl(FilesystemLenses* owner, std::string const& lens_directory)
152
, children_waiting_to_load_(0)
154
LOG_DEBUG(logger) << "Initialising in override lens directory mode";
156
directory_ = g_file_new_for_path(lens_directory.c_str());
161
FilesystemLenses::Impl::~Impl()
163
for (auto pair: cancel_map_)
165
g_cancellable_cancel(pair.second);
169
void FilesystemLenses::Impl::Init()
171
glib::String path(g_file_get_path(directory_));
172
LOG_DEBUG(logger) << "Searching for Lenses in: " << path;
174
glib::Object<GCancellable> cancellable(g_cancellable_new());
175
g_file_enumerate_children_async(directory_,
176
G_FILE_ATTRIBUTE_STANDARD_NAME,
177
G_FILE_QUERY_INFO_NONE,
180
(GAsyncReadyCallback)OnDirectoryEnumerated,
182
cancel_map_[directory_] = cancellable;
185
glib::Object<GFile> FilesystemLenses::Impl::BuildLensPathFile(std::string const& directory)
187
glib::Object<GFile> file(g_file_new_for_path(directory.c_str()));
191
void FilesystemLenses::Impl::OnDirectoryEnumerated(GFile* source, GAsyncResult* res, Impl* self)
150
void LensDirectoryReader::Impl::OnDirectoryEnumerated(GFile* source, GAsyncResult* res, Impl* self)
193
152
glib::Error error;
194
153
glib::Object<GFileEnumerator> enumerator(g_file_enumerate_children_finish(source, res, error.AsOutParam()));
196
155
if (error || !enumerator)
198
157
glib::String path(g_file_get_path(source));
199
LOG_WARN(logger) << "Unabled to enumerate children of directory "
158
LOG_WARN(logger) << "Unable to enumerate children of directory "
163
self->cancel_map_.erase(source);
204
164
self->EnumerateLensesDirectoryChildren(enumerator);
205
self->cancel_map_.erase(source);
208
void FilesystemLenses::Impl::EnumerateLensesDirectoryChildren(GFileEnumerator* enumerator)
167
void LensDirectoryReader::Impl::EnumerateLensesDirectoryChildren(GFileEnumerator* in_enumerator)
211
glib::Object<GFileInfo> info;
169
glib::Object<GCancellable> cancellable(g_cancellable_new());
213
while (info = g_file_enumerator_next_file(enumerator, NULL, error.AsOutParam()))
171
cancel_map_[g_file_enumerator_get_container(in_enumerator)] = cancellable;
172
g_file_enumerator_next_files_async (in_enumerator, 64, G_PRIORITY_DEFAULT,
174
[] (GObject *src, GAsyncResult *res,
175
gpointer data) -> void {
178
GFileEnumerator *enumerator = G_FILE_ENUMERATOR (src);
179
// FIXME: won't this kill the enumerator?
180
GList *files = g_file_enumerator_next_files_finish (enumerator, res, error.AsOutParam());
217
std::string name(g_file_info_get_name(info));
218
glib::String dir_path(g_file_get_path(g_file_enumerator_get_container(enumerator)));
219
std::string lensfile_name = name + ".lens";
221
glib::String lensfile_path(g_build_filename(dir_path.Value(),
223
lensfile_name.c_str(),
225
LoadLensFile(lensfile_path.Str());
183
Impl *self = (Impl*) data;
184
self->cancel_map_.erase(g_file_enumerator_get_container(enumerator));
185
for (GList *iter = files; iter; iter = iter->next)
187
glib::Object<GFileInfo> info((GFileInfo*) iter->data);
189
std::string name(g_file_info_get_name(info));
190
glib::String dir_path(g_file_get_path(g_file_enumerator_get_container(enumerator)));
191
std::string lensfile_name = name + ".lens";
193
glib::String lensfile_path(g_build_filename(dir_path.Value(),
195
lensfile_name.c_str(),
197
self->LoadLensFile(lensfile_path.Str());
199
// the GFileInfos got already freed during the iteration
201
self->enumeration_done_ = true;
229
205
LOG_WARN(logger) << "Cannot enumerate over directory: " << error;
235
void FilesystemLenses::Impl::LoadLensFile(std::string const& lensfile_path)
210
void LensDirectoryReader::Impl::LoadLensFile(std::string const& lensfile_path)
237
212
glib::Object<GFile> file(g_file_new_for_path(lensfile_path.c_str()));
238
213
glib::Object<GCancellable> cancellable(g_cancellable_new());
261
236
gboolean result = g_file_load_contents_finish(file, res,
262
237
&contents, &length,
263
238
NULL, error.AsOutParam());
264
if (result && !error)
266
self->CreateLensFromKeyFileData(file, contents.Value(), length);
241
self->GetLensDataFromKeyFile(file, contents.Value(), length);
242
self->SortLensList();
270
246
LOG_WARN(logger) << "Unable to read lens file "
271
247
<< path.Str() << ": "
249
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
250
return; // self is invalid now
275
self->DecrementAndCheckChildrenWaiting();
276
253
self->cancel_map_.erase(file);
279
void FilesystemLenses::Impl::DecrementAndCheckChildrenWaiting()
281
255
// If we're not waiting for any more children to load, signal that we're
282
256
// done reading the directory
283
children_waiting_to_load_--;
284
if (!children_waiting_to_load_)
257
self->children_waiting_to_load_--;
258
if (self->children_waiting_to_load_ == 0)
286
//FIXME: This should be it's own function, but we're trying not to break ABI
288
//FIXME: We don't have a strict order, but alphabetical serves us wonderfully for
289
// Oneiric. When we have an order/policy, please replace this.
290
auto sort_cb = [] (Lens::Ptr a, Lens::Ptr b) -> bool
292
if (a->id == "applications.lens")
294
else if (b->id == "applications.lens")
297
return g_strcmp0(a->id().c_str(), b->id().c_str()) < 0;
299
std::sort(lenses_.begin(),
302
for (Lens::Ptr& lens: lenses_)
303
owner_->lens_added.emit(lens);
305
owner_->lenses_loaded.emit();
260
self->owner_->load_finished.emit();
309
void FilesystemLenses::Impl::CreateLensFromKeyFileData(GFile* file,
264
void LensDirectoryReader::Impl::GetLensDataFromKeyFile(GFile* file,
310
265
const char* data,
350
295
g_key_file_free(key_file);
298
LensDirectoryReader::DataList LensDirectoryReader::Impl::GetLensData() const
303
void LensDirectoryReader::Impl::SortLensList()
305
//FIXME: We don't have a strict order, but alphabetical serves us well.
306
// When we have an order/policy, please replace this.
307
auto sort_cb = [] (LensFileData* a, LensFileData* b) -> bool
309
if (a->id.Str() == "applications.lens")
311
else if (b->id.Str() == "applications.lens")
314
return g_strcmp0(a->id.Value(), b->id.Value()) < 0;
316
std::sort(lenses_data_.begin(),
321
LensDirectoryReader::LensDirectoryReader(std::string const& directory)
322
: pimpl(new Impl(this, directory))
326
LensDirectoryReader::~LensDirectoryReader()
331
LensDirectoryReader::Ptr LensDirectoryReader::GetDefault()
333
static LensDirectoryReader::Ptr main_reader(new LensDirectoryReader(LENSES_DIR));
338
bool LensDirectoryReader::IsDataLoaded() const
340
return pimpl->children_waiting_to_load_ == 0 && pimpl->enumeration_done_;
343
LensDirectoryReader::DataList LensDirectoryReader::GetLensData() const
345
return pimpl->GetLensData();
348
class FilesystemLenses::Impl
351
Impl(FilesystemLenses* owner, LensDirectoryReader::Ptr const& reader);
354
if (timeout_id != 0) g_source_remove (timeout_id);
355
finished_slot_.disconnect();
358
void OnLoadingFinished();
360
LensList GetLenses() const;
361
Lens::Ptr GetLens(std::string const& lens_id) const;
362
Lens::Ptr GetLensAtIndex(std::size_t index) const;
363
Lens::Ptr GetLensForShortcut(std::string const& lens_shortcut) const;
364
std::size_t count() const;
366
FilesystemLenses* owner_;
367
LensDirectoryReader::Ptr reader_;
369
sigc::connection finished_slot_;
373
FilesystemLenses::Impl::Impl(FilesystemLenses* owner, LensDirectoryReader::Ptr const& reader)
378
finished_slot_ = reader_->load_finished.connect(sigc::mem_fun(this, &Impl::OnLoadingFinished));
379
if (reader_->IsDataLoaded())
381
// we won't get any signal, so let's just emit our signals after construction
382
timeout_id = g_idle_add_full (G_PRIORITY_DEFAULT,
383
[] (gpointer data) -> gboolean {
384
Impl *self = (Impl*) data;
385
self->timeout_id = 0;
386
self->OnLoadingFinished();
393
void FilesystemLenses::Impl::OnLoadingFinished()
395
// FIXME: clear lenses_ first?
396
for (auto lens_data : reader_->GetLensData())
398
Lens::Ptr lens(new Lens(lens_data->id,
399
lens_data->dbus_name,
400
lens_data->dbus_path,
403
lens_data->description,
404
lens_data->search_hint,
406
lens_data->shortcut));
407
lenses_.push_back (lens);
410
for (Lens::Ptr& lens: lenses_)
411
owner_->lens_added.emit(lens);
413
owner_->lenses_loaded.emit();
353
416
Lenses::LensList FilesystemLenses::Impl::GetLenses() const