~unity-api-team/unity-scopes-api/child-scopes-option

« back to all changes in this revision

Viewing changes to demo/scopes/scope-C/scope-C.cpp

  • Committer: Michi Henning
  • Date: 2013-11-19 02:51:46 UTC
  • mto: This revision was merged to the branch mainline in revision 62.
  • Revision ID: michi.henning@canonical.com-20131119025146-kglcalpphl4ozzk7
Fixed scoperegistry to use new scoperunner and to figure out which scopes to run from config files.
Still to do:
- deal with overrides and OEM scopes, particularly the grouping aspect.
- SignalThread needs to invoke a callback for clean shut-down on receipt of SIGINT.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2013 Canonical Ltd
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License version 3 as
 
6
 * published by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful,
 
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
 * GNU General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License
 
14
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 * Authored by: Michi Henning <michi.henning@canonical.com>
 
17
 */
 
18
 
 
19
#include <scopes/ScopeBase.h>
 
20
#include <scopes/ResultItem.h>
 
21
#include <scopes/Category.h>
 
22
#include <scopes/Reply.h>
 
23
 
 
24
#include <algorithm>
 
25
#include <condition_variable>
 
26
#include <iostream>
 
27
#include <list>
 
28
#include <mutex>
 
29
#include <unistd.h>
 
30
 
 
31
#define EXPORT __attribute__ ((visibility ("default")))
 
32
 
 
33
using namespace std;
 
34
using namespace unity::api::scopes;
 
35
 
 
36
// Simple queue that stores query-string/reply pairs, using MyQuery* as a key for removal.
 
37
// The put() method adds a pair at the tail, and the get() method returns a pair at the head.
 
38
// get() suspends the caller until an item is available or until the queue is told to finish.
 
39
// get() returns true if it returns a pair, false if the queue was told to finish.
 
40
// remove() searches for the entry with the given key and erases it.
 
41
 
 
42
class MyQuery;
 
43
 
 
44
class Queue
 
45
{
 
46
public:
 
47
    void put(MyQuery const* query, string const& query_string, ReplyProxy const& reply_proxy)
 
48
    {
 
49
        {
 
50
            std::lock_guard<std::mutex> lock(mutex_);
 
51
            queries_.push_back(QueryData { query, query_string, reply_proxy });
 
52
        }
 
53
        condvar_.notify_one();
 
54
    }
 
55
 
 
56
    bool get(string& query_string, ReplyProxy& reply_proxy)
 
57
    {
 
58
        std::unique_lock<std::mutex> lock(mutex_);
 
59
        condvar_.wait(lock, [this] { return !queries_.empty() || done_; });
 
60
        if (done_)
 
61
        {
 
62
            lock.unlock();
 
63
            condvar_.notify_all();
 
64
        }
 
65
        else
 
66
        {
 
67
            auto qd = queries_.front();
 
68
            queries_.pop_front();
 
69
            query_string = qd.query_string;
 
70
            reply_proxy = qd.reply_proxy;
 
71
        }
 
72
        return !done_;
 
73
    }
 
74
 
 
75
    void remove(MyQuery const* query)
 
76
    {
 
77
        std::lock_guard<std::mutex> lock(mutex_);
 
78
        QueryData qd { query, "", nullptr };
 
79
        auto it = std::find(queries_.begin(), queries_.end(), qd);
 
80
        if (it != queries_.end())
 
81
        {
 
82
            cerr << "Queue: removed query: " << it->query_string << endl;
 
83
            queries_.erase(it);
 
84
        }
 
85
        else
 
86
        {
 
87
            cerr << "Queue: did not find entry to be removed" << endl;
 
88
        }
 
89
    }
 
90
 
 
91
    void finish()
 
92
    {
 
93
        {
 
94
            std::unique_lock<std::mutex> lock(mutex_);
 
95
            queries_.clear();
 
96
            done_ = true;
 
97
        }
 
98
        condvar_.notify_all();
 
99
    }
 
100
 
 
101
    Queue()
 
102
        : done_(false)
 
103
    {
 
104
    }
 
105
 
 
106
private:
 
107
    struct QueryData
 
108
    {
 
109
        MyQuery const* query;
 
110
        string query_string;
 
111
        ReplyProxy reply_proxy;
 
112
 
 
113
        bool operator==(QueryData const& rhs) const
 
114
        {
 
115
            return query == rhs.query;
 
116
        }
 
117
    };
 
118
 
 
119
    std::list<QueryData> queries_;
 
120
    bool done_;
 
121
    std::mutex mutex_;
 
122
    std::condition_variable condvar_;
 
123
};
 
