~unity-team/unity/libunity-7.0-breakage

« back to all changes in this revision

Viewing changes to UnityCore/GLibDBusProxy.cpp

GDBusProxy: Add support for property changes callbacks

It's now possible to connect/disconnect to dbus-property changes.
The signal handler is enabled/disabled dinamically.

Show diffs side-by-side

added added

removed removed

Lines of Context:
80
80
  bool IsConnected() const;
81
81
 
82
82
  void OnProxyNameOwnerChanged(GDBusProxy*, GParamSpec*);
83
 
  void OnProxySignal(GDBusProxy* proxy, char* sender_name, char* signal_name,
84
 
                     GVariant* parameters);
 
83
  void OnProxySignal(GDBusProxy* proxy, const char*, const char*, GVariant*);
 
84
  void OnPropertyChanged(GDBusProxy*, GVariant*, GStrv*);
85
85
 
86
86
  static void OnProxyConnectCallback(GObject* source, GAsyncResult* res, gpointer impl);
87
87
  static void OnCallCallback(GObject* source, GAsyncResult* res, gpointer call_data);
104
104
  bool connected_;
105
105
  unsigned reconnection_attempts_;
106
106
 
107
 
  glib::Signal<void, GDBusProxy*, char*, char*, GVariant*> g_signal_connection_;
 
107
  glib::Signal<void, GDBusProxy*, const char*, const char*, GVariant*> g_signal_connection_;
 
108
  glib::Signal<void, GDBusProxy*, GVariant*, GStrv*> g_property_signal_;
108
109
  glib::Signal<void, GDBusProxy*, GParamSpec*> name_owner_signal_;
109
110
  glib::Source::UniquePtr reconnect_timeout_;
110
111
  sigc::signal<void> proxy_acquired;
111
112
 
112
 
  SignalHandlers handlers_;
 
113
  SignalHandlers signal_handlers_;
 
114
  SignalHandlers property_handlers_;
113
115
};
114
116
 
115
117
DBusProxy::Impl::Impl(DBusProxy* owner,
202
204
  self->name_owner_signal_.Connect(self->proxy_, "notify::g-name-owner",
203
205
                                   sigc::mem_fun(self, &Impl::OnProxyNameOwnerChanged));
204
206
 
205
 
  if (!self->handlers_.empty())
 
207
  if (!self->signal_handlers_.empty())
206
208
  {
207
209
    // Connecting to the signals only if we have handlers
208
210
    if (glib::object_cast<GObject>(self->proxy_) != self->g_signal_connection_.object())
209
211
      self->g_signal_connection_.Connect(self->proxy_, "g-signal", sigc::mem_fun(self, &Impl::OnProxySignal));
210
212
  }
211
213
 
 
214
  if (!self->property_handlers_.empty())
 
215
  {
 
216
    // Connecting to the property-changed only if we have handlers
 
217
    if (glib::object_cast<GObject>(self->proxy_) != self->g_property_signal_.object())
 
218
      self->g_property_signal_.Connect(self->proxy_, "g-properties-changed", sigc::mem_fun(self, &Impl::OnPropertyChanged));
 
219
  }
 
220
 
212
221
  // If a proxy cannot autostart a service, it doesn't throw an error, but
213
222
  // sets name_owner to NULL
214
223
  if (glib::String(g_dbus_proxy_get_name_owner(proxy)))
243
252
  }
244
253
}
245
254
 
246
 
void DBusProxy::Impl::OnProxySignal(GDBusProxy* proxy,
247
 
                                    char* sender_name,
248
 
                                    char* signal_name,
249
 
                                    GVariant* parameters)
 
255
void DBusProxy::Impl::OnProxySignal(GDBusProxy* proxy, const char* sender_name, const char* signal_name, GVariant* parameters)
250
256
{
251
257
  LOG_DEBUG(logger) << "Signal Received for proxy (" << object_path_ << ") "
252
258
                    << "SenderName: " << sender_name << " "
253
259
                    << "SignalName: " << signal_name << " "
254
260
                    << "ParameterType: " << g_variant_get_type_string(parameters);
255
261
 
256
 
  auto handler_it = handlers_.find(signal_name);
 
262
  auto handler_it = signal_handlers_.find(signal_name);
257
263
 
258
 
  if (handler_it != handlers_.end())
 
264
  if (handler_it != signal_handlers_.end())
259
265
  {
260
266
    for (ReplyCallback const& callback : handler_it->second)
261
267
      callback(parameters);
262
268
  }
263
269
}
264
270
 
 
271
void DBusProxy::Impl::OnPropertyChanged(GDBusProxy* proxy, GVariant* changed_props, GStrv* invalidated)
 
