~gordallott/unity/unity-gtk3

« back to all changes in this revision

Viewing changes to src/DBusIndicators.cpp

  • Committer: Gord Allott
  • Date: 2011-06-16 14:09:48 UTC
  • mfrom: (1187.1.53 trunk)
  • Revision ID: gord.allott@canonical.com-20110616140948-wz5f46qpvwwg3ttl
save point

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
2
2
/*
3
 
 * Copyright (C) 2010 Canonical Ltd
 
3
 * Copyright (C) 2010, 2011 Canonical Ltd
4
4
 *
5
5
 * This program is free software: you can redistribute it and/or modify
6
6
 * it under the terms of the GNU General Public License version 3 as
17
17
 * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
18
18
 */
19
19
 
20
 
#include "config.h"
21
 
 
22
 
#include "IndicatorObjectFactoryRemote.h"
23
 
 
24
 
#include "IndicatorObjectProxyRemote.h"
25
 
#include "IndicatorObjectEntryProxyRemote.h"
26
 
#include "IndicatorObjectEntryProxy.h"
27
 
 
 
20
#include "DBusIndicators.h"
 
21
 
 
22
#include <algorithm>
 
23
 
 
24
#include <gio/gio.h>
 
25
#include <dee.h>
 
26
 
 
27
#include <X11/Xlib.h>
28
28
#include "Nux/Nux.h"
29
29
#include "Nux/WindowThread.h"
30
30
#include "NuxGraphics/GLWindowManager.h"
31
 
#include <X11/Xlib.h>
32
 
#include <algorithm>
33
 
 
34
 
#define S_NAME  "com.canonical.Unity.Panel.Service"
35
 
#define S_PATH  "/com/canonical/Unity/Panel/Service"
36
 
#define S_IFACE "com.canonical.Unity.Panel.Service"
37
 
 
38
 
typedef struct
39
 
