~3v1n0/unity/overlay-border-scale

« back to all changes in this revision

Viewing changes to UnityCore/FilesystemLenses.cpp

  • Committer: Daniel van Vugt
  • Date: 2012-03-14 06:24:18 UTC
  • mfrom: (2108 unity)
  • mto: This revision was merged to the branch mainline in revision 2146.
  • Revision ID: daniel.van.vugt@canonical.com-20120314062418-nprucpbr0m7qky5e
MergedĀ latestĀ lp:unity

Show diffs side-by-side

added added

removed removed

Lines of Context:
46
46
}
47
47
 
48
48
// Loads data from a Lens key-file in a usable form
49
 
struct LensFileData
 
49
LensDirectoryReader::LensFileData::LensFileData(GKeyFile* file, 
 
50
                                                const gchar *lens_id)
 
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))
 
59
  , visible(true)
 
60
  , shortcut(g_key_file_get_string(file, GROUP, "Shortcut", NULL))
50
61
{
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))
61
 
  {}
62
 
 
63
 
  static bool IsValid(GKeyFile* file, glib::Error& error)
 
62
  if (g_key_file_has_key(file, GROUP, "Visible", NULL))
64
63
  {
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;
70
65
  }
 
66
}
71
67
 
72
 
  glib::String domain;
73
 
  glib::String dbus_name;
74
 
  glib::String dbus_path;
75
 
  glib::String name;
76
 
  glib::String icon;
77
 
  glib::String description;
78
 
  glib::String search_hint;
79
 
  bool         visible;
80
 
  glib::String shortcut;
81
 
};
 
68
bool LensDirectoryReader::LensFileData::IsValid(GKeyFile* file, glib::Error& error)
 
69
{
 
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));
 
75
}
82
76
 
83
77
/* A quick guide to finding Lens files
84
78
 *
103
97
 * override those found system-wide. This is to ease development of Lenses.
104
98
 *
105
99
 */
106
 
class FilesystemLenses::Impl
 
100
 
 
101
class LensDirectoryReader::Impl
107
102
{
108
103
public:
109
104
  typedef std::map<GFile*, glib::Object<GCancellable>> CancellableMap;
110
105
 
111
 
  Impl(FilesystemLenses* owner);
112
 
  Impl(FilesystemLenses* owner, std::string const& lens_directory);
113
 
 
114
 
  ~Impl();
115
 
 
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;
121
 
 
122
 
  void Init();
123
 
  glib::Object<GFile> BuildLensPathFile(std::string const& directory);
 
106
  Impl(LensDirectoryReader *owner, std::string const& directory)
 
107
    : owner_(owner)
 
108
    , directory_(g_file_new_for_path(directory.c_str()))
 
109
    , children_waiting_to_load_(0)
 
110
    , enumeration_done_(false)
 
111
  {
 
112
    LOG_DEBUG(logger) << "Initialising lens reader for: " << directory;
 
113
 
 
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,
 
118
                                    G_PRIORITY_DEFAULT,
 
119
                                    cancellable,
 
120
                                    (GAsyncReadyCallback)OnDirectoryEnumerated,
 
121
                                    this);
 
122
    cancel_map_[directory_] = cancellable;
 
123
  }
 
124
 
 
125
  ~Impl()
 
126
  {
 
127
    for (auto pair: cancel_map_)
 
128
    {
 
129
      g_cancellable_cancel(pair.second);
 
130
    }
 
131
  }
 
132
 
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;
 
137
  void SortLensList();
128
138
  
129
139
  static void OnDirectoryEnumerated(GFile* source, GAsyncResult* res, Impl* self);
130
140
  static void LoadFileContentCallback(GObject* source, GAsyncResult* res, gpointer user_data);
131
141
 
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_;
136
 
  LensList lenses_;
137
148
};
138
149
 
139
 
FilesystemLenses::Impl::Impl(FilesystemLenses* owner)
140
 
  : owner_(owner)
141
 
  , children_waiting_to_load_(0)
142
 
{
143
 
  LOG_DEBUG(logger) << "Initialising in standard lens directory mode: " << LENSES_DIR;
144
 
 
145
 
  directory_ = BuildLensPathFile(LENSES_DIR);
146
 
 
147
 
  Init();
148
 
}
149
 
 
150
 
FilesystemLenses::Impl::Impl(FilesystemLenses* owner, std::string const& lens_directory)
151
 
  : owner_(owner)