272
{
 
273
  LOG_DEBUG(logger) << "Properties changed for proxy (" << object_path_ << ")";
 
274
 
 
275
  if (g_variant_n_children(changed_props) > 0)
 
276
  {
 
277
    GVariantIter *iter;
 
278
    const gchar *property_name;
 
279
    GVariant *value;
 
280
 
 
281
    g_variant_get(changed_props, "a{sv}", &iter);
 
282
    while (g_variant_iter_loop (iter, "{&sv}", &property_name, &value))
 
283
    {
 
284
      LOG_DEBUG(logger) << "Property: '" << property_name << "': "
 
285
                        << glib::String(g_variant_print(value, TRUE));
 
286
 
 
287
      auto handler_it = property_handlers_.find(property_name);
 
288
 
 
289
      if (handler_it != property_handlers_.end())
 
290
      {
 
291
        for (ReplyCallback const& callback : handler_it->second)
 
292
          callback(value);
 
293
      }
 
294
    }
 
295
 
 
296
    g_variant_iter_free (iter);
 
297
  }
 
298
}
 
299
 
265
300
void DBusProxy::Impl::WaitForProxy(GCancellable* cancellable,
266
301
                                   int timeout_msec,
267
302
                                   std::function<void(glib::Error const&)> const& callback)
402
437
    g_signal_connection_.Connect(proxy_, "g-signal", sigc::mem_fun(this, &Impl::OnProxySignal));
403
438
  }
404
439
 
405
 
  handlers_[signal_name].push_back(callback);
 
440
  signal_handlers_[signal_name].push_back(callback);
406
441
}
407
442
 
408
443
void DBusProxy::Impl::DisconnectSignal(std::string const& signal_name)
409
444
{
410
445
  if (signal_name.empty())
411
446
  {
412
 
    handlers_.clear();
 
447
    signal_handlers_.clear();
413
448
  }
414
449
  else
415
450
  {
416
 
    handlers_.erase(signal_name);
 
451
    signal_handlers_.erase(signal_name);
417
452
  }
418
453
 
419
 
  if (handlers_.empty())
 
454
  if (signal_handlers_.empty())
420
455
    g_signal_connection_.Disconnect();
421
456
}
422
457
 
530
565
  }
531
566
}
532
567
 
 
568
void DBusProxy::ConnectProperty(std::string const& name, ReplyCallback const& callback)
 
569
{
 
570
  if (!callback || name.empty())
 
571
  {
 
572
    LOG_WARN(logger) << "Impossible to connect to empty property or with invalid callback";
 
573
    return;
 
574
  }
 
575
 
 
576
  if (pimpl->proxy_ && glib::object_cast<GObject>(pimpl->proxy_) != pimpl->g_property_signal_.object())
 
577
  {
 
578
    // It's the first time we connect to a property so we need to setup the call handler
 
579
    pimpl->g_property_signal_.Connect(pimpl->proxy_, "g-properties-changed", sigc::mem_fun(pimpl.get(), &Impl::OnPropertyChanged));
 
580
  }
 
581
 
 
582
  pimpl->property_handlers_[name].push_back(callback);
 
583
}
 
584
 
 
585
void DBusProxy::DisconnectProperty(std::string const& name)
 
586
{
 
587
  if (name.empty())
 
588
  {
 
589
    pimpl->property_handlers_.clear();
 
590
  }
 
591
  else
 
592
  {
 
593
    pimpl->property_handlers_.erase(name);
 
594
  }
 
595
 
 
596
  if (pimpl->property_handlers_.empty())
 
597
    pimpl->g_property_signal_.Disconnect();
 
598
}
 
599
 
533
600
void DBusProxy::Connect(std::string const& signal_name, ReplyCallback const& callback)
534
601
{
535
602
  pimpl->Connect(signal_name, callback);