~azzar1/unity/scale-left-padding

« back to all changes in this revision

Viewing changes to plugins/unityshell/src/DebugDBusInterface.cpp

  • Committer: Andrea Azzarone
  • Date: 2011-12-19 22:18:53 UTC
  • mfrom: (1792 unity)
  • mto: This revision was merged to the branch mainline in revision 1833.
  • Revision ID: azzaronea@gmail.com-20111219221853-wyy8fqwxk78s85ct
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 */
19
19
 
20
20
#include <queue>
 
21
#include <sstream>
 
22
#include <boost/algorithm/string.hpp>
 
23
#include <boost/algorithm/string/split.hpp>
 
24
#include <boost/algorithm/string/classification.hpp>
 
25
#include <boost/bind.hpp>
21
26
#include <core/core.h>
22
27
#include <NuxCore/Logger.h>
23
28
 
24
29
#include "DebugDBusInterface.h"
25
30
#include "Introspectable.h"
 
31
#include "XPathQueryPart.h"
26
32
 
27
33
namespace unity
28
34
{
29
 
const char* const DBUS_BUS_NAME = "com.canonical.Unity";
 
35
const std::string DBUS_BUS_NAME = "com.canonical.Unity";
30
36
 
31
37
namespace debug
32
38
{
35
41
  nux::logging::Logger logger("unity.debug.DebugDBusInterface");
36
42
}
37
43
 
38
 
GVariant* GetState(const gchar*);
39
 
Introspectable* FindPieceToIntrospect(std::queue<Introspectable*> queue, 
40
 
                                      const gchar* pieceName);
 
44
GVariant* GetState(std::string const& query);
41
45
 
42
46
const char* DebugDBusInterface::DBUS_DEBUG_OBJECT_PATH = "/com/canonical/Unity/Debug";
43
47
 
47
51
  ""
48
52
  "     <method name='GetState'>"
49
53
  "       <arg type='s' name='piece' direction='in' />"
50
 
  "       <arg type='a{sv}' name='state' direction='out' />"
 
54
  "       <arg type='aa{sv}' name='state' direction='out' />"
51
55
  "     </method>"
52
56
  ""
53
57
  "   </interface>"
69
73
  _screen = screen;
70
74
  _parent_introspectable = parent;
71
75
  _owner_id = g_bus_own_name(G_BUS_TYPE_SESSION,
72
 
                             unity::DBUS_BUS_NAME,
 
76
                             unity::DBUS_BUS_NAME.c_str(),
73
77
                             G_BUS_NAME_OWNER_FLAGS_NONE,
74
78
                             &DebugDBusInterface::OnBusAcquired,
75
79
                             &DebugDBusInterface::OnNameAcquired,
147
151
  }
148
152
  else
149
153
  {
150
 
    g_dbus_method_invocation_return_dbus_error(invocation, unity::DBUS_BUS_NAME,
 
154
    g_dbus_method_invocation_return_dbus_error(invocation, 
 
155
                                               unity::DBUS_BUS_NAME.c_str(),
151
156
                                               "Failed to find method");
152
157
  }
153
158
}
154
159
 
155
 
GVariant*
156
 
GetState(const gchar* pieceName)
 
160
 
 
161
GVariant* GetState(std::string const& query)
157
162
{
158
 
  std::queue<Introspectable*> queue;
159
 
  queue.push(_parent_introspectable);
160
 
 
161
 
  // Since the empty string won't really match the name of the parent (Unity),
162
 
  // we make sure that we're able to accept a blank string and just define it to
163
 
  // mean the top level.
164
 
  Introspectable* piece = g_strcmp0(pieceName, "") == 0
165
 
    ? _parent_introspectable
166
 
    : FindPieceToIntrospect(queue, pieceName);
167
 
 
168
 
  // FIXME this might not work, make sure it does.
169
 
  if (piece == NULL)
170
 
    return NULL;
171
 
 
172
 
  return piece->Introspect(true);
 
163
  // process the XPath query:
 
164
  std::list<Introspectable*> parts = GetIntrospectableNodesFromQuery(query, _parent_introspectable);
 
165
  GVariantBuilder  builder;
 
166
  g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}"));
 
167
  
 
168
  for (Introspectable *node : parts)
 
169
  {
 
170
    g_variant_builder_add_value(&builder, node->Introspect());
 
171
  }
 
172
  
 
173
  return g_variant_new("(aa{sv})", &builder);
173
174
}
174
175
 
175
176
/*
176
 
 * Do a breadth-first search of the introspectable tree.
 
177
 * Do a breadth-first search of the introspection tree and find all nodes that match the 
 
178
 * query.
177
179
 */
178
 
Introspectable*
179
 
FindPieceToIntrospect(std::queue<Introspectable*> queue, const gchar* pieceName)
 