152
 
  , children_waiting_to_load_(0)
153
 
{
154
 
  LOG_DEBUG(logger) << "Initialising in override lens directory mode";
155
 
 
156
 
  directory_ = g_file_new_for_path(lens_directory.c_str());
157
 
 
158
 
  Init();
159
 
}
160
 
 
161
 
FilesystemLenses::Impl::~Impl()
162
 
{
163
 
  for (auto pair: cancel_map_)
164
 
  {
165
 
    g_cancellable_cancel(pair.second);
166
 
  }
167
 
}
168
 
 
169
 
void FilesystemLenses::Impl::Init()
170
 
{
171
 
  glib::String path(g_file_get_path(directory_));
172
 
  LOG_DEBUG(logger) << "Searching for Lenses in: " << path;
173
 
 
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,
178
 
                                  G_PRIORITY_DEFAULT,
179
 
                                  cancellable,
180
 
                                  (GAsyncReadyCallback)OnDirectoryEnumerated,
181
 
                                  this);
182
 
  cancel_map_[directory_] = cancellable;
183
 
}
184
 
 
185
 
glib::Object<GFile> FilesystemLenses::Impl::BuildLensPathFile(std::string const& directory)
186
 
{
187
 
  glib::Object<GFile> file(g_file_new_for_path(directory.c_str()));
188
 
  return file;
189
 
}
190
 
 
191
 
void FilesystemLenses::Impl::OnDirectoryEnumerated(GFile* source, GAsyncResult* res, Impl* self)
 
150
void LensDirectoryReader::Impl::OnDirectoryEnumerated(GFile* source, GAsyncResult* res, Impl* self)
192
151
{
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)
197
156
  {
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 "
200
159
                     << path << " "
201
160
                     << error;
202
161
    return;
203
162
  }
 
163
  self->cancel_map_.erase(source);
204
164
  self->EnumerateLensesDirectoryChildren(enumerator);
205
 
  self->cancel_map_.erase(source);
206
165
}
207
166
 
208
 
void FilesystemLenses::Impl::EnumerateLensesDirectoryChildren(GFileEnumerator* enumerator)
 
167
void LensDirectoryReader::Impl::EnumerateLensesDirectoryChildren(GFileEnumerator* in_enumerator)
209
168
{
210
 
  glib::Error error;
211
 
  glib::Object<GFileInfo> info;
 
169
  glib::Object<GCancellable> cancellable(g_cancellable_new());
212
170
 
213
 
  while (info = g_file_enumerator_next_file(enumerator, NULL, error.AsOutParam()))
214
 
  {
215
 
    if (info && !error)
 
171
  cancel_map_[g_file_enumerator_get_container(in_enumerator)] = cancellable;
 
172
  g_file_enumerator_next_files_async (in_enumerator, 64, G_PRIORITY_DEFAULT,
 
173
                                      cancellable,
 
174
                                      [] (GObject *src, GAsyncResult *res,
 
175
                                          gpointer data) -> void {
 
176
    // async callback
 
177
    glib::Error error;
 
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());
 
181
    if (!error)
216
182
    {
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";
220
 
 
221
 
      glib::String lensfile_path(g_build_filename(dir_path.Value(),
222
 
                                                  name.c_str(),
223
 
                                                  lensfile_name.c_str(),
224
 
                                                  NULL));
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)
 
186
      {
 
187
        glib::Object<GFileInfo> info((GFileInfo*) iter->data);
 
188
 
 
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";
 
192
 
 
193
        glib::String lensfile_path(g_build_filename(dir_path.Value(),
 
194
                                                    name.c_str(),
 
195
                                                    lensfile_name.c_str(),
 
196
                                                    NULL));
 
197
        self->LoadLensFile(lensfile_path.Str());
 
198
      }
 
199
      // the GFileInfos got already freed during the iteration
 
200
      g_list_free (files);
 
201
      self->enumeration_done_ = true;
226
202
    }
227
203
    else
228
204
    {
229
205
      LOG_WARN(logger) << "Cannot enumerate over directory: " << error;
230
 
      continue;
231
206
    }
232
 
  }
 
207
  }, this);
233
208
}
234
209
 
235
 
void FilesystemLenses::Impl::LoadLensFile(std::string const& lensfile_path)
 
