Merge lp:unity-system-compositor into lp:unity-system-compositor/ubuntu

Proposed by Alan Griffiths on 2015-05-01
Status: Merged
Approved by: Alan Griffiths on 2015-05-07
Approved revision: 212
Merged at revision: 203
Proposed branch: lp:unity-system-compositor
Merge into: lp:unity-system-compositor/ubuntu
Diff against target: 7958 lines (+5641/-1342)
60 files modified
CMakeLists.txt (+2/-3)
debian/control (+5/-11)
spinner/eglapp.c (+7/-10)
src/CMakeLists.txt (+20/-13)
src/com.canonical.Unity.Screen.xml (+29/-0)
src/dbus_connection_handle.cpp (+102/-0)
src/dbus_connection_handle.h (+48/-0)
src/dbus_event_loop.cpp (+444/-0)
src/dbus_event_loop.h (+87/-0)
src/dbus_message_handle.cpp (+83/-0)
src/dbus_message_handle.h (+48/-0)
src/dbus_screen.cpp (+0/-213)
src/dbus_screen.h (+0/-77)
src/external_spinner.cpp (+28/-9)
src/external_spinner.h (+4/-2)
src/generate_header_with_string_from_file.sh (+26/-0)
src/mir_screen.cpp (+73/-75)
src/mir_screen.h (+42/-37)
src/powerd_mediator.cpp (+401/-237)
src/powerd_mediator.h (+71/-64)
src/scoped_dbus_error.h (+57/-0)
src/screen.h (+26/-9)
src/screen_event_handler.cpp (+52/-41)
src/screen_event_handler.h (+27/-22)
src/screen_hardware.h (+49/-0)
src/server.cpp (+76/-7)
src/server.h (+61/-35)
src/shell.cpp (+0/-157)
src/shell.h (+0/-54)
src/system_compositor.cpp (+15/-63)
src/system_compositor.h (+13/-6)
src/thread_name.cpp (+32/-0)
src/thread_name.h (+29/-0)
src/unity_screen_service.cpp (+358/-0)
src/unity_screen_service.h (+83/-0)
src/window_manager.cpp (+234/-0)
src/window_manager.h (+85/-0)
src/worker_thread.cpp (+0/-142)
src/worker_thread.h (+0/-55)
tests/CMakeLists.txt (+1/-0)
tests/integration-tests/CMakeLists.txt (+53/-0)
tests/integration-tests/dbus_bus.cpp (+52/-0)
tests/integration-tests/dbus_bus.h (+46/-0)
tests/integration-tests/dbus_client.cpp (+151/-0)
tests/integration-tests/dbus_client.h (+113/-0)
tests/integration-tests/run_command.cpp (+44/-0)
tests/integration-tests/run_command.h (+34/-0)
tests/integration-tests/test_dbus_event_loop.cpp (+232/-0)
tests/integration-tests/test_external_spinner.cpp (+167/-0)
tests/integration-tests/test_powerd_mediator.cpp (+655/-0)
tests/integration-tests/test_unity_screen_service.cpp (+413/-0)
tests/integration-tests/usc_test_helper_wait_for_signal.c (+24/-0)
tests/integration-tests/wait_condition.h (+72/-0)
tests/unit-tests/CMakeLists.txt (+4/-0)
tests/unit-tests/advanceable_timer.cpp (+211/-0)
tests/unit-tests/advanceable_timer.h (+53/-0)
tests/unit-tests/fake_shared.h (+33/-0)
tests/unit-tests/test_mir_screen.cpp (+366/-0)
tests/unit-tests/test_screen_event_handler.cpp (+196/-0)
tests/unit-tests/test_session_switcher.cpp (+4/-0)
To merge this branch: bzr merge lp:unity-system-compositor
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing on 2015-05-06
Cemil Azizoglu (community) Needs Information on 2015-05-06
Alexandros Frantzis (community) 2015-05-01 Approve on 2015-05-06
Review via email: mp+258047@code.launchpad.net

Commit Message

Release in step with Mir 0.13.0

Description of the Change

Release in step with Mir 0.13.0

To post a comment you must log in.
Alan Griffiths (alan-griffiths) wrote :

  o Did you test your feature/code change/bug fix ? what device(s) ?

Yes. manta, mako

  o Did you break mir server API or ABI and have the relevant bumps to .so and debian docs been made ?

Yes

  o Did you break mir client API or ABI and have you followed up with the known clients & announced on mir-devel mailing list ?

No

Alexandros Frantzis (afrantzis) wrote :

OK.

review: Approve
Cemil Azizoglu (cemil-azizoglu) wrote :

43 - libmirclient-dev (>= 0.6.0),
44 - libmirserver-dev (>= 0.11.0),
45 + libmirclient-dev (>= 0.13.0~),
46 + libmirserver-dev (>= 0.13.0~),

Are we actually using API from client and server 0.13.0 packages. What's the '~' for?

review: Needs Information
Alan Griffiths (alan-griffiths) wrote :

> 43 - libmirclient-dev (>= 0.6.0),
> 44 - libmirserver-dev (>= 0.11.0),
> 45 + libmirclient-dev (>= 0.13.0~),
> 46 + libmirserver-dev (>= 0.13.0~),
>
> Are we actually using API from client and server 0.13.0 packages.