180
std::list<Introspectable*> GetIntrospectableNodesFromQuery(std::string const& query, Introspectable* tree_root)
180
181
{
181
 
  Introspectable* piece;
182
 
 
183
 
  while (!queue.empty())
184
 
  {
185
 
    piece = queue.front();
186
 
    queue.pop();
187
 
 
188
 
    if (g_strcmp0 (piece->GetName(), pieceName) == 0)
189
 
    {
190
 
      return piece;
191
 
    }
192
 
 
193
 
    for (auto it = piece->GetIntrospectableChildren().begin(), last = piece->GetIntrospectableChildren().end(); it != last; it++)
194
 
    {
195
 
      queue.push(*it);
196
 
    }
197
 
  }
198
 
 
199
 
  return NULL;
 
182
  std::list<Introspectable*> start_points;
 
183
  std::string sanitised_query;
 
184
  // Allow user to be lazy when specifying root node.
 
185
  if (query == "" || query == "/")
 
186
  {
 
187
    sanitised_query = "/" + tree_root->GetName();
 
188
  }
 
189
  else
 
190
  {
 
191
    sanitised_query = query;
 
192
  }
 
193
  // split query into parts
 
194
  std::list<XPathQueryPart> query_parts;
 
195
 
 
196
  {
 
197
    std::list<std::string> query_strings;
 
198
    boost::algorithm::split(query_strings, sanitised_query, boost::algorithm::is_any_of("/"));
 
199
    // Boost's split() implementation does not match it's documentation! According to the 
 
200
    // docs, it's not supposed to add empty strings, but it does, which is a PITA. This 
 
201
    // next line removes them:
 
202
    query_strings.erase( std::remove_if( query_strings.begin(), 
 
203
                                        query_strings.end(), 
 
204
                                        boost::bind( &std::string::empty, _1 ) ), 
 
205
                      query_strings.end());
 
206
    foreach(std::string part, query_strings)
 
207
    {
 
208
      query_parts.push_back(XPathQueryPart(part));
 
209
    }
 
210
  }
 
211
 
 
212
  // absolute or relative query string?
 
213
  if (sanitised_query.at(0) == '/' && sanitised_query.at(1) != '/')
 
214
  {
 
215
    // absolute query - start point is tree root node.
 
216
    if (query_parts.front().Matches(tree_root))
 
217
    {
 
218
      start_points.push_back(tree_root);
 
219
    }
 
220
  }
 
221
  else
 
222
  {
 
223
    // relative - need to do a depth first tree search for all nodes that match the
 
224
    // first node in the query.
 
225
 
 
226
    // warn about malformed queries (all queries must start with '/')
 
227
    if (sanitised_query.at(0) != '/')
 
228
    {
 
229
      LOG_WARNING(logger) << "Malformed relative introspection query: '" << query << "'.";
 
230
    }
 
231
    
 
232
    // non-recursive BFS traversal to find starting points:
 
233
    std::queue<Introspectable*> queue;
 
234
    queue.push(tree_root);
 
235
    while (!queue.empty())
 
236
    {
 
237
      Introspectable *node = queue.front();
 
238
      queue.pop();
 
239
      if (query_parts.front().Matches(node))
 
240
      {
 
241
        // found one. We keep going deeper, as there may be another node beneath this one
 
242
        // with the same node name.
 
243
        start_points.push_back(node);
 
244
      }
 
245
      // Add all children of current node to queue.
 
246
      foreach(Introspectable* child, node->GetIntrospectableChildren())
 
247
      {
 
248
        queue.push(child);
 
249
      }
 
250
    }
 
251
  }
 
252
 
 
253
  // now we have the tree start points, process them:
 
254
  query_parts.pop_front();
 
255
  typedef std::pair<Introspectable*, std::list<XPathQueryPart>::iterator> node_match_pair;
 
256
  
 
257
  std::queue<node_match_pair> traverse_queue;
 
258
  foreach(Introspectable *node, start_points)
 
259
  {
 
260
    traverse_queue.push(node_match_pair(node, query_parts.begin()));
 
261
  }
 
262
  start_points.clear();
 
263
  
 
264
  while (!traverse_queue.empty())
 
265
  {
 
266
    node_match_pair p = traverse_queue.front();
 
267
    traverse_queue.pop();
 
268
 
 
269
    Introspectable *node = p.first;
 
270
    auto query_it = p.second;
 
271
 
 
272
    if (query_it == query_parts.end())
 
273
    {
 
274
      // found a match:
 
275
      start_points.push_back(node);
 
276
    }
 
277
    else
 
278
    {
 
279
      // push all children of current node to start of queue, advance search iterator, and loop again.
 
280
      foreach (Introspectable *child, node->GetIntrospectableChildren())
 
281
      {
 
282
        if (query_it->Matches(child))
 
283
        {
 
284
          auto it_copy(query_it);
 
285
          ++it_copy;
 
286
          traverse_queue.push(node_match_pair(child, it_copy));
 
287
        }
 
288
      }
 
289
    }
 
290
  }
 
291
  return start_points;
200
292
}
201
293
}
202
294
}