210
void LensDirectoryReader::Impl::LoadLensFile(std::string const& lensfile_path)
236
211
{
237
212
  glib::Object<GFile> file(g_file_new_for_path(lensfile_path.c_str()));
238
213
  glib::Object<GCancellable> cancellable(g_cancellable_new());
242
217
 
243
218
  g_file_load_contents_async(file,
244
219
                             cancellable,
245
 
                             (GAsyncReadyCallback)(FilesystemLenses::Impl::LoadFileContentCallback),
 
220
                             (GAsyncReadyCallback)(LensDirectoryReader::Impl::LoadFileContentCallback),
246
221
                             this);
247
222
  cancel_map_[file] = cancellable;
248
223
}
249
224
 
250
 
void FilesystemLenses::Impl::LoadFileContentCallback(GObject* source,
251
 
                                                     GAsyncResult* res,
252
 
                                                     gpointer user_data)
 
225
void LensDirectoryReader::Impl::LoadFileContentCallback(GObject* source,
 
226
                                                        GAsyncResult* res,
 
227
                                                        gpointer user_data)
253
228
{
254
229
  Impl* self = static_cast<Impl*>(user_data);
255
230
  glib::Error error;
261
236
  gboolean result = g_file_load_contents_finish(file, res,
262
237
                                                &contents, &length,
263
238
                                                NULL, error.AsOutParam());
264
 
  if (result && !error)
 
239
  if (result)
265
240
  {
266
 
    self->CreateLensFromKeyFileData(file, contents.Value(), length);
 
241
    self->GetLensDataFromKeyFile(file, contents.Value(), length);
 
242
    self->SortLensList();
267
243
  }
268
244
  else
269
245
  {
270
246
    LOG_WARN(logger) << "Unable to read lens file "
271
247
                     << path.Str() << ": "
272
248
                     << error;
 
249
    if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 
250
      return; // self is invalid now
273
251
  }
274
252
  
275
 
  self->DecrementAndCheckChildrenWaiting();
276
253
  self->cancel_map_.erase(file);
277
 
}
278
254
 
279
 
void FilesystemLenses::Impl::DecrementAndCheckChildrenWaiting()
280
 
{
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)
285
259
  {
286
 
    //FIXME: This should be it's own function, but we're trying not to break ABI
287
 
    // right now.
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
291
 
      {
292
 
        if (a->id == "applications.lens")
293
 
          return true;
294
 
        else if (b->id == "applications.lens")
295
 
          return false;
296
 
        else
297
 
          return g_strcmp0(a->id().c_str(), b->id().c_str()) < 0; 
298
 
      };
299
 
    std::sort(lenses_.begin(),
300
 
              lenses_.end(),
301
 
              sort_cb);
302
 
    for (Lens::Ptr& lens: lenses_)
303
 
      owner_->lens_added.emit(lens);
304
 
 
305
 
    owner_->lenses_loaded.emit();
 
260
    self->owner_->load_finished.emit();
306
261
  }
307
262
}
308
263
 
309
 
