Music Hub  ..
A session-wide music playback service
qtbridge.cpp
Go to the documentation of this file.
1 /*
2  * Copyright © 2014 Canonical Ltd.
3  *
4  * This program is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License version 3,
6  * as 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 Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  *
16  * Authored by: Jussi Pakkanen <jussi.pakkanen@canonical.com>
17  * Thomas Voß <thomas.voss@canonical.com>
18  */
19 
20 #include "qtbridge.h"
21 
22 #include<QCoreApplication>
23 #include<QNetworkAccessManager>
24 #include<QNetworkRequest>
25 #include<QNetworkReply>
26 #include<QThread>
27 #include<QDebug>
28 
29 namespace
30 {
31 QCoreApplication* app = nullptr;
32 }
33 
34 namespace qt
35 {
36 namespace core
37 {
38 namespace world
39 {
40 namespace detail
41 {
43 {
44  static QEvent::Type event_type = static_cast<QEvent::Type>(QEvent::registerEventType());
45  return event_type;
46 }
47 
48 class TaskEvent : public QEvent
49 {
50 public:
51  TaskEvent(const std::function<void()>& task)
53  task(task)
54  {
55  }
56 
57  void run()
58  {
59  try
60  {
61  task();
62  promise.set_value();
63  } catch(...)
64  {
65  promise.set_exception(std::current_exception());
66  }
67  }
68 
69  std::future<void> get_future()
70  {
71  return promise.get_future();
72  }
73 
74 private:
75  std::function<void()> task;
76  std::promise<void> promise;
77 };
78 
79 class TaskHandler : public QObject
80 {
81  Q_OBJECT
82 
83 public:
84  TaskHandler(QObject* parent) : QObject(parent)
85  {
86  }
87 
88  bool event(QEvent* e);
89 };
90 
91 
92 
93 void createCoreApplicationInstanceWithArgs(int argc, char** argv)
94 {
95  app = new QCoreApplication(argc, argv);
96 }
97 
99 {
100  delete app;
101 }
102 
103 QCoreApplication* coreApplicationInstance()
104 {
105  return app;
106 }
107 
109 {
110  static TaskHandler* instance = new TaskHandler(coreApplicationInstance());
111  return instance;
112 }
113 
115 {
116  if (e->type() != qt_core_world_task_event_type())
117  return QObject::event(e);
118 
119  auto te = dynamic_cast<TaskEvent*>(e);
120  if (te)
121  {
122  te->run();
123  return true;
124  }
125 
126  return false;
127 }
128 }
129 
130 void build_and_run(int argc, char** argv, const std::function<void()>& ready)
131 {
132  QThread::currentThread();
133  if (QCoreApplication::instance() != nullptr)
134  throw std::runtime_error(
135  "qt::core::world::build_and_run: "
136  "There is already a QCoreApplication running.");
137 
139 
140  detail::task_handler()->moveToThread(
141  detail::coreApplicationInstance()->thread());
142 
143  // Signal to other worlds that we are good to go.
144  ready();
145 
147 
148  // Someone has called quit and we clean up on the correct thread here.
150 }
151 
152 void destroy()
153 {
154  enter_with_task([]()
155  {
156  // We make sure that all tasks have completed before quitting the app.
157  QEventLoopLocker locker;
158  }).wait_for(std::chrono::seconds{1});
159 }
160 
161 std::future<void> enter_with_task(const std::function<void()>& task)
162 {
163  QCoreApplication* instance = QCoreApplication::instance();
164 
165  if (!instance)
166  {
167  throw std::runtime_error("Qt world has not been built before calling this function.");
168  }
169 
170  detail::TaskEvent* te = new detail::TaskEvent(task);
171  auto future = te->get_future();
172 
173  // We hand over ownership of te here. The event is deleted later after it has
174  // been processed by the event loop.
175  instance->postEvent(detail::task_handler(), te);
176 
177  return future;
178 }
179 
180 }
181 }
182 }
183 
184 #include "qtbridge.moc"
void destroyCoreApplicationInstace()
Definition: qtbridge.cpp:98
QEvent::Type qt_core_world_task_event_type()
Definition: qtbridge.cpp:42
void destroy()
Destroys the Qt core world and quits its event loop.
Definition: qtbridge.cpp:152
QCoreApplication * coreApplicationInstance()
Definition: qtbridge.cpp:103
Definition: player.h:33
void build_and_run(int argc, char **argv, const std::function< void()> &ready)
Sets up the Qt core world and executes its event loop. Blocks until destroy() is called.
Definition: qtbridge.cpp:130
void createCoreApplicationInstanceWithArgs(int argc, char **argv)
Definition: qtbridge.cpp:93
TaskEvent(const std::function< void()> &task)
Definition: qtbridge.cpp:51
std::future< void > get_future()
Definition: qtbridge.cpp:69
Definition: qtbridge.cpp:34
TaskHandler * task_handler()
Definition: qtbridge.cpp:108
std::future< void > enter_with_task(const std::function< void()> &task)
Enters the Qt core world and schedules the given task for execution.
Definition: qtbridge.cpp:161