{
40
 
  GDBusProxy *proxy;
41
 
  gchar *entry_id;
 
31
 
 
32
#include "config.h"
 
33
#include "GLibWrapper.h"
 
34
#include "Variant.h"
 
35
 
 
36
 
 
37
namespace unity {
 
38
namespace indicator {
 
39
 
 
40
namespace {
 
41
// This anonymous namespace holds the DBus callback methods.
 
42
 
 
43
struct SyncData
 
44
{
 
45
  SyncData(DBusIndicators::Impl* self_)
 
46
  : self(self_)
 
47
  , cancel(g_cancellable_new())
 
48
  {
 
49
  }
 
50
 
 
51
  ~SyncData()
 
52
  {
 
53
    if (cancel) {
 
54
      g_cancellable_cancel(cancel);
 
55
      g_object_unref(cancel);
 
56
    }
 
57
  }
 
58
 
 
59
  void SyncComplete()
 
60
  {
 
61
    if (cancel) {
 
62
     g_object_unref(cancel);
 
63
    }
 
64
    cancel = NULL;
 
65
  }
 
66
 
 
67
  DBusIndicators::Impl* self;
 
68
  GCancellable* cancel;
 
69
};
 
70
 
 
71
typedef boost::shared_ptr<SyncData> SyncDataPtr;
 
72
 
 
73
const char* const S_NAME = "com.canonical.Unity.Panel.Service";
 
74
const char* const S_PATH = "/com/canonical/Unity/Panel/Service";
 
75
const char* const S_IFACE = "com.canonical.Unity.Panel.Service";
 
76
 
 
77
struct ShowEntryData
 
78
{
 
79
  GDBusProxy* proxy;
 
80
  std::string entry_id;
42
81
  int x;
43
82
  int y;
44
83
  guint timestamp;
45
84
  guint32 button;
46
 
 
47
 
} ShowEntryData;
48
 
 
49
 
 
50
 
// Forwards
51
 
static void on_proxy_ready_cb (GObject      *source,
52
 
                               GAsyncResult *res,
53
 
                               gpointer      data);
54
 
 
55
 
static void on_proxy_signal_received (GDBusProxy *proxy,
56
 
                                      gchar      *sender_name,
57
 
                                      gchar      *signal_name,
58
 
                                      GVariant   *parameters,
59
 
                                      IndicatorObjectFactoryRemote *remote);
60
 
 
61
 
static void on_proxy_name_owner_changed (GDBusProxy *proxy,
62
 
                                         GParamSpec *pspec,
63
 
                                         IndicatorObjectFactoryRemote *remote);
64
 
 
65
 
static void on_sync_ready_cb (GObject      *source,
66
 
                              GAsyncResult *res,
67
 
                              gpointer      data);
68
 
 
69
 
static bool run_local_panel_service ();
70
 
static bool reconnect_to_service (gpointer data);
 
85
};
 
86
 
 
87
bool run_local_panel_service();
 
88
gboolean reconnect_to_service(gpointer data);
 
89
void on_proxy_ready_cb(GObject* source, GAsyncResult* res, gpointer data);
 
90
void on_proxy_name_owner_changed(GDBusProxy* proxy, GParamSpec* pspec,
 
91
                                 DBusIndicators::Impl* remote);
 
92
void on_proxy_signal_received(GDBusProxy* proxy,
 
93
                              char* sender_name, char* signal_name,
 
94
                              GVariant* parameters,
 
95
                              DBusIndicators::Impl* remote);
 
96
void request_sync(GDBusProxy* proxy, const char* method, GVariant* name,
 
97
                  SyncData* data);
 
98
void on_sync_ready_cb(GObject* source, GAsyncResult* res, gpointer data);
 
99
 
 
100
bool send_show_entry(ShowEntryData *data);
 
101
 
 
102
} // anonymous namespace
 
103
 
 
104
 
 
105
// Connects to the remote panel service (unity-panel-service) and translates
 
106
// that into something that the panel can show
 
107
class DBusIndicators::Impl
 
108
{
 
109
public:
 
110
  Impl(DBusIndicators* owner);
 
111
  ~Impl();
 
112
 
 
113
  void OnRemoteProxyReady(GDBusProxy *proxy);
 
114
  void Reconnect();
 
115
  void RequestSyncAll();
 
116
  void RequestSyncIndicator(std::string const& name);
 
117
  void Sync(GVariant* args, SyncData* data);
 
118
  void SyncGeometries(std::string const& name,
 
119
                      EntryLocationMap const& locations);
 
120
 
 
121
  virtual void OnEntryScroll(std::string const& entry_id, int delta);
 
122
  virtual void OnEntryShowMenu(std::string const& entry_id,
 
123
                               int x, int y, int timestamp, int button);
 
124
 
 
125
  std::string name() const;
 
126
  std::string owner_name() const;
 
127
  bool using_local_service() const;
 
128
 
 
129
  DBusIndicators* owner_;
 
130
  GDBusProxy* proxy_;
 
131
  guint32 proxy_signal_id_;
 
132
  guint32 proxy_name_id_;
 
133
  typedef std::vector<SyncDataPtr> PendingSyncs;
 
134
  PendingSyncs pending_syncs_;
 
135
};
 
136
 
71
137
 
72
138
// Public Methods
73
 
IndicatorObjectFactoryRemote::IndicatorObjectFactoryRemote ()
74
 
: _proxy (NULL)
75
 
{
76
 
  Reconnect ();
77
 
}
78
 
 
79
 
IndicatorObjectFactoryRemote::~IndicatorObjectFactoryRemote ()
80
 
{
81
 
  if (G_IS_OBJECT (_proxy))
82
 
  {
83
 
    g_signal_handler_disconnect (_proxy, _proxy_signal_id);
84
 
    g_signal_handler_disconnect (_proxy, _proxy_name_id);
85
 
    g_object_unref (_proxy);
86
 
  }
87
 
  _proxy = NULL;
88
 
 
89
 
  {
90
 
    std::vector<IndicatorObjectProxy*>::iterator it;
91
 
    for (it = _indicators.begin(); it != _indicators.end(); it++)
92
 
    {
93
 
      IndicatorObjectProxyRemote *remote = static_cast<IndicatorObjectProxyRemote *> (*it);
94
 
      delete remote;
95
 
    }
96
 
    _indicators.erase (_indicators.begin (), _indicators.end ());
97
 
  }
98
 
 
99
 
  { // We cancel all our async callbacks from pending Sync() calls
100
 
    std::vector<SyncData *>::iterator it, eit = _sync_cancellables.end ();
101
 
    for (it = _sync_cancellables.begin (); it != eit; ++it)
102
 
    {
103
 
      SyncData *data = (*it);
104
 
      g_cancellable_cancel (data->_cancel);
105
 
      delete data;
106
 
    }
107
 
    _sync_cancellables.erase (_sync_cancellables.begin (), _sync_cancellables.end ());
108
 
  }
109
 
}
110
 
 
111
 
std::vector<IndicatorObjectProxy *>&
112
 
IndicatorObjectFactoryRemote::GetIndicatorObjects ()
113
 
{
114
 
  return _indicators;
115
 
}
116
 
 
117
 
void
118
 
IndicatorObjectFactoryRemote::ForceRefresh ()
119
 
{
120
 
}
121
 
 
122
 
void
123
 
IndicatorObjectFactoryRemote::Reconnect ()
124
 
{
125
 
  g_spawn_command_line_sync ("killall unity-panel-service", NULL, NULL, NULL, NULL);
 
139
DBusIndicators::Impl::Impl(DBusIndicators* owner)
 
140
  : owner_(owner)
 
141
  , proxy_(NULL)
 
142
{
 
143
  Reconnect();
 
144
}
 
145
 
 
146
DBusIndicators::Impl::~Impl()
 
147
{
 
148
  if (G_IS_OBJECT (proxy_))
 
149
  {
 
150
    g_signal_handler_disconnect(proxy_, proxy_signal_id_);
 
151
    g_signal_handler_disconnect(proxy_, proxy_name_id_);
 
152
    g_object_unref(proxy_);
 
153
  }
 
154
}
 
155
 
 
156
void DBusIndicators::Impl::Reconnect()
 
157
{
 
158
  g_spawn_command_line_sync("killall unity-panel-service",
 
159
                            NULL, NULL, NULL, NULL);
126
160
 
127
161
  if (g_getenv ("PANEL_USE_LOCAL_SERVICE"))
128
162
  {
129
 
    run_local_panel_service ();
130
 
    g_timeout_add_seconds (1, (GSourceFunc)reconnect_to_service, this);
 
163
    run_local_panel_service();
 
164
    g_timeout_add_seconds(1, reconnect_to_service, this);
131
165
  }
132
166
  else
133
167
  {
134
168
    // We want to grab the Panel Service object. This is async, which is fine
135
 
    reconnect_to_service (this);
 
169
    reconnect_to_service(this);
136
170
  }
137
171
}
138
172
 
139
 
void
140
 
IndicatorObjectFactoryRemote::OnRemoteProxyReady (GDBusProxy *proxy)
 
173
void DBusIndicators::Impl::OnRemoteProxyReady(GDBusProxy *proxy)
141
174
{
142
 
  if (_proxy)
 
175
  if (proxy_)
143
176
  {
144
177
    // We've been connected before; We don't need new proxy, just continue
145
178
    // rocking with the old one.
146
 
    g_object_unref (proxy);
 
179
    g_object_unref(proxy);
147
180
  }
148
181
  else
149
182
  {
150
 
    _proxy = proxy;
151
 
 
 
183
    proxy_ = proxy;
152
184
    // Connect to interesting signals
153
 
    _proxy_signal_id = g_signal_connect (_proxy, "g-signal",
154
 
                                         G_CALLBACK (on_proxy_signal_received), this);
155
 
    _proxy_name_id = g_signal_connect (_proxy, "notify::g-name-owner",
156
 
                                       G_CALLBACK (on_proxy_name_owner_changed), this);
 
185
    proxy_signal_id_ = g_signal_connect(proxy_, "g-signal",
 
186
                                        G_CALLBACK(on_proxy_signal_received),
 
187
                                        this);
 
188
    proxy_name_id_ = g_signal_connect(proxy_, "notify::g-name-owner",
 
189
                                      G_CALLBACK(on_proxy_name_owner_changed),
 
190
                                      this);
157
191
  }
158
 
 
159
 
   SyncData * data = new SyncData (this);
160
 
  _sync_cancellables.push_back (data);
161
 
  g_dbus_proxy_call (_proxy,
162
 
                     "Sync",
163
 
                     NULL,
164
 
                     G_DBUS_CALL_FLAGS_NONE,
165
 
                     -1,
166
 
                     data->_cancel,
167
 
                     on_sync_ready_cb,
168
 
                     data);
169
 
}
170
 
 
171
 
static gboolean
172
 
send_show_entry (ShowEntryData *data)
173
 
{
174
 
  g_return_val_if_fail (data != NULL, FALSE);
175
 
  g_return_val_if_fail (G_IS_DBUS_PROXY (data->proxy), FALSE);
176
 
  
177
 
  /* Re-flush 'cos X is crap like that */
178
 
  Display* d = nux::GetThreadGLWindow()->GetX11Display();
179
 
  XFlush (d);
180
 
  
181
 
  g_dbus_proxy_call (data->proxy,
182
 
                     "ShowEntry",
183
 
                     g_variant_new ("(suiii)",
184
 
                                    data->entry_id,
185
 
                                    0,
186
 
                                    data->x,
187
 
                                    data->y,
188
 
                                    data->button),
189
 
                     G_DBUS_CALL_FLAGS_NONE,
190
 
                     -1,
191
 
                     NULL,
192
 
                     NULL,
193
 
                     NULL);
194
 
 
195
 
  g_free (data->entry_id);
196
 
  g_slice_free (ShowEntryData, data);
197
 
  return FALSE;
198
 
}
199
 
 
200
 
void
201
 
IndicatorObjectFactoryRemote::OnShowMenuRequestReceived (const char *entry_id,
202
 
                                                         int         x,
203
 
                                                         int         y,
204
 
                                                         guint       timestamp,
205
 
                                                         guint32     button)
206
 
{
207
 
  Display* d = nux::GetThreadGLWindow()->GetX11Display();
 
192
  RequestSyncAll();
 
193
}
 
194
 
 
195
void DBusIndicators::Impl::RequestSyncAll()
 
196
{
 
197
  SyncDataPtr data(new SyncData(this));
 
198
  pending_syncs_.push_back(data);
 
199
  request_sync(proxy_, "Sync", NULL, data.get());
 
200
}
 
201
 
 
202
void DBusIndicators::Impl::RequestSyncIndicator(std::string const& name)
 
203
{
 
204
  SyncDataPtr data(new SyncData(this));
 
205
  pending_syncs_.push_back(data);
 
206
  // The ownership of this variant is taken by the g_dbus_proxy_call.
 
207
  GVariant* v_name = g_variant_new("(s)", name.c_str());
 
208
  request_sync(proxy_, "SyncOne", v_name, data.get());
 
209
}
 
210
 
 
211
 
 
212
void DBusIndicators::Impl::OnEntryShowMenu(std::string const& entry_id,
 
213
                                           int x, int y, int timestamp, int button)
 
214
{
 
215
  Display* d = nux::GetGraphicsDisplay()->GetX11Display();
208
216
  XUngrabPointer(d, CurrentTime);
209
 
  XFlush (d);
 
217
  XFlush(d);
210
218
 
211
 
  // We have to do this because on certain systems X won't have time to 
 
219
  // We have to do this because on certain systems X won't have time to
212
220
  // respond to our request for XUngrabPointer and this will cause the
213
221
  // menu not to show
214
 
  ShowEntryData *data = g_slice_new0 (ShowEntryData);
215
 
  data->proxy = _proxy;
216
 
  data->entry_id = g_strdup (entry_id);
 
222
  ShowEntryData* data = new ShowEntryData();
 
223
  data->proxy = proxy_;
 
224
  data->entry_id = entry_id;
217
225
  data->x = x;
218
226
  data->y = y;
219
227
  data->timestamp = timestamp;
220
228
  data->button = button;
221
229
 
222
 
  g_timeout_add (0, (GSourceFunc)send_show_entry, data);
 
230
  g_timeout_add(0, (GSourceFunc)send_show_entry, data);
223
231
 
224
232
  // --------------------------------------------------------------------------
225
233
  // FIXME: This is a workaround until the non-paired events issue is fixed in
244
252
  // --------------------------------------------------------------------------
245
253
}
246
254
 
247
 
void
248
 
IndicatorObjectFactoryRemote::OnScrollReceived (const char *entry_id,
249
 
                                                       int delta)
250
 
{
251
 
  g_dbus_proxy_call (_proxy,
252
 
                     "ScrollEntry",
253
 
                     g_variant_new ("(si)",
254
 
                                    entry_id,
255
 
                                    delta),
256
 
                     G_DBUS_CALL_FLAGS_NONE,
257
 
                     -1,
258
 
                     NULL,
259
 
                     NULL,
260
 
                     NULL);
261
 
}
262
 
 
263
 
// We need to unset the last active entry and set the new one as active
264
 
void
265
 
IndicatorObjectFactoryRemote::OnEntryActivated (const char *entry_id)
266
 
{
267
 
  std::vector<IndicatorObjectProxy*>::iterator it;
268
 
  
269
 
  for (it = _indicators.begin(); it != _indicators.end(); ++it)
270
 
  {
271
 
    IndicatorObjectProxyRemote *object = static_cast<IndicatorObjectProxyRemote *> (*it);
272
 
    std::vector<IndicatorObjectEntryProxy*>::iterator it2;
273
 
  
274
 
    for (it2 = object->GetEntries ().begin(); it2 != object->GetEntries ().end(); ++it2)
275
 
    {
276
 
      IndicatorObjectEntryProxyRemote *entry = static_cast<IndicatorObjectEntryProxyRemote *> (*it2);
277
 
 
278
 
      entry->SetActive (g_strcmp0 (entry_id, entry->GetId ()) == 0);
279
 
    }
280
 
  }
281
 
 
282
 
  IndicatorObjectFactory::OnEntryActivated.emit (entry_id);
283
 
}
284
 
 
285
 
void
286
 
IndicatorObjectFactoryRemote::OnEntryActivateRequestReceived (const gchar *entry_id)
287
 
{
288
 
  OnEntryActivateRequest.emit (entry_id);
289
 
}
290
 
 
291
 
void
292
 
IndicatorObjectFactoryRemote::OnEntryShowNowChanged (const char *entry_id, bool show_now_state)
293
 
{
294
 
  std::vector<IndicatorObjectProxy*>::iterator it;
295
 
  
296
 
  for (it = _indicators.begin(); it != _indicators.end(); ++it)
297
 
  {
298
 
    IndicatorObjectProxyRemote *object = static_cast<IndicatorObjectProxyRemote *> (*it);
299
 
    std::vector<IndicatorObjectEntryProxy*>::iterator it2;
300
 
  
301
 
    for (it2 = object->GetEntries ().begin(); it2 != object->GetEntries ().end(); ++it2)
302
 
    {
303
 
      IndicatorObjectEntryProxyRemote *entry = static_cast<IndicatorObjectEntryProxyRemote *> (*it2);
304
 
 
305
 
      if (g_strcmp0 (entry_id, entry->GetId ()) == 0)
306
 
      {
307
 
        entry->OnShowNowChanged (show_now_state);
308
 
        return;
309
 
      }
310
 
    }
311
 
  }
312
 
}
313
 
 
314
 
IndicatorObjectProxyRemote *
315
 
IndicatorObjectFactoryRemote::IndicatorForID (const char *id)
316
 
{
317
 
  IndicatorObjectProxyRemote *remote = NULL;
318
 
  std::vector<IndicatorObjectProxy*>::iterator it;
319
 
  
320
 
  for (it = _indicators.begin(); it != _indicators.end(); it++)
321
 
  {
322
 
    IndicatorObjectProxyRemote *r = static_cast<IndicatorObjectProxyRemote *> (*it);
323
 
 
324
 
    if (g_strcmp0 (id, r->GetName ().c_str ()) == 0)
325
 
      {
326
 
        remote = r;
327
 
        break;
328
 
      }
329
 
  }
330
 
 
331
 
  if (remote == NULL)
332
 
    {
333
 
      // Create one
334
 
      remote = new IndicatorObjectProxyRemote (id);
335
 
      remote->OnShowMenuRequest.connect (sigc::mem_fun (this,
336
 
                                                        &IndicatorObjectFactoryRemote::OnShowMenuRequestReceived));
337
 
      remote->OnScroll.connect (sigc::mem_fun (this,
338
 
                                                &IndicatorObjectFactoryRemote::OnScrollReceived));
339
 
 
340
 
      _indicators.push_back (remote);
341
 
 
342
 
      OnObjectAdded.emit (remote);
343
 
    }
344
 
 
345
 
  return remote;
346
 
}
347
 
 
348
 
void
349
 
IndicatorObjectFactoryRemote::Sync (GVariant *args)
350
 
{    
 
255
void DBusIndicators::Impl::OnEntryScroll(std::string const& entry_id, int delta)
 
256
{
 
257
  g_dbus_proxy_call(proxy_, "ScrollEntry",
 
258
                    g_variant_new("(si)", entry_id.c_str(), delta),
 
259
                    G_DBUS_CALL_FLAGS_NONE,
 
260
                    -1, NULL, NULL, NULL);
 
261
}
 
262
 
 
263
void DBusIndicators::Impl::Sync(GVariant *args, SyncData* data)
 
264
{
351
265
  GVariantIter *iter            = NULL;
352
266
  gchar        *indicator_id    = NULL;
353
267
  gchar        *entry_id        = NULL;
358
272
  gchar        *image_data      = NULL;
359
273
  gboolean      image_sensitive = false;
360
274
  gboolean      image_visible   = false;
361
 
  IndicatorObjectProxyRemote *current_proxy = NULL;
362
 
  gchar                      *current_proxy_id = NULL;
363
275
 
364
276
  // sanity check
365
277
  if (!args)
366
278
    return;
367
279
 
 
280
  std::map<std::string, Indicator::Entries> indicators;
 
281
  // We need to make sure they are added in the order they arrive.
 
282
  std::vector<std::string> indicator_order;
 
283
 
368
284
  g_variant_get (args, "(a(sssbbusbb))", &iter);
369
285
  while (g_variant_iter_loop (iter, "(sssbbusbb)",
370
286
                              &indicator_id,
376
292
                              &image_data,
377
293
                              &image_sensitive,
378
294
                              &image_visible))
379
 
    {
380
 
      if (g_strcmp0 (current_proxy_id, indicator_id) != 0)
381
 
        {
382
 
          if (current_proxy)
383
 
            current_proxy->EndSync ();
384
 
          g_free (current_proxy_id);
385
 
 
386
 
          current_proxy_id = g_strdup (indicator_id);
387
 
          current_proxy = IndicatorForID (indicator_id);
388
 
          current_proxy->BeginSync ();
389
 
        }
390
 
 
391
 
      /* NULL entries (id == "") are just padding */
392
 
      if (g_strcmp0 (entry_id, "") != 0)
393
 
        current_proxy->AddEntry (entry_id,
394
 
                                 label,
395
 
                                 label_sensitive,
396
 
                                 label_visible,
397
 
                                 image_type,
398
 
                                 image_data,
399
 
                                 image_sensitive,
400
 
                                 image_visible);
401
 
    }
402
 
  if (current_proxy)
403
 
    current_proxy->EndSync ();
404
 
  
405
 
  g_free (current_proxy_id);
406
 
  g_variant_iter_free (iter);
407
 
 
408
 
  /* Notify listeners we have new data */
409
 
  OnSynced.emit ();
410
 
}
411
 
 
412
 
void
413
 
IndicatorObjectFactoryRemote::AddProperties (GVariantBuilder *builder)
414
 
{
415
 
  gchar *name = NULL;
416
 
  gchar *uname = NULL;
417
 
  
418
 
  g_object_get (_proxy,
419
 
                "g-name", &name,
420
 
                "g-name-owner", &uname,
421
 
                NULL);
422
 
 
423
 
  g_variant_builder_add (builder, "{sv}", "backend", g_variant_new_string ("remote"));
424
 
  g_variant_builder_add (builder, "{sv}", "service-name", g_variant_new_string (name));
425
 
  g_variant_builder_add (builder, "{sv}", "service-unique-name", g_variant_new_string (uname));
426
 
  g_variant_builder_add (builder, "{sv}", "using-local-service", g_variant_new_boolean (g_getenv ("PANEL_USE_LOCAL_SERVICE") == NULL ? FALSE : TRUE));
427
 
 
428
 
  g_free (name);
429
 
  g_free (uname);
430
 
}
431
 
 
432
 
GDBusProxy *
433
 
IndicatorObjectFactoryRemote::GetRemoteProxy ()
434
 
{
435
 
  return _proxy;
436
 
}
437
 
  
438
 
//
439
 
// C callbacks, they just link to class methods and aren't interesting
440
 
//
441
 
 
442
 
static bool
443
 
reconnect_to_service (gpointer data)
444
 
{
445
 
  g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
446
 
                            G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
447
 
                            NULL,
448
 
                            S_NAME,
449
 
                            S_PATH,
450
 
                            S_IFACE,
451
 
                            NULL,
452
 
                            on_proxy_ready_cb,
453
 
                            data);
454
 
 
 
295
  {
 
296
    // NULL entries (entry_id == "") are just padding.
 
297
    std::string entry(entry_id);
 
298
    // The reason for the padding is to provide the ordering for the
 
299
    // indicators... so we must record the order of the indicators provided
 
300
    // even if they only have padding entries.
 
301
    indicator_order.push_back(indicator_id);
 
302
    if (entry != "")
 
303
    {
 
304
      Indicator::Entries& entries = indicators[indicator_id];
 
305
      Entry::Ptr e(new Entry(entry,
 
306
                             label,
 
307
                             label_sensitive,
 
308
                             label_visible,
 
309
                             image_type,
 
310
                             image_data,
 
311
                             image_sensitive,
 
312
                             image_visible));
 
313
      entries.push_back(e);
 
314
    }
 
315
  }
 
316
  g_variant_iter_free(iter);
 
317
 
 
318
  // Now update each of the entries.
 
319
  std::string curr_indicator;
 
320
  for (std::vector<std::string>::iterator i = indicator_order.begin(), end = indicator_order.end();
 
321
       i != end; ++i)
 
322
  {
 
323
    std::string const& indicator_name = *i;
 
324
    if (curr_indicator != indicator_name) {
 
325
      curr_indicator = indicator_name;
 
326
      owner_->GetIndicator(curr_indicator).Sync(indicators[curr_indicator]);
 
327
    }
 
328
  }
 
329
 
 
330
  // Clean up the SyncData.  NOTE: don't use find when passing in a raw
 
331
  // pointer due to explicit construction of the shared pointer.  Could write
 
332
  // a predicate, but often a for loop is easier to understand.
 
333
  data->SyncComplete();
 
334
  for (PendingSyncs::iterator i = pending_syncs_.begin(), end = pending_syncs_.end();
 
335
       i != end; ++i)
 
336
  {
 
337
    if (i->get() == data)
 
338
    {
 
339
      pending_syncs_.erase(i);
 
340
      break;
 
341
    }
 
342
  }
 
343
 
 
344
  // Notify listeners we have new data
 
345
  owner_->on_synced.emit();
 
346
}
 
347
 
 
348
void DBusIndicators::Impl::SyncGeometries(std::string const& name,
 
349
                                          EntryLocationMap const& locations)
 
350
{
 
351
  if (!proxy_)
 
352
    return;
 
353
 
 
354
  GVariantBuilder b;
 
355
  g_variant_builder_init (&b, G_VARIANT_TYPE ("(a(ssiiii))"));
 
356
  g_variant_builder_open (&b, G_VARIANT_TYPE ("a(ssiiii)"));
 
357
 
 
358
  for (EntryLocationMap::const_iterator i = locations.begin(), end = locations.end();
 
359
       i != end; ++i)
 
360
  {
 
361
    nux::Rect const& rect = i->second;
 
362
    g_variant_builder_add(&b, "(ssiiii)",
 
363
                          name.c_str(),
 
364
                          i->first.c_str(),
 
365
                          rect.x,
 
366
                          rect.y,
 
367
                          rect.width,
 
368
                          rect.height);
 
369
  }
 
370
 
 
371
  g_variant_builder_close (&b);
 
372
  g_dbus_proxy_call(proxy_, "SyncGeometries",
 
373
                    g_variant_builder_end(&b),
 
374
                    G_DBUS_CALL_FLAGS_NONE,
 
375
                    -1,
 
376
                    NULL,
 
377
                    NULL,
 
378
                    NULL);
 
379
}
 
380
 
 
381
std::string DBusIndicators::Impl::name() const
 
382
{
 
383
  glib::String name;
 
384
  g_object_get(proxy_,
 
385
               "g-name", name.AsOutParam(),
 
386
               NULL);
 
387
  return name.Str();
 
388
}
 
389
 
 
390
std::string DBusIndicators::Impl::owner_name() const
 
391
{
 
392
  glib::String owner_name;
 
393
  g_object_get(proxy_,
 
394
               "g-name-owner", owner_name.AsOutParam(),
 
395
               NULL);
 
396
  return owner_name.Str();
 
397
}
 
398
 
 
399
bool DBusIndicators::Impl::using_local_service() const
 
400
{
 
401
  return g_getenv("PANEL_USE_LOCAL_SERVICE") != NULL;
 
402
}
 
403
 
 
404
 
 
405
DBusIndicators::DBusIndicators()
 
406
  : pimpl(new Impl(this))
 
407
{
 
408
}
 
409
 
 
410
DBusIndicators::~DBusIndicators()
 
411
{
 
412
  delete pimpl;
 
413
}
 
414
 
 
415
void DBusIndicators::SyncGeometries(std::string const& name,
 
416
                                    EntryLocationMap const& locations)
 
417
{
 
418
  pimpl->SyncGeometries(name, locations);
 
419
}
 
420
 
 
421
void DBusIndicators::OnEntryScroll(std::string const& entry_id, int delta)
 
422
{
 
423
  pimpl->OnEntryScroll(entry_id, delta);
 
424
}
 
425
 
 
426
void DBusIndicators::OnEntryShowMenu(std::string const& entry_id,
 
427
                                     int x, int y, int timestamp, int button)
 
428
{
 
429
  pimpl->OnEntryShowMenu(entry_id, x, y, timestamp, button);
 
430
}
 
431
 
 
432
std::string DBusIndicators::name() const
 
433
{
 
434
  return pimpl->name();
 
435
}
 
436
 
 
437
std::string DBusIndicators::owner_name() const
 
438
{
 
439
  return pimpl->owner_name();
 
440
}
 
441
 
 
442
bool DBusIndicators::using_local_service() const
 
443
{
 
444
  return pimpl->using_local_service();
 
445
}
 
446
 
 
447
 
 
448
namespace {
 
449
 
 
450
// Initialise DBus for the panel service, and let us know when it is
 
451
// ready.  The unused bool return is to fit with the GSourceFunc.
 
452
gboolean reconnect_to_service(gpointer data)
 
453
{
 
454
  g_dbus_proxy_new_for_bus(G_BUS_TYPE_SESSION,
 
455
                           G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
 
456
                           NULL,
 
457
                           S_NAME,
 
458
                           S_PATH,
 
459
                           S_IFACE,
 
460
                           NULL,
 
461
                           on_proxy_ready_cb,
 
462
                           data);
455
463
  return false;
456
464
}
457
465
 
458
 
static void
459
 
on_proxy_ready_cb (GObject      *source,
460
 
                   GAsyncResult *res,
461
 
                   gpointer      data)
 
466
// Make sure the proxy object exists and has a name, and if so, pass
 
467
// that on to the DBusIndicators.
 
468
void on_proxy_ready_cb(GObject* source, GAsyncResult* res, gpointer data)
462
469
{
463
 
  IndicatorObjectFactoryRemote *remote = static_cast<IndicatorObjectFactoryRemote *> (data);
464
 
  GDBusProxy *proxy;
465
 
  GError     *error = NULL;
 
470
  DBusIndicators::Impl* remote = reinterpret_cast<DBusIndicators::Impl*>(data);
 
471
  GError* error = NULL;
 
472
  GDBusProxy* proxy = g_dbus_proxy_new_for_bus_finish(res, &error);
 
473
 
466
474
  static bool force_tried = false;
467
 
  char       *name_owner;
468
 
 
469
 
  proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
470
 
  name_owner = g_dbus_proxy_get_name_owner (proxy);
471
 
 
472
 
  if (G_IS_DBUS_PROXY (proxy) && name_owner)
 
475
  char* name_owner = g_dbus_proxy_get_name_owner(proxy);
 
476
 
 
477
  if (G_IS_DBUS_PROXY(proxy) && name_owner)
473
478
  {
474
 
    remote->OnRemoteProxyReady (G_DBUS_PROXY (proxy));
475
 
    g_free (name_owner);
 
479
    remote->OnRemoteProxyReady(G_DBUS_PROXY(proxy));
 
480
    g_free(name_owner);
476
481
    return;
477
482
  }
478
483
  else
487
492
    else
488
493
    {
489
494
      force_tried = true;
490
 
      run_local_panel_service ();
491
 
 
492
 
      g_timeout_add_seconds (2, (GSourceFunc)reconnect_to_service, remote);
 
495
      run_local_panel_service();
 
496
      g_timeout_add_seconds (2, reconnect_to_service, remote);
493
497
    }
494
498
  }
495
499
 
496
500
  g_object_unref (proxy);
497
501
}
498
502
 
499
 
static bool
500
 
run_local_panel_service ()
 
503
 
 
504
bool run_local_panel_service()
501
505
{
502
 
  GError *error = NULL;
 
506
  GError* error = NULL;
503
507
 
504
508
  // This is obviously hackish, but this part of the code is mostly hackish...
505
509
  // Let's attempt to run it from where we expect it to be
506
 
  char *cmd = g_strdup_printf ("%s/lib/unity/unity-panel-service", PREFIXDIR);
507
 
  printf ("\nWARNING: Couldn't load panel from installed services, so trying to"
508
 
          "load panel from known location: %s\n", cmd);
 
510
  std::string cmd = PREFIXDIR + std::string("/lib/unity/unity-panel-service");
 
511
  std::cerr << "\nWARNING: Couldn't load panel from installed services, "
 
512
            << "so trying to load panel from known location: "
 
513
            << cmd << "\n";
509
514
 
510
 
  g_spawn_command_line_async (cmd, &error);
511
 
  g_free (cmd);
512
 
  
 
515
  g_spawn_command_line_async(cmd.c_str(), &error);
513
516
  if (error)
514
517
  {
515
 
    printf ("\nWARNING: Unable to launch remote service manually: %s\n", error->message);
516
 
    g_error_free (error);
 
518
    std::cerr << "\nWARNING: Unable to launch remote service manually: "
 
519
              << error->message << "\n";
 
520
    g_error_free(error);
517
521
    return false;
518
522
  }
519
523
  return true;
520
524
}
521
525
 
522
 
static void
523
 
on_proxy_signal_received (GDBusProxy *proxy,
524
 
                          gchar      *sender_name,
525
 
                          gchar      *signal_name,
526
 
                          GVariant   *parameters,
527
 
                          IndicatorObjectFactoryRemote *remote)
 
526
void on_proxy_signal_received(GDBusProxy* proxy,
 
527
                              char* sender_name, char* signal_name_,
 
528
                              GVariant* parameters,
 
529
                              DBusIndicators::Impl* remote)
528
530
{
529
 
  if (g_strcmp0 (signal_name, "EntryActivated") == 0)
530
 
  {
531
 
    remote->OnEntryActivated (g_variant_get_string (g_variant_get_child_value (parameters, 0), NULL));
532
 
  }
533
 
  else if (g_strcmp0 (signal_name, "EntryActivateRequest") == 0)
534
 
  {
535
 
    remote->OnEntryActivateRequestReceived (g_variant_get_string (g_variant_get_child_value (parameters, 0), NULL));
536
 
  }
537
 
  else if (g_strcmp0 (signal_name, "ReSync") == 0)
538
 
  {
539
 
    const gchar  *id = g_variant_get_string (g_variant_get_child_value (parameters, 0), NULL);
540
 
    bool          sync_one = !g_strcmp0 (id, "") == 0;
541
 
 
542
 
    SyncData *data = new SyncData (remote);
543
 
    remote->_sync_cancellables.push_back (data);
544
 
    
545
 
    g_dbus_proxy_call (proxy,
546
 
                       sync_one ? "SyncOne" : "Sync", 
547
 
                       sync_one ? g_variant_new ("(s)", id) : NULL,
548
 
                       G_DBUS_CALL_FLAGS_NONE,
549
 
                       -1,
550
 
                       data->_cancel,
551
 
                       on_sync_ready_cb,
552
 
                       data);
553
 
  }
554
 
  else if (g_strcmp0 (signal_name, "ActiveMenuPointerMotion") == 0)
555
 
  {
556
 
    int x=0, y=0;
557
 
 
 
531
  std::string signal_name(signal_name_);
 
532
  if (signal_name == "EntryActivated")
 
533
  {
 
534
    const char* entry_name = g_variant_get_string(g_variant_get_child_value(parameters, 0), NULL);
 
535
    if (entry_name) {
 
536
      remote->owner_->ActivateEntry(entry_name);
 
537
    }
 
538
  }
 
539
  else if (signal_name == "EntryActivateRequest")
 
540
  {
 
541
    const char* entry_name = g_variant_get_string(g_variant_get_child_value(parameters, 0), NULL);
 
542
    if (entry_name) {
 
543
      remote->owner_->on_entry_activate_request.emit(entry_name);
 
544
    }
 
545
  }
 
546
  else if (signal_name == "ReSync")
 
547
  {
 
548
    const char* id = g_variant_get_string(g_variant_get_child_value(parameters, 0), NULL);
 
549
    bool sync_one = !g_strcmp0 (id, "") == 0;
 
550
 
 
551
    if (sync_one) {
 
552
      remote->RequestSyncIndicator(id);
 
553
    }
 
554
    else {
 
555
      remote->RequestSyncAll();
 
556
    }
 
557
  }
 
558
  else if (signal_name == "ActiveMenuPointerMotion")
 
559
  {
 
560
    int x = 0;
 
561
    int y = 0;
558
562
    g_variant_get (parameters, "(ii)", &x, &y);
559
 
 
560
 
    remote->OnMenuPointerMoved.emit (x, y);
 
563
    remote->owner_->on_menu_pointer_moved.emit(x, y);
561
564
  }
562
 
  else if (g_strcmp0 (signal_name, "EntryShowNowChanged") == 0)
 
565
  else if (signal_name == "EntryShowNowChanged")
563
566
  {
564
567
    gchar    *id = NULL;
565
 
    gboolean  show_now_state;
566
 
 
567
 
    g_variant_get (parameters, "(sb)", &id, &show_now_state);
568
 
 
569
 
    remote->OnEntryShowNowChanged (id, show_now_state ? true : false);
 
568
    gboolean  show_now;
 
569
 
 
570
    g_variant_get (parameters, "(sb)", &id, &show_now);
 
571
    remote->owner_->SetEntryShowNow(id, show_now);
570
572
 
571
573
    g_free (id);
572
574
  }
573
575
}
574
576
 
575
 
static void
576
 
on_proxy_name_owner_changed (GDBusProxy *proxy,
577
 
                             GParamSpec *pspec,
578
 
                             IndicatorObjectFactoryRemote *remote)
 
577
void on_proxy_name_owner_changed(GDBusProxy* proxy, GParamSpec* pspec,
 
578
                                 DBusIndicators::Impl* remote)
579
579
{
580
 
  char *name_owner;
581
 
 
582
 
  name_owner = g_dbus_proxy_get_name_owner (proxy);
 
580
  char* name_owner = g_dbus_proxy_get_name_owner(proxy);
583
581
 
584
582
  if (name_owner == NULL)
585
583
  {
586
 
    // The panel service has stopped for some reason.  Restart it if not in dev mode
587
 
    if (! g_getenv ("UNITY_DEV_MODE"))
588
 
      remote->Reconnect ();
 
584
    // The panel service has stopped for some reason.  Restart it if not in
 
585
    // dev mode
 
586
    if (!g_getenv("UNITY_DEV_MODE"))
 
587
      remote->Reconnect();
589
588
  }
590
589
 
591
590
  g_free (name_owner);
592
591
}
593
592
 
594
 
static void
595
 
on_sync_ready_cb (GObject      *source,
596
 
                  GAsyncResult *res,
597
 
                  gpointer      data)
598
 
{
599
 
  SyncData     *sync_data = (SyncData *)data;
600
 
  IndicatorObjectFactoryRemote *remote = (IndicatorObjectFactoryRemote*)sync_data->_self;
601
 
  GVariant     *args;
602
 
  GError       *error = NULL;
603
 
 
604
 
  args = g_dbus_proxy_call_finish ((GDBusProxy*)source, res, &error);
 
593
void request_sync(GDBusProxy* proxy, const char* method, GVariant* name, SyncData* data)
 
594
{
 
595
  g_dbus_proxy_call(proxy, method, name, G_DBUS_CALL_FLAGS_NONE,
 
596
                    -1, data->cancel, on_sync_ready_cb, data);
 
597
}
 
598
 
 
599
void on_sync_ready_cb(GObject* source, GAsyncResult* res, gpointer data)
 
600
{
 
601
  SyncData* sync_data = reinterpret_cast<SyncData*>(data);
 
602
  GError* error = NULL;
 
603
 
 
604
  GVariant* args = g_dbus_proxy_call_finish((GDBusProxy*)source, res, &error);
605
605
 
606
606
  if (args == NULL)
607
 
    {
608
 
      g_warning ("Unable to perform Sync() on panel service: %s", error->message);
609
 
      g_error_free (error);
610
 
      return;
611
 
    }
612
 
 
613
 
  remote->Sync (args);
614
 
 
615
 
  std::vector<SyncData *>::iterator it = std::find (remote->_sync_cancellables.begin (),
616
 
                                                    remote->_sync_cancellables.end (),
617
 
                                                    sync_data);
618
 
  if (it != remote->_sync_cancellables.end ())
619
 
    remote->_sync_cancellables.erase (it);
620
 
  
621
 
  g_variant_unref (args);
622
 
  delete sync_data;
623
 
}
 
607
  {
 
608
    g_warning("Unable to perform Sync() on panel service: %s", error->message);
 
609
    g_error_free(error);
 
610
    return;
 
611
  }
 
612
 
 
613
  sync_data->self->Sync(args, sync_data);
 
614
  g_variant_unref(args);
 
615
}
 
616
 
 
617
bool send_show_entry(ShowEntryData *data)
 
618
{
 
619
  g_return_val_if_fail (data != NULL, FALSE);
 
620
  g_return_val_if_fail (G_IS_DBUS_PROXY (data->proxy), FALSE);
 
621
 
 
622
  /* Re-flush 'cos X is crap like that */
 
623
  Display* d = nux::GetGraphicsDisplay()->GetX11Display();
 
624
  XFlush (d);
 
625
 
 
626
  g_dbus_proxy_call(data->proxy,
 
627
                     "ShowEntry",
 
628
                     g_variant_new("(suiii)",
 
629
                                   data->entry_id.c_str(),
 
630
                                    0,
 
631
                                    data->x,
 
632
                                    data->y,
 
633
                                    data->button),
 
634
                     G_DBUS_CALL_FLAGS_NONE,
 
635
                     -1,
 
636
                     NULL,
 
637
                     NULL,
 
638
                     NULL);
 
639
  delete data;
 
640
  return FALSE;
 
641
}
 
642
 
 
643
} // anonymous namespace
 
644
 
 
645
} // namespace indicator
 
646
} // namespace unity