void FilesystemLenses::Impl::CreateLensFromKeyFileData(GFile* file,
 
264
void LensDirectoryReader::Impl::GetLensDataFromKeyFile(GFile* file,
310
265
                                                       const char* data,
311
266
                                                       gsize length)
312
267
{
318
273
  {
319
274
    if (LensFileData::IsValid(key_file, error))
320
275
    {
321
 
      LensFileData data(key_file);
322
276
      glib::String id(g_path_get_basename(path.Value()));
323
277
 
324
 
      Lens::Ptr lens(new Lens(id.Str(),
325
 
                              data.dbus_name.Str(),
326
 
                              data.dbus_path.Str(),
327
 
                              data.name.Str(),
328
 
                              data.icon.Str(),
329
 
                              data.description.Str(),
330
 
                              data.search_hint.Str(),
331
 
                              data.visible,
332
 
                              data.shortcut.Str()));
333
 
      lenses_.push_back(lens);
 
278
      lenses_data_.push_back(new LensFileData(key_file, id));
334
279
 
335
280
      LOG_DEBUG(logger) << "Sucessfully loaded lens file " << path;
336
281
    }
350
295
  g_key_file_free(key_file);
351
296
}
352
297
 
 
298
LensDirectoryReader::DataList LensDirectoryReader::Impl::GetLensData() const
 
299
{
 
300
  return lenses_data_;
 
301
}
 
302
 
 
303
void LensDirectoryReader::Impl::SortLensList()
 
304
{
 
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
 
308
  {
 
309
    if (a->id.Str() == "applications.lens")
 
310
      return true;
 
311
    else if (b->id.Str() == "applications.lens")
 
312
      return false;
 
313
    else
 
314
      return g_strcmp0(a->id.Value(), b->id.Value()) < 0;
 
315
  };
 
316
  std::sort(lenses_data_.begin(),
 
317
            lenses_data_.end(),
 
318
            sort_cb);
 
319
}
 
320
 
 
321
LensDirectoryReader::LensDirectoryReader(std::string const& directory)
 
322
  : pimpl(new Impl(this, directory))
 
323
{
 
324
}
 
325
 
 
326
LensDirectoryReader::~LensDirectoryReader()
 
327
{
 
328
  delete pimpl;
 
329
}
 
330
 
 
331
LensDirectoryReader::Ptr LensDirectoryReader::GetDefault()
 
332
{
 
333
  static LensDirectoryReader::Ptr main_reader(new LensDirectoryReader(LENSES_DIR));
 
334
 
 
335
  return main_reader;
 
336
}
 
337
 
 
338
bool LensDirectoryReader::IsDataLoaded() const
 
339
{
 
340
  return pimpl->children_waiting_to_load_ == 0 && pimpl->enumeration_done_;
 
341
}
 
342
 
 
343
LensDirectoryReader::DataList LensDirectoryReader::GetLensData() const
 
344
{
 
345
  return pimpl->GetLensData();
 
346
}
 
347
 
 
348
class FilesystemLenses::Impl
 
349
{
 
350
public:
 
351
  Impl(FilesystemLenses* owner, LensDirectoryReader::Ptr const& reader);
 
352
  ~Impl()
 
353
  {
 
354
    if (timeout_id != 0) g_source_remove (timeout_id);
 
355
    finished_slot_.disconnect();
 
356
  }
 
357
 
 
358
  void OnLoadingFinished();
 
359
 
 
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;
 
365
 
 
366
  FilesystemLenses* owner_;
 
367
  LensDirectoryReader::Ptr reader_;
 
368
  LensList lenses_;
 
369
  sigc::connection finished_slot_;
 
370
  guint timeout_id;
 
371
};
 
372
 
 
373
FilesystemLenses::Impl::Impl(FilesystemLenses* owner, LensDirectoryReader::Ptr const& reader)
 
374
  : owner_(owner)
 
375
  , reader_(reader)
 
376
  , timeout_id(0)
 
377
{
 
378
  finished_slot_ = reader_->load_finished.connect(sigc::mem_fun(this, &Impl::OnLoadingFinished));
 
379
  if (reader_->IsDataLoaded())
 
380
  {
 
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();
 
387
                                    return FALSE;
 
388
                                  },
 
389
                                  this, NULL);
 
390
  }
 
391
}
 
392
 
 
393
void FilesystemLenses::Impl::OnLoadingFinished()
 
394
{
 
395
  // FIXME: clear lenses_ first?
 
396
  for (auto lens_data : reader_->GetLensData())
 
397
  {
 
398
    Lens::Ptr lens(new Lens(lens_data->id,
 
399
                            lens_data->dbus_name,
 
400
                            lens_data->dbus_path,
 
401
                            lens_data->name,
 
402
                            lens_data->icon,
 
403
                            lens_data->description,
 
404
                            lens_data->search_hint,
 
405
                            lens_data->visible,
 
406
                            lens_data->shortcut));
 
407
    lenses_.push_back (lens);
 
408
  }
 
409
 
 
410
  for (Lens::Ptr& lens: lenses_)
 
411
    owner_->lens_added.emit(lens);
 
412
 
 
413
  owner_->lenses_loaded.emit();
 
414
}
 
415
 
353
416
Lenses::LensList FilesystemLenses::Impl::GetLenses() const
354
417
{
355
418
  return lenses_;
401
464
 
402
465
 
403
466
FilesystemLenses::FilesystemLenses()
404
 
  : pimpl(new Impl(this))
 
467
  : pimpl(new Impl(this, LensDirectoryReader::GetDefault()))
405
468
{
406
469
  Init();
407
470
}
408
471
 
409
 
FilesystemLenses::FilesystemLenses(std::string const& lens_directory)
410
 
  : pimpl(new Impl(this, lens_directory))
 
472
FilesystemLenses::FilesystemLenses(LensDirectoryReader::Ptr const& reader)
 
473
  : pimpl(new Impl(this, reader))
411
474
{
412
475
  Init();
413
476
}