Music Hub  ..
A session-wide music playback service
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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 #include <iostream>
30 
31 namespace
32 {
33 QCoreApplication* app = nullptr;
34 }
35 
36 namespace qt
37 {
38 namespace core
39 {
40 namespace world
41 {
42 namespace detail
43 {
45 {
46  static QEvent::Type event_type = static_cast<QEvent::Type>(QEvent::registerEventType());
47  return event_type;
48 }
49 
50 class TaskEvent : public QEvent
51 {
52 public:
53  TaskEvent(const std::function<void()>& task)
55  task(task)
56  {
57  }
58 
59  void run()
60  {
61  try
62  {
63  task();
64  promise.set_value();
65  } catch(...)
66  {
67  promise.set_exception(std::current_exception());
68  }
69  }
70 
71  std::future<void> get_future()
72  {
73  return promise.get_future();
74  }
75 
76 private:
77  std::function<void()> task;
78  std::promise<void> promise;
79 };
80 
81 class TaskHandler : public QObject
82 {
83  Q_OBJECT
84 
85 public:
86  TaskHandler(QObject* parent) : QObject(parent)
87  {
88  }
89 
90  bool event(QEvent* e);
91 };
92 
93 
94 
95 void createCoreApplicationInstanceWithArgs(int argc, char** argv)
96 {
97  app = new QCoreApplication(argc, argv);
98 }
99 
101 {
102  delete app;
103 }
104 
105 QCoreApplication* coreApplicationInstance()
106 {
107  return app;
108 }
109 
111 {
112  static TaskHandler* instance = new TaskHandler(coreApplicationInstance());
113  return instance;
114 }
115 
117 {
118  if (e->type() != qt_core_world_task_event_type())
119  return QObject::event(e);
120 
121  auto te = dynamic_cast<TaskEvent*>(e);
122  if (te)
123  {
124  te->run();
125  return true;
126  }
127 
128  return false;
129 }
130 }
131 
132 void build_and_run(int argc, char** argv, const std::function<void()>& ready)
133 {
134  QThread::currentThread();
135  if (QCoreApplication::instance() != nullptr)
136  throw std::runtime_error(
137  "qt::core::world::build_and_run: "
138  "There is already a QCoreApplication running.");
139 
141 
142  detail::task_handler()->moveToThread(
143  detail::coreApplicationInstance()->thread());
144 
145  // Signal to other worlds that we are good to go.
146  ready();
147 
149 
150  // Someone has called quit and we clean up on the correct thread here.
152 }
153 
154 void destroy()
155 {
156  enter_with_task([]()
157  {
158  // We make sure that all tasks have completed before quitting the app.
159  QEventLoopLocker locker;
160  }).wait_for(std::chrono::seconds{1});
161 }
162 
163 std::future<void> enter_with_task(const std::function<void()>& task)
164 {
165  QCoreApplication* instance = QCoreApplication::instance();
166 
167  if (!instance)
168  {
169  throw std::runtime_error("Qt world has not been built before calling this function.");
170  }
171 
172  detail::TaskEvent* te = new detail::TaskEvent(task);
173  auto future = te->get_future();
174 
175  // We hand over ownership of te here. The event is deleted later after it has
176  // been processed by the event loop.
177  instance->postEvent(detail::task_handler(), te);
178 
179  return future;
180 }
181 
182 }
183 }
184 }
185 
186 #include "qtbridge.moc"
void destroyCoreApplicationInstace()
Definition: qtbridge.cpp:100
QEvent::Type qt_core_world_task_event_type()
Definition: qtbridge.cpp:44
void destroy()
Destroys the Qt core world and quits its event loop.
Definition: qtbridge.cpp:154
QCoreApplication * coreApplicationInstance()
Definition: qtbridge.cpp:105
Definition: player.h:29
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:132
void createCoreApplicationInstanceWithArgs(int argc, char **argv)
Definition: qtbridge.cpp:95
TaskEvent(const std::function< void()> &task)
Definition: qtbridge.cpp:53
std::future< void > get_future()
Definition: qtbridge.cpp:71
Definition: qtbridge.cpp:36
TaskHandler * task_handler()
Definition: qtbridge.cpp:110
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:163