124
 
 
125
// Example scope C: Does not use the query's run() method other than to remember the query.
 
126
// The run() method of the scope acts as a worker thread to push replies to remembered queries.
 
127
// This example shows that letting run() return immediately is OK, and that the MyQuery instance stays
 
128
// alive as long as it can still be cancelled, which is while there is at least one
 
129
// ReplyProxy still in existence for this query.
 
130
 
 
131
class MyQuery : public QueryBase
 
132
{
 
133
public:
 
134
    MyQuery(string const& query, Queue& queue) :
 
135
        query_(query),
 
136
        queue_(queue)
 
137
    {
 
138
        cerr << "My Query created" << endl;
 
139
    }
 
140
 
 
141
    ~MyQuery() noexcept
 
142
    {
 
143
        cerr << "My Query destroyed" << endl;
 
144
    }
 
145
 
 
146
    virtual void cancelled() override
 
147
    {
 
148
        // Remove this query from the queue, if it is still there.
 
149
        // If it isn't, and the worker thread is still working on this
 
150
        // query, the worker thread's next call to push() will return false,
 
151
        // causing the worker thread to stop working on this query.
 
152
        queue_.remove(this);
 
153
        cerr << "scope-C: \"" + query_ + "\" cancelled" << endl;
 
154
    }
 
155
 
 
156
    virtual void run(ReplyProxy const& reply) override
 
157
    {
 
158
        queue_.put(this, query_, reply);
 
159
        cerr << "scope-C: run() returning" << endl;
 
160
    }
 
161
 
 
162
private:
 
163
    string query_;
 
164
    Queue& queue_;
 
165
};
 
166
 
 
167
class MyScope : public ScopeBase
 
168
{
 
169
public:
 
170
    virtual int start(string const& scope_name, RegistryProxy const&) override
 
171
    {
 
172
        scope_name_ = scope_name;
 
173
        return VERSION;
 
174
    }
 
175
 
 
176
    virtual void stop() override
 
177
    {
 
178
        queue.finish();
 
179
    }
 
180
 
 
181
    virtual void run() override
 
182
    {
 
183
        for (;;)
 
184
        {
 
185
            string query;
 
186
            ReplyProxy reply;
 
187
            if (!queue.get(query, reply))
 
188
            {
 
189
                cerr << "worker thread terminating, queue was cleared" << endl;
 
190
                break;  // stop() was called.
 
191
            }
 
192
            for (int i = 1; i < 4; ++i)
 
193
            {
 
194
                cerr << "worker thread: pushing" << endl;
 
195
                auto cat = std::make_shared<Category>("cat1");
 
196
                ResultItem result(cat);
 
197
                result.set_uri("uri");
 
198
                result.set_title("scope-C: result " + to_string(i) + " for query \"" + query + "\"");
 
199
                result.set_icon("icon");
 
200
                result.set_dnd_uri("dnd_uri");
 
201
                if (!reply->push(result))
 
202
                {
 
203
                    cerr << "worker thread: push returned false" << endl;
 
204
                    break; // Query was cancelled
 
205
                }
 
206
                sleep(1);
 
207
            }
 
208
        }
 
209
    }
 
210
 
 
211
    virtual QueryBase::UPtr create_query(string const& q, VariantMap const&) override
 
212
    {
 
213
        cout << scope_name_ << ": created query: \"" << q << "\"" << endl;
 
214
        return QueryBase::UPtr(new MyQuery(q, queue));
 
215
    }
 
216
 
 
217
private:
 
218
    string scope_name_;
 
219
    Queue queue;
 
220
};
 
221
 
 
222
extern "C"
 
223
{
 
224
 
 
225
    EXPORT
 
226
    unity::api::scopes::ScopeBase*
 
227
    // cppcheck-suppress unusedFunction
 
228
    UNITY_API_SCOPE_CREATE_FUNCTION()
 
229
    {
 
230
        return new MyScope;
 
231
    }
 
232
 
 
233
    EXPORT
 
234
    void
 
235
    // cppcheck-suppress unusedFunction
 
236
    UNITY_API_SCOPE_DESTROY_FUNCTION(unity::api::scopes::ScopeBase* scope_base)
 
237
    {
 
238
        delete scope_base;
 
239
    }
 
240
 
 
241
}