Yes. (we're using the "new" event functions in client API and lots of server stuff).

> What's the '~' for?

It's "magic" to me, but has been needed in the past.

lp:unity-system-compositor updated on 2015-05-06
212. By Alan Griffiths on 2015-05-06

Lose the magic '~'

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2014-11-28 11:39:04 +0000
3+++ CMakeLists.txt 2015-05-06 16:09:34 +0000
4@@ -44,11 +44,10 @@
5 pkg_check_modules(GLIB REQUIRED glib-2.0)
6 pkg_check_modules(MIRCLIENT REQUIRED mirclient)
7 pkg_check_modules(MIRSERVER REQUIRED mirserver)
8+pkg_check_modules(DBUS REQUIRED dbus-1)
9
10-find_package(Boost 1.48.0 COMPONENTS chrono date_time filesystem system thread program_options regex REQUIRED)
11+find_package(Boost 1.48.0 COMPONENTS system REQUIRED)
12 find_package(GLESv2 REQUIRED)
13-find_package(Qt5Core)
14-find_package(Qt5DBus)
15
16 add_subdirectory(spinner/)
17 add_subdirectory(src/)
18
19=== modified file 'debian/control'
20--- debian/control 2015-01-27 17:47:31 +0000
21+++ debian/control 2015-05-06 16:09:34 +0000
22@@ -4,29 +4,23 @@
23 Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
24 Build-Depends: cmake,
25 cmake-data,
26+ dbus,
27 debhelper (>= 9),
28 g++-4.9,
29 google-mock,
30 libandroid-properties-dev [i386 amd64 armhf],
31- libboost-chrono-dev,
32- libboost-date-time-dev,
33- libboost-filesystem-dev,
34- libboost-program-options-dev,
35- libboost-regex-dev,
36+ libboost-dev,
37 libboost-system-dev,
38- libboost-thread-dev,
39 libcairo2-dev,
40+ libdbus-1-dev,
41 libglib2.0-dev,
42 libgles2-mesa-dev,
43- libmirclient-dev (>= 0.6.0),
44- libmirserver-dev (>= 0.11.0),
45+ libmirclient-dev (>= 0.13.0),
46+ libmirserver-dev (>= 0.13.0),
47 libprotobuf-dev,
48 pkg-config,
49 python:any (>= 2.7),
50 python-setuptools,
51- qt5-default,
52- qtbase5-dev,
53- qtbase5-dev-tools,
54 Standards-Version: 3.9.4
55 Homepage: https://launchpad.net/unity-system-compositor
56 # if you don't have have commit access to this branch but would like to upload
57
58=== modified file 'spinner/eglapp.c'
59--- spinner/eglapp.c 2014-03-28 13:02:02 +0000
60+++ spinner/eglapp.c 2015-05-06 16:09:34 +0000
61@@ -92,8 +92,9 @@
62 {
63 (void) surface;
64 (void) context;
65- if (ev->type == mir_event_type_resize)
66+ if (mir_event_get_type(ev) == mir_event_type_resize)
67 {
68+ MirResizeEvent const* resize = mir_event_get_resize_event(ev);
69 /*
70 * FIXME: https://bugs.launchpad.net/mir/+bug/1194384
71 * It is unsafe to set the width and height here because we're in a
72@@ -101,7 +102,9 @@
73 * support for event queuing (directing them to another thread) or
74 * full single-threaded callbacks. (LP: #1194384).
75 */
76- printf("Resized to %dx%d\n", ev->resize.width, ev->resize.height);
77+ printf("Resized to %dx%d\n",
78+ mir_resize_event_get_width(resize),
79+ mir_resize_event_get_height(resize));
80 }
81 }
82
83@@ -144,11 +147,6 @@
84 mir_buffer_usage_hardware,
85 mir_display_output_id_invalid
86 };
87- MirEventDelegate delegate =
88- {
89- mir_eglapp_handle_event,
90- NULL
91- };
92 EGLConfig eglconfig;
93 EGLint neglconfigs;
94 EGLContext eglctx;
95@@ -323,7 +321,7 @@
96 surface = mir_connection_create_surface_sync(connection, &surfaceparm);
97 CHECK(mir_surface_is_valid(surface), "Can't create a surface");
98
99- mir_surface_set_event_handler(surface, &delegate);
100+ mir_surface_set_event_handler(surface, mir_eglapp_handle_event, NULL);
101
102 egldisplay = eglGetDisplay(
103 (EGLNativeDisplayType) mir_connection_get_egl_native_display(connection));
104@@ -337,8 +335,7 @@
105 CHECK(neglconfigs > 0, "No EGL config available");
106
107 eglsurface = eglCreateWindowSurface(egldisplay, eglconfig,
108- (EGLNativeWindowType)mir_surface_get_egl_native_window(surface),
109- NULL);
110+ (EGLNativeWindowType)mir_buffer_stream_get_egl_native_window(mir_surface_get_buffer_stream(surface)), NULL);
111 CHECK(eglsurface != EGL_NO_SURFACE, "eglCreateWindowSurface failed");
112
113 eglctx = eglCreateContext(egldisplay, eglconfig, EGL_NO_CONTEXT,
114
115=== modified file 'src/CMakeLists.txt'
116--- src/CMakeLists.txt 2015-01-27 17:43:17 +0000
117+++ src/CMakeLists.txt 2015-05-06 16:09:34 +0000
118@@ -16,23 +16,30 @@
119
120 set(USC_SRCS
121 asio_dm_connection.cpp
122- dbus_screen.cpp
123+ dbus_connection_handle.cpp
124+ dbus_event_loop.cpp
125+ dbus_message_handle.cpp
126 external_spinner.cpp
127+ mir_screen.cpp
128 powerd_mediator.cpp
129- powerkey_handler.cpp
130- screen_state_handler.cpp
131+ screen_event_handler.cpp
132 server.cpp
133- shell.cpp
134 session_switcher.cpp
135 system_compositor.cpp
136- worker_thread.cpp
137+ thread_name.cpp
138+ unity_screen_service.cpp
139+ unity_screen_service_introspection.h
140+ window_manager.cpp
141 )
142
143-qt5_generate_dbus_interface(dbus_screen.h com.canonical.Unity.Screen.xml)
144-qt5_add_dbus_adaptor(USC_SRCS
145- ${CMAKE_CURRENT_BINARY_DIR}/com.canonical.Unity.Screen.xml
146- dbus_screen.h DBusScreen
147- dbus_screen_adaptor DBusScreenAdaptor)
148+# Generate unity_screen_service_introspection.h from the introspection XML file
149+add_custom_command(
150+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/unity_screen_service_introspection.h
151+ COMMAND sh generate_header_with_string_from_file.sh ${CMAKE_CURRENT_BINARY_DIR}/unity_screen_service_introspection.h unity_screen_service_introspection com.canonical.Unity.Screen.xml
152+ DEPENDS com.canonical.Unity.Screen.xml generate_header_with_string_from_file.sh
153+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
154+ VERBATIM
155+)
156
157 # Compile system compositor
158 add_library(
159@@ -51,13 +58,12 @@
160 ${Boost_INCLUDE_DIRS}
161 ${GLESv2_INCLUDE_DIRS}
162 ${MIRSERVER_INCLUDE_DIRS}
163+ ${DBUS_INCLUDE_DIRS}
164 )
165 add_definitions(
166 -DDEFAULT_SPINNER="${CMAKE_INSTALL_FULL_BINDIR}/unity-system-compositor-spinner"
167 )
168
169-qt5_use_modules(usc Core DBus)
170-
171 link_directories(${MIRSERVER_LIBRARY_DIRS})
172
173 target_link_libraries(usc
174@@ -65,6 +71,7 @@
175 pthread
176 ${Boost_LIBRARIES}
177 ${GLESv2_LIBRARIES}
178+ ${DBUS_LIBRARIES}
179 )
180
181 target_link_libraries(unity-system-compositor
182@@ -80,6 +87,6 @@
183 install(FILES com.canonical.Unity.Screen.conf
184 DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/dbus-1/system.d
185 )
186-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/com.canonical.Unity.Screen.xml
187+install(FILES com.canonical.Unity.Screen.xml
188 DESTINATION ${CMAKE_INSTALL_DATADIR}/dbus-1/interfaces
189 )
190
191=== added file 'src/com.canonical.Unity.Screen.xml'
192--- src/com.canonical.Unity.Screen.xml 1970-01-01 00:00:00 +0000
193+++ src/com.canonical.Unity.Screen.xml 2015-05-06 16:09:34 +0000
194@@ -0,0 +1,29 @@
195+<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN' 'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
196+<node>
197+ <interface name='com.canonical.Unity.Screen'>
198+ <method name='setScreenPowerMode'>
199+ <arg type='b' direction='out'/>
200+ <arg name='mode' type='s' direction='in'/>
201+ <arg name='reason' type='i' direction='in'/>
202+ </method>
203+ <method name='keepDisplayOn'>
204+ <arg type='i' direction='out'/>
205+ </method>
206+ <method name='removeDisplayOnRequest'>
207+ <arg name='id' type='i' direction='in'/>
208+ </method>
209+ <method name='setUserBrightness'>
210+ <arg name='brightness' type='i' direction='in'/>
211+ </method>
212+ <method name='userAutobrightnessEnable'>
213+ <arg name='enable' type='b' direction='in'/>
214+ </method>
215+ <method name='setInactivityTimeouts'>
216+ <arg name='poweroff_timeout' type='i' direction='in'/>
217+ <arg name='dimmer_timeout' type='i' direction='in'/>
218+ </method>
219+ <method name='setTouchVisualizationEnabled'>
220+ <arg name='enabled' type='b' direction='in'/>
221+ </method>
222+ </interface>
223+</node>
224
225=== added file 'src/dbus_connection_handle.cpp'
226--- src/dbus_connection_handle.cpp 1970-01-01 00:00:00 +0000
227+++ src/dbus_connection_handle.cpp 2015-05-06 16:09:34 +0000
228@@ -0,0 +1,102 @@
229+/*
230+ * Copyright © 2015 Canonical Ltd.
231+ *
232+ * This program is free software: you can redistribute it and/or modify
233+ * it under the terms of the GNU General Public License version 3 as
234+ * published by the Free Software Foundation.
235+ *
236+ * This program is distributed in the hope that it will be useful,
237+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
238+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
239+ * GNU General Public License for more details.
240+ *
241+ * You should have received a copy of the GNU General Public License
242+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
243+ *
244+ * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
245+ */
246+
247+#include "dbus_connection_handle.h"
248+#include "scoped_dbus_error.h"
249+
250+#include <stdexcept>
251+#include <boost/throw_exception.hpp>
252+
253+usc::DBusConnectionHandle::DBusConnectionHandle(const char* address)
254+{
255+ dbus_threads_init_default();
256+ ScopedDBusError error;
257+
258+ connection = dbus_connection_open_private(address, &error);
259+ if (!connection || error)
260+ {
261+ BOOST_THROW_EXCEPTION(
262+ std::runtime_error("dbus_connection_open: " + error.message_str()));
263+ }
264+
265+ if (!dbus_bus_register(connection, &error))
266+ {
267+ BOOST_THROW_EXCEPTION(
268+ std::runtime_error("dbus_bus_register: " + error.message_str()));
269+ }
270+}
271+
272+usc::DBusConnectionHandle::~DBusConnectionHandle()
273+{
274+ if (dbus_connection_get_is_connected(connection))
275+ dbus_connection_close(connection);
276+ dbus_connection_unref(connection);
277+}
278+
279+void usc::DBusConnectionHandle::request_name(char const* name) const
280+{
281+ ScopedDBusError error;
282+
283+ auto const request_result = dbus_bus_request_name(
284+ connection, name, DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
285+ if (error)
286+ {
287+ BOOST_THROW_EXCEPTION(
288+ std::runtime_error("dbus_request_name: " + error.message_str()));
289+ }
290+
291+ if (request_result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
292+ {
293+ BOOST_THROW_EXCEPTION(
294+ std::runtime_error("dbus_request_name: Failed to become primary owner"));
295+ }
296+}
297+
298+void usc::DBusConnectionHandle::add_match(char const* match) const
299+{
300+ ScopedDBusError error;
301+
302+ dbus_bus_add_match(connection, match, &error);
303+ if (error)
304+ {
305+ BOOST_THROW_EXCEPTION(
306+ std::runtime_error("dbus_add_match: " + error.message_str()));
307+ }
308+}
309+
310+void usc::DBusConnectionHandle::add_filter(
311+ DBusHandleMessageFunction filter_func,
312+ void* user_data) const
313+{
314+ auto const added = dbus_connection_add_filter(
315+ connection,
316+ filter_func,
317+ user_data,
318+ nullptr);
319+
320+ if (!added)
321+ {
322+ BOOST_THROW_EXCEPTION(
323+ std::runtime_error("dbus_connection_add_filter: Failed to add filter"));
324+ }
325+}
326+
327+usc::DBusConnectionHandle::operator ::DBusConnection*() const
328+{
329+ return connection;
330+}
331
332=== added file 'src/dbus_connection_handle.h'
333--- src/dbus_connection_handle.h 1970-01-01 00:00:00 +0000
334+++ src/dbus_connection_handle.h 2015-05-06 16:09:34 +0000
335@@ -0,0 +1,48 @@
336+/*
337+ * Copyright © 2015 Canonical Ltd.
338+ *
339+ * This program is free software: you can redistribute it and/or modify
340+ * it under the terms of the GNU General Public License version 3 as
341+ * published by the Free Software Foundation.
342+ *
343+ * This program is distributed in the hope that it will be useful,
344+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
345+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
346+ * GNU General Public License for more details.
347+ *
348+ * You should have received a copy of the GNU General Public License
349+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
350+ *
351+ * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
352+ */
353+
354+#ifndef USC_DBUS_CONNECTION_HANDLE_H_
355+#define USC_DBUS_CONNECTION_HANDLE_H_
356+
357+#include <dbus/dbus.h>
358+
359+namespace usc
360+{
361+
362+class DBusConnectionHandle
363+{
364+public:
365+ DBusConnectionHandle(char const* address);
366+ ~DBusConnectionHandle();
367+
368+ void request_name(char const* name) const;
369+ void add_match(char const* match) const;
370+ void add_filter(DBusHandleMessageFunction filter_func, void* user_data) const;
371+
372+ operator ::DBusConnection*() const;
373+
374+private:
375+ DBusConnectionHandle(DBusConnectionHandle const&) = delete;
376+ DBusConnectionHandle& operator=(DBusConnectionHandle const&) = delete;
377+
378+ ::DBusConnection* connection;
379+};
380+
381+}
382+
383+#endif
384
385=== added file 'src/dbus_event_loop.cpp'
386--- src/dbus_event_loop.cpp 1970-01-01 00:00:00 +0000
387+++ src/dbus_event_loop.cpp 2015-05-06 16:09:34 +0000
388@@ -0,0 +1,444 @@
389+/*
390+ * Copyright © 2015 Canonical Ltd.
391+ *
392+ * This program is free software: you can redistribute it and/or modify
393+ * it under the terms of the GNU General Public License version 3 as
394+ * published by the Free Software Foundation.
395+ *
396+ * This program is distributed in the hope that it will be useful,
397+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
398+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
399+ * GNU General Public License for more details.
400+ *
401+ * You should have received a copy of the GNU General Public License
402+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
403+ *
404+ * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
405+ */
406+
407+#ifndef _GNU_SOURCE
408+#define _GNU_SOURCE
409+#endif
410+
411+#include "dbus_event_loop.h"
412+
413+#include <algorithm>
414+
415+#include <sys/epoll.h>
416+#include <sys/timerfd.h>
417+#include <unistd.h>
418+#include <fcntl.h>
419+
420+#include <system_error>
421+#include <boost/throw_exception.hpp>
422+
423+namespace
424+{
425+
426+uint32_t dbus_flags_to_epoll_events(DBusWatch* bus_watch)
427+{
428+ unsigned int flags;
429+ uint32_t events{0};
430+
431+ if (!dbus_watch_get_enabled(bus_watch))
432+ return 0;
433+
434+ flags = dbus_watch_get_flags(bus_watch);
435+ if (flags & DBUS_WATCH_READABLE)
436+ events |= EPOLLIN;
437+ if (flags & DBUS_WATCH_WRITABLE)
438+ events |= EPOLLOUT;
439+
440+ return events | EPOLLHUP | EPOLLERR;
441+}
442+
443+unsigned int epoll_events_to_dbus_flags(uint32_t events)
444+{
445+ unsigned int flags{0};
446+
447+ if (events & EPOLLIN)
448+ flags |= DBUS_WATCH_READABLE;
449+ if (events & EPOLLOUT)
450+ flags |= DBUS_WATCH_WRITABLE;
451+ if (events & EPOLLHUP)
452+ flags |= DBUS_WATCH_HANGUP;
453+ if (events & EPOLLERR)
454+ flags |= DBUS_WATCH_ERROR;
455+
456+ return flags;
457+}
458+
459+timespec msec_to_timespec(int msec)
460+{
461+ static long const milli_to_nano = 1000000;
462+ time_t const sec = msec / 1000;
463+ long const nsec = (msec % 1000) * milli_to_nano;
464+ return timespec{sec, nsec};
465+}
466+
467+}
468+
469+usc::DBusEventLoop::DBusEventLoop(DBusConnection* connection)
470+ : connection{connection},
471+ running{false},
472+ epoll_fd{epoll_create1(EPOLL_CLOEXEC)}
473+{
474+ if (epoll_fd == -1)
475+ {
476+ BOOST_THROW_EXCEPTION(
477+ std::system_error(errno, std::system_category(), "epoll_create1"));
478+ }
479+
480+ int pipefd[2]{};
481+
482+ if (pipe2(pipefd, O_CLOEXEC) == -1)
483+ {
484+ BOOST_THROW_EXCEPTION(
485+ std::system_error(errno, std::system_category(), "pipe2"));
486+
487+ }
488+
489+ wake_up_fd_r = mir::Fd{pipefd[0]};
490+ wake_up_fd_w = mir::Fd{pipefd[1]};
491+
492+ epoll_event ev{};
493+ ev.data.fd = wake_up_fd_r;
494+ ev.events = EPOLLIN;
495+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1)
496+ {
497+ BOOST_THROW_EXCEPTION(
498+ std::system_error(errno, std::system_category(), "epoll_ctl"));
499+ }
500+
501+ dbus_connection_set_watch_functions(
502+ connection,
503+ DBusEventLoop::static_add_watch,
504+ DBusEventLoop::static_remove_watch,
505+ DBusEventLoop::static_toggle_watch,
506+ this,
507+ nullptr);
508+
509+ dbus_connection_set_timeout_functions(
510+ connection,
511+ DBusEventLoop::static_add_timeout,
512+ DBusEventLoop::static_remove_timeout,
513+ DBusEventLoop::static_toggle_timeout,
514+ this,
515+ nullptr);
516+
517+ dbus_connection_set_wakeup_main_function(
518+ connection,
519+ DBusEventLoop::static_wake_up_loop,
520+ this, nullptr);
521+}
522+
523+usc::DBusEventLoop::~DBusEventLoop()
524+{
525+ stop();
526+
527+ dbus_connection_set_watch_functions(
528+ connection, nullptr, nullptr, nullptr, nullptr, nullptr);
529+
530+ dbus_connection_set_timeout_functions(
531+ connection, nullptr, nullptr, nullptr, nullptr, nullptr);
532+
533+ dbus_connection_set_wakeup_main_function(
534+ connection, nullptr, nullptr, nullptr);
535+}
536+
537+void usc::DBusEventLoop::run(std::promise<void>& started)
538+{
539+ running = true;
540+ started.set_value();
541+
542+ while (running)
543+ {
544+ epoll_event event{};
545+ int n = epoll_wait(epoll_fd, &event, 1, -1);
546+ if (n == -1)
547+ {
548+ if (errno == EINTR)
549+ continue;
550+
551+ BOOST_THROW_EXCEPTION(
552+ std::system_error(errno, std::system_category(), "epoll_wait"));
553+ }
554+
555+ if (event.data.fd == wake_up_fd_r)
556+ {
557+ char c;
558+ if (read(event.data.fd, &c, 1));
559+ }
560+ else
561+ {
562+ auto const& matching_watches = enabled_watches_for(event.data.fd);
563+ for (auto const& watch : matching_watches)
564+ {
565+ dbus_watch_handle(watch, epoll_events_to_dbus_flags(event.events));
566+ }
567+
568+ if (matching_watches.empty())
569+ {
570+ auto timeout = enabled_timeout_for(event.data.fd);
571+ if (timeout)
572+ dbus_timeout_handle(timeout);
573+ }
574+ }
575+
576+ dispatch_actions();
577+
578+ dbus_connection_flush(connection);
579+
580+ while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS)
581+ continue;
582+ }
583+
584+ // Flush any remaining outgoing messages
585+ dbus_connection_flush(connection);
586+}
587+
588+void usc::DBusEventLoop::stop()
589+{
590+ running = false;
591+ wake_up_loop();
592+}
593+
594+std::vector<DBusWatch*> usc::DBusEventLoop::enabled_watches_for(int fd)
595+{
596+ std::lock_guard<std::mutex> lock{mutex};
597+
598+ std::vector<DBusWatch*> ret_watches;
599+
600+ for (auto const& w : watches)
601+ {
602+ if (dbus_watch_get_unix_fd(w) == fd &&
603+ dbus_watch_get_enabled(w))
604+ {
605+ ret_watches.push_back(w);
606+ }
607+ }
608+
609+ return ret_watches;
610+}
611+
612+DBusTimeout* usc::DBusEventLoop::enabled_timeout_for(int fd)
613+{
614+ std::lock_guard<std::mutex> lock{mutex};
615+
616+ for (auto const& p : timeouts)
617+ {
618+ if (p.second == fd && dbus_timeout_get_enabled(p.first))
619+ return p.first;
620+ }
621+
622+ return nullptr;
623+}
624+
625+dbus_bool_t usc::DBusEventLoop::add_watch(DBusWatch* watch)
626+{
627+ std::lock_guard<std::mutex> lock{mutex};
628+
629+ int const watch_fd = dbus_watch_get_unix_fd(watch);
630+
631+ if (!is_watched(watch_fd))
632+ {
633+ epoll_event ev{};
634+ ev.data.fd = watch_fd;
635+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, watch_fd, &ev) == -1)
636+ return FALSE;
637+ }
638+
639+ watches.push_back(watch);
640+
641+ update_events_for_watch_fd(watch_fd);
642+
643+ return TRUE;
644+}
645+
646+void usc::DBusEventLoop::remove_watch(DBusWatch* watch)
647+{
648+ std::lock_guard<std::mutex> lock{mutex};
649+
650+ watches.erase(std::remove(begin(watches), end(watches), watch), end(watches));
651+
652+ int const watch_fd = dbus_watch_get_unix_fd(watch);
653+ if (!is_watched(watch_fd))
654+ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, watch_fd, nullptr);
655+ else
656+ update_events_for_watch_fd(watch_fd);
657+}
658+
659+void usc::DBusEventLoop::toggle_watch(DBusWatch* watch)
660+{
661+ std::lock_guard<std::mutex> lock{mutex};
662+
663+ int const watch_fd = dbus_watch_get_unix_fd(watch);
664+ update_events_for_watch_fd(watch_fd);
665+}
666+
667+void usc::DBusEventLoop::update_events_for_watch_fd(int watch_fd)
668+{
669+ epoll_event ev{};
670+ ev.events = epoll_events_for_watch_fd(watch_fd);
671+ ev.data.fd = watch_fd;
672+ epoll_ctl(epoll_fd, EPOLL_CTL_MOD, watch_fd, &ev);
673+}
674+
675+bool usc::DBusEventLoop::is_watched(int watch_fd)
676+{
677+ auto const iter = std::find_if(
678+ begin(watches), end(watches),
679+ [watch_fd] (DBusWatch* w) { return dbus_watch_get_unix_fd(w) == watch_fd; });
680+
681+ return iter != end(watches);
682+}
683+
684+uint32_t usc::DBusEventLoop::epoll_events_for_watch_fd(int fd)
685+{
686+ uint32_t events{};
687+
688+ for (auto const& watch : watches)
689+ {
690+ if (dbus_watch_get_unix_fd(watch) == fd)
691+ events |= dbus_flags_to_epoll_events(watch);
692+ }
693+
694+ return events;
695+}
696+
697+dbus_bool_t usc::DBusEventLoop::add_timeout(DBusTimeout* timeout)
698+{
699+ std::lock_guard<std::mutex> lock{mutex};
700+
701+ auto tfd = mir::Fd{timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)};
702+
703+ epoll_event ev{};
704+ ev.events = EPOLLIN;
705+ ev.data.fd = tfd;
706+
707+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, tfd, &ev))
708+ return FALSE;
709+
710+ timeouts.emplace_back(timeout, std::move(tfd));
711+
712+ return update_timer_fd_for(timeout);
713+}
714+
715+void usc::DBusEventLoop::remove_timeout(DBusTimeout* timeout)
716+{
717+ std::lock_guard<std::mutex> lock{mutex};
718+
719+ auto tfd = timer_fd_for(timeout);
720+ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, tfd, nullptr);
721+
722+ timeouts.erase(
723+ std::remove_if(begin(timeouts), end(timeouts),
724+ [timeout] (decltype(timeouts)::const_reference p)
725+ {
726+ return p.first == timeout;
727+ }),
728+ end(timeouts));
729+
730+}
731+
732+void usc::DBusEventLoop::toggle_timeout(DBusTimeout* timeout)
733+{
734+ std::lock_guard<std::mutex> lock{mutex};
735+ update_timer_fd_for(timeout);
736+}
737+
738+
739+dbus_bool_t usc::DBusEventLoop::update_timer_fd_for(DBusTimeout* timeout)
740+{
741+ itimerspec spec{};
742+
743+ auto tfd = timer_fd_for(timeout);
744+
745+ if (dbus_timeout_get_enabled(timeout))
746+ {
747+ spec.it_interval = msec_to_timespec(dbus_timeout_get_interval(timeout));
748+ spec.it_value = spec.it_interval;
749+ }
750+
751+ if (timerfd_settime(tfd, 0, &spec, nullptr) == -1)
752+ return FALSE;
753+
754+ return TRUE;
755+}
756+
757+int usc::DBusEventLoop::timer_fd_for(DBusTimeout* timeout)
758+{
759+ auto iter = std::find_if(begin(timeouts), end(timeouts),
760+ [timeout] (std::pair<DBusTimeout*,int> const& p)
761+ {
762+ return p.first == timeout;
763+ });
764+ return (iter == end(timeouts) ? -1 : iter->second);
765+}
766+
767+void usc::DBusEventLoop::wake_up_loop()
768+{
769+ if (write(wake_up_fd_w, "a", 1) != 1)
770+ {
771+ BOOST_THROW_EXCEPTION(
772+ std::system_error(errno, std::system_category(), "write"));
773+ }
774+}
775+
776+void usc::DBusEventLoop::enqueue(std::function<void()> const& action)
777+{
778+ {
779+ std::lock_guard<std::mutex> lock{mutex};
780+ actions.push_back(action);
781+ }
782+
783+ wake_up_loop();
784+}
785+
786+void usc::DBusEventLoop::dispatch_actions()
787+{
788+ decltype(actions) actions_to_dispatch;
789+
790+ {
791+ std::lock_guard<std::mutex> lock{mutex};
792+ actions.swap(actions_to_dispatch);
793+ }
794+
795+ for (auto const& action : actions_to_dispatch)
796+ action();
797+}
798+
799+dbus_bool_t usc::DBusEventLoop::static_add_watch(DBusWatch* watch, void* data)
800+{
801+ return static_cast<DBusEventLoop*>(data)->add_watch(watch);
802+}
803+
804+void usc::DBusEventLoop::static_remove_watch(DBusWatch* watch, void* data)
805+{
806+ static_cast<DBusEventLoop*>(data)->remove_watch(watch);
807+}
808+
809+void usc::DBusEventLoop::static_toggle_watch(DBusWatch* watch, void* data)
810+{
811+ static_cast<DBusEventLoop*>(data)->toggle_watch(watch);
812+}
813+
814+dbus_bool_t usc::DBusEventLoop::static_add_timeout(DBusTimeout* timeout, void* data)
815+{
816+ return static_cast<DBusEventLoop*>(data)->add_timeout(timeout);
817+}
818+
819+void usc::DBusEventLoop::static_remove_timeout(DBusTimeout* timeout, void* data)
820+{
821+ static_cast<DBusEventLoop*>(data)->remove_timeout(timeout);
822+}
823+
824+void usc::DBusEventLoop::static_toggle_timeout(DBusTimeout* timeout, void* data)
825+{
826+ static_cast<DBusEventLoop*>(data)->toggle_timeout(timeout);
827+}
828+
829+void usc::DBusEventLoop::static_wake_up_loop(void* data)
830+{
831+ static_cast<DBusEventLoop*>(data)->wake_up_loop();
832+}
833
834=== added file 'src/dbus_event_loop.h'
835--- src/dbus_event_loop.h 1970-01-01 00:00:00 +0000
836+++ src/dbus_event_loop.h 2015-05-06 16:09:34 +0000
837@@ -0,0 +1,87 @@
838+/*
839+ * Copyright © 2015 Canonical Ltd.
840+ *
841+ * This program is free software: you can redistribute it and/or modify
842+ * it under the terms of the GNU General Public License version 3 as
843+ * published by the Free Software Foundation.
844+ *
845+ * This program is distributed in the hope that it will be useful,
846+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
847+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
848+ * GNU General Public License for more details.
849+ *
850+ * You should have received a copy of the GNU General Public License
851+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
852+ *
853+ * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
854+ */
855+
856+#ifndef USC_DBUS_EVENT_LOOP_H_
857+#define USC_DBUS_EVENT_LOOP_H_
858+
859+#include <mir/fd.h>
860+
861+#include <dbus/dbus.h>
862+
863+#include <atomic>
864+#include <vector>
865+#include <mutex>
866+#include <future>
867+
868+namespace usc
869+{
870+
871+class DBusEventLoop
872+{
873+public:
874+ DBusEventLoop(DBusConnection* connection);
875+ ~DBusEventLoop();
876+
877+ void run(std::promise<void>& started);
878+ void stop();
879+
880+ void enqueue(std::function<void()> const& action);
881+
882+private:
883+ std::vector<DBusWatch*> enabled_watches_for(int fd);
884+ DBusTimeout* enabled_timeout_for(int fd);
885+
886+ dbus_bool_t add_watch(DBusWatch* watch);
887+ void remove_watch(DBusWatch* watch);
888+ void toggle_watch(DBusWatch* watch);
889+ void update_events_for_watch_fd(int watch_fd);
890+ bool is_watched(int watch_fd);
891+ uint32_t epoll_events_for_watch_fd(int watch_fd);
892+
893+ dbus_bool_t add_timeout(DBusTimeout* timeout);
894+ void remove_timeout(DBusTimeout* timeout);
895+ void toggle_timeout(DBusTimeout* timeout);
896+ dbus_bool_t update_timer_fd_for(DBusTimeout* timeout);
897+ int timer_fd_for(DBusTimeout* timeout);
898+
899+ void wake_up_loop();
900+ void dispatch_actions();
901+
902+ static dbus_bool_t static_add_watch(DBusWatch* watch, void* data);
903+ static void static_remove_watch(DBusWatch* watch, void* data);
904+ static void static_toggle_watch(DBusWatch* watch, void* data);
905+ static dbus_bool_t static_add_timeout(DBusTimeout* timeout, void* data);
906+ static void static_remove_timeout(DBusTimeout* timeout, void* data);
907+ static void static_toggle_timeout(DBusTimeout* timeout, void* data);
908+ static void static_wake_up_loop(void* data);
909+
910+ DBusConnection* const connection;
911+ std::atomic<bool> running;
912+
913+ std::mutex mutex;
914+ std::vector<DBusWatch*> watches;
915+ std::vector<std::pair<DBusTimeout*,mir::Fd>> timeouts;
916+ std::vector<std::function<void(void)>> actions;
917+ mir::Fd epoll_fd;
918+ mir::Fd wake_up_fd_r;
919+ mir::Fd wake_up_fd_w;
920+};
921+
922+}
923+
924+#endif
925
926=== added file 'src/dbus_message_handle.cpp'
927--- src/dbus_message_handle.cpp 1970-01-01 00:00:00 +0000
928+++ src/dbus_message_handle.cpp 2015-05-06 16:09:34 +0000
929@@ -0,0 +1,83 @@
930+/*
931+ * Copyright © 2015 Canonical Ltd.
932+ *
933+ * This program is free software: you can redistribute it and/or modify
934+ * it under the terms of the GNU General Public License version 3 as
935+ * published by the Free Software Foundation.
936+ *
937+ * This program is distributed in the hope that it will be useful,
938+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
939+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
940+ * GNU General Public License for more details.
941+ *
942+ * You should have received a copy of the GNU General Public License
943+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
944+ *
945+ * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
946+ */
947+
948+#include "dbus_message_handle.h"
949+
950+#include <stdexcept>
951+#include <boost/throw_exception.hpp>
952+
953+usc::DBusMessageHandle::DBusMessageHandle(DBusMessage* message)
954+ : message{message}
955+{
956+}
957+
958+usc::DBusMessageHandle::DBusMessageHandle(::DBusMessage* message, int first_arg_type, ...)
959+ : message{message}
960+{
961+ if (!message)
962+ BOOST_THROW_EXCEPTION(std::runtime_error("Invalid dbus message"));
963+
964+ va_list args;
965+ va_start(args, first_arg_type);
966+ auto appended = dbus_message_append_args_valist(message, first_arg_type, args);
967+ va_end(args);
968+
969+ if (!appended)
970+ {
971+ dbus_message_unref(message);
972+ BOOST_THROW_EXCEPTION(
973+ std::runtime_error("dbus_message_append_args_valist: Failed to append args"));
974+ }
975+}
976+
977+usc::DBusMessageHandle::DBusMessageHandle(
978+ ::DBusMessage* message, int first_arg_type, va_list args)
979+ : message{message}
980+{
981+ if (!message)
982+ BOOST_THROW_EXCEPTION(std::runtime_error("Invalid dbus message"));
983+
984+ if (!dbus_message_append_args_valist(message, first_arg_type, args))
985+ {
986+ dbus_message_unref(message);
987+ BOOST_THROW_EXCEPTION(
988+ std::runtime_error("dbus_message_append_args_valist: Failed to append args"));
989+ }
990+}
991+
992+usc::DBusMessageHandle::DBusMessageHandle(DBusMessageHandle&& other) noexcept
993+ : message{other.message}
994+{
995+ other.message = nullptr;
996+}
997+
998+usc::DBusMessageHandle::~DBusMessageHandle()
999+{
1000+ if (message)
1001+ dbus_message_unref(message);
1002+}
1003+
1004+usc::DBusMessageHandle::operator ::DBusMessage*() const
1005+{
1006+ return message;
1007+}
1008+
1009+usc::DBusMessageHandle::operator bool() const
1010+{
1011+ return message != nullptr;
1012+}
1013
1014=== added file 'src/dbus_message_handle.h'
1015--- src/dbus_message_handle.h 1970-01-01 00:00:00 +0000
1016+++ src/dbus_message_handle.h 2015-05-06 16:09:34 +0000
1017@@ -0,0 +1,48 @@
1018+/*
1019+ * Copyright © 2015 Canonical Ltd.
1020+ *
1021+ * This program is free software: you can redistribute it and/or modify
1022+ * it under the terms of the GNU General Public License version 3 as
1023+ * published by the Free Software Foundation.
1024+ *
1025+ * This program is distributed in the hope that it will be useful,
1026+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1027+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1028+ * GNU General Public License for more details.
1029+ *
1030+ * You should have received a copy of the GNU General Public License
1031+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1032+ *
1033+ * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
1034+ */
1035+
1036+#ifndef USC_DBUS_MESSAGE_HANDLE_H_
1037+#define USC_DBUS_MESSAGE_HANDLE_H_
1038+
1039+#include <dbus/dbus.h>
1040+#include <cstdarg>
1041+
1042+namespace usc
1043+{
1044+
1045+class DBusMessageHandle
1046+{
1047+public:
1048+ DBusMessageHandle(DBusMessage* message);
1049+ DBusMessageHandle(DBusMessage* message, int first_arg_type, ...);
1050+ DBusMessageHandle(DBusMessage* message, int first_arg_type, va_list args);
1051+ DBusMessageHandle(DBusMessageHandle&&) noexcept;
1052+ ~DBusMessageHandle();
1053+
1054+ operator ::DBusMessage*() const;
1055+ operator bool() const;
1056+
1057+private:
1058+ DBusMessageHandle(DBusMessageHandle const&) = delete;
1059+ DBusMessageHandle& operator=(DBusMessageHandle const&) = delete;
1060+ ::DBusMessage* message;
1061+};
1062+
1063+}
1064+
1065+#endif
1066
1067=== removed file 'src/dbus_screen.cpp'
1068--- src/dbus_screen.cpp 2014-10-10 22:43:34 +0000
1069+++ src/dbus_screen.cpp 1970-01-01 00:00:00 +0000
1070@@ -1,213 +0,0 @@
1071-/*
1072- * Copyright © 2013-2014 Canonical Ltd.
1073- *
1074- * This program is free software: you can redistribute it and/or modify
1075- * it under the terms of the GNU General Public License version 3 as
1076- * published by the Free Software Foundation.
1077- *
1078- * This program is distributed in the hope that it will be useful,
1079- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1080- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1081- * GNU General Public License for more details.
1082- *
1083- * You should have received a copy of the GNU General Public License
1084- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1085- */
1086-
1087-#include "dbus_screen.h"
1088-#include "dbus_screen_adaptor.h"
1089-#include "dbus_screen_observer.h"
1090-#include "power_state_change_reason.h"
1091-#include "worker_thread.h"
1092-
1093-#include <atomic>
1094-#include <memory>
1095-#include <thread>
1096-#include <iostream>
1097-
1098-#include <QDBusMessage>
1099-#include <QDBusConnection>
1100-#include <QDBusServiceWatcher>
1101-#include <QDebug>
1102-
1103-namespace
1104-{
1105-bool is_valid_reason(int raw_reason)
1106-{
1107- auto reason = static_cast<PowerStateChangeReason>(raw_reason);
1108- switch (reason)
1109- {
1110- case PowerStateChangeReason::unknown:
1111- case PowerStateChangeReason::inactivity:
1112- case PowerStateChangeReason::power_key:
1113- case PowerStateChangeReason::proximity:
1114- return true;
1115- }
1116- return false;
1117-}
1118-
1119-enum DBusHandlerTaskId
1120-{
1121- set_power_mode
1122-};
1123-}
1124-
1125-
1126-DBusScreen::DBusScreen(DBusScreenObserver& observer, QObject *parent)
1127- : QObject(parent),
1128- dbus_adaptor{new DBusScreenAdaptor(this)},
1129- service_watcher{new QDBusServiceWatcher()},
1130- observer{&observer},
1131- worker_thread{new usc::WorkerThread("USC/DBusHandler")}
1132-{
1133- QDBusConnection bus = QDBusConnection::systemBus();
1134- bus.registerObject("/com/canonical/Unity/Screen", this);
1135- bus.registerService("com.canonical.Unity.Screen");
1136-
1137- service_watcher->setConnection(bus);
1138- service_watcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
1139-
1140- connect(service_watcher.get(),
1141- SIGNAL(serviceUnregistered(QString const&)),
1142- this, SLOT(remove_display_on_requestor(QString const&)));
1143-
1144- //QT's ~QObject will release this child object
1145- //so release ownership from the unique_ptr
1146- dbus_adaptor.release();
1147-}
1148-
1149-DBusScreen::~DBusScreen() = default;
1150-
1151-bool DBusScreen::setScreenPowerMode(const QString &mode, int reason)
1152-{
1153- if (!is_valid_reason(reason))
1154- return false;
1155-
1156- MirPowerMode newPowerMode;
1157-
1158- // Note: the "standby" and "suspend" modes are mostly unused
1159- if (mode == "on") {
1160- newPowerMode = MirPowerMode::mir_power_mode_on;
1161- } else if (mode == "standby") {
1162- newPowerMode = MirPowerMode::mir_power_mode_standby; // higher power "off" mode (fastest resume)
1163- } else if (mode == "suspend") {
1164- newPowerMode = MirPowerMode::mir_power_mode_suspend; // medium power "off" mode
1165- } else if (mode == "off") {
1166- newPowerMode = MirPowerMode::mir_power_mode_off; // lowest power "off" mode (slowest resume)
1167- } else {
1168- qWarning() << "DBusScreen: unknown mode type" << mode;
1169- return false;
1170- }
1171-
1172- //This call may block - avoid blocking this dbus handling thread
1173- worker_thread->queue_task([this, newPowerMode, reason]{
1174- observer->set_screen_power_mode(newPowerMode, static_cast<PowerStateChangeReason>(reason));
1175- }, DBusHandlerTaskId::set_power_mode);
1176-
1177- return true;
1178-}
1179-
1180-void DBusScreen::emit_power_state_change(MirPowerMode power_mode, PowerStateChangeReason reason)
1181-{
1182- QDBusMessage message = QDBusMessage::createSignal("/com/canonical/Unity/Screen",
1183- "com.canonical.Unity.Screen", "DisplayPowerStateChange");
1184-
1185- int power_state = (power_mode == MirPowerMode::mir_power_mode_off) ? 0 : 1;
1186-
1187- QVariant state(power_state);
1188- QList<QVariant> arguments;
1189- arguments.append(state);
1190- arguments.append(static_cast<int>(reason));
1191- message.setArguments(arguments);
1192-
1193- QDBusConnection bus = QDBusConnection::systemBus();
1194- bus.send(message);
1195-}
1196-
1197-int DBusScreen::keepDisplayOn()
1198-{
1199- static std::atomic<uint32_t> request_id{0};
1200-
1201- int id = request_id.fetch_add(1);
1202- auto const& caller = message().service();
1203-
1204- worker_thread->queue_task([this, id, caller]{
1205- std::lock_guard<decltype(guard)> lock{guard};
1206-
1207- //Check that the owner of the request is still valid
1208- auto system_bus_if = QDBusConnection::systemBus().interface();
1209- QDBusReply<QString> reply = system_bus_if->serviceOwner(caller);
1210- if (!reply.isValid())
1211- return;
1212-
1213- auto& caller_requests = display_requests[caller.toStdString()];
1214-
1215- if (caller_requests.size() == 0)
1216- service_watcher->addWatchedService(caller);
1217-
1218- caller_requests.insert(id);
1219-
1220- //This call may block so it needs to be executed outside the thread
1221- //that received the dbus call
1222- observer->keep_display_on(true);
1223-
1224- std::cout << "keepDisplayOn request id:" << id;
1225- std::cout << " requested by \"" << caller.toStdString() << "\"" << std::endl;
1226- });
1227- return id;
1228-}
1229-
1230-void DBusScreen::removeDisplayOnRequest(int cookie)
1231-{
1232- std::lock_guard<decltype(guard)> lock{guard};
1233- auto const& requestor = message().service();
1234-
1235- auto it = display_requests.find(requestor.toStdString());
1236- if (it == display_requests.end())
1237- return;
1238-
1239- std::cout << "removeDisplayOnRequest id:" << cookie;
1240- std::cout << " requested by \"" << requestor.toStdString() << "\"" << std::endl;
1241-
1242- auto& caller_requests = it->second;
1243- caller_requests.erase(cookie);
1244- if (caller_requests.size() == 0)
1245- remove_requestor(requestor, lock);
1246-}
1247-
1248-void DBusScreen::remove_display_on_requestor(QString const& requestor)
1249-{
1250- std::lock_guard<decltype(guard)> lock{guard};
1251- remove_requestor(requestor, lock);
1252-}
1253-
1254-void DBusScreen::remove_requestor(QString const& requestor, std::lock_guard<std::mutex> const&)
1255-{
1256- std::cout << "remove_display_on_requestor \"" << requestor.toStdString() << "\"";
1257- std::cout << std::endl;
1258-
1259- display_requests.erase(requestor.toStdString());
1260- service_watcher->removeWatchedService(requestor);
1261- if (display_requests.size() == 0)
1262- observer->keep_display_on(false);
1263-}
1264-
1265-void DBusScreen::setUserBrightness(int brightness)
1266-{
1267- observer->set_brightness(brightness);
1268-}
1269-
1270-void DBusScreen::userAutobrightnessEnable(bool enable)
1271-{
1272- observer->enable_auto_brightness(enable);
1273-}
1274-
1275-void DBusScreen::setInactivityTimeouts(int poweroff_timeout, int dimmer_timeout)
1276-{
1277- observer->set_inactivity_timeouts(poweroff_timeout, dimmer_timeout);
1278-}
1279-
1280-void DBusScreen::setTouchVisualizationEnabled(bool enabled)
1281-{
1282- observer->set_touch_visualization_enabled(enabled);
1283-}
1284
1285=== removed file 'src/dbus_screen.h'
1286--- src/dbus_screen.h 2014-09-22 17:19:52 +0000
1287+++ src/dbus_screen.h 1970-01-01 00:00:00 +0000
1288@@ -1,77 +0,0 @@
1289-/*
1290- * Copyright © 2013-2014 Canonical Ltd.
1291- *
1292- * This program is free software: you can redistribute it and/or modify
1293- * it under the terms of the GNU General Public License version 3 as
1294- * published by the Free Software Foundation.
1295- *
1296- * This program is distributed in the hope that it will be useful,
1297- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1298- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1299- * GNU General Public License for more details.
1300- *
1301- * You should have received a copy of the GNU General Public License
1302- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1303- */
1304-
1305-#ifndef DBUS_SCREEN_H_
1306-#define DBUS_SCREEN_H_
1307-
1308-#include <mir_toolkit/common.h>
1309-
1310-#include <memory>
1311-#include <mutex>
1312-#include <unordered_map>
1313-#include <unordered_set>
1314-
1315-#include <QObject>
1316-#include <QtCore>
1317-#include <QDBusContext>
1318-
1319-namespace usc {class WorkerThread;}
1320-
1321-class DBusScreenAdaptor;
1322-class DBusScreenObserver;
1323-class QDBusInterface;
1324-class QDBusServiceWatcher;
1325-enum class PowerStateChangeReason;
1326-
1327-class DBusScreen : public QObject, protected QDBusContext
1328-{
1329- Q_OBJECT
1330- Q_CLASSINFO("D-Bus Interface", "com.canonical.Unity.Screen")
1331-
1332-public:
1333- explicit DBusScreen(DBusScreenObserver& observer, QObject *parent = 0);
1334- virtual ~DBusScreen();
1335-
1336- void emit_power_state_change(MirPowerMode mode, PowerStateChangeReason reason);
1337-
1338-public Q_SLOTS:
1339- bool setScreenPowerMode(const QString &mode, int reason);
1340- int keepDisplayOn();
1341- void removeDisplayOnRequest(int id);
1342-
1343- //TODO: Expose same DBus powerd interface for now
1344- void setUserBrightness(int brightness);
1345- void userAutobrightnessEnable(bool enable);
1346-
1347- void setInactivityTimeouts(int poweroff_timeout, int dimmer_timeout);
1348-
1349- void setTouchVisualizationEnabled(bool enabled);
1350-
1351-private Q_SLOTS:
1352- void remove_display_on_requestor(QString const& requestor);
1353-
1354-private:
1355- void remove_requestor(QString const& requestor, std::lock_guard<std::mutex> const& lock);
1356-
1357- std::mutex guard;
1358- std::unique_ptr<DBusScreenAdaptor> dbus_adaptor;
1359- std::unique_ptr<QDBusServiceWatcher> service_watcher;
1360- std::unordered_map<std::string, std::unordered_set<int>> display_requests;
1361- DBusScreenObserver* const observer;
1362- std::unique_ptr<usc::WorkerThread> worker_thread;
1363-};
1364-
1365-#endif /* DBUS_SCREEN_H_ */
1366
1367=== modified file 'src/external_spinner.cpp'
1368--- src/external_spinner.cpp 2014-07-14 14:26:17 +0000
1369+++ src/external_spinner.cpp 2015-05-06 16:09:34 +0000
1370@@ -18,11 +18,15 @@
1371
1372 #include "external_spinner.h"
1373
1374+#include <unistd.h>
1375+#include <signal.h>
1376+
1377 usc::ExternalSpinner::ExternalSpinner(
1378 std::string const& executable,
1379 std::string const& mir_socket)
1380 : executable{executable},
1381- mir_socket{mir_socket}
1382+ mir_socket{mir_socket},
1383+ spinner_pid{0}
1384 {
1385 }
1386
1387@@ -33,22 +37,37 @@
1388
1389 void usc::ExternalSpinner::ensure_running()
1390 {
1391- if (executable.empty() || process.state() != QProcess::NotRunning)
1392+ std::lock_guard<std::mutex> lock{mutex};
1393+
1394+ if (executable.empty() || spinner_pid)
1395 return;
1396
1397- // Launch spinner process to provide default background when a session isn't ready
1398- QStringList env = QProcess::systemEnvironment();
1399- env << "MIR_SOCKET=" + QString::fromStdString(mir_socket);
1400- process.setEnvironment(env);
1401- process.start(executable.c_str());
1402+ auto pid = fork();
1403+ if (!pid)
1404+ {
1405+ setenv("MIR_SOCKET", mir_socket.c_str(), 1);
1406+ execlp(executable.c_str(), executable.c_str(), nullptr);
1407+ }
1408+ else
1409+ {
1410+ spinner_pid = pid;
1411+ }
1412 }
1413
1414 void usc::ExternalSpinner::kill()
1415 {
1416- process.close();
1417+ std::lock_guard<std::mutex> lock{mutex};
1418+
1419+ if (spinner_pid)
1420+ {
1421+ ::kill(spinner_pid, SIGTERM);
1422+ spinner_pid = 0;
1423+ }
1424 }
1425
1426 pid_t usc::ExternalSpinner::pid()
1427 {
1428- return process.processId();
1429+ std::lock_guard<std::mutex> lock{mutex};
1430+
1431+ return spinner_pid;
1432 }
1433
1434=== modified file 'src/external_spinner.h'
1435--- src/external_spinner.h 2014-07-14 14:26:17 +0000
1436+++ src/external_spinner.h 2015-05-06 16:09:34 +0000
1437@@ -21,8 +21,9 @@
1438
1439 #include "spinner.h"
1440
1441-#include <QProcess>
1442 #include <string>
1443+#include <sys/types.h>
1444+#include <mutex>
1445
1446 namespace usc
1447 {
1448@@ -41,7 +42,8 @@
1449 private:
1450 std::string const executable;
1451 std::string const mir_socket;
1452- QProcess process;
1453+ std::mutex mutex;
1454+ pid_t spinner_pid;
1455 };
1456
1457 }
1458
1459=== added file 'src/generate_header_with_string_from_file.sh'
1460--- src/generate_header_with_string_from_file.sh 1970-01-01 00:00:00 +0000
1461+++ src/generate_header_with_string_from_file.sh 2015-05-06 16:09:34 +0000
1462@@ -0,0 +1,26 @@
1463+# Copyright © 2015 Canonical Ltd.
1464+#
1465+# This program is free software: you can redistribute it and/or modify
1466+# it under the terms of the GNU General Public License version 3 as
1467+# published by the Free Software Foundation.
1468+#
1469+# This program is distributed in the hope that it will be useful,
1470+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1471+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1472+# GNU General Public License for more details.
1473+#
1474+# You should have received a copy of the GNU General Public License
1475+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1476+#
1477+# Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
1478+
1479+header=$1
1480+varname=$2
1481+filename=$3
1482+
1483+header_guard=$(echo "USC_$(basename $header)_" | tr '[a-z].' '[A-Z]_')
1484+
1485+echo "#ifndef $header_guard
1486+#define $header_guard
1487+const char* const $varname = R\"($(cat $filename))\";
1488+#endif" > $header
1489
1490=== renamed file 'src/screen_state_handler.cpp' => 'src/mir_screen.cpp'
1491--- src/screen_state_handler.cpp 2015-02-09 16:26:25 +0000
1492+++ src/mir_screen.cpp 2015-05-06 16:09:34 +0000
1493@@ -1,5 +1,5 @@
1494 /*
1495- * Copyright © 2014 Canonical Ltd.
1496+ * Copyright © 2014-2015 Canonical Ltd.
1497 *
1498 * This program is free software: you can redistribute it and/or modify
1499 * it under the terms of the GNU General Public License version 3 as
1500@@ -14,80 +14,72 @@
1501 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1502 */
1503
1504-#include "screen_state_handler.h"
1505+#include "mir_screen.h"
1506
1507 #include <mir/main_loop.h>
1508-#include <mir/time/timer.h>
1509+#include <mir/time/alarm_factory.h>
1510 #include <mir/compositor/compositor.h>
1511 #include <mir/graphics/display.h>
1512 #include <mir/graphics/display_configuration.h>
1513 #include <mir/input/touch_visualizer.h>
1514
1515 #include <cstdio>
1516-#include "dbus_screen.h"
1517-#include "dbus_screen_observer.h"
1518-#include "powerd_mediator.h"
1519+#include "screen_hardware.h"
1520 #include "power_state_change_reason.h"
1521 #include "server.h"
1522
1523 namespace mi = mir::input;
1524-namespace mc = mir::compositor;
1525 namespace mg = mir::graphics;
1526
1527-ScreenStateHandler::ScreenStateHandler(std::shared_ptr<usc::Server> const& server,
1528- std::chrono::milliseconds poweroff_timeout,
1529- std::chrono::milliseconds dimmer_timeout)
1530- : current_power_mode{MirPowerMode::mir_power_mode_on},
1531+usc::MirScreen::MirScreen(
1532+ std::shared_ptr<usc::ScreenHardware> const& screen_hardware,
1533+ std::shared_ptr<mir::compositor::Compositor> const& compositor,
1534+ std::shared_ptr<mir::graphics::Display> const& display,
1535+ std::shared_ptr<mir::input::TouchVisualizer> const& touch_visualizer,
1536+ std::shared_ptr<mir::time::AlarmFactory> const& alarm_factory,
1537+ std::chrono::milliseconds power_off_timeout,
1538+ std::chrono::milliseconds dimmer_timeout)
1539+ : screen_hardware{screen_hardware},
1540+ compositor{compositor},
1541+ display{display},
1542+ touch_visualizer{touch_visualizer},
1543+ alarm_factory{alarm_factory},
1544+ power_off_alarm{alarm_factory->create_alarm(
1545+ std::bind(&usc::MirScreen::power_off_alarm_notification, this))},
1546+ dimmer_alarm{alarm_factory->create_alarm(
1547+ std::bind(&usc::MirScreen::dimmer_alarm_notification, this))},
1548+ power_off_timeout{power_off_timeout},
1549+ dimming_timeout{dimmer_timeout},
1550+ current_power_mode{MirPowerMode::mir_power_mode_on},
1551 restart_timers{true},
1552- power_off_timeout{poweroff_timeout},
1553- dimming_timeout{dimmer_timeout},
1554- powerd_mediator{new PowerdMediator()},
1555- server{server},
1556- power_off_alarm{server->the_main_loop()->create_alarm(
1557- std::bind(&ScreenStateHandler::power_off_alarm_notification, this))},
1558- dimmer_alarm{server->the_main_loop()->create_alarm(
1559- std::bind(&ScreenStateHandler::dimmer_alarm_notification, this))},
1560- dbus_screen{new DBusScreen(*this)}
1561+ power_state_change_handler{[](MirPowerMode,PowerStateChangeReason){}}
1562 {
1563 /*
1564 * Make sure the compositor is running as certain conditions can
1565 * cause Mir to tear down the compositor threads before we get
1566 * to this point. See bug #1410381.
1567 */
1568- server->the_compositor()->start();
1569+ compositor->start();
1570 reset_timers_l();
1571 }
1572
1573-ScreenStateHandler::~ScreenStateHandler() = default;
1574+usc::MirScreen::~MirScreen() = default;
1575
1576-bool ScreenStateHandler::handle(MirEvent const& event)
1577+void usc::MirScreen::keep_display_on_temporarily()
1578 {
1579- if (mir_event_get_type(&event) != mir_event_type_input)
1580- return false;
1581-
1582- auto input_event_type = mir_input_event_get_type(mir_event_get_input_event(&event));
1583- // TODO: We should consider resetting the timer for key events too
1584- // we have to make sure we wont introduce a bug where pressing the power
1585- // key (to turn screen off) or just the volume keys will wake the screen though!
1586- if (!(input_event_type == mir_input_event_type_touch
1587- || input_event_type == mir_input_event_type_pointer))
1588- return false;
1589-
1590 std::lock_guard<std::mutex> lock{guard};
1591 reset_timers_l();
1592 if (current_power_mode == MirPowerMode::mir_power_mode_on)
1593- powerd_mediator->set_normal_backlight();
1594-
1595- return false;
1596+ screen_hardware->set_normal_backlight();
1597 }
1598
1599-void ScreenStateHandler::enable_inactivity_timers(bool enable)
1600+void usc::MirScreen::enable_inactivity_timers(bool enable)
1601 {
1602 std::lock_guard<std::mutex> lock{guard};
1603 enable_inactivity_timers_l(enable);
1604 }
1605
1606-void ScreenStateHandler::toggle_screen_power_mode(PowerStateChangeReason reason)
1607+void usc::MirScreen::toggle_screen_power_mode(PowerStateChangeReason reason)
1608 {
1609 std::lock_guard<std::mutex> lock{guard};
1610 MirPowerMode new_mode = (current_power_mode == MirPowerMode::mir_power_mode_on) ?
1611@@ -96,13 +88,13 @@
1612 set_screen_power_mode_l(new_mode, reason);
1613 }
1614
1615-void ScreenStateHandler::set_screen_power_mode(MirPowerMode mode, PowerStateChangeReason reason)
1616+void usc::MirScreen::set_screen_power_mode(MirPowerMode mode, PowerStateChangeReason reason)
1617 {
1618 std::lock_guard<std::mutex> lock{guard};
1619 set_screen_power_mode_l(mode, reason);
1620 }
1621
1622-void ScreenStateHandler::keep_display_on(bool on)
1623+void usc::MirScreen::keep_display_on(bool on)
1624 {
1625 std::lock_guard<std::mutex> lock{guard};
1626 restart_timers = !on;
1627@@ -112,19 +104,19 @@
1628 set_screen_power_mode_l(MirPowerMode::mir_power_mode_on, PowerStateChangeReason::unknown);
1629 }
1630
1631-void ScreenStateHandler::set_brightness(int brightness)
1632-{
1633- std::lock_guard<std::mutex> lock{guard};
1634- powerd_mediator->set_brightness(brightness);
1635-}
1636-
1637-void ScreenStateHandler::enable_auto_brightness(bool enable)
1638-{
1639- std::lock_guard<std::mutex> lock{guard};
1640- powerd_mediator->enable_auto_brightness(enable);
1641-}
1642-
1643-void ScreenStateHandler::set_inactivity_timeouts(int raw_poweroff_timeout, int raw_dimmer_timeout)
1644+void usc::MirScreen::set_brightness(int brightness)
1645+{
1646+ std::lock_guard<std::mutex> lock{guard};
1647+ screen_hardware->set_brightness(brightness);
1648+}
1649+
1650+void usc::MirScreen::enable_auto_brightness(bool enable)
1651+{
1652+ std::lock_guard<std::mutex> lock{guard};
1653+ screen_hardware->enable_auto_brightness(enable);
1654+}
1655+
1656+void usc::MirScreen::set_inactivity_timeouts(int raw_poweroff_timeout, int raw_dimmer_timeout)
1657 {
1658 std::lock_guard<std::mutex> lock{guard};
1659
1660@@ -141,13 +133,13 @@
1661 reset_timers_l();
1662 }
1663
1664-void ScreenStateHandler::set_screen_power_mode_l(MirPowerMode mode, PowerStateChangeReason reason)
1665+void usc::MirScreen::set_screen_power_mode_l(MirPowerMode mode, PowerStateChangeReason reason)
1666 {
1667 if (mode == MirPowerMode::mir_power_mode_on)
1668 {
1669 /* The screen may be dim, but on - make sure to reset backlight */
1670 if (current_power_mode == MirPowerMode::mir_power_mode_on)
1671- powerd_mediator->set_normal_backlight();
1672+ screen_hardware->set_normal_backlight();
1673 configure_display_l(mode, reason);
1674 reset_timers_l();
1675 }
1676@@ -158,14 +150,12 @@
1677 }
1678 }
1679
1680-void ScreenStateHandler::configure_display_l(MirPowerMode mode, PowerStateChangeReason reason)
1681+void usc::MirScreen::configure_display_l(MirPowerMode mode, PowerStateChangeReason reason)
1682 {
1683 if (current_power_mode == mode)
1684 return;
1685
1686- std::shared_ptr<mg::Display> display = server->the_display();
1687 std::shared_ptr<mg::DisplayConfiguration> displayConfig = display->configuration();
1688- std::shared_ptr<mc::Compositor> compositor = server->the_compositor();
1689
1690 displayConfig->for_each_output(
1691 [&](const mg::UserDisplayConfigurationOutput displayConfigOutput) {
1692@@ -179,11 +169,11 @@
1693 if (power_on)
1694 {
1695 //Some devices do not turn screen on properly from suspend mode
1696- powerd_mediator->disable_suspend();
1697+ screen_hardware->disable_suspend();
1698 }
1699 else
1700 {
1701- powerd_mediator->turn_off_backlight();
1702+ screen_hardware->turn_off_backlight();
1703 }
1704
1705 display->configure(*displayConfig.get());
1706@@ -191,24 +181,25 @@
1707 if (power_on)
1708 {
1709 compositor->start();
1710- powerd_mediator->set_normal_backlight();
1711+ screen_hardware->set_normal_backlight();
1712 }
1713
1714 current_power_mode = mode;
1715
1716- dbus_screen->emit_power_state_change(mode, reason);
1717+ // TODO: Don't call this under lock
1718+ power_state_change_handler(mode, reason);
1719
1720 if (!power_on)
1721- powerd_mediator->allow_suspend();
1722+ screen_hardware->allow_suspend();
1723 }
1724
1725-void ScreenStateHandler::cancel_timers_l()
1726+void usc::MirScreen::cancel_timers_l()
1727 {
1728 power_off_alarm->cancel();
1729 dimmer_alarm->cancel();
1730 }
1731
1732-void ScreenStateHandler::reset_timers_l()
1733+void usc::MirScreen::reset_timers_l()
1734 {
1735 if (restart_timers && current_power_mode != MirPowerMode::mir_power_mode_off)
1736 {
1737@@ -220,7 +211,7 @@
1738 }
1739 }
1740
1741-void ScreenStateHandler::enable_inactivity_timers_l(bool enable)
1742+void usc::MirScreen::enable_inactivity_timers_l(bool enable)
1743 {
1744 if (enable)
1745 reset_timers_l();
1746@@ -228,25 +219,32 @@
1747 cancel_timers_l();
1748 }
1749
1750-void ScreenStateHandler::power_off_alarm_notification()
1751+void usc::MirScreen::power_off_alarm_notification()
1752 {
1753 std::lock_guard<std::mutex> lock{guard};
1754 configure_display_l(MirPowerMode::mir_power_mode_off, PowerStateChangeReason::inactivity);
1755 }
1756
1757-void ScreenStateHandler::dimmer_alarm_notification()
1758+void usc::MirScreen::dimmer_alarm_notification()
1759 {
1760 std::lock_guard<std::mutex> lock{guard};
1761- powerd_mediator->set_dim_backlight();
1762+ screen_hardware->set_dim_backlight();
1763 }
1764
1765-void ScreenStateHandler::set_touch_visualization_enabled(bool enabled)
1766+void usc::MirScreen::set_touch_visualization_enabled(bool enabled)
1767 {
1768 std::lock_guard<std::mutex> lock{guard};
1769-
1770- auto visualizer = server->the_touch_visualizer();
1771+
1772 if (enabled)
1773- visualizer->enable();
1774+ touch_visualizer->enable();
1775 else
1776- visualizer->disable();
1777+ touch_visualizer->disable();
1778+}
1779+
1780+void usc::MirScreen::register_power_state_change_handler(
1781+ PowerStateChangeHandler const& handler)
1782+{
1783+ std::lock_guard<std::mutex> lock{guard};
1784+
1785+ power_state_change_handler = handler;
1786 }
1787
1788=== renamed file 'src/screen_state_handler.h' => 'src/mir_screen.h'
1789--- src/screen_state_handler.h 2014-11-06 12:18:08 +0000
1790+++ src/mir_screen.h 2015-05-06 16:09:34 +0000
1791@@ -1,5 +1,5 @@
1792 /*
1793- * Copyright © 2014 Canonical Ltd.
1794+ * Copyright © 2014-2015 Canonical Ltd.
1795 *
1796 * This program is free software: you can redistribute it and/or modify
1797 * it under the terms of the GNU General Public License version 3 as
1798@@ -14,51 +14,55 @@
1799 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1800 */
1801
1802-#ifndef SCREEN_STATE_HANDLER_
1803-#define SCREEN_STATE_HANDLER_
1804+#ifndef USC_MIR_SCREEN_H_
1805+#define USC_MIR_SCREEN_H_
1806
1807-#include "mir/input/event_filter.h"
1808-#include "dbus_screen_observer.h"
1809+#include "screen.h"
1810
1811 #include <chrono>
1812 #include <memory>
1813 #include <mutex>
1814
1815-class DBusScreen;
1816-class PowerdMediator;
1817 enum class PowerStateChangeReason;
1818-namespace usc { class Server; }
1819
1820 namespace mir
1821 {
1822-namespace time
1823+namespace compositor { class Compositor; }
1824+namespace graphics {class Display;}
1825+namespace input { class TouchVisualizer; }
1826+namespace time { class AlarmFactory; class Alarm; }
1827+}
1828+
1829+namespace usc
1830 {
1831-class Alarm;
1832-class Timer;
1833-}
1834-}
1835+class Server;
1836+class ScreenHardware;
1837
1838-class ScreenStateHandler: public mir::input::EventFilter, public DBusScreenObserver
1839+class MirScreen: public Screen
1840 {
1841 public:
1842- ScreenStateHandler(std::shared_ptr<usc::Server> const& server,
1843- std::chrono::milliseconds power_off_timeout,
1844- std::chrono::milliseconds dimmer_timeout);
1845- virtual ~ScreenStateHandler();
1846-
1847- //from EventFilter
1848- bool handle(MirEvent const& event) override;
1849-
1850- void enable_inactivity_timers(bool enable);
1851- void toggle_screen_power_mode(PowerStateChangeReason reason);
1852+ MirScreen(std::shared_ptr<usc::ScreenHardware> const& screen_hardware,
1853+ std::shared_ptr<mir::compositor::Compositor> const& compositor,
1854+ std::shared_ptr<mir::graphics::Display> const& display,
1855+ std::shared_ptr<mir::input::TouchVisualizer> const& touch_visualizer,
1856+ std::shared_ptr<mir::time::AlarmFactory> const& alarm_factory,
1857+ std::chrono::milliseconds power_off_timeout,
1858+ std::chrono::milliseconds dimmer_timeout);
1859+ ~MirScreen();
1860+
1861+ void enable_inactivity_timers(bool enable) override;
1862+ void toggle_screen_power_mode(PowerStateChangeReason reason) override;
1863+ void keep_display_on_temporarily() override;
1864
1865 void set_screen_power_mode(MirPowerMode mode, PowerStateChangeReason reason) override;
1866 void keep_display_on(bool on) override;
1867 void set_brightness(int brightness) override;
1868 void enable_auto_brightness(bool enable) override;
1869 void set_inactivity_timeouts(int power_off_timeout, int dimmer_timeout) override;
1870-
1871+
1872 void set_touch_visualization_enabled(bool enabled) override;
1873+ void register_power_state_change_handler(
1874+ PowerStateChangeHandler const& power_state_change_handler) override;
1875
1876 private:
1877 void set_screen_power_mode_l(MirPowerMode mode, PowerStateChangeReason reason);
1878@@ -72,21 +76,22 @@
1879 void dimmer_alarm_notification();
1880 void long_press_alarm_notification();
1881
1882+ std::shared_ptr<usc::ScreenHardware> const screen_hardware;
1883+ std::shared_ptr<mir::compositor::Compositor> const compositor;
1884+ std::shared_ptr<mir::graphics::Display> const display;
1885+ std::shared_ptr<mir::input::TouchVisualizer> const touch_visualizer;
1886+ std::shared_ptr<mir::time::AlarmFactory> const alarm_factory;
1887+ std::unique_ptr<mir::time::Alarm> const power_off_alarm;
1888+ std::unique_ptr<mir::time::Alarm> const dimmer_alarm;
1889+
1890 std::mutex guard;
1891-
1892+ std::chrono::milliseconds power_off_timeout;
1893+ std::chrono::milliseconds dimming_timeout;
1894 MirPowerMode current_power_mode;
1895 bool restart_timers;
1896-
1897- std::chrono::milliseconds power_off_timeout;
1898- std::chrono::milliseconds dimming_timeout;
1899-
1900- std::unique_ptr<PowerdMediator> powerd_mediator;
1901- std::shared_ptr<usc::Server> server;
1902-
1903- std::unique_ptr<mir::time::Alarm> power_off_alarm;
1904- std::unique_ptr<mir::time::Alarm> dimmer_alarm;
1905-
1906- std::unique_ptr<DBusScreen> dbus_screen;
1907+ PowerStateChangeHandler power_state_change_handler;
1908 };
1909
1910+}
1911+
1912 #endif
1913
1914=== modified file 'src/powerd_mediator.cpp'
1915--- src/powerd_mediator.cpp 2014-09-17 09:44:55 +0000
1916+++ src/powerd_mediator.cpp 2015-05-06 16:09:34 +0000
1917@@ -1,5 +1,5 @@
1918 /*
1919- * Copyright © 2014 Canonical Ltd.
1920+ * Copyright © 2015 Canonical Ltd.
1921 *
1922 * This program is free software: you can redistribute it and/or modify
1923 * it under the terms of the GNU General Public License version 3 as
1924@@ -15,163 +15,253 @@
1925 */
1926
1927 #include "powerd_mediator.h"
1928-
1929-#include <QDBusConnection>
1930-#include <QDBusInterface>
1931-#include <QDBusReply>
1932-#include <QDBusMetaType>
1933-#include <QDBusArgument>
1934-#include <QDBusServiceWatcher>
1935-
1936-#include <iostream>
1937-
1938-/* Struct for reply to getBrightnessParams DBus call */
1939-struct BrightnessParams
1940- {
1941- int dim_brightness;
1942- int min_brightness;
1943- int max_brightness;
1944- int default_brightness;
1945- bool auto_brightness_supported;
1946-};
1947-Q_DECLARE_METATYPE(BrightnessParams);
1948-
1949-/* Not used but required by qDBusRegisterMetaType*/
1950-QDBusArgument &operator<<(QDBusArgument &argument, const BrightnessParams &mystruct)
1951-{
1952- argument.beginStructure();
1953- argument << mystruct.dim_brightness <<
1954- mystruct.min_brightness <<
1955- mystruct.max_brightness <<
1956- mystruct.default_brightness <<
1957- mystruct.auto_brightness_supported;
1958- argument.endStructure();
1959- return argument;
1960-}
1961-
1962-/* Needed to un-marshall powerd response */
1963-const QDBusArgument &operator>>(const QDBusArgument &argument, BrightnessParams &mystruct)
1964-{
1965- argument.beginStructure();
1966- argument >> mystruct.dim_brightness >>
1967- mystruct.min_brightness >>
1968- mystruct.max_brightness >>
1969- mystruct.default_brightness >>
1970- mystruct.auto_brightness_supported;
1971- argument.endStructure();
1972- return argument;
1973-}
1974-
1975-PowerdMediator::PowerdMediator()
1976- : dim_brightness{10},
1977- normal_brightness{102},
1978+#include "thread_name.h"
1979+#include "scoped_dbus_error.h"
1980+
1981+#include "dbus_message_handle.h"
1982+
1983+#include <future>
1984+#include <cstdint>
1985+
1986+namespace
1987+{
1988+
1989+char const* const powerd_service_name = "com.canonical.powerd";
1990+char const* const powerd_service_interface = "com.canonical.powerd";
1991+char const* const powerd_service_path = "/com/canonical/powerd";
1992+
1993+usc::DBusMessageHandle make_powerd_method_call_message(
1994+ char const* method, int first_arg_type, va_list args)
1995+{
1996+ return usc::DBusMessageHandle{
1997+ dbus_message_new_method_call(
1998+ powerd_service_name,
1999+ powerd_service_path,
2000+ powerd_service_interface,
2001+ method),
2002+ first_arg_type, args};
2003+}
2004+
2005+}
2006+
2007+usc::PowerdMediator::PowerdMediator(std::string const& bus_addr)
2008+ : connection{bus_addr.c_str()},
2009+ dbus_event_loop{connection},
2010+ pending_suspend_block_request{false},
2011+ dim_brightness_{10},
2012+ min_brightness_{0},
2013+ max_brightness_{102},
2014+ normal_brightness_{102},
2015 current_brightness{0},
2016- min_brightness_{10},
2017- max_brightness_{102},
2018+ backlight_state{BacklightState::normal},
2019 auto_brightness_supported_{false},
2020 auto_brightness_requested{false},
2021- backlight_state{BacklightState::normal},
2022- pending_suspend_blocker_request{true},
2023- powerd_interface{new QDBusInterface("com.canonical.powerd",
2024- "/com/canonical/powerd", "com.canonical.powerd", QDBusConnection::systemBus())},
2025- service_watcher{new QDBusServiceWatcher("com.canonical.powerd",
2026- QDBusConnection::systemBus(), QDBusServiceWatcher::WatchForRegistration)},
2027- system_state{unknown}
2028+ sys_state{SysState::unknown}
2029 {
2030- qDBusRegisterMetaType<BrightnessParams>();
2031-
2032- //Powerd interface may not be available right now or it may restart in the future
2033- //watch for changes so brightness params get initialized to the most recent values.
2034- connect(service_watcher.get(),
2035- SIGNAL(serviceRegistered(QString const&)),
2036- this, SLOT(powerd_registered()));
2037-
2038- powerd_interface->connection().connect("com.canonical.powerd",
2039- "/com/canonical/powerd",
2040- "com.canonical.powerd",
2041- "SysPowerStateChange",
2042- this,
2043- SLOT(powerd_state_changed(int)));
2044-
2045- if (powerd_interface->isValid())
2046- {
2047- init_brightness_params();
2048- if (request_suspend_blocker())
2049+ connection.add_match(
2050+ "type='signal',"
2051+ "sender='com.canonical.powerd',"
2052+ "interface='com.canonical.powerd',"
2053+ "member='SysPowerStateChange'");
2054+ connection.add_match(
2055+ "type='signal',"
2056+ "sender='org.freedesktop.DBus',"
2057+ "interface='org.freedesktop.DBus',"
2058+ "member='NameOwnerChanged'");
2059+ connection.add_filter(handle_dbus_message_thunk, this);
2060+
2061+ std::promise<void> event_loop_started;
2062+ auto event_loop_started_future = event_loop_started.get_future();
2063+
2064+ dbus_loop_thread = std::thread(
2065+ [this,&event_loop_started]
2066 {
2067- /*
2068- * If powerd is already up it may already be in the active state
2069- * and the SysPowerStateChange signal could have already been broadcasted
2070- * before we got a chance to register a listener for it.
2071- * We will assume that if the active request succeeds that the system state
2072- * will become active at some point in the future - this is only a workaround
2073- * for the lack of a system state query api in powerd
2074- */
2075- system_state = active;
2076- }
2077- }
2078-}
2079-
2080-PowerdMediator::~PowerdMediator()
2081-{
2082- if (current_brightness > 0)
2083- turn_off_backlight();
2084-}
2085-
2086-void PowerdMediator::set_dim_backlight()
2087-{
2088- change_backlight_state(BacklightState::dim);
2089-}
2090-
2091-void PowerdMediator::set_normal_backlight()
2092-{
2093- if (auto_brightness_requested)
2094- change_backlight_state(BacklightState::automatic);
2095+ usc::set_thread_name("USC/DBusPowerd");
2096+ dbus_event_loop.run(event_loop_started);
2097+ });
2098+
2099+ event_loop_started_future.wait();
2100+
2101+ init_powerd_state(ForceDisableSuspend::yes);
2102+}
2103+
2104+usc::PowerdMediator::~PowerdMediator()
2105+{
2106+ turn_off_backlight();
2107+
2108+ dbus_event_loop.stop();
2109+ dbus_loop_thread.join();
2110+}
2111+
2112+void usc::PowerdMediator::set_dim_backlight()
2113+{
2114+ std::lock_guard<decltype(mutex)> lock{mutex};
2115+
2116+ change_backlight_state(BacklightState::dim, ForceBacklightState::no);
2117+}
2118+
2119+void usc::PowerdMediator::set_normal_backlight()
2120+{
2121+ std::lock_guard<decltype(mutex)> lock{mutex};
2122+
2123+ if (auto_brightness_supported_ && auto_brightness_requested)
2124+ change_backlight_state(BacklightState::automatic, ForceBacklightState::no);
2125 else
2126- change_backlight_state(BacklightState::normal);
2127-}
2128-
2129-void PowerdMediator::turn_off_backlight()
2130-{
2131- change_backlight_state(BacklightState::off);
2132-}
2133-
2134-void PowerdMediator::change_backlight_values(int dim, int normal)
2135-{
2136- if (normal >= min_brightness_ && normal <= max_brightness_)
2137- normal_brightness = normal;
2138- if (dim >= min_brightness_ && dim <= max_brightness_)
2139- dim_brightness = dim;
2140-}
2141-
2142-void PowerdMediator::enable_auto_brightness(bool enable)
2143-{
2144+ change_backlight_state(BacklightState::normal, ForceBacklightState::no);
2145+}
2146+
2147+void usc::PowerdMediator::turn_off_backlight()
2148+{
2149+ std::lock_guard<decltype(mutex)> lock{mutex};
2150+
2151+ change_backlight_state(BacklightState::off, ForceBacklightState::no);
2152+}
2153+
2154+void usc::PowerdMediator::change_backlight_values(int dim, int normal)
2155+{
2156+ std::lock_guard<decltype(mutex)> lock{mutex};
2157+
2158+ if (is_valid_brightness(dim))
2159+ dim_brightness_ = dim;
2160+ if (is_valid_brightness(normal))
2161+ normal_brightness_ = normal;
2162+}
2163+
2164+void usc::PowerdMediator::allow_suspend()
2165+{
2166+ std::lock_guard<decltype(mutex)> lock{mutex};
2167+
2168+ if (!suspend_block_cookie.empty())
2169+ {
2170+ auto const cstr = suspend_block_cookie.c_str();
2171+ invoke_with_reply("clearSysState",
2172+ DBUS_TYPE_STRING, &cstr,
2173+ DBUS_TYPE_INVALID);
2174+
2175+ suspend_block_cookie.clear();
2176+ }
2177+
2178+ pending_suspend_block_request = false;
2179+}
2180+
2181+void usc::PowerdMediator::disable_suspend()
2182+{
2183+ std::unique_lock<decltype(mutex)> lock{mutex};
2184+
2185+ if (request_suspend_block())
2186+ {
2187+ lock.unlock();
2188+ wait_for_sys_state(SysState::active);
2189+ }
2190+}
2191+
2192+void usc::PowerdMediator::enable_auto_brightness(bool enable)
2193+{
2194+ std::lock_guard<decltype(mutex)> lock{mutex};
2195+
2196 auto_brightness_requested = enable;
2197+
2198 if (auto_brightness_supported_ && enable)
2199- change_backlight_state(BacklightState::automatic);
2200+ change_backlight_state(BacklightState::automatic, ForceBacklightState::no);
2201 else
2202- change_backlight_state(BacklightState::normal);
2203+ change_backlight_state(BacklightState::normal, ForceBacklightState::no);
2204 }
2205
2206-bool PowerdMediator::auto_brightness_supported()
2207+bool usc::PowerdMediator::auto_brightness_supported()
2208 {
2209+ std::lock_guard<decltype(mutex)> lock{mutex};
2210+
2211 return auto_brightness_supported_;
2212 }
2213
2214-int PowerdMediator::min_brightness()
2215-{
2216+void usc::PowerdMediator::set_brightness(int brightness)
2217+{
2218+ std::lock_guard<decltype(mutex)> lock{mutex};
2219+
2220+ normal_brightness_ = brightness;
2221+ if (backlight_state != BacklightState::automatic)
2222+ change_backlight_state(BacklightState::normal, ForceBacklightState::yes);
2223+}
2224+
2225+int usc::PowerdMediator::min_brightness()
2226+{
2227+ std::lock_guard<decltype(mutex)> lock{mutex};
2228+
2229 return min_brightness_;
2230 }
2231
2232-int PowerdMediator::max_brightness()
2233+int usc::PowerdMediator::max_brightness()
2234 {
2235+ std::lock_guard<decltype(mutex)> lock{mutex};
2236+
2237 return max_brightness_;
2238 }
2239
2240-void PowerdMediator::powerd_registered()
2241-{
2242+bool usc::PowerdMediator::is_system_suspended()
2243+{
2244+ std::lock_guard<decltype(mutex)> lock{mutex};
2245+
2246+ return sys_state == SysState::suspend;
2247+}
2248+
2249+::DBusHandlerResult usc::PowerdMediator::handle_dbus_message_thunk(
2250+ ::DBusConnection* connection, DBusMessage* message, void* user_data)
2251+{
2252+ auto const powerd_mediator = static_cast<PowerdMediator*>(user_data);
2253+
2254+ return powerd_mediator->handle_dbus_message(connection, message, user_data);
2255+}
2256+
2257+::DBusHandlerResult usc::PowerdMediator::handle_dbus_message(
2258+ ::DBusConnection* connection, ::DBusMessage* message, void* user_data)
2259+{
2260+ ScopedDBusError error;
2261+
2262+ if (dbus_message_is_signal(message, powerd_service_interface, "SysPowerStateChange"))
2263+ {
2264+ int32_t state{-1};
2265+ dbus_message_get_args(
2266+ message, &error, DBUS_TYPE_INT32, &state, DBUS_TYPE_INVALID);
2267+
2268+ if (!error)
2269+ {
2270+ update_sys_state(state == static_cast<int32_t>(SysState::suspend) ?
2271+ SysState::suspend : SysState::active);
2272+ }
2273+ }
2274+ else if (dbus_message_is_signal(message, "org.freedesktop.DBus", "NameOwnerChanged"))
2275+ {
2276+ char const* name = "";
2277+ char const* old_owner = "";
2278+ char const* new_owner = "";
2279+
2280+ dbus_message_get_args(
2281+ message, &error,
2282+ DBUS_TYPE_STRING, &name,
2283+ DBUS_TYPE_STRING, &old_owner,
2284+ DBUS_TYPE_STRING, &new_owner,
2285+ DBUS_TYPE_INVALID);
2286+
2287+ if (!error &&
2288+ std::string{powerd_service_name} == name &&
2289+ *old_owner == '\0' &&
2290+ *new_owner != '\0')
2291+ {
2292+ init_powerd_state(ForceDisableSuspend::no);
2293+ }
2294+ }
2295+
2296+ return DBUS_HANDLER_RESULT_HANDLED;
2297+}
2298+
2299+void usc::PowerdMediator::init_powerd_state(ForceDisableSuspend force_disable_suspend)
2300+{
2301+ std::lock_guard<decltype(mutex)> lock{mutex};
2302+
2303 init_brightness_params();
2304
2305- /* A suspend block request needs to be issued here on the following scenarios:
2306+ /*
2307+ * A suspend block request needs to be issued here on the following scenarios:
2308 * 1. powerd has restarted and PowerdMediator had already issued a request
2309 * to the previous powerd instance
2310 * 2. When booting up the screen is assumed to be on and consequently we need to also issue
2311@@ -179,125 +269,199 @@
2312 * 3. If powerd interface is not available yet, but the screen had been turned on
2313 * then now is the time to issue the request
2314 */
2315- if (!suspend_block_cookie.isEmpty() || pending_suspend_blocker_request)
2316+ if (!suspend_block_cookie.empty() || pending_suspend_block_request ||
2317+ force_disable_suspend == ForceDisableSuspend::yes)
2318 {
2319- //Clear the previous cookie as powerd has restarted anyway
2320+ // Clear the previous cookie as powerd has restarted anyway
2321 suspend_block_cookie.clear();
2322- request_suspend_blocker();
2323- }
2324-
2325- //Powerd may have restarted, re-apply backlight settings
2326- change_backlight_state(backlight_state, true);
2327-}
2328-
2329-void PowerdMediator::set_brightness(int brightness)
2330-{
2331- normal_brightness = brightness;
2332-
2333- if (backlight_state != BacklightState::automatic)
2334- powerd_interface->call("setUserBrightness", brightness);
2335-}
2336-
2337-void PowerdMediator::change_backlight_state(BacklightState new_state, bool force_change)
2338-{
2339- if (backlight_state == new_state && !force_change)
2340+ if (request_suspend_block())
2341+ {
2342+ /*
2343+ * If powerd is already up it may already be in the active state
2344+ * and the SysPowerStateChange signal could have already been broadcasted
2345+ * before we got a chance to register a listener for it.
2346+ * We will assume that if the active request succeeds that the system state
2347+ * will become active at some point in the future - this is only a workaround
2348+ * for the lack of a system state query api in powerd
2349+ */
2350+ update_sys_state(SysState::active);
2351+ }
2352+ }
2353+
2354+ // Powerd may have restarted, re-apply backlight settings
2355+ change_backlight_state(backlight_state, ForceBacklightState::yes);
2356+}
2357+
2358+void usc::PowerdMediator::init_brightness_params()
2359+{
2360+ auto reply = invoke_with_reply("getBrightnessParams", DBUS_TYPE_INVALID);
2361+
2362+ if (reply)
2363+ {
2364+ DBusMessageIter msg_iter;
2365+ dbus_message_iter_init(reply, &msg_iter);
2366+ if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_STRUCT)
2367+ return;
2368+
2369+ DBusMessageIter struct_iter;
2370+ dbus_message_iter_recurse(&msg_iter, &struct_iter);
2371+
2372+ int32_t dim, min, max, normal;
2373+ dbus_bool_t auto_b;
2374+ struct { int type; void* address; } args[]{
2375+ { DBUS_TYPE_INT32, &dim },
2376+ { DBUS_TYPE_INT32, &min },
2377+ { DBUS_TYPE_INT32, &max },
2378+ { DBUS_TYPE_INT32, &normal },
2379+ { DBUS_TYPE_BOOLEAN, &auto_b }
2380+ };
2381+
2382+ for (auto const& arg : args)
2383+ {
2384+ if (dbus_message_iter_get_arg_type(&struct_iter) == arg.type)
2385+ dbus_message_iter_get_basic(&struct_iter, arg.address);
2386+ else
2387+ return;
2388+ dbus_message_iter_next(&struct_iter);
2389+ }
2390+
2391+ dim_brightness_ = dim;
2392+ min_brightness_ = min;
2393+ max_brightness_ = max;
2394+ normal_brightness_ = normal;
2395+ auto_brightness_supported_ = (auto_b == TRUE);
2396+ }
2397+}
2398+
2399+void usc::PowerdMediator::change_backlight_state(
2400+ BacklightState new_state,
2401+ ForceBacklightState force_backlight_state)
2402+{
2403+ if (backlight_state == new_state &&
2404+ force_backlight_state == ForceBacklightState::no)
2405+ {
2406 return;
2407+ }
2408+
2409+ update_current_brightness_for_state(new_state);
2410+ backlight_state = new_state;
2411
2412 if (new_state == BacklightState::automatic)
2413 {
2414- powerd_interface->call("userAutobrightnessEnable", true);
2415- backlight_state = BacklightState::automatic;
2416- return;
2417- }
2418-
2419- switch (new_state)
2420+ dbus_bool_t const enable{TRUE};
2421+ invoke_with_reply("userAutobrightnessEnable",
2422+ DBUS_TYPE_BOOLEAN, &enable,
2423+ DBUS_TYPE_INVALID);
2424+ }
2425+ else
2426+ {
2427+ int32_t const b{current_brightness};
2428+ invoke_with_reply("setUserBrightness",
2429+ DBUS_TYPE_INT32, &b,
2430+ DBUS_TYPE_INVALID);
2431+ }
2432+}
2433+
2434+bool usc::PowerdMediator::is_valid_brightness(int brightness)
2435+{
2436+ return brightness >= min_brightness_ && brightness <= max_brightness_;
2437+}
2438+
2439+bool usc::PowerdMediator::request_suspend_block()
2440+{
2441+ if (suspend_block_cookie.empty())
2442+ {
2443+ char const* const name{"com.canonical.Unity.Screen"};
2444+ int const sys_state_active{static_cast<int>(SysState::active)};
2445+
2446+ auto reply = invoke_with_reply(
2447+ "requestSysState",
2448+ DBUS_TYPE_STRING, &name,
2449+ DBUS_TYPE_INT32, &sys_state_active,
2450+ DBUS_TYPE_INVALID);
2451+
2452+ if (reply)
2453+ {
2454+ char const* cookie{nullptr};
2455+
2456+ dbus_message_get_args(
2457+ reply, nullptr,
2458+ DBUS_TYPE_STRING, &cookie,
2459+ DBUS_TYPE_INVALID);
2460+
2461+ if (cookie)
2462+ suspend_block_cookie = cookie;
2463+
2464+ return true;
2465+ }
2466+ else
2467+ {
2468+ pending_suspend_block_request = true;
2469+ }
2470+ }
2471+
2472+ return false;
2473+}
2474+
2475+void usc::PowerdMediator::update_sys_state(SysState state)
2476+{
2477+ {
2478+ std::lock_guard<decltype(mutex)> lock{sys_state_mutex};
2479+ sys_state = state;
2480+ }
2481+ sys_state_changed.notify_one();
2482+}
2483+
2484+void usc::PowerdMediator::wait_for_sys_state(SysState state)
2485+{
2486+ std::unique_lock<decltype(sys_state_mutex)> lock{sys_state_mutex};
2487+ sys_state_changed.wait(lock, [this, state]{ return sys_state == state; });
2488+}
2489+
2490+void usc::PowerdMediator::update_current_brightness_for_state(BacklightState state)
2491+{
2492+ switch (state)
2493 {
2494 case BacklightState::normal:
2495- current_brightness = normal_brightness;
2496+ current_brightness = normal_brightness_;
2497 break;
2498 case BacklightState::off:
2499 current_brightness = 0;
2500 break;
2501 case BacklightState::dim:
2502- current_brightness = dim_brightness;
2503+ current_brightness = dim_brightness_;
2504 break;
2505 default:
2506- std::cerr << "unknown backlight state" << std::endl;
2507 break;
2508 }
2509-
2510- powerd_interface->call("setUserBrightness", current_brightness);
2511- backlight_state = new_state;
2512-}
2513-
2514-void PowerdMediator::allow_suspend()
2515-{
2516- if (!suspend_block_cookie.isEmpty())
2517- {
2518- powerd_interface->call("clearSysState", suspend_block_cookie);
2519- suspend_block_cookie.clear();
2520- }
2521- pending_suspend_blocker_request = false;
2522-}
2523-
2524-void PowerdMediator::disable_suspend()
2525-{
2526- if (request_suspend_blocker())
2527- wait_for_state(active);
2528-}
2529-
2530-bool PowerdMediator::request_suspend_blocker()
2531-{
2532- if (suspend_block_cookie.isEmpty())
2533- {
2534- QDBusReply<QString> reply = powerd_interface->call("requestSysState", "com.canonical.Unity.Screen", 1);
2535- if (reply.isValid())
2536- {
2537- suspend_block_cookie = reply.value();
2538- pending_suspend_blocker_request = false;
2539- return true;
2540- }
2541- else
2542- {
2543- //Powerd may not yet be available, so save the pending request
2544- pending_suspend_blocker_request = true;
2545- }
2546- }
2547- return false;
2548-}
2549-
2550-void PowerdMediator::init_brightness_params()
2551-{
2552- QDBusReply<BrightnessParams> reply = powerd_interface->call("getBrightnessParams");
2553- if (reply.isValid())
2554- {
2555- auto const& params = reply.value();
2556- dim_brightness = params.dim_brightness;
2557- normal_brightness = params.default_brightness;
2558- min_brightness_ = params.min_brightness;
2559- max_brightness_ = params.max_brightness;
2560- auto_brightness_supported_ = params.auto_brightness_supported;
2561- std::cerr << "initialized brightness parameters" << std::endl;
2562- }
2563+}
2564+
2565+usc::DBusMessageHandle usc::PowerdMediator::invoke_with_reply(
2566+ char const* method, int first_arg_type, ...)
2567+{
2568+ va_list args;
2569+ va_start(args, first_arg_type);
2570+ auto msg = make_powerd_method_call_message(method, first_arg_type, args);
2571+ va_end(args);
2572+
2573+ std::promise<DBusMessage*> reply_promise;
2574+ auto reply_future = reply_promise.get_future();
2575+
2576+ auto const send_message_with_reply =
2577+ [this, &msg, &reply_promise]
2578+ {
2579+ auto const reply = dbus_connection_send_with_reply_and_block(
2580+ connection, msg, DBUS_TIMEOUT_USE_DEFAULT, nullptr);
2581+
2582+ reply_promise.set_value(reply);
2583+ };
2584+
2585+ // Run in the context of the dbus event loop to avoid
2586+ // strange dbus behaviors.
2587+ if (std::this_thread::get_id() == dbus_loop_thread.get_id())
2588+ send_message_with_reply();
2589 else
2590- {
2591- std::cerr << "getBrightnessParams call failed with: ";
2592- std::cerr << reply.error().message().toStdString() << std::endl;
2593- }
2594-}
2595-
2596-void PowerdMediator::powerd_state_changed(int state)
2597-{
2598- std::unique_lock<std::mutex> lock(system_state_mutex);
2599-
2600- system_state = state == 0 ? suspended : active;
2601-
2602- lock.unlock();
2603- state_change.notify_one();
2604-}
2605-
2606-void PowerdMediator::wait_for_state(SystemState state)
2607-{
2608- std::unique_lock<std::mutex> lock(system_state_mutex);
2609- state_change.wait(lock, [this, state]{ return (system_state == state); });
2610+ dbus_event_loop.enqueue(send_message_with_reply);
2611+
2612+ return usc::DBusMessageHandle{reply_future.get()};
2613 }
2614
2615=== modified file 'src/powerd_mediator.h'
2616--- src/powerd_mediator.h 2014-08-14 18:06:05 +0000
2617+++ src/powerd_mediator.h 2015-05-06 16:09:34 +0000
2618@@ -1,5 +1,5 @@
2619 /*
2620- * Copyright © 2014 Canonical Ltd.
2621+ * Copyright © 2015 Canonical Ltd.
2622 *
2623 * This program is free software: you can redistribute it and/or modify
2624 * it under the terms of the GNU General Public License version 3 as
2625@@ -14,53 +14,42 @@
2626 * along with this program. If not, see <http://www.gnu.org/licenses/>.
2627 */
2628
2629-#ifndef POWERD_MEDIATOR_
2630-#define POWERD_MEDIATOR_
2631-
2632-#include <mir_toolkit/common.h>
2633-
2634-#include <QString>
2635-#include <QObject>
2636-
2637-#include <memory>
2638-#include <mutex>
2639-#include <condition_variable>
2640-
2641-class QDBusInterface;
2642-class QDBusServiceWatcher;
2643-
2644-/*
2645- * A Proxy to powerd. Note this class is not thread-safe,
2646- * synchronization should be done externally.
2647- */
2648-class PowerdMediator : public QObject
2649-{
2650- Q_OBJECT
2651+#ifndef USC_POWERD_MEDIATOR_H_
2652+#define USC_POWERD_MEDIATOR_H_
2653+
2654+#include "screen_hardware.h"
2655+
2656+#include "dbus_connection_handle.h"
2657+#include "dbus_event_loop.h"
2658+
2659+namespace usc
2660+{
2661+class DBusMessageHandle;
2662+
2663+class PowerdMediator : public ScreenHardware
2664+{
2665 public:
2666- PowerdMediator();
2667+ PowerdMediator(std::string const& bus_addr);
2668 ~PowerdMediator();
2669
2670- void set_dim_backlight();
2671- void set_normal_backlight();
2672- void turn_off_backlight();
2673- void allow_suspend();
2674- void disable_suspend();
2675-
2676- void change_backlight_values(int dim_brightness, int normal_brightness);
2677- void enable_auto_brightness(bool flag);
2678-
2679- bool auto_brightness_supported();
2680- int min_brightness();
2681- int max_brightness();
2682-
2683- void set_brightness(int brightness);
2684-
2685-private Q_SLOTS:
2686- void powerd_registered();
2687- void powerd_state_changed(int state);
2688+ void set_dim_backlight() override;
2689+ void set_normal_backlight() override;
2690+ void turn_off_backlight() override;
2691+ void change_backlight_values(int dim_brightness, int normal_brightness) override;
2692+
2693+ void allow_suspend() override;
2694+ void disable_suspend() override;
2695+
2696+ void enable_auto_brightness(bool flag) override;
2697+ bool auto_brightness_supported() override;
2698+ void set_brightness(int brightness) override;
2699+ int min_brightness() override;
2700+ int max_brightness() override;
2701+
2702+ bool is_system_suspended();
2703
2704 private:
2705- enum BacklightState
2706+ enum class BacklightState
2707 {
2708 off,
2709 dim,
2710@@ -68,35 +57,53 @@
2711 automatic
2712 };
2713
2714- enum SystemState
2715+ enum class SysState
2716 {
2717 unknown = -1,
2718- suspended = 0,
2719+ suspend = 0,
2720 active,
2721 };
2722- void change_backlight_state(BacklightState state, bool force_change = false);
2723+
2724+ enum class ForceDisableSuspend { no, yes };
2725+ enum class ForceBacklightState { no, yes };
2726+
2727+ static ::DBusHandlerResult handle_dbus_message_thunk(
2728+ ::DBusConnection* connection, ::DBusMessage* message, void* user_data);
2729+
2730+ ::DBusHandlerResult handle_dbus_message(
2731+ ::DBusConnection* connection, ::DBusMessage* message, void* user_data);
2732+ void init_powerd_state(ForceDisableSuspend force_disable_suspend);
2733 void init_brightness_params();
2734- bool request_suspend_blocker();
2735- void wait_for_state(SystemState state);
2736-
2737- int dim_brightness;
2738- int normal_brightness;
2739- int current_brightness;
2740+ void change_backlight_state(
2741+ BacklightState new_state, ForceBacklightState force_backlight_state);
2742+ bool is_valid_brightness(int brightness);
2743+ bool request_suspend_block();
2744+ void wait_for_sys_state(SysState state);
2745+ void update_sys_state(SysState state);
2746+ void update_current_brightness_for_state(BacklightState state);
2747+ void invoke(char const* method, int first_arg_type, ...);
2748+ usc::DBusMessageHandle invoke_with_reply(char const* method, int first_arg_type, ...);
2749+
2750+ usc::DBusConnectionHandle connection;
2751+ usc::DBusEventLoop dbus_event_loop;
2752+ std::thread dbus_loop_thread;
2753+
2754+ std::mutex mutex;
2755+ bool pending_suspend_block_request;
2756+ int dim_brightness_;
2757 int min_brightness_;
2758 int max_brightness_;
2759+ int normal_brightness_;
2760+ int current_brightness;
2761+ BacklightState backlight_state;
2762 bool auto_brightness_supported_;
2763 bool auto_brightness_requested;
2764- BacklightState backlight_state;
2765-
2766- QString suspend_block_cookie;
2767- bool pending_suspend_blocker_request;
2768-
2769- std::unique_ptr<QDBusInterface> powerd_interface;
2770- std::unique_ptr<QDBusServiceWatcher> service_watcher;
2771-
2772- SystemState system_state;
2773-
2774- std::mutex system_state_mutex;
2775- std::condition_variable state_change;
2776+ std::string suspend_block_cookie;
2777+ std::mutex sys_state_mutex;
2778+ SysState sys_state;
2779+ std::condition_variable sys_state_changed;
2780 };
2781+
2782+}
2783+
2784 #endif
2785
2786=== added file 'src/scoped_dbus_error.h'
2787--- src/scoped_dbus_error.h 1970-01-01 00:00:00 +0000
2788+++ src/scoped_dbus_error.h 2015-05-06 16:09:34 +0000
2789@@ -0,0 +1,57 @@
2790+/*
2791+ * Copyright © 2015 Canonical Ltd.
2792+ *
2793+ * This program is free software: you can redistribute it and/or modify
2794+ * it under the terms of the GNU General Public License version 3 as
2795+ * published by the Free Software Foundation.
2796+ *
2797+ * This program is distributed in the hope that it will be useful,
2798+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2799+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2800+ * GNU General Public License for more details.
2801+ *
2802+ * You should have received a copy of the GNU General Public License
2803+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2804+ *
2805+ * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
2806+ */
2807+
2808+#ifndef USC_SCOPED_DBUS_ERROR_H_
2809+#define USC_SCOPED_DBUS_ERROR_H_
2810+
2811+#include <dbus/dbus.h>
2812+#include <string>
2813+
2814+namespace usc
2815+{
2816+
2817+struct ScopedDBusError : ::DBusError
2818+{
2819+ ScopedDBusError()
2820+ {
2821+ dbus_error_init(this);
2822+ }
2823+
2824+ ~ScopedDBusError()
2825+ {
2826+ if (dbus_error_is_set(this) == TRUE)
2827+ dbus_error_free(this);
2828+ }
2829+
2830+ std::string message_str() const
2831+ {
2832+ return message;
2833+ }
2834+
2835+ operator bool() const
2836+ {
2837+ return dbus_error_is_set(this) == TRUE;
2838+ }
2839+
2840+ ScopedDBusError(ScopedDBusError const&) = delete;
2841+ ScopedDBusError& operator=(ScopedDBusError const&) = delete;
2842+};
2843+
2844+}
2845+
2846+#endif
2847
2848=== renamed file 'src/dbus_screen_observer.h' => 'src/screen.h'
2849--- src/dbus_screen_observer.h 2014-09-04 22:30:24 +0000
2850+++ src/screen.h 2015-05-06 16:09:34 +0000
2851@@ -1,5 +1,5 @@
2852 /*
2853- * Copyright © 2014 Canonical Ltd.
2854+ * Copyright © 2014-2015 Canonical Ltd.
2855 *
2856 * This program is free software: you can redistribute it and/or modify
2857 * it under the terms of the GNU General Public License version 3 as
2858@@ -14,27 +14,44 @@
2859 * along with this program. If not, see <http://www.gnu.org/licenses/>.
2860 */
2861
2862-#ifndef DBUS_SCREEN_OBSERVER_H_
2863-#define DBUS_SCREEN_OBSERVER_H_
2864+#ifndef USC_SCREEN_H_
2865+#define USC_SCREEN_H_
2866+
2867+#include <mir_toolkit/common.h>
2868+#include <functional>
2869
2870 enum class PowerStateChangeReason;
2871
2872-class DBusScreenObserver
2873+namespace usc
2874+{
2875+
2876+using PowerStateChangeHandler = std::function<void(MirPowerMode, PowerStateChangeReason)>;
2877+
2878+class Screen
2879 {
2880 public:
2881- virtual ~DBusScreenObserver() = default;
2882+ virtual ~Screen() = default;
2883+
2884+ virtual void enable_inactivity_timers(bool enable) = 0;
2885+ virtual void toggle_screen_power_mode(PowerStateChangeReason reason) = 0;
2886+ virtual void keep_display_on_temporarily() = 0;
2887
2888 virtual void set_screen_power_mode(MirPowerMode mode, PowerStateChangeReason reason) = 0;
2889 virtual void keep_display_on(bool on) = 0;
2890 virtual void set_brightness(int brightness) = 0;
2891 virtual void enable_auto_brightness(bool enable) = 0;
2892- virtual void set_inactivity_timeouts(int poweroff_timeout, int dimmer_timeout) = 0;
2893+ virtual void set_inactivity_timeouts(int power_off_timeout, int dimmer_timeout) = 0;
2894+
2895 virtual void set_touch_visualization_enabled(bool enabled) = 0;
2896+ virtual void register_power_state_change_handler(
2897+ PowerStateChangeHandler const& handler) = 0;
2898
2899 protected:
2900- DBusScreenObserver() = default;
2901- DBusScreenObserver(const DBusScreenObserver&) = delete;
2902- DBusScreenObserver& operator=(const DBusScreenObserver&) = delete;
2903+ Screen() = default;
2904+ Screen(Screen const&) = delete;
2905+ Screen& operator=(Screen const&) = delete;
2906 };
2907
2908+}
2909+
2910 #endif
2911
2912=== renamed file 'src/powerkey_handler.cpp' => 'src/screen_event_handler.cpp'
2913--- src/powerkey_handler.cpp 2014-12-11 22:15:07 +0000
2914+++ src/screen_event_handler.cpp 2015-05-06 16:09:34 +0000
2915@@ -1,5 +1,5 @@
2916 /*
2917- * Copyright © 2014 Canonical Ltd.
2918+ * Copyright © 2014-2015 Canonical Ltd.
2919 *
2920 * This program is free software: you can redistribute it and/or modify
2921 * it under the terms of the GNU General Public License version 3 as
2922@@ -14,85 +14,96 @@
2923 * along with this program. If not, see <http://www.gnu.org/licenses/>.
2924 */
2925
2926-#include "powerkey_handler.h"
2927-#include "screen_state_handler.h"
2928+#include "screen_event_handler.h"
2929+#include "screen.h"
2930 #include "power_state_change_reason.h"
2931
2932-#include <mir/time/timer.h>
2933+#include <mir/time/alarm_factory.h>
2934+#include <mir_toolkit/events/input/input_event.h>
2935
2936 #include <cstdio>
2937-#include "dbus_screen.h"
2938-#include "powerd_mediator.h"
2939-
2940-namespace mi = mir::input;
2941-
2942-PowerKeyHandler::PowerKeyHandler(mir::time::Timer& timer,
2943- std::chrono::milliseconds power_key_ignore_timeout,
2944- std::chrono::milliseconds shutdown_timeout,
2945- ScreenStateHandler& screen_state_handler)
2946- : long_press_detected{false},
2947- screen_state_handler{&screen_state_handler},
2948+
2949+usc::ScreenEventHandler::ScreenEventHandler(
2950+ std::shared_ptr<Screen> const& screen,
2951+ std::shared_ptr<mir::time::AlarmFactory> const& alarm_factory,
2952+ std::chrono::milliseconds power_key_ignore_timeout,
2953+ std::chrono::milliseconds shutdown_timeout,
2954+ std::function<void()> const& shutdown)
2955+ : screen{screen},
2956+ alarm_factory{alarm_factory},
2957 power_key_ignore_timeout{power_key_ignore_timeout},
2958 shutdown_timeout{shutdown_timeout},
2959- shutdown_alarm{timer.create_alarm([this]{ shutdown_alarm_notification(); })},
2960- long_press_alarm{timer.create_alarm([this]{ long_press_notification(); })}
2961+ shutdown{shutdown},
2962+ long_press_detected{false},
2963+ shutdown_alarm{alarm_factory->create_alarm([this]{ shutdown_alarm_notification(); })},
2964+ long_press_alarm{alarm_factory->create_alarm([this]{ long_press_notification(); })}
2965 {
2966 }
2967
2968-PowerKeyHandler::~PowerKeyHandler() = default;
2969+usc::ScreenEventHandler::~ScreenEventHandler() = default;
2970
2971-bool PowerKeyHandler::handle(MirEvent const& event)
2972+bool usc::ScreenEventHandler::handle(MirEvent const& event)
2973 {
2974 static const int32_t POWER_KEY_CODE = 26;
2975-
2976+
2977 if (mir_event_get_type(&event) != mir_event_type_input)
2978 return false;
2979- auto input_event = mir_event_get_input_event(&event);
2980- if (mir_input_event_get_type(input_event) != mir_input_event_type_key)
2981- return false;
2982- auto kev = mir_input_event_get_key_input_event(input_event);
2983- if (mir_key_input_event_get_key_code(kev) != POWER_KEY_CODE)
2984- return false;
2985-
2986- auto action = mir_key_input_event_get_action(kev);
2987- if (action == mir_key_input_event_action_down)
2988- power_key_down();
2989- else if (action == mir_key_input_event_action_up)
2990- power_key_up();
2991+
2992+ auto const input_event = mir_event_get_input_event(&event);
2993+ auto const input_event_type = mir_input_event_get_type(input_event);
2994+
2995+ if (input_event_type == mir_input_event_type_key)
2996+ {
2997+ auto const kev = mir_input_event_get_keyboard_event(input_event);
2998+ if (mir_keyboard_event_key_code(kev) != POWER_KEY_CODE)
2999+ return false;
3000+
3001+ auto const action = mir_keyboard_event_action(kev);
3002+ if (action == mir_keyboard_action_down)
3003+ power_key_down();
3004+ else if (action == mir_keyboard_action_up)
3005+ power_key_up();
3006+ }
3007+ else if (input_event_type == mir_input_event_type_touch ||
3008+ input_event_type == mir_input_event_type_pointer)
3009+ {
3010+ std::lock_guard<std::mutex> lock{guard};
3011+ screen->keep_display_on_temporarily();
3012+ }
3013
3014 return false;
3015 }
3016
3017-void PowerKeyHandler::power_key_down()
3018+void usc::ScreenEventHandler::power_key_down()
3019 {
3020 std::lock_guard<std::mutex> lock{guard};
3021- screen_state_handler->enable_inactivity_timers(false);
3022+ screen->enable_inactivity_timers(false);
3023 long_press_detected = false;
3024 long_press_alarm->reschedule_in(power_key_ignore_timeout);
3025 shutdown_alarm->reschedule_in(shutdown_timeout);
3026 }
3027
3028-void PowerKeyHandler::power_key_up()
3029+void usc::ScreenEventHandler::power_key_up()
3030 {
3031 std::lock_guard<std::mutex> lock{guard};
3032 shutdown_alarm->cancel();
3033 long_press_alarm->cancel();
3034 if (!long_press_detected)
3035 {
3036- screen_state_handler->toggle_screen_power_mode(PowerStateChangeReason::power_key);
3037+ screen->toggle_screen_power_mode(PowerStateChangeReason::power_key);
3038 }
3039 }
3040
3041-void PowerKeyHandler::shutdown_alarm_notification()
3042+void usc::ScreenEventHandler::shutdown_alarm_notification()
3043 {
3044- screen_state_handler->set_screen_power_mode(
3045+ screen->set_screen_power_mode(
3046 MirPowerMode::mir_power_mode_off, PowerStateChangeReason::power_key);
3047- system("shutdown -P now");
3048+ shutdown();
3049 }
3050
3051-void PowerKeyHandler::long_press_notification()
3052+void usc::ScreenEventHandler::long_press_notification()
3053 {
3054- screen_state_handler->set_screen_power_mode(
3055+ screen->set_screen_power_mode(
3056 MirPowerMode::mir_power_mode_on, PowerStateChangeReason::power_key);
3057 long_press_detected = true;
3058 }
3059
3060=== renamed file 'src/powerkey_handler.h' => 'src/screen_event_handler.h'
3061--- src/powerkey_handler.h 2014-11-03 17:57:10 +0000
3062+++ src/screen_event_handler.h 2015-05-06 16:09:34 +0000
3063@@ -1,5 +1,5 @@
3064 /*
3065- * Copyright © 2014 Canonical Ltd.
3066+ * Copyright © 2014-2015 Canonical Ltd.
3067 *
3068 * This program is free software: you can redistribute it and/or modify
3069 * it under the terms of the GNU General Public License version 3 as
3070@@ -14,8 +14,8 @@
3071 * along with this program. If not, see <http://www.gnu.org/licenses/>.
3072 */
3073
3074-#ifndef POWERKEY_HANDLER_H_
3075-#define POWERKEY_HANDLER_H_
3076+#ifndef USC_SCREEN_EVENT_HANDLER_H_
3077+#define USC_SCREEN_EVENT_HANDLER_H_
3078
3079 #include "mir/input/event_filter.h"
3080
3081@@ -29,21 +29,25 @@
3082 namespace time
3083 {
3084 class Alarm;
3085-class Timer;
3086-}
3087-}
3088-
3089-class ScreenStateHandler;
3090-
3091-class PowerKeyHandler : public mir::input::EventFilter
3092+class AlarmFactory;
3093+}
3094+}
3095+
3096+namespace usc
3097+{
3098+class Screen;
3099+
3100+class ScreenEventHandler : public mir::input::EventFilter
3101 {
3102 public:
3103- PowerKeyHandler(mir::time::Timer& timer,
3104- std::chrono::milliseconds power_key_ignore_timeout,
3105- std::chrono::milliseconds shutdown_timeout,
3106- ScreenStateHandler& screen_state_handler);
3107+ ScreenEventHandler(
3108+ std::shared_ptr<Screen> const& screen,
3109+ std::shared_ptr<mir::time::AlarmFactory> const& alarm_factory,
3110+ std::chrono::milliseconds power_key_ignore_timeout,
3111+ std::chrono::milliseconds shutdown_timeout,
3112+ std::function<void()> const& shutdown);
3113
3114- ~PowerKeyHandler();
3115+ ~ScreenEventHandler();
3116
3117 bool handle(MirEvent const& event) override;
3118
3119@@ -54,16 +58,17 @@
3120 void long_press_notification();
3121
3122 std::mutex guard;
3123+ std::shared_ptr<Screen> const screen;
3124+ std::shared_ptr<mir::time::AlarmFactory> const alarm_factory;
3125+ std::chrono::milliseconds const power_key_ignore_timeout;
3126+ std::chrono::milliseconds const shutdown_timeout;
3127+ std::function<void()> const shutdown;
3128+
3129 std::atomic<bool> long_press_detected;
3130-
3131- ScreenStateHandler* screen_state_handler;
3132-
3133- std::chrono::milliseconds power_key_ignore_timeout;
3134- std::chrono::milliseconds shutdown_timeout;
3135-
3136 std::unique_ptr<mir::time::Alarm> shutdown_alarm;
3137 std::unique_ptr<mir::time::Alarm> long_press_alarm;
3138-
3139 };
3140
3141+}
3142+
3143 #endif
3144
3145=== added file 'src/screen_hardware.h'
3146--- src/screen_hardware.h 1970-01-01 00:00:00 +0000
3147+++ src/screen_hardware.h 2015-05-06 16:09:34 +0000
3148@@ -0,0 +1,49 @@
3149+/*
3150+ * Copyright © 2015 Canonical Ltd.
3151+ *
3152+ * This program is free software: you can redistribute it and/or modify
3153+ * it under the terms of the GNU General Public License version 3 as
3154+ * published by the Free Software Foundation.
3155+ *
3156+ * This program is distributed in the hope that it will be useful,
3157+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3158+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3159+ * GNU General Public License for more details.
3160+ *
3161+ * You should have received a copy of the GNU General Public License
3162+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3163+ */
3164+
3165+#ifndef USC_SCREEN_HARDWARE_H_
3166+#define USC_SCREEN_HARDWARE_H_
3167+
3168+namespace usc
3169+{
3170+
3171+class ScreenHardware
3172+{
3173+public:
3174+ virtual ~ScreenHardware() = default;
3175+
3176+ virtual void set_dim_backlight() = 0;
3177+ virtual void set_normal_backlight() = 0;
3178+ virtual void turn_off_backlight() = 0;
3179+ virtual void change_backlight_values(int dim_brightness, int normal_brightness) = 0;
3180+
3181+ virtual void allow_suspend() = 0;
3182+ virtual void disable_suspend() = 0;
3183+
3184+ virtual void enable_auto_brightness(bool flag) = 0;
3185+ virtual bool auto_brightness_supported() = 0;
3186+ virtual void set_brightness(int brightness) = 0;
3187+ virtual int min_brightness() = 0;
3188+ virtual int max_brightness() = 0;
3189+
3190+protected:
3191+ ScreenHardware() = default;
3192+ ScreenHardware(ScreenHardware const&) = delete;
3193+ ScreenHardware& operator=(ScreenHardware const&) = delete;
3194+};
3195+
3196+}
3197+#endif
3198
3199=== modified file 'src/server.cpp'
3200--- src/server.cpp 2015-01-27 17:43:17 +0000
3201+++ src/server.cpp 2015-05-06 16:09:34 +0000
3202@@ -18,14 +18,19 @@
3203
3204 #include "server.h"
3205 #include "external_spinner.h"
3206-#include "shell.h"
3207 #include "asio_dm_connection.h"
3208 #include "session_switcher.h"
3209+#include "window_manager.h"
3210+#include "mir_screen.h"
3211+#include "screen_event_handler.h"
3212+#include "powerd_mediator.h"
3213+#include "unity_screen_service.h"
3214
3215 #include <mir/input/cursor_listener.h>
3216 #include <mir/server_status_listener.h>
3217 #include <mir/shell/focus_controller.h>
3218 #include <mir/scene/session.h>
3219+#include <mir/main_loop.h>
3220
3221 #include <iostream>
3222
3223@@ -82,7 +87,7 @@
3224
3225 std::weak_ptr<ms::Session> weak_active_session()
3226 {
3227- return focus_controller->focussed_application();
3228+ return focus_controller->focused_session();
3229 }
3230
3231 std::shared_ptr<msh::FocusController> const focus_controller;
3232@@ -126,11 +131,14 @@
3233 return std::make_shared<ServerStatusListener>(the_focus_controller());
3234 });
3235
3236- wrap_shell([this](std::shared_ptr<msh::Shell> const& wrapped)
3237- -> std::shared_ptr<msh::Shell>
3238- {
3239- return std::make_shared<Shell>(wrapped, the_session_switcher());
3240- });
3241+ override_the_window_manager_builder([this](msh::FocusController* focus_controller)
3242+ {
3243+ return std::make_shared<WindowManager>(
3244+ focus_controller,
3245+ the_shell_display_layout(),
3246+ the_session_coordinator(),
3247+ the_session_switcher());
3248+ });
3249
3250 set_config_filename("unity-system-compositor.conf");
3251
3252@@ -174,3 +182,64 @@
3253 the_dm_message_handler());
3254 });
3255 }
3256+
3257+std::shared_ptr<usc::Screen> usc::Server::the_screen()
3258+{
3259+ return screen(
3260+ [this]
3261+ {
3262+ return std::make_shared<MirScreen>(
3263+ the_screen_hardware(),
3264+ the_compositor(),
3265+ the_display(),
3266+ the_touch_visualizer(),
3267+ the_main_loop(),
3268+ inactivity_display_off_timeout(),
3269+ inactivity_display_dim_timeout());
3270+ });
3271+}
3272+
3273+std::shared_ptr<mi::EventFilter> usc::Server::the_screen_event_handler()
3274+{
3275+ return screen_event_handler(
3276+ [this]
3277+ {
3278+ return std::make_shared<ScreenEventHandler>(
3279+ the_screen(),
3280+ the_main_loop(),
3281+ power_key_ignore_timeout(),
3282+ shutdown_timeout(),
3283+ [] { if (system("shutdown -P now")); }); // ignore warning
3284+ });
3285+}
3286+
3287+std::shared_ptr<usc::ScreenHardware> usc::Server::the_screen_hardware()
3288+{
3289+ return screen_hardware(
3290+ [this]
3291+ {
3292+ return std::make_shared<usc::PowerdMediator>(dbus_bus_address());
3293+ });
3294+}
3295+
3296+std::shared_ptr<usc::UnityScreenService> usc::Server::the_unity_screen_service()
3297+{
3298+ return unity_screen_service(
3299+ [this]
3300+ {
3301+ return std::make_shared<UnityScreenService>(
3302+ dbus_bus_address(),
3303+ the_screen());
3304+ });
3305+}
3306+
3307+std::string usc::Server::dbus_bus_address()
3308+{
3309+ static char const* const default_bus_address{"unix:path=/var/run/dbus/system_bus_socket"};
3310+
3311+ char const* bus = getenv("DBUS_SYSTEM_BUS_ADDRESS");
3312+ if (!bus)
3313+ bus = default_bus_address;
3314+
3315+ return std::string{bus};
3316+}
3317
3318=== modified file 'src/server.h'
3319--- src/server.h 2014-11-28 11:39:04 +0000
3320+++ src/server.h 2015-05-06 16:09:34 +0000
3321@@ -23,12 +23,25 @@
3322 #include <mir/cached_ptr.h>
3323 #include <mir/options/option.h>
3324
3325+#include <chrono>
3326+
3327+namespace mir
3328+{
3329+namespace input
3330+{
3331+class EventFilter;
3332+}
3333+}
3334+
3335 namespace usc
3336 {
3337 class Spinner;
3338 class SessionSwitcher;
3339 class DMMessageHandler;
3340 class DMConnection;
3341+class Screen;
3342+class ScreenHardware;
3343+class UnityScreenService;
3344
3345 class Server : private mir::Server
3346 {
3347@@ -46,37 +59,16 @@
3348 virtual std::shared_ptr<Spinner> the_spinner();
3349 virtual std::shared_ptr<DMMessageHandler> the_dm_message_handler();
3350 virtual std::shared_ptr<DMConnection> the_dm_connection();
3351+ virtual std::shared_ptr<Screen> the_screen();
3352+ virtual std::shared_ptr<mir::input::EventFilter> the_screen_event_handler();
3353+ virtual std::shared_ptr<ScreenHardware> the_screen_hardware();
3354+ virtual std::shared_ptr<UnityScreenService> the_unity_screen_service();
3355
3356 bool show_version()
3357 {
3358 return the_options()->is_set("version");
3359 }
3360
3361- int inactivity_display_off_timeout()
3362- {
3363- return the_options()->get("inactivity-display-off-timeout", 60);
3364- }
3365-
3366- int inactivity_display_dim_timeout()
3367- {
3368- return the_options()->get("inactivity-display-dim-timeout", 45);
3369- }
3370-
3371- int shutdown_timeout()
3372- {
3373- return the_options()->get("shutdown-timeout", 5000);
3374- }
3375-
3376- int power_key_ignore_timeout()
3377- {
3378- return the_options()->get("power-key-ignore-timeout", 2000);
3379- }
3380-
3381- bool enable_hardware_cursor()
3382- {
3383- return the_options()->get("enable-hardware-cursor", false);
3384- }
3385-
3386 bool disable_inactivity_policy()
3387 {
3388 return the_options()->get("disable-inactivity-policy", false);
3389@@ -85,16 +77,6 @@
3390 std::string blacklist()
3391 {
3392 auto x = the_options()->get("blacklist", "");
3393- //boost::trim(x);
3394- return x;
3395- }
3396-
3397- std::string spinner_executable()
3398- {
3399- // TODO: once our default spinner is ready for use everywhere, replace
3400- // default value with DEFAULT_SPINNER instead of the empty string.
3401- auto x = the_options()->get("spinner", "");
3402- //boost::trim(x);
3403 return x;
3404 }
3405
3406@@ -114,11 +96,55 @@
3407 -> decltype(mir::Server::get_options())
3408 { return mir::Server::get_options(); }
3409
3410+ std::chrono::milliseconds inactivity_display_off_timeout()
3411+ {
3412+ using namespace std::chrono;
3413+ return duration_cast<milliseconds>(
3414+ seconds{the_options()->get("inactivity-display-off-timeout", 60)});
3415+ }
3416+
3417+ std::chrono::milliseconds inactivity_display_dim_timeout()
3418+ {
3419+ using namespace std::chrono;
3420+ return duration_cast<milliseconds>(
3421+ seconds{the_options()->get("inactivity-display-dim-timeout", 45)});
3422+ }
3423+
3424+ std::chrono::milliseconds shutdown_timeout()
3425+ {
3426+ return std::chrono::milliseconds{
3427+ the_options()->get("shutdown-timeout", 5000)};
3428+ }
3429+
3430+ std::chrono::milliseconds power_key_ignore_timeout()
3431+ {
3432+ return std::chrono::milliseconds{
3433+ the_options()->get("power-key-ignore-timeout", 2000)};
3434+ }
3435+
3436+ bool enable_hardware_cursor()
3437+ {
3438+ return the_options()->get("enable-hardware-cursor", false);
3439+ }
3440+
3441+ std::string spinner_executable()
3442+ {
3443+ // TODO: once our default spinner is ready for use everywhere, replace
3444+ // default value with DEFAULT_SPINNER instead of the empty string.
3445+ auto x = the_options()->get("spinner", "");
3446+ return x;
3447+ }
3448+
3449 virtual std::shared_ptr<SessionSwitcher> the_session_switcher();
3450+ std::string dbus_bus_address();
3451
3452 mir::CachedPtr<Spinner> spinner;
3453 mir::CachedPtr<DMConnection> dm_connection;
3454 mir::CachedPtr<SessionSwitcher> session_switcher;
3455+ mir::CachedPtr<Screen> screen;
3456+ mir::CachedPtr<mir::input::EventFilter> screen_event_handler;
3457+ mir::CachedPtr<ScreenHardware> screen_hardware;
3458+ mir::CachedPtr<UnityScreenService> unity_screen_service;
3459 };
3460
3461 }
3462
3463=== removed file 'src/shell.cpp'
3464--- src/shell.cpp 2015-01-27 17:43:17 +0000
3465+++ src/shell.cpp 1970-01-01 00:00:00 +0000
3466@@ -1,157 +0,0 @@
3467-/*
3468- * Copyright © 2014-2015 Canonical Ltd.
3469- *
3470- * This program is free software: you can redistribute it and/or modify
3471- * it under the terms of the GNU General Public License version 3 as
3472- * published by the Free Software Foundation.
3473- *
3474- * This program is distributed in the hope that it will be useful,
3475- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3476- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3477- * GNU General Public License for more details.
3478- *
3479- * You should have received a copy of the GNU General Public License
3480- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3481- *
3482- * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
3483- */
3484-
3485-#include "shell.h"
3486-#include "session_switcher.h"
3487-
3488-#include <mir/scene/null_surface_observer.h>
3489-#include <mir/scene/session.h>
3490-#include <mir/scene/surface.h>
3491-#include <mir/frontend/session.h>
3492-
3493-#include <iostream>
3494-
3495-namespace msh = mir::shell;
3496-namespace ms = mir::scene;
3497-namespace mf = mir::frontend;
3498-
3499-namespace
3500-{
3501-
3502-class UscSession : public usc::Session
3503-{
3504-public:
3505- UscSession(
3506- std::shared_ptr<ms::Session> const& scene_session,
3507- msh::FocusController& focus_controller)
3508- : scene_session{scene_session},
3509- focus_controller(focus_controller)
3510- {
3511- }
3512-
3513- std::string name()
3514- {
3515- return scene_session->name();
3516- }
3517-
3518- void show() override
3519- {
3520- scene_session->show();
3521- }
3522-
3523- void hide() override
3524- {
3525- scene_session->hide();
3526- }
3527-
3528- void raise_and_focus() override
3529- {
3530- focus_controller.set_focus_to(scene_session);
3531- }
3532-
3533- bool corresponds_to(mir::frontend::Session const* s) override
3534- {
3535- return scene_session.get() == s;
3536- }
3537-
3538- std::shared_ptr<ms::Session> const scene_session;
3539- msh::FocusController& focus_controller;
3540-};
3541-
3542-
3543-struct SessionReadyObserver : ms::NullSurfaceObserver,
3544- std::enable_shared_from_this<SessionReadyObserver>
3545-{
3546- SessionReadyObserver(
3547- std::shared_ptr<usc::SessionSwitcher> const& switcher,
3548- std::shared_ptr<ms::Surface> const& surface,
3549- ms::Session const* session)
3550- : switcher{switcher},
3551- surface{surface},
3552- session{session}
3553- {
3554- }
3555-
3556- void frame_posted(int) override
3557- {
3558- ++num_frames_posted;
3559- if (num_frames_posted == num_frames_for_session_ready)
3560- {
3561- switcher->mark_ready(session);
3562- surface->remove_observer(shared_from_this());
3563- }
3564- }
3565-
3566- std::shared_ptr<usc::SessionSwitcher> const switcher;
3567- std::shared_ptr<ms::Surface> const surface;
3568- ms::Session const* const session;
3569- // We need to wait for the second frame before marking the session
3570- // as ready. The first frame posted from sessions is a blank frame.
3571- // TODO: Solve this issue at its root and remove this workaround
3572- int const num_frames_for_session_ready{2};
3573- int num_frames_posted{0};
3574-};
3575-
3576-}
3577-
3578-usc::Shell::Shell(
3579- std::shared_ptr<msh::Shell> const& wrapped,
3580- std::shared_ptr<SessionSwitcher> const& session_switcher)
3581- : msh::ShellWrapper{wrapped},
3582- session_switcher{session_switcher}
3583-{
3584-}
3585-
3586-std::shared_ptr<ms::Session>
3587-usc::Shell::open_session(
3588- pid_t client_pid,
3589- std::string const& name,
3590- std::shared_ptr<mf::EventSink> const& sink)
3591-{
3592- std::cerr << "Opening session " << name << std::endl;
3593-
3594- auto orig = msh::ShellWrapper::open_session(client_pid, name, sink);
3595-
3596- auto const usc_session = std::make_shared<UscSession>(orig, *this);
3597-
3598- session_switcher->add(usc_session, client_pid);
3599-
3600- return orig;
3601-}
3602-
3603-void usc::Shell::close_session(std::shared_ptr<ms::Session> const& session)
3604-{
3605- std::cerr << "Closing session " << session->name() << std::endl;
3606-
3607- msh::ShellWrapper::close_session(session);
3608-
3609- session_switcher->remove(session);
3610-}
3611-
3612-mf::SurfaceId usc::Shell::create_surface(std::shared_ptr<ms::Session> const& session, ms::SurfaceCreationParameters const& params)
3613-{
3614- auto const id = msh::ShellWrapper::create_surface(session, params);
3615-
3616- auto const surface = session->surface(id);
3617- auto const session_ready_observer = std::make_shared<SessionReadyObserver>(
3618- session_switcher, surface, session.get());
3619-
3620- surface->add_observer(session_ready_observer);
3621-
3622- return id;
3623-}
3624
3625=== removed file 'src/shell.h'
3626--- src/shell.h 2015-01-27 17:43:17 +0000
3627+++ src/shell.h 1970-01-01 00:00:00 +0000
3628@@ -1,54 +0,0 @@
3629-/*
3630- * Copyright © 2014-2015 Canonical Ltd.
3631- *
3632- * This program is free software: you can redistribute it and/or modify
3633- * it under the terms of the GNU General Public License version 3 as
3634- * published by the Free Software Foundation.
3635- *
3636- * This program is distributed in the hope that it will be useful,
3637- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3638- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3639- * GNU General Public License for more details.
3640- *
3641- * You should have received a copy of the GNU General Public License
3642- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3643- *
3644- * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
3645- */
3646-
3647-#ifndef USC_SHELL_H_
3648-#define USC_SHELL_H_
3649-
3650-#include <mir/shell/shell_wrapper.h>
3651-
3652-#include <memory>
3653-
3654-
3655-namespace usc
3656-{
3657-class SessionSwitcher;
3658-
3659-class Shell : public mir::shell::ShellWrapper
3660-{
3661-public:
3662- Shell(
3663- std::shared_ptr<mir::shell::Shell> const& wrapped,
3664- std::shared_ptr<SessionSwitcher> const& session_switcher);
3665-
3666-private:
3667- std::shared_ptr<mir::scene::Session> open_session(
3668- pid_t client_pid,
3669- std::string const& name,
3670- std::shared_ptr<mir::frontend::EventSink> const& sink) override;
3671- void close_session(std::shared_ptr<mir::scene::Session> const& session) override;
3672-
3673- mir::frontend::SurfaceId create_surface(
3674- std::shared_ptr<mir::scene::Session> const& session,
3675- mir::scene::SurfaceCreationParameters const& params) override;
3676-
3677- std::shared_ptr<SessionSwitcher> const session_switcher;
3678-};
3679-
3680-}
3681-
3682-#endif
3683
3684=== modified file 'src/system_compositor.cpp'
3685--- src/system_compositor.cpp 2015-01-05 22:38:04 +0000
3686+++ src/system_compositor.cpp 2015-05-06 16:09:34 +0000
3687@@ -17,30 +17,18 @@
3688 * Alexandros Frantzis <alexandros.frantzis@canonical.com>
3689 */
3690
3691-
3692 #include "system_compositor.h"
3693 #include "server.h"
3694 #include "dm_connection.h"
3695-#include "spinner.h"
3696-#include "screen_state_handler.h"
3697-#include "powerkey_handler.h"
3698-
3699-// Qt headers will introduce a #define of "signals"
3700-// but some mir headers use "signals" as a variable name in
3701-// method declarations
3702-#undef signals
3703
3704 #include <mir/input/composite_event_filter.h>
3705 #include <mir/abnormal_exit.h>
3706-#include <mir/main_loop.h>
3707
3708 #include <cerrno>
3709 #include <iostream>
3710 #include <sys/stat.h>
3711-#include <thread>
3712 #include <regex.h>
3713 #include <GLES2/gl2.h>
3714-#include <QCoreApplication>
3715
3716 namespace
3717 {
3718@@ -99,31 +87,21 @@
3719 return;
3720 }
3721
3722- struct ScopeGuard
3723- {
3724- ~ScopeGuard()
3725- {
3726- if (qt_thread.joinable())
3727- {
3728- QCoreApplication::quit();
3729- qt_thread.join();
3730- }
3731- }
3732-
3733- std::thread qt_thread;
3734- } guard;
3735-
3736 server->add_init_callback([&]
3737 {
3738 auto vendor = (char *) glGetString(GL_VENDOR);
3739 auto renderer = (char *) glGetString (GL_RENDERER);
3740 auto version = (char *) glGetString (GL_VERSION);
3741+
3742 std::cerr << "GL_VENDOR = " << vendor << std::endl;
3743 std::cerr << "GL_RENDERER = " << renderer << std::endl;
3744 std::cerr << "GL_VERSION = " << version << std::endl;
3745
3746 if (!check_blacklist(server->blacklist(), vendor, renderer, version))
3747- throw mir::AbnormalExit ("Video driver is blacklisted, exiting");
3748+ {
3749+ BOOST_THROW_EXCEPTION(
3750+ mir::AbnormalExit("Video driver is blacklisted, exiting"));
3751+ }
3752
3753 dm_connection = server->the_dm_connection();
3754
3755@@ -135,43 +113,17 @@
3756
3757 dm_connection->start();
3758
3759- guard.qt_thread = std::thread(&SystemCompositor::qt_main, this);
3760+ if (!server->disable_inactivity_policy())
3761+ {
3762+ screen = server->the_screen();
3763+ screen_event_handler = server->the_screen_event_handler();
3764+
3765+ auto composite_filter = server->the_composite_event_filter();
3766+ composite_filter->append(screen_event_handler);
3767+
3768+ unity_screen_service = server->the_unity_screen_service();
3769+ }
3770 });
3771
3772 server->run();
3773 }
3774-
3775-void usc::SystemCompositor::qt_main()
3776-{
3777- int argc{0};
3778- QCoreApplication app(argc, nullptr);
3779-
3780- if (!server->disable_inactivity_policy())
3781- {
3782- std::chrono::seconds inactivity_display_off_timeout{server->inactivity_display_off_timeout()};
3783- std::chrono::seconds inactivity_display_dim_timeout{server->inactivity_display_dim_timeout()};
3784- std::chrono::milliseconds power_key_ignore_timeout{server->power_key_ignore_timeout()};
3785- std::chrono::milliseconds shutdown_timeout{server->shutdown_timeout()};
3786-
3787- screen_state_handler = std::make_shared<ScreenStateHandler>(server,
3788- std::chrono::duration_cast<std::chrono::milliseconds>(inactivity_display_off_timeout),
3789- std::chrono::duration_cast<std::chrono::milliseconds>(inactivity_display_dim_timeout));
3790-
3791- power_key_handler = std::make_shared<PowerKeyHandler>(*(server->the_main_loop()),
3792- power_key_ignore_timeout,
3793- shutdown_timeout,
3794- *screen_state_handler);
3795-
3796- auto composite_filter = server->the_composite_event_filter();
3797- composite_filter->append(screen_state_handler);
3798- composite_filter->append(power_key_handler);
3799- }
3800-
3801- app.exec();
3802-
3803- // Destroy components that depend on Qt event handling inside the Qt thread,
3804- // to silence warnings during shutdown
3805-
3806- // ScreenStateHandler uses the Qt DBus infrastructure
3807- screen_state_handler.reset();
3808-}
3809
3810=== modified file 'src/system_compositor.h'
3811--- src/system_compositor.h 2014-11-28 13:19:29 +0000
3812+++ src/system_compositor.h 2015-05-06 16:09:34 +0000
3813@@ -22,8 +22,13 @@
3814
3815 #include <memory>
3816
3817-class ScreenStateHandler;
3818-class PowerKeyHandler;
3819+namespace mir
3820+{
3821+namespace input
3822+{
3823+class EventFilter;
3824+}
3825+}
3826
3827 namespace usc
3828 {
3829@@ -31,6 +36,9 @@
3830 class Server;
3831 class DMConnection;
3832 class Spinner;
3833+class ScreenEventHandler;
3834+class Screen;
3835+class UnityScreenService;
3836
3837 class SystemCompositor
3838 {
3839@@ -39,13 +47,12 @@
3840 void run();
3841
3842 private:
3843- void qt_main();
3844-
3845 std::shared_ptr<Server> const server;
3846 std::shared_ptr<DMConnection> dm_connection;
3847 std::shared_ptr<Spinner> const spinner;
3848- std::shared_ptr<ScreenStateHandler> screen_state_handler;
3849- std::shared_ptr<PowerKeyHandler> power_key_handler;
3850+ std::shared_ptr<Screen> screen;
3851+ std::shared_ptr<mir::input::EventFilter> screen_event_handler;
3852+ std::shared_ptr<UnityScreenService> unity_screen_service;
3853 };
3854
3855 }
3856
3857=== added file 'src/thread_name.cpp'
3858--- src/thread_name.cpp 1970-01-01 00:00:00 +0000
3859+++ src/thread_name.cpp 2015-05-06 16:09:34 +0000
3860@@ -0,0 +1,32 @@
3861+/*
3862+ * Copyright © 2014-2015 Canonical Ltd.
3863+ *
3864+ * This program is free software: you can redistribute it and/or modify it
3865+ * under the terms of the GNU Lesser General Public License version 3,
3866+ * as published by the Free Software Foundation.
3867+ *
3868+ * This program is distributed in the hope that it will be useful,
3869+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3870+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3871+ * GNU Lesser General Public License for more details.
3872+ *
3873+ * You should have received a copy of the GNU Lesser General Public License
3874+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3875+ *
3876+ * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
3877+ */
3878+
3879+#include "thread_name.h"
3880+
3881+#ifndef _GNU_SOURCE
3882+#define _GNU_SOURCE
3883+#endif
3884+#include <pthread.h>
3885+
3886+void usc::set_thread_name(std::string const& name)
3887+{
3888+ static size_t const max_name_len = 15;
3889+ auto const proper_name = name.substr(0, max_name_len);
3890+
3891+ pthread_setname_np(pthread_self(), proper_name.c_str());
3892+}
3893
3894=== added file 'src/thread_name.h'
3895--- src/thread_name.h 1970-01-01 00:00:00 +0000
3896+++ src/thread_name.h 2015-05-06 16:09:34 +0000
3897@@ -0,0 +1,29 @@
3898+/*
3899+ * Copyright © 2015 Canonical Ltd.
3900+ *
3901+ * This program is free software: you can redistribute it and/or modify it
3902+ * under the terms of the GNU Lesser General Public License version 3,
3903+ * as published by the Free Software Foundation.
3904+ *
3905+ * This program is distributed in the hope that it will be useful,
3906+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3907+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3908+ * GNU Lesser General Public License for more details.
3909+ *
3910+ * You should have received a copy of the GNU Lesser General Public License
3911+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3912+ *
3913+ * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
3914+ */
3915+
3916+#ifndef USC_THREAD_NAME_H_
3917+#define USC_THREAD_NAME_H_
3918+
3919+#include <string>
3920+
3921+namespace usc
3922+{
3923+void set_thread_name(std::string const& name);
3924+}
3925+
3926+#endif
3927
3928=== added file 'src/unity_screen_service.cpp'
3929--- src/unity_screen_service.cpp 1970-01-01 00:00:00 +0000
3930+++ src/unity_screen_service.cpp 2015-05-06 16:09:34 +0000
3931@@ -0,0 +1,358 @@
3932+/*
3933+ * Copyright © 2015 Canonical Ltd.
3934+ *
3935+ * This program is free software: you can redistribute it and/or modify
3936+ * it under the terms of the GNU General Public License version 3 as
3937+ * published by the Free Software Foundation.
3938+ *
3939+ * This program is distributed in the hope that it will be useful,
3940+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3941+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3942+ * GNU General Public License for more details.
3943+ *
3944+ * You should have received a copy of the GNU General Public License
3945+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3946+ *
3947+ * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
3948+ */
3949+
3950+#include "unity_screen_service.h"
3951+#include "screen.h"
3952+#include "dbus_message_handle.h"
3953+#include "thread_name.h"
3954+#include "scoped_dbus_error.h"
3955+
3956+#include "unity_screen_service_introspection.h" // autogenerated
3957+
3958+namespace
3959+{
3960+
3961+char const* const dbus_screen_interface = "com.canonical.Unity.Screen";
3962+char const* const dbus_screen_path = "/com/canonical/Unity/Screen";
3963+char const* const dbus_screen_service_name = "com.canonical.Unity.Screen";
3964+
3965+}
3966+
3967+usc::UnityScreenService::UnityScreenService(
3968+ std::string const& bus_addr,
3969+ std::shared_ptr<usc::Screen> const& screen)
3970+ : connection{bus_addr.c_str()},
3971+ screen{screen},
3972+ dbus_event_loop{connection},
3973+ request_id{0}
3974+{
3975+ connection.request_name(dbus_screen_service_name);
3976+ connection.add_match(
3977+ "type='signal',"
3978+ "sender='org.freedesktop.DBus',"
3979+ "interface='org.freedesktop.DBus',"
3980+ "member='NameOwnerChanged'");
3981+ connection.add_filter(handle_dbus_message_thunk, this);
3982+
3983+ screen->register_power_state_change_handler(
3984+ [this](MirPowerMode mode, PowerStateChangeReason reason)
3985+ {
3986+ dbus_emit_DisplayPowerStateChange(mode, reason);
3987+ });
3988+
3989+ std::promise<void> event_loop_started;
3990+ auto event_loop_started_future = event_loop_started.get_future();
3991+
3992+ dbus_loop_thread = std::thread(
3993+ [this,&event_loop_started]
3994+ {
3995+ usc::set_thread_name("USC/DBusScreen");
3996+ dbus_event_loop.run(event_loop_started);
3997+ });
3998+
3999+ event_loop_started_future.wait();
4000+}
4001+
4002+usc::UnityScreenService::~UnityScreenService()
4003+{
4004+ dbus_event_loop.stop();
4005+ dbus_loop_thread.join();
4006+}
4007+
4008+::DBusHandlerResult usc::UnityScreenService::handle_dbus_message_thunk(
4009+ ::DBusConnection* connection, DBusMessage* message, void* user_data)
4010+{
4011+ auto const dbus_screen_service = static_cast<usc::UnityScreenService*>(user_data);
4012+ return dbus_screen_service->handle_dbus_message(connection, message, user_data);
4013+}
4014+
4015+DBusHandlerResult usc::UnityScreenService::handle_dbus_message(
4016+ ::DBusConnection* connection, DBusMessage* message, void* user_data)
4017+{
4018+ auto const sender = dbus_message_get_sender(message);
4019+ ScopedDBusError args_error;
4020+
4021+ if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect"))
4022+ {
4023+ DBusMessageHandle reply{
4024+ dbus_message_new_method_return(message),
4025+ DBUS_TYPE_STRING, &unity_screen_service_introspection,
4026+ DBUS_TYPE_INVALID};
4027+
4028+ dbus_connection_send(connection, reply, nullptr);
4029+ }
4030+ else if (dbus_message_is_method_call(message, dbus_screen_interface, "setUserBrightness"))
4031+ {
4032+ int32_t brightness{0};
4033+ dbus_message_get_args(
4034+ message, &args_error, DBUS_TYPE_INT32, &brightness, DBUS_TYPE_INVALID);
4035+
4036+ if (!args_error)
4037+ {
4038+ dbus_setUserBrightness(brightness);
4039+
4040+ DBusMessageHandle reply{dbus_message_new_method_return(message)};
4041+ dbus_connection_send(connection, reply, nullptr);
4042+ }
4043+ }
4044+ else if (dbus_message_is_method_call(message, dbus_screen_interface, "userAutobrightnessEnable"))
4045+ {
4046+ dbus_bool_t enable{false};
4047+ dbus_message_get_args(
4048+ message, &args_error, DBUS_TYPE_BOOLEAN, &enable, DBUS_TYPE_INVALID);
4049+
4050+ if (!args_error)
4051+ {
4052+ dbus_userAutobrightnessEnable(enable);
4053+
4054+ DBusMessageHandle reply{dbus_message_new_method_return(message)};
4055+ dbus_connection_send(connection, reply, nullptr);
4056+ }
4057+ }
4058+ else if (dbus_message_is_method_call(message, dbus_screen_interface, "setInactivityTimeouts"))
4059+ {
4060+ int32_t poweroff_timeout{-1};
4061+ int32_t dimmer_timeout{-1};
4062+ dbus_message_get_args(
4063+ message, &args_error,
4064+ DBUS_TYPE_INT32, &poweroff_timeout,
4065+ DBUS_TYPE_INT32, &dimmer_timeout,
4066+ DBUS_TYPE_INVALID);
4067+
4068+ if (!args_error)
4069+ {
4070+ dbus_setInactivityTimeouts(poweroff_timeout, dimmer_timeout);
4071+
4072+ DBusMessageHandle reply{dbus_message_new_method_return(message)};
4073+ dbus_connection_send(connection, reply, nullptr);
4074+ }
4075+ }
4076+ else if (dbus_message_is_method_call(message, dbus_screen_interface, "setTouchVisualizationEnabled"))
4077+ {
4078+ dbus_bool_t enable{false};
4079+ dbus_message_get_args(
4080+ message, &args_error, DBUS_TYPE_BOOLEAN, &enable, DBUS_TYPE_INVALID);
4081+
4082+ if (!args_error)
4083+ {
4084+ dbus_setTouchVisualizationEnabled(enable);
4085+
4086+ DBusMessageHandle reply{dbus_message_new_method_return(message)};
4087+ dbus_connection_send(connection, reply, nullptr);
4088+ }
4089+ }
4090+ else if (dbus_message_is_method_call(message, dbus_screen_interface, "setScreenPowerMode"))
4091+ {
4092+ char const* mode = nullptr;
4093+ int32_t reason{-1};
4094+
4095+ dbus_message_get_args(
4096+ message, &args_error,
4097+ DBUS_TYPE_STRING, &mode,
4098+ DBUS_TYPE_INT32, &reason,
4099+ DBUS_TYPE_INVALID);
4100+
4101+ if (!args_error)
4102+ {
4103+ auto const result = dbus_setScreenPowerMode(mode, reason);
4104+ dbus_bool_t bresult = (result == true);
4105+
4106+ DBusMessageHandle reply{
4107+ dbus_message_new_method_return(message),
4108+ DBUS_TYPE_BOOLEAN, &bresult,
4109+ DBUS_TYPE_INVALID};
4110+
4111+ dbus_connection_send(connection, reply, nullptr);
4112+ }
4113+ }
4114+ else if (dbus_message_is_method_call(message, dbus_screen_interface, "keepDisplayOn"))
4115+ {
4116+ auto const id = dbus_keepDisplayOn(sender);
4117+
4118+ DBusMessageHandle reply{
4119+ dbus_message_new_method_return(message),
4120+ DBUS_TYPE_INT32, &id,
4121+ DBUS_TYPE_INVALID};
4122+
4123+ dbus_connection_send(connection, reply, nullptr);
4124+ }
4125+ else if (dbus_message_is_method_call(message, dbus_screen_interface, "removeDisplayOnRequest"))
4126+ {
4127+ int32_t id{-1};
4128+ dbus_message_get_args(
4129+ message, &args_error,
4130+ DBUS_TYPE_INT32, &id,
4131+ DBUS_TYPE_INVALID);
4132+
4133+ if (!args_error)
4134+ {
4135+ dbus_removeDisplayOnRequest(sender, id);
4136+
4137+ DBusMessageHandle reply{dbus_message_new_method_return(message)};
4138+ dbus_connection_send(connection, reply, nullptr);
4139+ }
4140+ }
4141+ else if (dbus_message_is_signal(message, "org.freedesktop.DBus", "NameOwnerChanged"))
4142+ {
4143+ char const* name = nullptr;
4144+ char const* old_owner = nullptr;
4145+ char const* new_owner = nullptr;
4146+
4147+ dbus_message_get_args(
4148+ message, &args_error,
4149+ DBUS_TYPE_STRING, &name,
4150+ DBUS_TYPE_STRING, &old_owner,
4151+ DBUS_TYPE_STRING, &new_owner,
4152+ DBUS_TYPE_INVALID);
4153+
4154+ if (!args_error)
4155+ dbus_NameOwnerChanged(name, old_owner, new_owner);
4156+ }
4157+ else if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL)
4158+ {
4159+ DBusMessageHandle reply{
4160+ dbus_message_new_error(message, DBUS_ERROR_FAILED, "Not supported")};
4161+
4162+ dbus_connection_send(connection, reply, nullptr);
4163+ }
4164+
4165+ if (args_error)
4166+ {
4167+ DBusMessageHandle reply{
4168+ dbus_message_new_error(message, DBUS_ERROR_FAILED, "Invalid arguments")};
4169+
4170+ dbus_connection_send(connection, reply, nullptr);
4171+ }
4172+
4173+ return DBUS_HANDLER_RESULT_HANDLED;
4174+}
4175+
4176+void usc::UnityScreenService::dbus_setUserBrightness(int32_t brightness)
4177+{
4178+ screen->set_brightness(brightness);
4179+}
4180+
4181+void usc::UnityScreenService::dbus_userAutobrightnessEnable(dbus_bool_t enable)
4182+{
4183+ screen->enable_auto_brightness(enable == TRUE);
4184+}
4185+
4186+void usc::UnityScreenService::dbus_setInactivityTimeouts(
4187+ int32_t poweroff_timeout, int32_t dimmer_timeout)
4188+{
4189+ screen->set_inactivity_timeouts(poweroff_timeout, dimmer_timeout);
4190+}
4191+
4192+void usc::UnityScreenService::dbus_setTouchVisualizationEnabled(dbus_bool_t enable)
4193+{
4194+ screen->set_touch_visualization_enabled(enable == TRUE);
4195+}
4196+
4197+bool usc::UnityScreenService::dbus_setScreenPowerMode(
4198+ std::string const& mode,
4199+ int32_t reason)
4200+{
4201+ MirPowerMode new_power_mode;
4202+
4203+ // Note: the "standby" and "suspend" modes are mostly unused
4204+ if (mode == "on")
4205+ new_power_mode = MirPowerMode::mir_power_mode_on;
4206+ else if (mode == "standby") // higher power "off" mode (fastest resume)
4207+ new_power_mode = MirPowerMode::mir_power_mode_standby;
4208+ else if (mode == "suspend") // medium power "off" mode
4209+ new_power_mode = MirPowerMode::mir_power_mode_suspend;
4210+ else if (mode == "off") // lowest power "off" mode (slowest resume)
4211+ new_power_mode = MirPowerMode::mir_power_mode_off;
4212+ else
4213+ return false;
4214+
4215+ screen->set_screen_power_mode(
4216+ new_power_mode, static_cast<PowerStateChangeReason>(reason));
4217+
4218+ return true;
4219+}
4220+
4221+int32_t usc::UnityScreenService::dbus_keepDisplayOn(
4222+ std::string const& sender)
4223+{
4224+ std::lock_guard<std::mutex> lock{keep_display_on_mutex};
4225+
4226+ auto const id = ++request_id;
4227+
4228+ keep_display_on_ids.emplace(sender, id);
4229+ screen->keep_display_on(true);
4230+
4231+ return id;
4232+}
4233+
4234+void usc::UnityScreenService::dbus_removeDisplayOnRequest(
4235+ std::string const& sender, int32_t id)
4236+{
4237+ std::lock_guard<std::mutex> lock{keep_display_on_mutex};
4238+
4239+ auto range = keep_display_on_ids.equal_range(sender);
4240+ for (auto iter = range.first;
4241+ iter != range.second;
4242+ ++iter)
4243+ {
4244+ if (iter->second == id)
4245+ {
4246+ keep_display_on_ids.erase(iter);
4247+ break;
4248+ }
4249+ }
4250+
4251+ if (keep_display_on_ids.empty())
4252+ screen->keep_display_on(false);
4253+}
4254+
4255+void usc::UnityScreenService::dbus_NameOwnerChanged(
4256+ std::string const& name,
4257+ std::string const& old_owner,
4258+ std::string const& new_owner)
4259+{
4260+ if (new_owner.empty() && old_owner == name)
4261+ {
4262+ std::lock_guard<std::mutex> lock{keep_display_on_mutex};
4263+ keep_display_on_ids.erase(name);
4264+ if (keep_display_on_ids.empty())
4265+ screen->keep_display_on(false);
4266+ }
4267+}
4268+
4269+void usc::UnityScreenService::dbus_emit_DisplayPowerStateChange(
4270+ MirPowerMode power_mode, PowerStateChangeReason reason)
4271+{
4272+ int32_t const power_state = (power_mode == MirPowerMode::mir_power_mode_off) ? 0 : 1;
4273+ int32_t const reason_int = static_cast<int32_t>(reason);
4274+
4275+ dbus_event_loop.enqueue(
4276+ [this, power_state, reason_int]
4277+ {
4278+ DBusMessageHandle signal{
4279+ dbus_message_new_signal(
4280+ dbus_screen_path,
4281+ dbus_screen_interface,
4282+ "DisplayPowerStateChange"),
4283+ DBUS_TYPE_INT32, &power_state,
4284+ DBUS_TYPE_INT32, &reason_int,
4285+ DBUS_TYPE_INVALID};
4286+
4287+ dbus_connection_send(connection, signal, nullptr);
4288+ });
4289+}
4290
4291=== added file 'src/unity_screen_service.h'
4292--- src/unity_screen_service.h 1970-01-01 00:00:00 +0000
4293+++ src/unity_screen_service.h 2015-05-06 16:09:34 +0000
4294@@ -0,0 +1,83 @@
4295+/*
4296+ * Copyright © 2015 Canonical Ltd.
4297+ *
4298+ * This program is free software: you can redistribute it and/or modify
4299+ * it under the terms of the GNU General Public License version 3 as
4300+ * published by the Free Software Foundation.
4301+ *
4302+ * This program is distributed in the hope that it will be useful,
4303+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4304+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4305+ * GNU General Public License for more details.
4306+ *
4307+ * You should have received a copy of the GNU General Public License
4308+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4309+ *
4310+ * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
4311+ */
4312+
4313+#ifndef USC_UNITY_SCREEN_SERVICE_H_
4314+#define USC_UNITY_SCREEN_SERVICE_H_
4315+
4316+#include "dbus_event_loop.h"
4317+#include "dbus_connection_handle.h"
4318+
4319+#include <mir_toolkit/common.h>
4320+
4321+#include <cstdint>
4322+#include <memory>
4323+#include <thread>
4324+#include <atomic>
4325+#include <mutex>
4326+#include <unordered_map>
4327+
4328+enum class PowerStateChangeReason;
4329+
4330+namespace usc
4331+{
4332+class Screen;
4333+class WorkerThread;
4334+
4335+class UnityScreenService
4336+{
4337+public:
4338+ UnityScreenService(
4339+ std::string const& bus_addr,
4340+ std::shared_ptr<usc::Screen> const& screen);
4341+ ~UnityScreenService();
4342+
4343+private:
4344+ void dbus_loop();
4345+ void stop_loop();
4346+ static ::DBusHandlerResult handle_dbus_message_thunk(
4347+ DBusConnection* connection, DBusMessage* message, void* user_data);
4348+ ::DBusHandlerResult handle_dbus_message(
4349+ DBusConnection* connection, DBusMessage* message, void* user_data);
4350+
4351+ void dbus_setUserBrightness(int32_t brightness);
4352+ void dbus_userAutobrightnessEnable(dbus_bool_t enable);
4353+ void dbus_setInactivityTimeouts(int32_t poweroff_timeout, int32_t dimmer_timeout);
4354+ void dbus_setTouchVisualizationEnabled(dbus_bool_t enable);
4355+ bool dbus_setScreenPowerMode(std::string const& mode, int32_t reason);
4356+ int32_t dbus_keepDisplayOn(std::string const& sender);
4357+ void dbus_removeDisplayOnRequest(std::string const& sender, int32_t id);
4358+ void dbus_NameOwnerChanged(
4359+ std::string const& name,
4360+ std::string const& old_owner,
4361+ std::string const& new_owner);
4362+ void dbus_emit_DisplayPowerStateChange(
4363+ MirPowerMode power_mode, PowerStateChangeReason reason);
4364+
4365+ DBusConnectionHandle const connection;
4366+ std::shared_ptr<usc::Screen> const screen;
4367+
4368+ DBusEventLoop dbus_event_loop;
4369+ std::thread dbus_loop_thread;
4370+ std::mutex keep_display_on_mutex;
4371+ std::unordered_multimap<std::string,int32_t> keep_display_on_ids;
4372+ int32_t request_id;
4373+};
4374+
4375+}
4376+
4377+#endif
4378
4379=== added file 'src/window_manager.cpp'
4380--- src/window_manager.cpp 1970-01-01 00:00:00 +0000
4381+++ src/window_manager.cpp 2015-05-06 16:09:34 +0000
4382@@ -0,0 +1,234 @@
4383+/*
4384+ * Copyright © 2015 Canonical Ltd.
4385+ *
4386+ * This program is free software: you can redistribute it and/or modify it
4387+ * under the terms of the GNU General Public License version 3,
4388+ * as published by the Free Software Foundation.
4389+ *
4390+ * This program is distributed in the hope that it will be useful,
4391+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4392+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4393+ * GNU General Public License for more details.
4394+ *
4395+ * You should have received a copy of the GNU General Public License
4396+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4397+ *
4398+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
4399+ */
4400+
4401+#include "window_manager.h"
4402+
4403+#include "session_switcher.h"
4404+
4405+#include "mir/geometry/rectangle.h"
4406+#include "mir/scene/null_surface_observer.h"
4407+#include "mir/scene/session.h"
4408+#include "mir/scene/session_coordinator.h"
4409+#include "mir/scene/surface.h"
4410+#include "mir/scene/surface_creation_parameters.h"
4411+#include "mir/shell/display_layout.h"
4412+#include "mir/shell/focus_controller.h"
4413+#include "mir/shell/surface_specification.h"
4414+
4415+#include "mir_toolkit/client_types.h"
4416+
4417+#include <iostream>
4418+
4419+namespace mf = mir::frontend;
4420+namespace ms = mir::scene;
4421+namespace msh = mir::shell;
4422+
4423+namespace
4424+{
4425+
4426+class UscSession : public usc::Session
4427+{
4428+public:
4429+ UscSession(
4430+ std::shared_ptr<ms::Session> const& scene_session,
4431+ msh::FocusController& focus_controller)
4432+ : scene_session{scene_session},
4433+ focus_controller(focus_controller)
4434+ {
4435+ }
4436+
4437+ std::string name()
4438+ {
4439+ return scene_session->name();
4440+ }
4441+
4442+ void show() override
4443+ {
4444+ scene_session->show();
4445+ }
4446+
4447+ void hide() override
4448+ {
4449+ scene_session->hide();
4450+ }
4451+
4452+ void raise_and_focus() override
4453+ {
4454+ auto const surface = scene_session->default_surface();
4455+ focus_controller.raise({surface});
4456+ focus_controller.set_focus_to(scene_session, surface);
4457+ }
4458+
4459+ bool corresponds_to(mir::frontend::Session const* s) override
4460+ {
4461+ return scene_session.get() == s;
4462+ }
4463+
4464+ std::shared_ptr<ms::Session> const scene_session;
4465+ msh::FocusController& focus_controller;
4466+};
4467+
4468+
4469+struct SessionReadyObserver : ms::NullSurfaceObserver,
4470+ std::enable_shared_from_this<SessionReadyObserver>
4471+{
4472+ SessionReadyObserver(
4473+ std::shared_ptr<usc::SessionSwitcher> const& switcher,
4474+ std::shared_ptr<ms::Surface> const& surface,
4475+ ms::Session const* session)
4476+ : switcher{switcher},
4477+ surface{surface},
4478+ session{session}
4479+ {
4480+ }
4481+
4482+ void frame_posted(int) override
4483+ {
4484+ ++num_frames_posted;
4485+ if (num_frames_posted == num_frames_for_session_ready)
4486+ {
4487+ switcher->mark_ready(session);
4488+ surface->remove_observer(shared_from_this());
4489+ }
4490+ }
4491+
4492+ std::shared_ptr<usc::SessionSwitcher> const switcher;
4493+ std::shared_ptr<ms::Surface> const surface;
4494+ ms::Session const* const session;
4495+ // We need to wait for the second frame before marking the session
4496+ // as ready. The first frame posted from sessions is a blank frame.
4497+ // TODO: Solve this issue at its root and remove this workaround
4498+ int const num_frames_for_session_ready{2};
4499+ int num_frames_posted{0};
4500+};
4501+
4502+}
4503+
4504+usc::WindowManager::WindowManager(
4505+ mir::shell::FocusController* focus_controller,
4506+ std::shared_ptr<mir::shell::DisplayLayout> const& display_layout,
4507+ std::shared_ptr<ms::SessionCoordinator> const& session_coordinator,
4508+ std::shared_ptr<SessionSwitcher> const& session_switcher) :
4509+ focus_controller{focus_controller},
4510+ display_layout{display_layout},
4511+ session_coordinator{session_coordinator},
4512+ session_switcher{session_switcher}
4513+{
4514+}
4515+
4516+void usc::WindowManager::add_session(std::shared_ptr<ms::Session> const& session)
4517+{
4518+ std::cerr << "Opening session " << session->name() << std::endl;
4519+
4520+ focus_controller->set_focus_to(session, {});
4521+
4522+ auto const usc_session = std::make_shared<UscSession>(session, *focus_controller);
4523+
4524+ session_switcher->add(usc_session, session->process_id());
4525+}
4526+
4527+void usc::WindowManager::remove_session(std::shared_ptr<ms::Session> const& session)
4528+{
4529+ std::cerr << "Closing session " << session->name() << std::endl;
4530+
4531+ auto const next_session = session_coordinator->successor_of({});
4532+ if (next_session)
4533+ focus_controller->set_focus_to(next_session, next_session->default_surface());
4534+ else
4535+ focus_controller->set_focus_to(next_session, {});
4536+
4537+ session_switcher->remove(session);
4538+}
4539+
4540+auto usc::WindowManager::add_surface(
4541+ std::shared_ptr<ms::Session> const& session,
4542+ ms::SurfaceCreationParameters const& params,
4543+ std::function<mf::SurfaceId(std::shared_ptr<ms::Session> const& session, ms::SurfaceCreationParameters const& params)> const& build)
4544+-> mf::SurfaceId
4545+{
4546+ mir::graphics::DisplayConfigurationOutputId const output_id_invalid{
4547+ mir_display_output_id_invalid};
4548+ auto placed_parameters = params;
4549+
4550+ mir::geometry::Rectangle rect{params.top_left, params.size};
4551+
4552+ if (params.output_id != output_id_invalid)
4553+ {
4554+ display_layout->place_in_output(params.output_id, rect);
4555+ }
4556+
4557+ placed_parameters.top_left = rect.top_left;
4558+ placed_parameters.size = rect.size;
4559+
4560+ auto const result = build(session, placed_parameters);
4561+ auto const surface = session->surface(result);
4562+
4563+ auto const session_ready_observer = std::make_shared<SessionReadyObserver>(
4564+ session_switcher, surface, session.get());
4565+
4566+ surface->add_observer(session_ready_observer);
4567+
4568+ return result;
4569+}
4570+
4571+void usc::WindowManager::modify_surface(
4572+ std::shared_ptr<ms::Session> const& /*session*/,
4573+ std::shared_ptr<ms::Surface> const& surface,
4574+ msh::SurfaceSpecification const& modifications)
4575+{
4576+ if (modifications.name.is_set())
4577+ surface->rename(modifications.name.value());
4578+}
4579+
4580+void usc::WindowManager::remove_surface(
4581+ std::shared_ptr<ms::Session> const& /*session*/,
4582+ std::weak_ptr<ms::Surface> const& /*surface*/)
4583+{
4584+}
4585+
4586+void usc::WindowManager::add_display(mir::geometry::Rectangle const& /*area*/)
4587+{
4588+}
4589+
4590+void usc::WindowManager::remove_display(mir::geometry::Rectangle const& /*area*/)
4591+{
4592+}
4593+
4594+bool usc::WindowManager::handle_keyboard_event(MirKeyboardEvent const* /*event*/)
4595+{
4596+ return false;
4597+}
4598+
4599+bool usc::WindowManager::handle_touch_event(MirTouchEvent const* /*event*/)
4600+{
4601+ return false;
4602+}
4603+
4604+bool usc::WindowManager::handle_pointer_event(MirPointerEvent const* /*event*/)
4605+{
4606+ return false;
4607+}
4608+
4609+int usc::WindowManager::set_surface_attribute(
4610+ std::shared_ptr<ms::Session> const& /*session*/,
4611+ std::shared_ptr<ms::Surface> const& surface,
4612+ MirSurfaceAttrib attrib,
4613+ int value)
4614+{
4615+ return surface->configure(attrib, value);
4616+}
4617
4618=== added file 'src/window_manager.h'
4619--- src/window_manager.h 1970-01-01 00:00:00 +0000
4620+++ src/window_manager.h 2015-05-06 16:09:34 +0000
4621@@ -0,0 +1,85 @@
4622+/*
4623+ * Copyright © 2015 Canonical Ltd.
4624+ *
4625+ * This program is free software: you can redistribute it and/or modify it
4626+ * under the terms of the GNU General Public License version 3,
4627+ * as published by the Free Software Foundation.
4628+ *
4629+ * This program is distributed in the hope that it will be useful,
4630+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4631+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4632+ * GNU General Public License for more details.
4633+ *
4634+ * You should have received a copy of the GNU General Public License
4635+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4636+ *
4637+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
4638+ */
4639+
4640+#ifndef USC_WINDOW_MANAGER_H_
4641+#define USC_WINDOW_MANAGER_H_
4642+
4643+#include <mir/shell/window_manager.h>
4644+
4645+namespace mir
4646+{
4647+namespace scene { class PlacementStrategy; class SessionCoordinator; }
4648+namespace shell { class FocusController; class DisplayLayout; }
4649+}
4650+
4651+namespace usc
4652+{
4653+class SessionSwitcher;
4654+
4655+class WindowManager : public mir::shell::WindowManager
4656+{
4657+public:
4658+ explicit WindowManager(
4659+ mir::shell::FocusController* focus_controller,
4660+ std::shared_ptr<mir::shell::DisplayLayout> const& display_layout,
4661+ std::shared_ptr<mir::scene::SessionCoordinator> const& session_coordinator,
4662+ std::shared_ptr<SessionSwitcher> const& session_switcher);
4663+
4664+ void add_session(std::shared_ptr<mir::scene::Session> const& session) override;
4665+
4666+ void remove_session(std::shared_ptr<mir::scene::Session> const& session) override;
4667+
4668+ mir::frontend::SurfaceId add_surface(
4669+ std::shared_ptr<mir::scene::Session> const& session,
4670+ mir::scene::SurfaceCreationParameters const& params,
4671+ std::function<mir::frontend::SurfaceId(std::shared_ptr<mir::scene::Session> const& session, mir::scene::SurfaceCreationParameters const& params)> const& build) override;
4672+
4673+ void modify_surface(
4674+ std::shared_ptr<mir::scene::Session> const& session,
4675+ std::shared_ptr<mir::scene::Surface> const& surface,
4676+ mir::shell::SurfaceSpecification const& modifications) override;
4677+
4678+ void remove_surface(
4679+ std::shared_ptr<mir::scene::Session> const& session,
4680+ std::weak_ptr<mir::scene::Surface> const& surface) override;
4681+
4682+ void add_display(mir::geometry::Rectangle const& area) override;
4683+
4684+ void remove_display(mir::geometry::Rectangle const& area) override;
4685+
4686+ bool handle_keyboard_event(MirKeyboardEvent const* event) override;
4687+
4688+ bool handle_touch_event(MirTouchEvent const* event) override;
4689+
4690+ bool handle_pointer_event(MirPointerEvent const* event) override;
4691+
4692+ int set_surface_attribute(
4693+ std::shared_ptr<mir::scene::Session> const& session,
4694+ std::shared_ptr<mir::scene::Surface> const& surface,
4695+ MirSurfaceAttrib attrib,
4696+ int value) override;
4697+
4698+private:
4699+ mir::shell::FocusController* const focus_controller;
4700+ std::shared_ptr<mir::shell::DisplayLayout> const display_layout;
4701+ std::shared_ptr<mir::scene::SessionCoordinator> const session_coordinator;
4702+ std::shared_ptr<SessionSwitcher> const session_switcher;
4703+};
4704+}
4705+
4706+#endif /* USC_WINDOW_MANAGER_H_ */
4707
4708=== removed file 'src/worker_thread.cpp'
4709--- src/worker_thread.cpp 2015-01-05 23:05:48 +0000
4710+++ src/worker_thread.cpp 1970-01-01 00:00:00 +0000
4711@@ -1,142 +0,0 @@
4712-/*
4713- * Copyright © 2014 Canonical Ltd.
4714- *
4715- * This program is free software: you can redistribute it and/or modify it
4716- * under the terms of the GNU General Public License version 3,
4717- * as published by the Free Software Foundation.
4718- *
4719- * This program is distributed in the hope that it will be useful,
4720- * but WITHOUT ANY WARRANTY; without even the implied warranty of
4721- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4722- * GNU General Public License for more details.
4723- *
4724- * You should have received a copy of the GNU General Public License
4725- * along with this program. If not, see <http://www.gnu.org/licenses/>.
4726- *
4727- * Authored by: Alberto Aguirre <alberto.aguirre@canonical.com>
4728- */
4729-
4730-#include "worker_thread.h"
4731-
4732-#include <mir/terminate_with_current_exception.h>
4733-
4734-#include <algorithm>
4735-#include <condition_variable>
4736-#include <deque>
4737-#include <map>
4738-
4739-#ifndef _GNU_SOURCE
4740-#define _GNU_SOURCE
4741-#endif
4742-#include <pthread.h>
4743-
4744-namespace usc
4745-{
4746-
4747-class Worker
4748-{
4749-public:
4750- explicit Worker(std::string name)
4751- : name{name.substr(0, 15)}, exiting{false}
4752- {
4753- }
4754-
4755- ~Worker()
4756- {
4757- exit();
4758- }
4759-
4760- void operator()() noexcept
4761- try
4762- {
4763- pthread_setname_np(pthread_self(), name.c_str());
4764-
4765- std::unique_lock<std::mutex> lock{state_mutex};
4766- while (!exiting)
4767- {
4768- task_available_cv.wait(lock, [&]{ return exiting || !tasks.empty(); });
4769-
4770- if (!exiting)
4771- {
4772- auto& task = tasks.front();
4773-
4774- lock.unlock();
4775- task();
4776- lock.lock();
4777- tasks.pop_front();
4778- }
4779- }
4780- }
4781- catch(...)
4782- {
4783- mir::terminate_with_current_exception();
4784- }
4785-
4786- void queue_task(std::function<void()> task)
4787- {
4788- std::lock_guard<std::mutex> lock{state_mutex};
4789- tasks.push_back(std::move(task));
4790- task_available_cv.notify_one();
4791- }
4792-
4793- void queue_task(std::function<void()> task, int id)
4794- {
4795- std::lock_guard<std::mutex> lock{state_mutex};
4796- coalesced_tasks[id] = task;
4797- tasks.push_back([this, id]{ run_coalesced_task(id);});
4798- task_available_cv.notify_one();
4799- }
4800-
4801- void run_coalesced_task(int id)
4802- {
4803- std::unique_lock<std::mutex> lock{state_mutex};
4804- auto it = coalesced_tasks.find(id);
4805- if (it != coalesced_tasks.end())
4806- {
4807- auto task = it->second;
4808- coalesced_tasks.erase(it);
4809- lock.unlock();
4810- task();
4811- }
4812- }
4813-
4814- void exit()
4815- {
4816- std::lock_guard<std::mutex> lock{state_mutex};
4817- exiting = true;
4818- task_available_cv.notify_one();
4819- }
4820-
4821-private:
4822- std::mutex mutable state_mutex;
4823- std::string name;
4824- bool exiting;
4825- std::map<int, std::function<void()>> coalesced_tasks;
4826- std::deque<std::function<void()>> tasks;
4827- std::condition_variable task_available_cv;
4828-};
4829-
4830-}
4831-
4832-usc::WorkerThread::WorkerThread(std::string name)
4833- : worker{new Worker(name)},
4834- thread{std::ref(*worker)}
4835-{
4836-}
4837-
4838-usc::WorkerThread::~WorkerThread()
4839-{
4840- worker->exit();
4841- if (thread.joinable())
4842- thread.join();
4843-}
4844-
4845-void usc::WorkerThread::queue_task(std::function<void()> task)
4846-{
4847- worker->queue_task(std::move(task));
4848-}
4849-
4850-void usc::WorkerThread::queue_task(std::function<void()> task, int id)
4851-{
4852- worker->queue_task(std::move(task), id);
4853-}
4854
4855=== removed file 'src/worker_thread.h'
4856--- src/worker_thread.h 2014-10-22 19:31:57 +0000
4857+++ src/worker_thread.h 1970-01-01 00:00:00 +0000
4858@@ -1,55 +0,0 @@
4859-/*
4860- * Copyright © 2014 Canonical Ltd.
4861- *
4862- * This program is free software: you can redistribute it and/or modify it
4863- * under the terms of the GNU General Public License version 3,
4864- * as published by the Free Software Foundation.
4865- *
4866- * This program is distributed in the hope that it will be useful,
4867- * but WITHOUT ANY WARRANTY; without even the implied warranty of
4868- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4869- * GNU General Public License for more details.
4870- *
4871- * You should have received a copy of the GNU General Public License
4872- * along with this program. If not, see <http://www.gnu.org/licenses/>.
4873- *
4874- * Authored by: Alberto Aguirre <alberto.aguirre@canonical.com>
4875- */
4876-
4877-#ifndef USC_WORKER_THREAD_H_
4878-#define USC_WORKER_THREAD_H_
4879-
4880-#include <memory>
4881-#include <string>
4882-#include <thread>
4883-
4884-namespace usc
4885-{
4886-class Worker;
4887-class WorkerThread
4888-{
4889-public:
4890- explicit WorkerThread(std::string name);
4891- ~WorkerThread();
4892-
4893- /**
4894- * Queues a task to be executed on the worker thread
4895- */
4896- void queue_task(std::function<void()> task);
4897-
4898- /**
4899- * Queues and coalesces tasks that share the same id
4900- */
4901- void queue_task(std::function<void()> task, int id);
4902-
4903-private:
4904- WorkerThread(WorkerThread const&) = delete;
4905- WorkerThread& operator=(WorkerThread const&) = delete;
4906-
4907- std::unique_ptr<Worker> worker;
4908- std::thread thread;
4909-};
4910-
4911-}
4912-
4913-#endif
4914
4915=== modified file 'tests/CMakeLists.txt'
4916--- tests/CMakeLists.txt 2014-07-09 06:58:05 +0000
4917+++ tests/CMakeLists.txt 2015-05-06 16:09:34 +0000
4918@@ -15,3 +15,4 @@
4919 # Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
4920
4921 add_subdirectory(unit-tests/)
4922+add_subdirectory(integration-tests/)
4923
4924=== added directory 'tests/integration-tests'
4925=== added file 'tests/integration-tests/CMakeLists.txt'
4926--- tests/integration-tests/CMakeLists.txt 1970-01-01 00:00:00 +0000
4927+++ tests/integration-tests/CMakeLists.txt 2015-05-06 16:09:34 +0000
4928@@ -0,0 +1,53 @@
4929+# Copyright © 2015 Canonical Ltd.
4930+#
4931+# This program is free software: you can redistribute it and/or modify
4932+# it under the terms of the GNU General Public License version 3 as
4933+# published by the Free Software Foundation.
4934+#
4935+# This program is distributed in the hope that it will be useful,
4936+# but WITHOUT ANY WARRANTY; without even the implied warranty of
4937+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4938+# GNU General Public License for more details.
4939+#
4940+# You should have received a copy of the GNU General Public License
4941+# along with this program. If not, see <http://www.gnu.org/licenses/>.
4942+#
4943+# Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
4944+
4945+include_directories(
4946+ ${CMAKE_SOURCE_DIR}
4947+ ${CMAKE_BINARY_DIR}
4948+ ${MIRSERVER_INCLUDE_DIRS}
4949+ ${DBUS_INCLUDE_DIRS}
4950+)
4951+
4952+add_executable(
4953+ usc_test_helper_wait_for_signal
4954+ usc_test_helper_wait_for_signal.c
4955+)
4956+
4957+add_executable(
4958+ usc_integration_tests
4959+
4960+ run_command.cpp
4961+ dbus_bus.cpp
4962+ dbus_client.cpp
4963+ test_dbus_event_loop.cpp
4964+ test_unity_screen_service.cpp
4965+ test_external_spinner.cpp
4966+ test_powerd_mediator.cpp
4967+)
4968+
4969+target_link_libraries(
4970+ usc_integration_tests
4971+
4972+ usc
4973+ ${GTEST_BOTH_LIBRARIES}
4974+ ${GMOCK_LIBRARY}
4975+ ${GMOCK_MAIN_LIBRARY}
4976+)
4977+
4978+add_test(usc_integration_tests ${EXECUTABLE_OUTPUT_PATH}/usc_integration_tests)
4979+
4980+add_dependencies(usc_integration_tests GMock)
4981+add_dependencies(usc_integration_tests usc_test_helper_wait_for_signal)
4982
4983=== added file 'tests/integration-tests/dbus_bus.cpp'
4984--- tests/integration-tests/dbus_bus.cpp 1970-01-01 00:00:00 +0000
4985+++ tests/integration-tests/dbus_bus.cpp 2015-05-06 16:09:34 +0000
4986@@ -0,0 +1,52 @@
4987+/*
4988+ * Copyright © 2015 Canonical Ltd.
4989+ *
4990+ * This program is free software: you can redistribute it and/or modify
4991+ * it under the terms of the GNU General Public License version 3 as
4992+ * published by the Free Software Foundation.
4993+ *
4994+ * This program is distributed in the hope that it will be useful,
4995+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4996+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4997+ * GNU General Public License for more details.
4998+ *
4999+ * You should have received a copy of the GNU General Public License
5000+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches