From 6819f403a6b8a1ab5e8cdffd9fd1460d49045059 Mon Sep 17 00:00:00 2001 From: Kazumasa Mitsunari Date: Wed, 17 Oct 2018 17:42:42 +0900 Subject: Refactor : Hide wayland operations from Window Manager Window Manager now uses abstract client, area for layer/surface management, then hide wayland operation into LayerControl class. LayerControl class uses ilmControl library instead of wayland protocol. This patch reduces the binary size of binding by 30% than before. Currently, the following debug methods are not available. * debug_status * debug_layers * debug_surfaces * list_drawing_names Bug-AGL: SPEC-1817 Change-Id: I7313787f3c4a286ceee3c23783e5c0e713388dac Signed-off-by: Kazumasa Mitsunari --- src/CMakeLists.txt | 17 +- src/controller_hooks.hpp | 41 --- src/json_helper.cpp | 65 ----- src/json_helper.hpp | 3 - src/layout.cpp | 17 -- src/layout.hpp | 41 --- src/main.cpp | 128 ++------- src/util.hpp | 25 +- src/wayland_ivi_wm.cpp | 721 ----------------------------------------------- src/wayland_ivi_wm.hpp | 326 --------------------- src/window_manager.cpp | 702 +++++++++------------------------------------ src/window_manager.hpp | 114 +++----- src/wm_layer.cpp | 334 +--------------------- src/wm_layer.hpp | 145 ++-------- src/wm_layer_control.cpp | 594 ++++++++++++++++++++++++++++++++++++++ src/wm_layer_control.hpp | 105 +++++++ 16 files changed, 946 insertions(+), 2432 deletions(-) delete mode 100644 src/controller_hooks.hpp delete mode 100644 src/layout.cpp delete mode 100644 src/layout.hpp delete mode 100644 src/wayland_ivi_wm.cpp delete mode 100644 src/wayland_ivi_wm.hpp create mode 100644 src/wm_layer_control.cpp create mode 100644 src/wm_layer_control.hpp (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 223dd33..d8f1143 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,10 +14,9 @@ # limitations under the License. # -wlproto(IVI_CON ivi-wm) - include(FindPkgConfig) pkg_check_modules(AFB REQUIRED afb-daemon) +pkg_check_modules(ILM REQUIRED ilmControl ilmCommon) pkg_check_modules(SD REQUIRED libsystemd>=222) # We do not want a prefix for our module @@ -27,23 +26,22 @@ set(TARGETS_WM windowmanager-service) add_library(${TARGETS_WM} MODULE main.cpp - wayland_ivi_wm.cpp util.cpp - layout.cpp - ${IVI_CON_PROTO} json_helper.cpp + applist.cpp + request.cpp + pm_wrapper.cpp window_manager.cpp - wm_layer.cpp wm_client.cpp wm_error.cpp - applist.cpp - request.cpp - pm_wrapper.cpp) + wm_layer.cpp + wm_layer_control.cpp) target_include_directories(${TARGETS_WM} PRIVATE ${AFB_INCLUDE_DIRS} ${SD_INCLUDE_DIRS} + ${ILM_INCLUDE_DIRS} ../include ../src ../${PLUGIN_PM}) @@ -52,6 +50,7 @@ target_link_libraries(${TARGETS_WM} PRIVATE ${AFB_LIBRARIES} ${WLC_LIBRARIES} + ${ILM_LIBRARIES} ${SD_LIBRARIES} ${PLUGIN_PM}) diff --git a/src/controller_hooks.hpp b/src/controller_hooks.hpp deleted file mode 100644 index dd0a3aa..0000000 --- a/src/controller_hooks.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2017 TOYOTA MOTOR CORPORATION - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef TMCAGLWM_CONTROLLER_HOOKS_HPP -#define TMCAGLWM_CONTROLLER_HOOKS_HPP - -#include - -#include - -namespace wm -{ - -class WindowManager; - -struct controller_hooks -{ - WindowManager *wmgr; - - void surface_created(uint32_t surface_id); - void surface_removed(uint32_t surface_id); - void surface_visibility(uint32_t surface_id, uint32_t v); - void surface_destination_rectangle(uint32_t surface_id, uint32_t x, uint32_t y, uint32_t w, uint32_t h); -}; - -} // namespace wm - -#endif // TMCAGLWM_CONTROLLER_HOOKS_HPP diff --git a/src/json_helper.cpp b/src/json_helper.cpp index cf13363..72ae36a 100644 --- a/src/json_helper.cpp +++ b/src/json_helper.cpp @@ -17,66 +17,6 @@ #include "json_helper.hpp" #include "util.hpp" -json_object *to_json(compositor::surface_properties const &s) -{ - // auto j = json::object({ - auto j = json_object_new_object(); - - // {"id", s.id}, - json_object_object_add(j, "id", json_object_new_int(s.id)); - - // {"size", {{"width", s.size.w}, {"height", s.size.h}}}, - auto jsize = json_object_new_object(); - json_object_object_add(jsize, "width", json_object_new_int(s.size.w)); - json_object_object_add(jsize, "height", json_object_new_int(s.size.h)); - json_object_object_add(j, "size", jsize); - - // {"dst", - // {{"width", s.dst_rect.w}, - // {"height", s.dst_rect.h}, - // {"x", s.dst_rect.x}, - // {"y", s.dst_rect.y}}}, - auto jdst = json_object_new_object(); - json_object_object_add(jdst, "width", json_object_new_int(s.dst_rect.w)); - json_object_object_add(jdst, "height", json_object_new_int(s.dst_rect.h)); - json_object_object_add(jdst, "x", json_object_new_int(s.dst_rect.x)); - json_object_object_add(jdst, "y", json_object_new_int(s.dst_rect.y)); - json_object_object_add(j, "dst", jdst); - - // {"src", - // {{"width", s.src_rect.w}, - // {"height", s.src_rect.h}, - // {"x", s.src_rect.x}, - // {"y", s.src_rect.y}}}, - auto jsrc = json_object_new_object(); - json_object_object_add(jsrc, "width", json_object_new_int(s.src_rect.w)); - json_object_object_add(jsrc, "height", json_object_new_int(s.src_rect.h)); - json_object_object_add(jsrc, "x", json_object_new_int(s.src_rect.x)); - json_object_object_add(jsrc, "y", json_object_new_int(s.src_rect.y)); - json_object_object_add(j, "src", jsrc); - - // {"visibility", s.visibility}, - json_object_object_add( - j, "visibility", - json_object_new_boolean(static_cast(s.visibility == 1))); - - // {"opacity", s.opacity}, - json_object_object_add(j, "opacity", json_object_new_double(s.opacity)); - - // {"orientation", s.orientation}, - json_object_object_add(j, "orientation", json_object_new_int(s.orientation)); - - // }); - return j; -} - -json_object *to_json(compositor::screen const *s) -{ - auto o = json_object_new_object(); - json_object_object_add(o, "id", json_object_new_int(s->id)); - return o; -} - template json_object *to_json_(T const &s) { @@ -93,11 +33,6 @@ json_object *to_json_(T const &s) return a; } -json_object *to_json(compositor::controller::props_map const &s) -{ - return to_json_(s); -} - json_object *to_json(std::vector const &v) { auto a = json_object_new_array(); diff --git a/src/json_helper.hpp b/src/json_helper.hpp index 2321f8b..6ccbcc1 100644 --- a/src/json_helper.hpp +++ b/src/json_helper.hpp @@ -19,12 +19,9 @@ #include #include -#include "wayland_ivi_wm.hpp" struct json_object; -json_object *to_json(compositor::screen const *s); -json_object *to_json(compositor::controller::props_map const &s); json_object *to_json(std::vector const &v); namespace jh { diff --git a/src/layout.cpp b/src/layout.cpp deleted file mode 100644 index fbf2baa..0000000 --- a/src/layout.cpp +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2017 TOYOTA MOTOR CORPORATION - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "layout.hpp" diff --git a/src/layout.hpp b/src/layout.hpp deleted file mode 100644 index 3430ef3..0000000 --- a/src/layout.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2017 TOYOTA MOTOR CORPORATION - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef TMCAGLWM_LAYOUT_HPP -#define TMCAGLWM_LAYOUT_HPP - -namespace wm -{ - -struct LayoutState -{ - int main{-1}; - int sub{-1}; - - bool operator==(const LayoutState &b) const - { - return main == b.main && sub == b.sub; - } - - bool operator!=(const LayoutState &b) const - { - return !(*this == b); - } -}; - -} // namespace wm - -#endif // TMCAGLWM_LAYOUT_HPP diff --git a/src/main.cpp b/src/main.cpp index d9f0302..36577fe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,7 +20,6 @@ #include #include "window_manager.hpp" #include "json_helper.hpp" -#include "wayland_ivi_wm.hpp" extern "C" { @@ -41,10 +40,10 @@ typedef struct WMClientCtxt struct afb_instance { - std::unique_ptr display; wm::WindowManager wmgr; - afb_instance() : display{new wl::display}, wmgr{this->display.get()} {} + afb_instance() : wmgr() {} + ~afb_instance() = default; int init(); }; @@ -57,78 +56,11 @@ int afb_instance::init() return this->wmgr.init(); } -int display_event_callback(sd_event_source *evs, int /*fd*/, uint32_t events, - void * /*data*/) -{ - if ((events & EPOLLHUP) != 0) - { - HMI_ERROR("The compositor hung up, dying now."); - delete g_afb_instance; - g_afb_instance = nullptr; - goto error; - } - - if ((events & EPOLLIN) != 0u) - { - { - g_afb_instance->wmgr.display->read_events(); - g_afb_instance->wmgr.set_pending_events(); - } - { - // We want do dispatch pending wayland events from within - // the API context - afb_service_call("windowmanager", "ping", json_object_new_object(), - [](void *c, int st, json_object *j) { - }, - nullptr); - } - } - - return 0; - -error: - sd_event_source_unref(evs); - if (getenv("WINMAN_EXIT_ON_HANGUP") != nullptr) - { - exit(1); - } - return -1; -} - int _binding_init() { HMI_NOTICE("WinMan ver. %s", WINMAN_VERSION_STRING); - if (g_afb_instance != nullptr) - { - HMI_ERROR("Wayland context already initialized?"); - return 0; - } - - if (getenv("XDG_RUNTIME_DIR") == nullptr) - { - HMI_ERROR("Environment variable XDG_RUNTIME_DIR not set"); - goto error; - } - - { - // wait until wayland compositor starts up. - int cnt = 0; - g_afb_instance = new afb_instance; - while (!g_afb_instance->display->ok()) - { - cnt++; - if (20 <= cnt) - { - HMI_ERROR("Could not connect to compositor"); - goto error; - } - HMI_ERROR("Wait to start weston ..."); - sleep(1); - delete g_afb_instance; - g_afb_instance = new afb_instance; - } - } + g_afb_instance = new afb_instance; if (g_afb_instance->init() == -1) { @@ -136,17 +68,6 @@ int _binding_init() goto error; } - { - int ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr, - g_afb_instance->display->get_fd(), EPOLLIN, - display_event_callback, g_afb_instance); - if (ret < 0) - { - HMI_ERROR("Could not initialize afb_instance event handler: %d", -ret); - goto error; - } - } - atexit([] { delete g_afb_instance; }); return 0; @@ -511,10 +432,9 @@ void windowmanager_wm_subscribe(afb_req req) noexcept afb_req_fail(req, "failed", "Need char const* argument event"); return; } - int event_type = json_object_get_int(j); - const char *event_name = g_afb_instance->wmgr.kListEventName[event_type]; - struct afb_event event = g_afb_instance->wmgr.map_afb_event[event_name]; - int ret = afb_req_subscribe(req, event); + int event_id = json_object_get_int(j); + int ret = g_afb_instance->wmgr.api_subscribe(req, event_id); + if (ret) { afb_req_fail(req, "failed", "Error: afb_req_subscribe()"); @@ -531,7 +451,8 @@ void windowmanager_wm_subscribe(afb_req req) noexcept void windowmanager_list_drawing_names(afb_req req) noexcept { - std::lock_guard guard(binding_m); + /* std::lock_guard guard(binding_m); + if (g_afb_instance == nullptr) { afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); @@ -555,36 +476,30 @@ void windowmanager_list_drawing_names(afb_req req) noexcept { afb_req_fail_f(req, "failed", "Uncaught exception while calling list_drawing_names: %s", e.what()); return; - } + } */ + afb_req_success(req, NULL, "not-implemented"); } void windowmanager_ping(afb_req req) noexcept { std::lock_guard guard(binding_m); + if (g_afb_instance == nullptr) { afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); return; } - - try + else { - - g_afb_instance->wmgr.api_ping(); - afb_req_success(req, NULL, "success"); } - catch (std::exception &e) - { - afb_req_fail_f(req, "failed", "Uncaught exception while calling ping: %s", e.what()); - return; - } } void windowmanager_debug_status(afb_req req) noexcept { std::lock_guard guard(binding_m); - if (g_afb_instance == nullptr) + + /* if (g_afb_instance == nullptr) { afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); return; @@ -604,12 +519,14 @@ void windowmanager_debug_status(afb_req req) noexcept { afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_status: %s", e.what()); return; - } + } */ + afb_req_fail(req, NULL, "not-implemented"); } void windowmanager_debug_layers(afb_req req) noexcept { - std::lock_guard guard(binding_m); + /* std::lock_guard guard(binding_m); + if (g_afb_instance == nullptr) { afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); @@ -626,12 +543,14 @@ void windowmanager_debug_layers(afb_req req) noexcept { afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_layers: %s", e.what()); return; - } + } */ + afb_req_fail(req, NULL, "not-implemented"); } void windowmanager_debug_surfaces(afb_req req) noexcept { - std::lock_guard guard(binding_m); + /* std::lock_guard guard(binding_m); + if (g_afb_instance == nullptr) { afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); @@ -654,7 +573,8 @@ void windowmanager_debug_surfaces(afb_req req) noexcept { afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_surfaces: %s", e.what()); return; - } + } */ + afb_req_fail(req, NULL, "not-implemented"); } void windowmanager_debug_terminate(afb_req req) noexcept diff --git a/src/util.hpp b/src/util.hpp index 812a130..077f212 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -52,24 +52,15 @@ void _HMI_LOG(enum LOG_LEVEL level, const char* file, const char* func, const in void _HMI_SEQ_LOG(enum LOG_LEVEL level, const char* file, const char* func, const int line, unsigned seq_num, const char* log, ...); void _DUMP(enum LOG_LEVEL level, const char *log, ...); -/** - * @struct unique_fd - */ -struct unique_fd +struct rect { - int fd{-1}; - unique_fd() = default; - explicit unique_fd(int f) : fd{f} {} - operator int() const { return fd; } - ~unique_fd(); - unique_fd(unique_fd const &) = delete; - unique_fd &operator=(unique_fd const &) = delete; - unique_fd(unique_fd &&o) : fd(o.fd) { o.fd = -1; } - unique_fd &operator=(unique_fd &&o) - { - std::swap(this->fd, o.fd); - return *this; - } + int32_t w, h; + int32_t x, y; +}; + +struct size +{ + uint32_t w, h; }; class rectangle diff --git a/src/wayland_ivi_wm.cpp b/src/wayland_ivi_wm.cpp deleted file mode 100644 index bbf745b..0000000 --- a/src/wayland_ivi_wm.cpp +++ /dev/null @@ -1,721 +0,0 @@ -/* - * Copyright (c) 2017 TOYOTA MOTOR CORPORATION - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "wayland_ivi_wm.hpp" - -/** - * namespace wl - */ -namespace wl -{ - -/** - * display - */ -display::display() - : d(std::unique_ptr( - wl_display_connect(nullptr), &wl_display_disconnect)), - r(d.get()) {} - -bool display::ok() const { return d && wl_display_get_error(d.get()) == 0; } - -void display::roundtrip() { wl_display_roundtrip(this->d.get()); } - -int display::dispatch() { return wl_display_dispatch(this->d.get()); } - -int display::dispatch_pending() { return wl_display_dispatch_pending(this->d.get()); } - -int display::read_events() -{ - while (wl_display_prepare_read(this->d.get()) == -1) - { - if (wl_display_dispatch_pending(this->d.get()) == -1) - { - return -1; - } - } - - if (wl_display_flush(this->d.get()) == -1) - { - return -1; - } - - if (wl_display_read_events(this->d.get()) == -1) - { - wl_display_cancel_read(this->d.get()); - } - - return 0; -} - -void display::flush() { wl_display_flush(this->d.get()); } - -int display::get_fd() const { return wl_display_get_fd(this->d.get()); } - -int display::get_error() { return wl_display_get_error(this->d.get()); } - -/** - * registry - */ -namespace -{ -void registry_global_created(void *data, struct wl_registry * /*r*/, uint32_t name, - char const *iface, uint32_t v) -{ - static_cast(data)->global_created(name, iface, v); -} - -void registry_global_removed(void *data, struct wl_registry * /*r*/, - uint32_t name) -{ - static_cast(data)->global_removed(name); -} - -constexpr struct wl_registry_listener registry_listener = { - registry_global_created, registry_global_removed}; -} // namespace - -registry::registry(struct wl_display *d) - : wayland_proxy(d == nullptr ? nullptr : wl_display_get_registry(d)) -{ - if (this->proxy != nullptr) - { - wl_registry_add_listener(this->proxy.get(), ®istry_listener, this); - } -} - -void registry::add_global_handler(char const *iface, binder bind) -{ - this->bindings[iface] = std::move(bind); -} - -void registry::global_created(uint32_t name, char const *iface, uint32_t v) -{ - auto b = this->bindings.find(iface); - if (b != this->bindings.end()) - { - b->second(this->proxy.get(), name, v); - } - HMI_DEBUG("wl::registry @ %p global n %u i %s v %u", this->proxy.get(), name, - iface, v); -} - -void registry::global_removed(uint32_t /*name*/) {} - -/** - * output - */ -namespace -{ -void output_geometry(void *data, struct wl_output * /*wl_output*/, int32_t x, - int32_t y, int32_t physical_width, int32_t physical_height, - int32_t subpixel, const char *make, const char *model, - int32_t transform) -{ - static_cast(data)->geometry( - x, y, physical_width, physical_height, subpixel, make, model, transform); -} - -void output_mode(void *data, struct wl_output * /*wl_output*/, uint32_t flags, - int32_t width, int32_t height, int32_t refresh) -{ - static_cast(data)->mode(flags, width, height, refresh); -} - -void output_done(void *data, struct wl_output * /*wl_output*/) -{ - static_cast(data)->done(); -} - -void output_scale(void *data, struct wl_output * /*wl_output*/, - int32_t factor) -{ - static_cast(data)->scale(factor); -} - -constexpr struct wl_output_listener output_listener = { - output_geometry, output_mode, output_done, output_scale}; -} // namespace - -output::output(struct wl_registry *r, uint32_t name, uint32_t v) - : wayland_proxy(wl_registry_bind(r, name, &wl_output_interface, v)) -{ - wl_output_add_listener(this->proxy.get(), &output_listener, this); -} - -void output::geometry(int32_t x, int32_t y, int32_t pw, int32_t ph, - int32_t subpel, char const *make, char const *model, - int32_t tx) -{ - HMI_DEBUG("wl::output %s @ %p x %i y %i w %i h %i spel %x make %s model %s tx %i", - __func__, this->proxy.get(), x, y, pw, ph, subpel, make, model, tx); - this->physical_width = pw; - this->physical_height = ph; - this->transform = tx; -} - -void output::mode(uint32_t flags, int32_t w, int32_t h, int32_t r) -{ - HMI_DEBUG("wl::output %s @ %p f %x w %i h %i r %i", __func__, - this->proxy.get(), flags, w, h, r); - if ((flags & WL_OUTPUT_MODE_CURRENT) != 0u) - { - this->width = w; - this->height = h; - this->refresh = r; - } -} - -void output::done() -{ - HMI_DEBUG("wl::output %s @ %p done", __func__, this->proxy.get()); - // Pivot and flipped - if (this->transform == WL_OUTPUT_TRANSFORM_90 || - this->transform == WL_OUTPUT_TRANSFORM_270 || - this->transform == WL_OUTPUT_TRANSFORM_FLIPPED_90 || - this->transform == WL_OUTPUT_TRANSFORM_FLIPPED_270) - { - std::swap(this->width, this->height); - std::swap(this->physical_width, this->physical_height); - } -} - -void output::scale(int32_t factor) -{ - HMI_DEBUG("wl::output %s @ %p f %i", __func__, this->proxy.get(), factor); -} -} // namespace wl - -/** - * namespace compositor - */ -namespace compositor -{ - -namespace -{ - -void surface_visibility_changed( - void *data, struct ivi_wm * /*ivi_wm*/, - uint32_t surface_id, int32_t visibility) -{ - auto c = static_cast(data); - c->surface_visibility_changed(surface_id, visibility); -} - -void surface_opacity_changed(void *data, struct ivi_wm * /*ivi_wm*/, - uint32_t surface_id, wl_fixed_t opacity) -{ - auto c = static_cast(data); - c->surface_opacity_changed(surface_id, float(wl_fixed_to_double(opacity))); -} - -void surface_source_rectangle_changed( - void *data, struct ivi_wm * /*ivi_wm*/, uint32_t surface_id, - int32_t x, int32_t y, int32_t width, int32_t height) -{ - auto c = static_cast(data); - c->surface_source_rectangle_changed(surface_id, x, y, width, height); -} - -void surface_destination_rectangle_changed( - void *data, struct ivi_wm * /*ivi_wm*/, uint32_t surface_id, - int32_t x, int32_t y, int32_t width, int32_t height) -{ - auto c = static_cast(data); - c->surface_destination_rectangle_changed(surface_id, x, y, width, height); -} - -void surface_created(void *data, struct ivi_wm * /*ivi_wm*/, - uint32_t id_surface) -{ - static_cast(data)->surface_created(id_surface); -} - -void surface_destroyed( - void *data, struct ivi_wm * /*ivi_wm*/, uint32_t surface_id) -{ - auto c = static_cast(data); - c->surface_destroyed(surface_id); -} - -void surface_error_detected(void *data, struct ivi_wm * /*ivi_wm*/, uint32_t object_id, - uint32_t error_code, const char *error_text) -{ - static_cast(data)->surface_error_detected( - object_id, error_code, error_text); -} - -void surface_size_changed( - void *data, struct ivi_wm * /*ivi_wm*/, uint32_t surface_id, - int32_t width, int32_t height) -{ - auto c = static_cast(data); - c->surface_size_changed(surface_id, width, height); -} - -void surface_stats_received(void *data, struct ivi_wm * /*ivi_wm*/, - uint32_t surface_id, uint32_t frame_count, uint32_t pid) -{ - auto c = static_cast(data); - c->surface_stats_received(surface_id, frame_count, pid); -} - -void surface_added_to_layer(void *data, struct ivi_wm * /*ivi_wm*/, - uint32_t layer_id, uint32_t surface_id) -{ - auto c = static_cast(data); - c->surface_added_to_layer(layer_id, surface_id); -} - -void layer_visibility_changed(void *data, struct ivi_wm * /*ivi_wm*/, - uint32_t layer_id, int32_t visibility) -{ - auto c = static_cast(data); - c->layer_visibility_changed(layer_id, visibility); -} - -void layer_opacity_changed(void *data, struct ivi_wm * /*ivi_wm*/, - uint32_t layer_id, wl_fixed_t opacity) -{ - auto c = static_cast(data); - c->layer_opacity_changed(layer_id, float(wl_fixed_to_double(opacity))); -} - -void layer_source_rectangle_changed( - void *data, struct ivi_wm * /*ivi_wm*/, uint32_t layer_id, - int32_t x, int32_t y, int32_t width, int32_t height) -{ - auto c = static_cast(data); - c->layer_source_rectangle_changed(layer_id, x, y, width, height); -} - -void layer_destination_rectangle_changed( - void *data, struct ivi_wm * /*ivi_wm*/, uint32_t layer_id, - int32_t x, int32_t y, int32_t width, int32_t height) -{ - auto c = static_cast(data); - c->layer_destination_rectangle_changed(layer_id, x, y, width, height); -} - -void layer_created(void *data, struct ivi_wm * /*ivi_wm*/, - uint32_t id_layer) -{ - static_cast(data)->layer_created(id_layer); -} - -void layer_destroyed(void *data, struct ivi_wm * /*ivi_wm*/, uint32_t layer_id) -{ - auto c = static_cast(data); - c->layer_destroyed(layer_id); -} - -void layer_error_detected(void *data, struct ivi_wm * /*ivi_wm*/, uint32_t object_id, - uint32_t error_code, const char *error_text) -{ - static_cast(data)->layer_error_detected( - object_id, error_code, error_text); -} - -constexpr struct ivi_wm_listener listener = { - surface_visibility_changed, - layer_visibility_changed, - surface_opacity_changed, - layer_opacity_changed, - surface_source_rectangle_changed, - layer_source_rectangle_changed, - surface_destination_rectangle_changed, - layer_destination_rectangle_changed, - surface_created, - layer_created, - surface_destroyed, - layer_destroyed, - surface_error_detected, - layer_error_detected, - surface_size_changed, - surface_stats_received, - surface_added_to_layer, -}; - -void screen_created(void *data, struct ivi_wm_screen *ivi_wm_screen, uint32_t id) -{ - static_cast(data)->screen_created((struct screen *)data, id); -} - -void layer_added(void *data, - struct ivi_wm_screen *ivi_wm_screen, - uint32_t layer_id) -{ - HMI_DEBUG("added layer_id:%d", layer_id); -} - -void connector_name(void *data, - struct ivi_wm_screen *ivi_wm_screen, - const char *process_name) -{ - HMI_DEBUG("process_name:%s", process_name); -} - -void screen_error(void *data, - struct ivi_wm_screen *ivi_wm_screen, - uint32_t error, - const char *message) -{ - HMI_DEBUG("screen error:%d message:%s", error, message); -} - -constexpr struct ivi_wm_screen_listener screen_listener = { - screen_created, - layer_added, - connector_name, - screen_error, -}; -} // namespace - -/** - * surface - */ -surface::surface(uint32_t i, struct controller *c) - : controller_child(c, i) -{ - this->parent->add_proxy_to_sid_mapping(this->parent->proxy.get(), i); -} - -void surface::set_visibility(uint32_t visibility) -{ - HMI_DEBUG("compositor::surface id:%d v:%d", this->id, visibility); - ivi_wm_set_surface_visibility(this->parent->proxy.get(), this->id, visibility); -} - -void surface::set_source_rectangle(int32_t x, int32_t y, - int32_t width, int32_t height) -{ - ivi_wm_set_surface_source_rectangle(this->parent->proxy.get(), this->id, - x, y, width, height); -} - -void surface::set_destination_rectangle(int32_t x, int32_t y, - int32_t width, int32_t height) -{ - ivi_wm_set_surface_destination_rectangle(this->parent->proxy.get(), this->id, - x, y, width, height); -} - -/** - * layer - */ -layer::layer(uint32_t i, struct controller *c) : layer(i, 0, 0, c) {} - -layer::layer(uint32_t i, int32_t w, int32_t h, struct controller *c) - : controller_child(c, i) -{ - this->parent->add_proxy_to_lid_mapping(this->parent->proxy.get(), i); - ivi_wm_create_layout_layer(c->proxy.get(), i, w, h); -} - -void layer::set_visibility(uint32_t visibility) -{ - ivi_wm_set_layer_visibility(this->parent->proxy.get(), this->id, visibility); -} - -void layer::set_destination_rectangle(int32_t x, int32_t y, - int32_t width, int32_t height) -{ - ivi_wm_set_layer_destination_rectangle(this->parent->proxy.get(), this->id, - x, y, width, height); -} - -void layer::add_surface(uint32_t surface_id) -{ - ivi_wm_layer_add_surface(this->parent->proxy.get(), this->id, surface_id); -} - -void layer::remove_surface(uint32_t surface_id) -{ - ivi_wm_layer_remove_surface(this->parent->proxy.get(), this->id, surface_id); -} - -/** - * screen - */ -screen::screen(uint32_t i, struct controller *c, struct wl_output *o) - : wayland_proxy(ivi_wm_create_screen(c->proxy.get(), o)), - controller_child(c, i) -{ - HMI_DEBUG("compositor::screen @ %p id %u o %p", this->proxy.get(), i, o); - - // Add listener for screen - ivi_wm_screen_add_listener(this->proxy.get(), &screen_listener, this); -} - -void screen::clear() { ivi_wm_screen_clear(this->proxy.get()); } - -void screen::screen_created(struct screen *screen, uint32_t id) -{ - HMI_DEBUG("compositor::screen @ %p screen %u (%x) @ %p", this->proxy.get(), - id, id, screen); - this->id = id; - this->parent->screens[id] = screen; -} - -void screen::set_render_order(std::vector const &ro) -{ - std::size_t i; - - // Remove all layers from the screen render order - ivi_wm_screen_clear(this->proxy.get()); - - for (i = 0; i < ro.size(); i++) - { - HMI_DEBUG("compositor::screen @ %p add layer %u", this->proxy.get(), ro[i]); - // Add the layer to screen render order at nearest z-position - ivi_wm_screen_add_layer(this->proxy.get(), ro[i]); - } -} - -/** - * controller - */ -controller::controller(struct wl_registry *r, uint32_t name, uint32_t version) - : wayland_proxy( - wl_registry_bind(r, name, &ivi_wm_interface, version)), - output_size{} -{ - ivi_wm_add_listener(this->proxy.get(), &listener, this); -} - -void controller::layer_create(uint32_t id, int32_t w, int32_t h) -{ - this->layers[id] = std::make_unique(id, w, h, this); -} - -void controller::surface_create(uint32_t id) -{ - this->surfaces[id] = std::make_unique(id, this); - - // TODO: If Clipping is necessary, this process should be modified. - { - // Set surface type:IVI_WM_SURFACE_TYPE_DESKTOP) - // for resizing wayland surface when switching from split to full surface. - ivi_wm_set_surface_type(this->proxy.get(), id, IVI_WM_SURFACE_TYPE_DESKTOP); - - // Set source reactangle even if we should not need to set it - // for enable setting for destination region. - this->surfaces[id]->set_source_rectangle(0, 0, this->output_size.w, this->output_size.h); - - // Flush display - this->display->flush(); - } -} - -void controller::create_screen(struct wl_output *output) -{ - // TODO: screen id is 0 (WM manages one screen for now) - this->screen = std::make_unique(0, this, output); -} - -void controller::get_surface_properties(uint32_t surface_id, int param) -{ - ivi_wm_surface_get(this->proxy.get(), surface_id, param); -} - -void controller::layer_created(uint32_t id) -{ - HMI_DEBUG("compositor::controller @ %p layer %u (%x)", this->proxy.get(), id, id); - if (this->layers.find(id) != this->layers.end()) - { - HMI_DEBUG("WindowManager has created layer %u (%x) already", id, id); - } - else - { - this->layers[id] = std::make_unique(id, this); - } -} - -void controller::layer_error_detected(uint32_t object_id, - uint32_t error_code, const char *error_text) -{ - HMI_DEBUG("compositor::controller @ %p error o %d c %d text %s", - this->proxy.get(), object_id, error_code, error_text); -} - -void controller::surface_visibility_changed(uint32_t id, int32_t visibility) -{ - HMI_DEBUG("compositor::surface %s @ %d v %i", __func__, id, - visibility); - this->sprops[id].visibility = visibility; - this->chooks->surface_visibility(id, visibility); -} - -void controller::surface_opacity_changed(uint32_t id, float opacity) -{ - HMI_DEBUG("compositor::surface %s @ %d o %f", - __func__, id, opacity); - this->sprops[id].opacity = opacity; -} - -void controller::surface_source_rectangle_changed(uint32_t id, int32_t x, - int32_t y, int32_t width, - int32_t height) -{ - HMI_DEBUG("compositor::surface %s @ %d x %i y %i w %i h %i", __func__, - id, x, y, width, height); - this->sprops[id].src_rect = rect{width, height, x, y}; -} - -void controller::surface_destination_rectangle_changed(uint32_t id, int32_t x, - int32_t y, int32_t width, - int32_t height) -{ - HMI_DEBUG("compositor::surface %s @ %d x %i y %i w %i h %i", __func__, - id, x, y, width, height); - this->sprops[id].dst_rect = rect{width, height, x, y}; - this->chooks->surface_destination_rectangle(id, x, y, width, height); -} - -void controller::surface_size_changed(uint32_t id, int32_t width, - int32_t height) -{ - HMI_DEBUG("compositor::surface %s @ %d w %i h %i", __func__, id, - width, height); - this->sprops[id].size = size{uint32_t(width), uint32_t(height)}; - this->surfaces[id]->set_source_rectangle(0, 0, width, height); -} - -void controller::surface_added_to_layer(uint32_t layer_id, uint32_t surface_id) -{ - HMI_DEBUG("compositor::surface %s @ %d l %u", - __func__, layer_id, surface_id); -} - -void controller::surface_stats_received(uint32_t surface_id, - uint32_t frame_count, uint32_t pid) -{ - HMI_DEBUG("compositor::surface %s @ %d f %u pid %u", - __func__, surface_id, frame_count, pid); -} - -void controller::surface_created(uint32_t id) -{ - HMI_DEBUG("compositor::controller @ %p surface %u (%x)", this->proxy.get(), id, - id); - if (this->surfaces.find(id) == this->surfaces.end()) - { - this->surfaces[id] = std::make_unique(id, this); - this->chooks->surface_created(id); - - // Set surface type:IVI_WM_SURFACE_TYPE_DESKTOP) - // for resizing wayland surface when switching from split to full surface. - ivi_wm_set_surface_type(this->proxy.get(), id, IVI_WM_SURFACE_TYPE_DESKTOP); - - // Flush display - this->display->flush(); - } -} - -void controller::surface_destroyed(uint32_t surface_id) -{ - HMI_DEBUG("compositor::surface %s @ %d", __func__, surface_id); - this->chooks->surface_removed(surface_id); - this->sprops.erase(surface_id); - this->surfaces.erase(surface_id); -} - -void controller::surface_error_detected(uint32_t object_id, - uint32_t error_code, const char *error_text) -{ - HMI_DEBUG("compositor::controller @ %p error o %d c %d text %s", - this->proxy.get(), object_id, error_code, error_text); -} - -void controller::layer_visibility_changed(uint32_t layer_id, int32_t visibility) -{ - HMI_DEBUG("compositor::layer %s @ %d v %i", __func__, layer_id, visibility); - this->lprops[layer_id].visibility = visibility; -} - -void controller::layer_opacity_changed(uint32_t layer_id, float opacity) -{ - HMI_DEBUG("compositor::layer %s @ %d o %f", __func__, layer_id, opacity); - this->lprops[layer_id].opacity = opacity; -} - -void controller::layer_source_rectangle_changed(uint32_t layer_id, - int32_t x, int32_t y, - int32_t width, int32_t height) -{ - HMI_DEBUG("compositor::layer %s @ %d x %i y %i w %i h %i", - __func__, layer_id, x, y, width, height); - this->lprops[layer_id].src_rect = rect{width, height, x, y}; -} - -void controller::layer_destination_rectangle_changed(uint32_t layer_id, - int32_t x, int32_t y, - int32_t width, int32_t height) -{ - HMI_DEBUG("compositor::layer %s @ %d x %i y %i w %i h %i", - __func__, layer_id, x, y, width, height); - this->lprops[layer_id].dst_rect = rect{width, height, x, y}; -} - -void controller::layer_destroyed(uint32_t layer_id) -{ - HMI_DEBUG("compositor::layer %s @ %d", __func__, layer_id); - this->lprops.erase(layer_id); - this->layers.erase(layer_id); -} - -void controller::add_proxy_to_sid_mapping(struct ivi_wm *p, - uint32_t id) -{ - HMI_DEBUG("Add surface proxy mapping for %p (%u)", p, id); - this->surface_proxy_to_id[uintptr_t(p)] = id; - this->sprops[id].id = id; -} - -void controller::remove_proxy_to_sid_mapping(struct ivi_wm *p) -{ - HMI_DEBUG("Remove surface proxy mapping for %p", p); - this->surface_proxy_to_id.erase(uintptr_t(p)); -} - -void controller::add_proxy_to_lid_mapping(struct ivi_wm *p, - uint32_t id) -{ - HMI_DEBUG("Add layer proxy mapping for %p (%u)", p, id); - this->layer_proxy_to_id[uintptr_t(p)] = id; - this->lprops[id].id = id; -} - -void controller::remove_proxy_to_lid_mapping(struct ivi_wm *p) -{ - HMI_DEBUG("Remove layer proxy mapping for %p", p); - this->layer_proxy_to_id.erase(uintptr_t(p)); -} - -void controller::add_proxy_to_id_mapping(struct wl_output *p, uint32_t id) -{ - HMI_DEBUG("Add screen proxy mapping for %p (%u)", p, id); - this->screen_proxy_to_id[uintptr_t(p)] = id; -} - -void controller::remove_proxy_to_id_mapping(struct wl_output *p) -{ - HMI_DEBUG("Remove screen proxy mapping for %p", p); - this->screen_proxy_to_id.erase(uintptr_t(p)); -} - -} // namespace compositor diff --git a/src/wayland_ivi_wm.hpp b/src/wayland_ivi_wm.hpp deleted file mode 100644 index b515a06..0000000 --- a/src/wayland_ivi_wm.hpp +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright (c) 2017 TOYOTA MOTOR CORPORATION - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef WM_WAYLAND_HPP -#define WM_WAYLAND_HPP - -#include "controller_hooks.hpp" -#include "ivi-wm-client-protocol.h" -#include "util.hpp" - -#include -#include -#include -#include - -/** - * @struct wayland_proxy - */ -template -struct wayland_proxy -{ - std::unique_ptr> proxy; - wayland_proxy(wayland_proxy const &) = delete; - wayland_proxy &operator=(wayland_proxy const &) = delete; - wayland_proxy(void *p) - : wayland_proxy(p, - reinterpret_cast(wl_proxy_destroy)) {} - wayland_proxy(void *p, std::function &&p_del) - : proxy(std::unique_ptr>( - static_cast(p), p_del)) {} -}; - -/** - * namespace wl - */ -namespace wl -{ - -/** - * @struct registry - */ -struct registry : public wayland_proxy -{ - typedef std::function binder; - std::unordered_map bindings; - - registry(registry const &) = delete; - registry &operator=(registry const &) = delete; - registry(struct wl_display *d); - - void add_global_handler(char const *iface, binder bind); - - // Events - void global_created(uint32_t name, char const *iface, uint32_t v); - void global_removed(uint32_t name); -}; - -/** - * @struct display - */ -struct display -{ - std::unique_ptr d; - struct registry r; - - display(display const &) = delete; - display &operator=(display const &) = delete; - display(); - bool ok() const; - void roundtrip(); - int dispatch(); - int dispatch_pending(); - int read_events(); - void flush(); - int get_fd() const; - int get_error(); - - // Lets just proxy this for the registry - inline void add_global_handler(char const *iface, registry::binder bind) - { - this->r.add_global_handler(iface, bind); - } -}; - -/** - * @struct output - */ -struct output : public wayland_proxy -{ - int width{}; - int height{}; - int physical_width{}; - int physical_height{}; - int refresh{}; - int transform{}; - - output(output const &) = delete; - output &operator=(output const &) = delete; - output(struct wl_registry *r, uint32_t name, uint32_t v); - - // Events - void geometry(int32_t x, int32_t y, int32_t pw, int32_t ph, int32_t subpel, - char const *make, char const *model, int32_t tx); - void mode(uint32_t flags, int32_t w, int32_t h, int32_t r); - void done(); - void scale(int32_t factor); -}; -} // namespace wl - -/** - * namespace compositor - */ -namespace compositor -{ - -struct size -{ - uint32_t w, h; -}; - -struct rect -{ - int32_t w, h; - int32_t x, y; -}; - -static const constexpr rect full_rect = rect{-1, -1, 0, 0}; - -inline bool operator==(struct rect a, struct rect b) -{ - return a.w == b.w && a.h == b.h && a.x == b.x && a.y == b.y; -} - -struct controller; - -struct controller_child -{ - struct controller *parent; - uint32_t id; - - controller_child(controller_child const &) = delete; - controller_child &operator=(controller_child const &) = delete; - controller_child(struct controller *c, uint32_t i) : parent(c), id(i) {} - virtual ~controller_child() {} -}; - -struct surface_properties -{ - uint32_t id; // let's just save an ID here too - struct rect dst_rect; - struct rect src_rect; - struct size size; - int32_t orientation; - int32_t visibility; - float opacity; -}; - -/** - * @struct surface - */ -struct surface : public controller_child -{ - surface(surface const &) = delete; - surface &operator=(surface const &) = delete; - surface(uint32_t i, struct controller *c); - - // Requests - void set_visibility(uint32_t visibility); - void set_source_rectangle(int32_t x, int32_t y, - int32_t width, int32_t height); - void set_destination_rectangle(int32_t x, int32_t y, - int32_t width, int32_t height); -}; - -/** - * @struct layer - */ -struct layer : public controller_child -{ - layer(layer const &) = delete; - layer &operator=(layer const &) = delete; - layer(uint32_t i, struct controller *c); - layer(uint32_t i, int32_t w, int32_t h, struct controller *c); - - // Requests - void set_visibility(uint32_t visibility); - void set_destination_rectangle(int32_t x, int32_t y, - int32_t width, int32_t height); - void add_surface(uint32_t surface_id); - void remove_surface(uint32_t surface_id); -}; - -/** - * @struct screen - */ -struct screen : public wayland_proxy, - public controller_child -{ - screen(screen const &) = delete; - screen &operator=(screen const &) = delete; - screen(uint32_t i, struct controller *c, struct wl_output *o); - - void clear(); - void screen_created(struct screen *screen, uint32_t id); - void set_render_order(std::vector const &ro); -}; - -/** - * @struct controller - */ -struct controller : public wayland_proxy -{ - // This controller is still missing ivi-input - - typedef std::unordered_map proxy_to_id_map_type; - typedef std::unordered_map> - surface_map_type; - typedef std::unordered_map> - layer_map_type; - typedef std::unordered_map screen_map_type; - typedef std::unordered_map props_map; - - // HACK: - // The order of these member is mandatory, as when objects are destroyed - // they will call their parent (that's us right here!) and remove their - // proxy-to-id mapping. I.e. the *_proxy_to_id members need to be valid - // when the surfaces/layers/screens maps are destroyed. This sucks, but - // I cannot see a better solution w/o globals or some other horrible - // call-our-parent construct. - proxy_to_id_map_type surface_proxy_to_id; - proxy_to_id_map_type layer_proxy_to_id; - proxy_to_id_map_type screen_proxy_to_id; - - props_map sprops; - props_map lprops; - - surface_map_type surfaces; - layer_map_type layers; - screen_map_type screens; - - std::unique_ptr screen; - - size output_size; // Display size[pixel] - size physical_size; // Display size[mm] - - // Scale for conversion CSS PX -> DP(Device Pixel) - double scale; - - wm::controller_hooks *chooks; - - struct wl::display *display; - - void add_proxy_to_sid_mapping(struct ivi_wm *p, uint32_t id); - void remove_proxy_to_sid_mapping(struct ivi_wm *p); - - void add_proxy_to_lid_mapping(struct ivi_wm *p, uint32_t id); - void remove_proxy_to_lid_mapping(struct ivi_wm *p); - - void add_proxy_to_id_mapping(struct wl_output *p, uint32_t id); - void remove_proxy_to_id_mapping(struct wl_output *p); - - bool surface_exists(uint32_t id) const - { - return this->surfaces.find(id) != this->surfaces.end(); - } - - bool layer_exists(uint32_t id) const - { - return this->layers.find(id) != this->layers.end(); - } - - controller(struct wl_registry *r, uint32_t name, uint32_t version); - - // Requests - void commit_changes() const - { - ivi_wm_commit_changes(this->proxy.get()); - } - void layer_create(uint32_t id, int32_t w, int32_t h); - void surface_create(uint32_t id); - void create_screen(struct wl_output *output); - void get_surface_properties(uint32_t surface_id, int param = 0); - - // Events - void surface_visibility_changed(uint32_t id, int32_t visibility); - void surface_opacity_changed(uint32_t id, float opacity); - void surface_source_rectangle_changed(uint32_t id, int32_t x, int32_t y, - int32_t width, int32_t height); - void surface_destination_rectangle_changed(uint32_t id, int32_t x, int32_t y, - int32_t width, int32_t height); - void surface_created(uint32_t id); - void surface_destroyed(uint32_t surface_id); - void surface_error_detected(uint32_t object_id, - uint32_t error_code, char const *error_text); - void surface_size_changed(uint32_t id, int32_t width, int32_t height); - void surface_stats_received(uint32_t surface_id, - uint32_t frame_count, uint32_t pid); - void surface_added_to_layer(uint32_t layer_id, uint32_t surface_id); - - void layer_visibility_changed(uint32_t layer_id, int32_t visibility); - void layer_opacity_changed(uint32_t layer_id, float opacity); - void layer_source_rectangle_changed(uint32_t layer_id, int32_t x, int32_t y, - int32_t width, int32_t height); - void layer_destination_rectangle_changed(uint32_t layer_id, int32_t x, int32_t y, - int32_t width, int32_t height); - void layer_created(uint32_t id); - void layer_destroyed(uint32_t layer_id); - void layer_error_detected(uint32_t object_id, - uint32_t error_code, char const *error_text); -}; -} // namespace compositor - -#endif // !WM_WAYLAND_HPP diff --git a/src/window_manager.cpp b/src/window_manager.cpp index 3e1a8bc..c69c839 100644 --- a/src/window_manager.cpp +++ b/src/window_manager.cpp @@ -56,6 +56,16 @@ const char kKeyHeightMm[] = "height_mm"; const char kKeyScale[] = "scale"; const char kKeyIds[] = "ids"; +static const vector kListEventName{ + "active", + "inactive", + "visible", + "invisible", + "syncDraw", + "flushDraw", + "screenUpdated", + "error"}; + static sd_event_source *g_timer_ev_src = nullptr; static AppList g_app_list; static WindowManager *g_context; @@ -63,39 +73,6 @@ static WindowManager *g_context; namespace { -using nlohmann::json; - -result file_to_json(char const *filename) -{ - json j; - std::ifstream i(filename); - if (i.fail()) - { - HMI_DEBUG("Could not open config file, so use default layer information"); - j = default_layers_json; - } - else - { - i >> j; - } - - return Ok(j); -} - -struct result load_layer_map(char const *filename) -{ - HMI_DEBUG("loading IDs from %s", filename); - - auto j = file_to_json(filename); - if (j.is_err()) - { - return Err(j.unwrap_err()); - } - json jids = j.unwrap(); - - return to_layer_map(jids); -} - static int processTimerHandler(sd_event_source *s, uint64_t usec, void *userdata) { HMI_NOTICE("Time out occurs because the client replys endDraw slow, so revert the request"); @@ -117,57 +94,33 @@ static void onError() /** * WindowManager Impl */ -WindowManager::WindowManager(wl::display *d) - : chooks{this}, - display{d}, - controller{}, - outputs(), - layers(), - id_alloc{}, - pending_events(false) +WindowManager::WindowManager() + : id_alloc{} { - char const *path_layers_json = getenv("AFM_APP_INSTALL_DIR"); - string path; - if (!path_layers_json) + const char *path = getenv("AFM_APP_INSTALL_DIR"); + if (!path) { HMI_ERROR("AFM_APP_INSTALL_DIR is not defined"); - path = string(path_layers_json); - } - else - { - path = string(path_layers_json) + string("/etc/layers.json"); } + string root = path; - try - { - { - auto l = load_layer_map(path.c_str()); - if (l.is_ok()) - { - this->layers = l.unwrap(); - } - else - { - HMI_ERROR("%s", l.err().value()); - } - } - } - catch (std::exception &e) - { - HMI_ERROR("Loading of configuration failed: %s", e.what()); - } + this->lc = std::make_shared(root); + + HMI_DEBUG("Layer Controller initialized"); } int WindowManager::init() { - if (!this->display->ok()) - { - return -1; - } + LayerControlCallbacks lmcb; + lmcb.surfaceCreated = [&](unsigned pid, unsigned surface){ + this->surface_created(surface); + }; + lmcb.surfaceDestroyed = [&](unsigned surface){ + this->surface_removed(surface); + }; - if (this->layers.mapping.empty()) + if(this->lc->init(lmcb) != WMError::SUCCESS) { - HMI_ERROR("No surface -> layer mapping loaded"); return -1; } @@ -188,58 +141,25 @@ int WindowManager::init() // Make afb event for (int i = Event_Val_Min; i <= Event_Val_Max; i++) { - map_afb_event[kListEventName[i]] = afb_daemon_make_event(kListEventName[i]); + map_afb_event[kListEventName[i]] = afb_daemon_make_event(kListEventName[i].c_str()); } - this->display->add_global_handler( - "wl_output", [this](wl_registry *r, uint32_t name, uint32_t v) { - this->outputs.emplace_back(std::make_unique(r, name, v)); - }); - - this->display->add_global_handler( - "ivi_wm", [this](wl_registry *r, uint32_t name, uint32_t v) { - this->controller = - std::make_unique(r, name, v); - - // Init controller hooks - this->controller->chooks = &this->chooks; + const struct rect css_bg = this->lc->getAreaSize("fullscreen"); + Screen screen = this->lc->getScreenInfo(); + rectangle dp_bg(screen.width(), screen.height()); - // This protocol needs the output, so lets just add our mapping here... - this->controller->add_proxy_to_id_mapping( - this->outputs.front()->proxy.get(), - wl_proxy_get_id(reinterpret_cast( - this->outputs.front()->proxy.get()))); - - // Create screen - this->controller->create_screen(this->outputs.front()->proxy.get()); - - // Set display to controller - this->controller->display = this->display; - }); - - // First level objects - this->display->roundtrip(); - // Second level objects - this->display->roundtrip(); - // Third level objects - this->display->roundtrip(); + dp_bg.set_aspect(static_cast(css_bg.w) / css_bg.h); + dp_bg.fit(screen.width(), screen.height()); + dp_bg.center(screen.width(), screen.height()); + HMI_DEBUG("SCALING: CSS BG(%dx%d) -> DDP %dx%d,(%dx%d)", + css_bg.w, css_bg.h, dp_bg.left(), dp_bg.top(), dp_bg.width(), dp_bg.height()); - return init_layers(); -} + double scale = static_cast(dp_bg.height()) / css_bg.h; + this->lc->setupArea(dp_bg, scale); -int WindowManager::dispatch_pending_events() -{ - if (this->pop_pending_events()) - { - this->display->dispatch_pending(); - return 0; - } - return -1; -} + this->lc->createLayers(); -void WindowManager::set_pending_events() -{ - this->pending_events.store(true, std::memory_order_release); + return 0; } result WindowManager::api_request_surface(char const *appid, char const *drawing_name) @@ -248,38 +168,33 @@ result WindowManager::api_request_surface(char const *appid, char const *dr // so convert role old to new const char *role = this->convertRoleOldToNew(drawing_name); - auto lid = this->layers.get_layer_id(string(role)); - if (!lid) + // auto lid = this->layers.get_layer_id(string(role)); + unsigned lid = this->lc->getLayerID(string(role)); + if (lid == 0) { /** * register drawing_name as fallback and make it displayed. */ - lid = this->layers.get_layer_id(string("fallback")); + // lid = this->layers.get_layer_id(string("fallback")); + lid = this->lc->getLayerID(string("fallback")); HMI_DEBUG("%s is not registered in layers.json, then fallback as normal app", role); - if (!lid) + if (lid == 0) { return Err("Drawing name does not match any role, fallback is disabled"); } } - auto rname = this->lookup_id(role); + auto rname = this->id_alloc.lookup(role); if (!rname) { // name does not exist yet, allocate surface id... auto id = int(this->id_alloc.generate_id(role)); - this->layers.add_surface(id, *lid); - - // set the main_surface[_name] here and now - if (!this->layers.main_surface_name.empty() && - this->layers.main_surface_name == drawing_name) - { - this->layers.main_surface = id; - HMI_DEBUG("Set main_surface id to %u", id); - } + // this->layers.add_surface(id, *lid); + this->tmp_surface2app[id] = {string(appid), lid}; // add client into the db string appid_str(appid); - g_app_list.addClient(appid_str, *lid, id, string(role)); + g_app_list.addClient(appid_str, lid, id, string(role)); // Set role map of (new, old) this->rolenew2old[role] = string(drawing_name); @@ -298,23 +213,31 @@ char const *WindowManager::api_request_surface(char const *appid, char const *dr // so convert role old to new const char *role = this->convertRoleOldToNew(drawing_name); - auto lid = this->layers.get_layer_id(string(role)); unsigned sid = std::stol(ivi_id); + WMError ret = this->lc->setXDGSurfaceOriginSize(sid); + if(ret != SUCCESS) + { + HMI_ERROR("%s", errorDescription(ret)); + HMI_WARNING("The main user of this API is runXDG"); + return "fail"; + } - if (!lid) + // auto lid = this->layers.get_layer_id(string(role)); + auto lid = this->lc->getLayerID(string(role)); + if (lid == 0) { /** * register drawing_name as fallback and make it displayed. */ - lid = this->layers.get_layer_id(string("fallback")); + lid = this->lc->getLayerID(string("fallback")); HMI_DEBUG("%s is not registered in layers.json, then fallback as normal app", role); - if (!lid) + if (lid == 0) { return "Drawing name does not match any role, fallback is disabled"; } } - auto rname = this->lookup_id(role); + auto rname = this->id_alloc.lookup(role); if (rname) { @@ -323,17 +246,13 @@ char const *WindowManager::api_request_surface(char const *appid, char const *dr // register pair drawing_name and ivi_id this->id_alloc.register_name_id(role, sid); - this->layers.add_surface(sid, *lid); - - // this surface is already created - HMI_DEBUG("surface_id is %u, layer_id is %u", sid, *lid); + this->lc->addSurface(sid, lid); - this->controller->layers[*lid]->add_surface(sid); - this->layout_commit(); + HMI_DEBUG("surface_id is %u, layer_id is %u", sid, lid); - // add client into the db + // add client into the list string appid_str(appid); - g_app_list.addClient(appid_str, *lid, sid, string(role)); + g_app_list.addClient(appid_str, lid, sid, string(role)); // Set role map of (new, old) this->rolenew2old[role] = string(drawing_name); @@ -351,6 +270,14 @@ void WindowManager::api_activate_surface(char const *appid, char const *drawing_ string id = appid; string role = c_role; string area = drawing_area; + + if(!g_app_list.contains(id)) + { + reply("app doesn't request 'requestSurface' or 'setRole' yet"); + return; + } + + auto client = g_app_list.lookUpClient(id); Task task = Task::TASK_ALLOCATE; unsigned req_num = 0; WMError ret = WMError::UNKNOWN; @@ -375,7 +302,7 @@ void WindowManager::api_activate_surface(char const *appid, char const *drawing_ /* * Do allocate tasks */ - ret = this->doTransition(req_num); + ret = this->checkPolicy(req_num); if (ret != WMError::SUCCESS) { @@ -423,7 +350,7 @@ void WindowManager::api_deactivate_surface(char const *appid, char const *drawin /* * Do allocate tasks */ - ret = this->doTransition(req_num); + ret = this->checkPolicy(req_num); if (ret != WMError::SUCCESS) { @@ -478,23 +405,23 @@ void WindowManager::api_enddraw(char const *appid, char const *drawing_name) } } -result WindowManager::api_get_display_info() +int WindowManager::api_subscribe(afb_req req, int event_id) { - if (!this->display->ok()) - { - return Err("Wayland compositor is not available"); - } + struct afb_event event = this->map_afb_event[kListEventName[event_id]]; + return afb_req_subscribe(req, event); +} - // Set display info - compositor::size o_size = this->controller->output_size; - compositor::size p_size = this->controller->physical_size; +result WindowManager::api_get_display_info() +{ + Screen screen = this->lc->getScreenInfo(); json_object *object = json_object_new_object(); - json_object_object_add(object, kKeyWidthPixel, json_object_new_int(o_size.w)); - json_object_object_add(object, kKeyHeightPixel, json_object_new_int(o_size.h)); - json_object_object_add(object, kKeyWidthMm, json_object_new_int(p_size.w)); - json_object_object_add(object, kKeyHeightMm, json_object_new_int(p_size.h)); - json_object_object_add(object, kKeyScale, json_object_new_double(this->controller->scale)); + json_object_object_add(object, kKeyWidthPixel, json_object_new_int(screen.width())); + json_object_object_add(object, kKeyHeightPixel, json_object_new_int(screen.height())); + // TODO: set size + json_object_object_add(object, kKeyWidthMm, json_object_new_int(0)); + json_object_object_add(object, kKeyHeightMm, json_object_new_int(0)); + json_object_object_add(object, kKeyScale, json_object_new_double(this->lc->scale())); return Ok(object); } @@ -508,25 +435,14 @@ result WindowManager::api_get_area_info(char const *drawing_name) const char *role = this->convertRoleOldToNew(drawing_name); // Check drawing name, surface/layer id - auto const &surface_id = this->lookup_id(role); + auto const &surface_id = this->id_alloc.lookup(role); if (!surface_id) { return Err("Surface does not exist"); } - if (!this->controller->surface_exists(*surface_id)) - { - return Err("Surface does not exist in controller!"); - } - - auto layer_id = this->layers.get_layer_id(*surface_id); - if (!layer_id) - { - return Err("Surface is not on any layer!"); - } - // Set area rectangle - compositor::rect area_info = this->area_info[*surface_id]; + struct rect area_info = this->area_info[*surface_id]; json_object *object = json_object_new_object(); json_object_object_add(object, kKeyX, json_object_new_int(area_info.x)); json_object_object_add(object, kKeyY, json_object_new_int(area_info.y)); @@ -536,14 +452,10 @@ result WindowManager::api_get_area_info(char const *drawing_name) return Ok(object); } -void WindowManager::api_ping() { this->dispatch_pending_events(); } - -void WindowManager::send_event(char const *evname, char const *label) +void WindowManager::send_event(const string& evname, const string& role) { - HMI_DEBUG("%s: %s(%s)", __func__, evname, label); - json_object *j = json_object_new_object(); - json_object_object_add(j, kKeyDrawingName, json_object_new_string(label)); + json_object_object_add(j, kKeyDrawingName, json_object_new_string(role.c_str())); int ret = afb_event_push(this->map_afb_event[evname], j); if (ret != 0) @@ -552,12 +464,9 @@ void WindowManager::send_event(char const *evname, char const *label) } } -void WindowManager::send_event(char const *evname, char const *label, char const *area, +void WindowManager::send_event(const string& evname, const string& role, const string& area, int x, int y, int w, int h) { - HMI_DEBUG("%s: %s(%s, %s) x:%d y:%d w:%d h:%d", - __func__, evname, label, area, x, y, w, h); - json_object *j_rect = json_object_new_object(); json_object_object_add(j_rect, kKeyX, json_object_new_int(x)); json_object_object_add(j_rect, kKeyY, json_object_new_int(y)); @@ -565,8 +474,8 @@ void WindowManager::send_event(char const *evname, char const *label, char const json_object_object_add(j_rect, kKeyHeight, json_object_new_int(h)); json_object *j = json_object_new_object(); - json_object_object_add(j, kKeyDrawingName, json_object_new_string(label)); - json_object_object_add(j, kKeyDrawingArea, json_object_new_string(area)); + json_object_object_add(j, kKeyDrawingName, json_object_new_string(role.c_str())); + json_object_object_add(j, kKeyDrawingArea, json_object_new_string(area.c_str())); json_object_object_add(j, kKeyDrawingRect, j_rect); int ret = afb_event_push(this->map_afb_event[evname], j); @@ -579,29 +488,22 @@ void WindowManager::send_event(char const *evname, char const *label, char const /** * proxied events */ -void WindowManager::surface_created(uint32_t surface_id) +void WindowManager::surface_created(unsigned surface_id) { - this->controller->get_surface_properties(surface_id, IVI_WM_PARAM_SIZE); - - auto layer_id = this->layers.get_layer_id(surface_id); - if (!layer_id) + // requestSurface + if(this->tmp_surface2app.count(surface_id) != 0) { - HMI_DEBUG("Newly created surfce %d is not associated with any layer!", - surface_id); - return; + unsigned layer_id = this->tmp_surface2app[surface_id].layer; + this->lc->addSurface(surface_id, layer_id); + this->tmp_surface2app.erase(surface_id); + HMI_DEBUG("surface_id is %u, layer_id is %u", surface_id, layer_id); } - - HMI_DEBUG("surface_id is %u, layer_id is %u", surface_id, *layer_id); - - this->controller->layers[*layer_id]->add_surface(surface_id); - this->layout_commit(); } -void WindowManager::surface_removed(uint32_t surface_id) +void WindowManager::surface_removed(unsigned surface_id) { HMI_DEBUG("Delete surface_id %u", surface_id); this->id_alloc.remove_id(surface_id); - this->layers.remove_surface(surface_id); g_app_list.removeSurface(surface_id); } @@ -653,7 +555,7 @@ void WindowManager::startTransitionWrapper(vector &actions) if ("" != act.role) { bool found; - auto const &surface_id = this->lookup_id(act.role.c_str()); + auto const &surface_id = this->id_alloc.lookup(act.role.c_str()); if(surface_id == nullopt) { goto proc_remove_request; @@ -727,281 +629,44 @@ void WindowManager::processError(WMError error) ******* Private Functions ******* */ -bool WindowManager::pop_pending_events() +void WindowManager::emit_activated(const string& role) { - bool x{true}; - return this->pending_events.compare_exchange_strong( - x, false, std::memory_order_consume); + this->send_event(kListEventName[Event_Active], role); } -optional WindowManager::lookup_id(char const *name) -{ - return this->id_alloc.lookup(string(name)); -} -optional WindowManager::lookup_name(int id) +void WindowManager::emit_deactivated(const string& role) { - return this->id_alloc.lookup(id); + this->send_event(kListEventName[Event_Inactive], role); } -/** - * init_layers() - */ -int WindowManager::init_layers() +void WindowManager::emit_syncdraw(const string& role, char const *area, int x, int y, int w, int h) { - if (!this->controller) - { - HMI_ERROR("ivi_controller global not available"); - return -1; - } - - if (this->outputs.empty()) - { - HMI_ERROR("no output was set up!"); - return -1; - } - - auto &c = this->controller; - - auto &o = this->outputs.front(); - auto &s = c->screens.begin()->second; - auto &layers = c->layers; - - // Write output dimensions to ivi controller... - c->output_size = compositor::size{uint32_t(o->width), uint32_t(o->height)}; - c->physical_size = compositor::size{uint32_t(o->physical_width), - uint32_t(o->physical_height)}; - - - HMI_DEBUG("SCALING: screen (%dx%d), physical (%dx%d)", - o->width, o->height, o->physical_width, o->physical_height); - - this->layers.loadAreaDb(); - - const compositor::rect css_bg = this->layers.getAreaSize("fullscreen"); - rectangle dp_bg(o->width, o->height); - - dp_bg.set_aspect(static_cast(css_bg.w) / css_bg.h); - dp_bg.fit(o->width, o->height); - dp_bg.center(o->width, o->height); - HMI_DEBUG("SCALING: CSS BG(%dx%d) -> DDP %dx%d,(%dx%d)", - css_bg.w, css_bg.h, dp_bg.left(), dp_bg.top(), dp_bg.width(), dp_bg.height()); - - // Clear scene - layers.clear(); - - // Clear screen - s->clear(); - - // Quick and dirty setup of layers - for (auto const &i : this->layers.mapping) - { - c->layer_create(i.second.layer_id, dp_bg.width(), dp_bg.height()); - auto &l = layers[i.second.layer_id]; - l->set_destination_rectangle(dp_bg.left(), dp_bg.top(), dp_bg.width(), dp_bg.height()); - l->set_visibility(1); - HMI_DEBUG("Setting up layer %s (%d) for surface role match \"%s\"", - i.second.name.c_str(), i.second.layer_id, i.second.role.c_str()); - } - - // Add layers to screen - s->set_render_order(this->layers.layers); - - this->layout_commit(); - - c->scale = static_cast(dp_bg.height()) / css_bg.h; - this->layers.setupArea(c->scale); - - return 0; -} - -void WindowManager::surface_set_layout(int surface_id, const string& area) -{ - if (!this->controller->surface_exists(surface_id)) - { - HMI_ERROR("Surface %d does not exist", surface_id); - return; - } - - auto o_layer_id = this->layers.get_layer_id(surface_id); - - if (!o_layer_id) - { - HMI_ERROR("Surface %d is not associated with any layer!", surface_id); - return; - } - - uint32_t layer_id = *o_layer_id; - - auto const &layer = this->layers.get_layer(layer_id); - auto rect = this->layers.getAreaSize(area); - HMI_SEQ_DEBUG(g_app_list.currentRequestNumber(), "%s : x:%d y:%d w:%d h:%d", area.c_str(), - rect.x, rect.y, rect.w, rect.h); - auto &s = this->controller->surfaces[surface_id]; - - int x = rect.x; - int y = rect.y; - int w = rect.w; - int h = rect.h; - - HMI_DEBUG("surface_set_layout for surface %u on layer %u", surface_id, - layer_id); - - // set destination to the display rectangle - s->set_destination_rectangle(x, y, w, h); - - // update area information - this->area_info[surface_id].x = x; - this->area_info[surface_id].y = y; - this->area_info[surface_id].w = w; - this->area_info[surface_id].h = h; - - HMI_DEBUG("Surface %u now on layer %u with rect { %d, %d, %d, %d }", - surface_id, layer_id, x, y, w, h); -} - -void WindowManager::layout_commit() -{ - this->controller->commit_changes(); - this->display->flush(); -} - -void WindowManager::emit_activated(char const *label) -{ - this->send_event(kListEventName[Event_Active], label); -} - -void WindowManager::emit_deactivated(char const *label) -{ - this->send_event(kListEventName[Event_Inactive], label); -} - -void WindowManager::emit_syncdraw(char const *label, char const *area, int x, int y, int w, int h) -{ - this->send_event(kListEventName[Event_SyncDraw], label, area, x, y, w, h); + this->send_event(kListEventName[Event_SyncDraw], role, area, x, y, w, h); } void WindowManager::emit_syncdraw(const string &role, const string &area) { - compositor::rect rect = this->layers.getAreaSize(area); + struct rect rect = this->lc->getAreaSize(area); this->send_event(kListEventName[Event_SyncDraw], role.c_str(), area.c_str(), rect.x, rect.y, rect.w, rect.h); } -void WindowManager::emit_flushdraw(char const *label) +void WindowManager::emit_flushdraw(const string& role) { - this->send_event(kListEventName[Event_FlushDraw], label); + this->send_event(kListEventName[Event_FlushDraw], role); } -void WindowManager::emit_visible(char const *label, bool is_visible) +void WindowManager::emit_visible(const string& role, bool is_visible) { - this->send_event(is_visible ? kListEventName[Event_Visible] : kListEventName[Event_Invisible], label); + this->send_event(is_visible ? kListEventName[Event_Visible] : kListEventName[Event_Invisible], role); } -void WindowManager::emit_invisible(char const *label) +void WindowManager::emit_invisible(const string& role) { - return emit_visible(label, false); + return emit_visible(role, false); } -void WindowManager::emit_visible(char const *label) { return emit_visible(label, true); } - -void WindowManager::activate(int id) -{ - auto ip = this->controller->sprops.find(id); - if (ip != this->controller->sprops.end()) - { - this->controller->surfaces[id]->set_visibility(1); - char const *label = - this->lookup_name(id).value_or("unknown-name").c_str(); - - // FOR CES DEMO >>> - if ((0 == strcmp(label, "radio")) || - (0 == strcmp(label, "music")) || - (0 == strcmp(label, "video")) || - (0 == strcmp(label, "map"))) - { - for (auto i = surface_bg.begin(); i != surface_bg.end(); ++i) - { - if (id == *i) - { - // Remove id - this->surface_bg.erase(i); - - // Remove from BG layer (999) - HMI_DEBUG("Remove %s(%d) from BG layer", label, id); - this->controller->layers[999]->remove_surface(id); - - // Add to FG layer (1001) - HMI_DEBUG("Add %s(%d) to FG layer", label, id); - this->controller->layers[1001]->add_surface(id); - - for (int j : this->surface_bg) - { - HMI_DEBUG("Stored id:%d", j); - } - break; - } - } - } - // <<< FOR CES DEMO - - this->layout_commit(); - - // TODO: application requests by old role, - // so convert role new to old for emitting event - const char* old_role = this->rolenew2old[label].c_str(); - - this->emit_visible(old_role); - this->emit_activated(old_role); - } -} - -void WindowManager::deactivate(int id) -{ - auto ip = this->controller->sprops.find(id); - if (ip != this->controller->sprops.end()) - { - char const *label = - this->lookup_name(id).value_or("unknown-name").c_str(); - - // FOR CES DEMO >>> - if ((0 == strcmp(label, "radio")) || - (0 == strcmp(label, "music")) || - (0 == strcmp(label, "video")) || - (0 == strcmp(label, "map"))) - { - - // Store id - this->surface_bg.push_back(id); - - // Remove from FG layer (1001) - HMI_DEBUG("Remove %s(%d) from FG layer", label, id); - this->controller->layers[1001]->remove_surface(id); - - // Add to BG layer (999) - HMI_DEBUG("Add %s(%d) to BG layer", label, id); - this->controller->layers[999]->add_surface(id); - - for (int j : surface_bg) - { - HMI_DEBUG("Stored id:%d", j); - } - } - else - { - this->controller->surfaces[id]->set_visibility(0); - } - // <<< FOR CES DEMO - - this->layout_commit(); - - // TODO: application requests by old role, - // so convert role new to old for emitting event - const char* old_role = this->rolenew2old[label].c_str(); - - this->emit_deactivated(old_role); - this->emit_invisible(old_role); - } -} +void WindowManager::emit_visible(const string& role) { return emit_visible(role, true); } WMError WindowManager::setRequest(const string& appid, const string &role, const string &area, Task task, unsigned* req_num) @@ -1035,13 +700,6 @@ WMError WindowManager::setRequest(const string& appid, const string &role, const return WMError::SUCCESS; } -WMError WindowManager::doTransition(unsigned req_num) -{ - HMI_SEQ_DEBUG(req_num, "check policy"); - WMError ret = this->checkPolicy(req_num); - return ret; -} - WMError WindowManager::checkPolicy(unsigned req_num) { /* @@ -1131,11 +789,14 @@ WMError WindowManager::startTransition(unsigned req_num) // Make it deactivate here for (const auto &x : actions) { - if (g_app_list.contains(x.client->appID())) + this->lc->visibilityChange(x); + string old_role = this->rolenew2old[x.role]; + emit_deactivated(old_role.c_str()); + /* if (g_app_list.contains(x.client->appID())) { auto client = g_app_list.lookUpClient(x.client->appID()); this->deactivate(client->surfaceID(x.role)); - } + } */ } ret = WMError::NO_LAYOUT_CHANGE; } @@ -1162,17 +823,26 @@ WMError WindowManager::doEndDraw(unsigned req_num) if(act.visible != TaskVisible::NO_CHANGE) { // layout change - if(!g_app_list.contains(act.client->appID())){ - ret = WMError::NOT_REGISTERED; - } - ret = this->layoutChange(act); + ret = this->lc->layoutChange(act); if(ret != WMError::SUCCESS) { HMI_SEQ_WARNING(req_num, "Failed to manipulate surfaces while state change : %s", errorDescription(ret)); return ret; } - ret = this->visibilityChange(act); + ret = this->lc->visibilityChange(act); + + // Emit active/deactive event + string old_role = this->rolenew2old[act.role]; + if(act.visible == VISIBLE) + { + emit_activated(old_role.c_str()); + } + else + { + emit_deactivated(old_role.c_str()); + } + if (ret != WMError::SUCCESS) { HMI_SEQ_WARNING(req_num, @@ -1180,10 +850,8 @@ WMError WindowManager::doEndDraw(unsigned req_num) return ret; } HMI_SEQ_DEBUG(req_num, "visible %s", act.role.c_str()); - //this->lm_enddraw(act.role.c_str()); } } - this->layout_commit(); HMI_SEQ_INFO(req_num, "emit flushDraw"); @@ -1202,60 +870,6 @@ WMError WindowManager::doEndDraw(unsigned req_num) return ret; } -WMError WindowManager::layoutChange(const WMAction &action) -{ - if (action.visible == TaskVisible::INVISIBLE) - { - // Visibility is not change -> no redraw is required - return WMError::SUCCESS; - } - auto client = g_app_list.lookUpClient(action.client->appID()); - unsigned surface = client->surfaceID(action.role); - if (surface == 0) - { - HMI_SEQ_ERROR(g_app_list.currentRequestNumber(), - "client doesn't have surface with role(%s)", action.role.c_str()); - return WMError::NOT_REGISTERED; - } - // Layout Manager - WMError ret = this->setSurfaceSize(surface, action.area); - return ret; -} - -WMError WindowManager::visibilityChange(const WMAction &action) -{ - HMI_SEQ_DEBUG(g_app_list.currentRequestNumber(), "Change visibility"); - if(!g_app_list.contains(action.client->appID())) - { - return WMError::NOT_REGISTERED; - } - auto client = g_app_list.lookUpClient(action.client->appID()); - unsigned surface = client->surfaceID(action.role); - if(surface == 0) - { - HMI_SEQ_ERROR(g_app_list.currentRequestNumber(), - "client doesn't have surface with role(%s)", action.role.c_str()); - return WMError::NOT_REGISTERED; - } - - if (action.visible != TaskVisible::INVISIBLE) - { - this->activate(surface); // Layout Manager task - } - else - { - this->deactivate(surface); // Layout Manager task - } - return WMError::SUCCESS; -} - -WMError WindowManager::setSurfaceSize(unsigned surface, const string &area) -{ - this->surface_set_layout(surface, area); - - return WMError::SUCCESS; -} - void WindowManager::emitScreenUpdated(unsigned req_num) { // Get visible apps @@ -1331,7 +945,7 @@ void WindowManager::processNextRequest() if (g_app_list.haveRequest()) { HMI_SEQ_DEBUG(req_num, "Process next request"); - WMError rc = doTransition(req_num); + WMError rc = checkPolicy(req_num); if (rc != WMError::SUCCESS) { HMI_SEQ_ERROR(req_num, errorDescription(rc)); @@ -1444,25 +1058,11 @@ int WindowManager::loadOldRoleDb() const char *WindowManager::check_surface_exist(const char *drawing_name) { - auto const &surface_id = this->lookup_id(drawing_name); + auto const &surface_id = this->id_alloc.lookup(drawing_name); if (!surface_id) { return "Surface does not exist"; } - - if (!this->controller->surface_exists(*surface_id)) - { - return "Surface does not exist in controller!"; - } - - auto layer_id = this->layers.get_layer_id(*surface_id); - - if (!layer_id) - { - return "Surface is not on any layer!"; - } - - HMI_DEBUG("surface %d is detected", *surface_id); return nullptr; } @@ -1535,26 +1135,4 @@ const char* WindowManager::kDefaultOldRoleDb = "{ \ ] \ }"; -/** - * controller_hooks - */ -void controller_hooks::surface_created(uint32_t surface_id) -{ - this->wmgr->surface_created(surface_id); -} - -void controller_hooks::surface_removed(uint32_t surface_id) -{ - this->wmgr->surface_removed(surface_id); -} - -void controller_hooks::surface_visibility(uint32_t /*surface_id*/, - uint32_t /*v*/) {} - -void controller_hooks::surface_destination_rectangle(uint32_t /*surface_id*/, - uint32_t /*x*/, - uint32_t /*y*/, - uint32_t /*w*/, - uint32_t /*h*/) {} - } // namespace wm diff --git a/src/window_manager.hpp b/src/window_manager.hpp index b591149..6416e67 100644 --- a/src/window_manager.hpp +++ b/src/window_manager.hpp @@ -21,14 +21,12 @@ #include #include #include -#include "util.hpp" -#include "controller_hooks.hpp" -#include "wm_layer.hpp" -#include "layout.hpp" -#include "wayland_ivi_wm.hpp" +#include "result.hpp" #include "pm_wrapper.hpp" +#include "util.hpp" #include "request.hpp" #include "wm_error.hpp" +#include "wm_layer_control.hpp" extern "C" { #include @@ -36,16 +34,6 @@ extern "C" struct json_object; -namespace wl -{ -struct display; -} - -namespace compositor -{ -struct controller; -} - namespace wm { @@ -76,7 +64,6 @@ extern const char kKeyIds[]; struct id_allocator { unsigned next = 1; - // Surfaces that where requested but not yet created std::unordered_map id2name; std::unordered_map name2id; @@ -141,10 +128,17 @@ struct id_allocator } }; +struct TmpClient +{ + std::string appid; + unsigned layer; +}; + + class WindowManager { public: - typedef std::unordered_map rect_map; + typedef std::unordered_map rect_map; typedef std::function reply_func; enum EventType @@ -167,42 +161,7 @@ class WindowManager Event_Val_Max = Event_Error, }; - const std::vector kListEventName{ - "active", - "inactive", - "visible", - "invisible", - "syncDraw", - "flushDraw", - "screenUpdated", - "error"}; - - struct controller_hooks chooks; - - // This is the one thing, we do not own. - struct wl::display *display; - - std::unique_ptr controller; - std::vector> outputs; - - // track current layouts separately - layer_map layers; - - // ID allocation and proxy methods for lookup - struct id_allocator id_alloc; - - // Set by AFB API when wayland events need to be dispatched - std::atomic pending_events; - - std::map map_afb_event; - - // Surface are info (x, y, w, h) - rect_map area_info; - - // FOR CES DEMO - std::vector surface_bg; - - explicit WindowManager(wl::display *d); + explicit WindowManager(); ~WindowManager() = default; WindowManager(WindowManager const &) = delete; @@ -211,23 +170,22 @@ class WindowManager WindowManager &operator=(WindowManager &&) = delete; int init(); - int dispatch_pending_events(); - void set_pending_events(); result api_request_surface(char const *appid, char const *role); char const *api_request_surface(char const *appid, char const *role, char const *ivi_id); void api_activate_surface(char const *appid, char const *role, char const *drawing_area, const reply_func &reply); void api_deactivate_surface(char const *appid, char const *role, const reply_func &reply); - void api_enddraw(char const *appid, char const *role); + void api_enddraw(char const *appid, char const *role); + int api_subscribe(afb_req req, int event_id); result api_get_display_info(); result api_get_area_info(char const *role); void api_ping(); - void send_event(char const *evname, char const *label); - void send_event(char const *evname, char const *label, char const *area, int x, int y, int w, int h); + void send_event(const std::string& evname, const std::string& role); + void send_event(const std::string& evname, const std::string& role, const std::string& area, int x, int y, int w, int h); // Events from the compositor we are interested in - void surface_created(uint32_t surface_id); - void surface_removed(uint32_t surface_id); + void surface_created(unsigned surface_id); + void surface_removed(unsigned surface_id); void removeClient(const std::string &appid); void exceptionProcessForTransition(); @@ -239,35 +197,22 @@ class WindowManager void processError(WMError error); private: - bool pop_pending_events(); - optional lookup_id(char const *name); - optional lookup_name(int id); - int init_layers(); - void surface_set_layout(int surface_id, const std::string& area = ""); - void layout_commit(); - // WM Events to clients - void emit_activated(char const *label); - void emit_deactivated(char const *label); - void emit_syncdraw(char const *label, char const *area, int x, int y, int w, int h); + void emit_activated(const std::string& role); + void emit_deactivated(const std::string& role); + void emit_syncdraw(const std::string& role, char const *area, int x, int y, int w, int h); void emit_syncdraw(const std::string &role, const std::string &area); - void emit_flushdraw(char const *label); - void emit_visible(char const *label, bool is_visible); - void emit_invisible(char const *label); - void emit_visible(char const *label); + void emit_flushdraw(const std::string& role); + void emit_visible(const std::string& role, bool is_visible); + void emit_invisible(const std::string& role); + void emit_visible(const std::string& role); - void activate(int id); - void deactivate(int id); WMError setRequest(const std::string &appid, const std::string &role, const std::string &area, Task task, unsigned *req_num); - WMError doTransition(unsigned sequence_number); WMError checkPolicy(unsigned req_num); WMError startTransition(unsigned req_num); WMError doEndDraw(unsigned req_num); - WMError layoutChange(const WMAction &action); - WMError visibilityChange(const WMAction &action); - WMError setSurfaceSize(unsigned surface, const std::string& area); void emitScreenUpdated(unsigned req_num); void setTimer(); @@ -279,12 +224,17 @@ class WindowManager const char *check_surface_exist(const char *role); private: - std::unordered_map area2size; + std::map map_afb_event; + std::unordered_map area2size; std::unordered_map roleold2new; std::unordered_map rolenew2old; - + std::shared_ptr lc; PMWrapper pmw; + rect_map area_info; + struct id_allocator id_alloc; + // ID allocation and proxy methods for lookup + std::unordered_map tmp_surface2app; static const char* kDefaultOldRoleDb; }; diff --git a/src/wm_layer.cpp b/src/wm_layer.cpp index 6a98884..c702651 100644 --- a/src/wm_layer.cpp +++ b/src/wm_layer.cpp @@ -15,338 +15,34 @@ */ #include - +#include +#include +#include "wm_client.hpp" #include "wm_layer.hpp" #include "json_helper.hpp" #include "util.hpp" -namespace wm -{ - -using json = nlohmann::json; - -layer::layer(nlohmann::json const &j) -{ - this->role = j["role"]; - this->name = j["name"]; - this->layer_id = j["layer_id"]; - - HMI_DEBUG("layer_id:%d name:%s", this->layer_id, this->name.c_str()); -} - -struct result to_layer_map(nlohmann::json const &j) -{ - try - { - layer_map stl{}; - auto m = j["mappings"]; - - std::transform(std::cbegin(m), std::cend(m), - std::inserter(stl.mapping, stl.mapping.end()), - [](nlohmann::json const &j) { - return std::pair( - j.value("layer_id", -1), layer(j)); - }); - - // TODO: add sanity checks here? - // * check for double IDs - // * check for double names/roles - - stl.layers.reserve(m.size()); - std::transform(std::cbegin(stl.mapping), std::cend(stl.mapping), - std::back_inserter(stl.layers), - [&stl](std::pair const &k) { - stl.roles.emplace_back( - std::make_pair(k.second.role, k.second.layer_id)); - return unsigned(k.second.layer_id); - }); - - std::sort(stl.layers.begin(), stl.layers.end()); - - for (auto i : stl.mapping) - { - if (i.second.name.empty()) - { - return Err("Found mapping w/o name"); - } - if (i.second.layer_id == -1) - { - return Err("Found invalid/unset IDs in mapping"); - } - } - - auto msi = j.find("main_surface"); - if (msi != j.end()) - { - stl.main_surface_name = msi->value("surface_role", ""); - stl.main_surface = -1; - } - - return Ok(stl); - } - catch (std::exception &e) - { - return Err(e.what()); - } -} - -optional -layer_map::get_layer_id(int surface_id) -{ - auto i = this->surfaces.find(surface_id); - if (i != this->surfaces.end()) - { - return optional(i->second); - } - return nullopt; -} - -optional layer_map::get_layer_id(std::string const &role) -{ - for (auto const &r : this->roles) - { - auto re = std::regex(r.first); - if (std::regex_match(role, re)) - { - HMI_DEBUG("role %s matches layer %d", role.c_str(), r.second); - return optional(r.second); - } - } - HMI_DEBUG("role %s does NOT match any layer", role.c_str()); - return nullopt; -} - -json layer::to_json() const -{ - auto is_full = this->rect == compositor::full_rect; - - json r{}; - if (is_full) - { - r = {{"type", "full"}}; - } - else - { - r = {{"type", "rect"}, - {"rect", - {{"x", this->rect.x}, - {"y", this->rect.y}, - {"width", this->rect.w}, - {"height", this->rect.h}}}}; - } - - return { - {"name", this->name}, - {"role", this->role}, - {"layer_id", this->layer_id}, - {"area", r}, - }; -} +using std::string; -json layer_map::to_json() const +namespace wm { - json j{}; - for (auto const &i : this->mapping) - { - j.push_back(i.second.to_json()); - } - return j; -} -void layer_map::setupArea(double scaling) +WMLayer::WMLayer(json_object* j) { - compositor::rect rct; - - rct = this->area2size["normal.full"]; - this->area2size["normalfull"] = rct; - this->area2size["normal"] = rct; - - for (auto &i : this->area2size) - { - i.second.x = static_cast(scaling * i.second.x + 0.5); - i.second.y = static_cast(scaling * i.second.y + 0.5); - i.second.w = static_cast(scaling * i.second.w + 0.5); - i.second.h = static_cast(scaling * i.second.h + 0.5); - - HMI_DEBUG("area:%s size(after) : x:%d y:%d w:%d h:%d", - i.first.c_str(), i.second.x, i.second.y, i.second.w, i.second.h); - } -} - -compositor::rect layer_map::getAreaSize(const std::string &area) -{ - return area2size[area]; + this->name = jh::getStringFromJson(j, "name"); + this->role_list = jh::getStringFromJson(j, "role"); + this->layer_id = static_cast(jh::getIntFromJson(j, "layer_id")); } -int layer_map::loadAreaDb() +bool WMLayer::hasRole(const string& role) { - // Get afm application installed dir - char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR"); - HMI_DEBUG("afm_app_install_dir:%s", afm_app_install_dir); - - std::string file_name; - if (!afm_app_install_dir) - { - HMI_ERROR("AFM_APP_INSTALL_DIR is not defined"); - } - else - { - file_name = std::string(afm_app_install_dir) + std::string("/etc/areas.db"); - } - - // Load area.db - json_object *json_obj; - int ret = jh::inputJsonFilie(file_name.c_str(), &json_obj); - if (0 > ret) - { - HMI_DEBUG("Could not open area.db, so use default area information"); - json_obj = json_tokener_parse(kDefaultAreaDb); - } - HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj)); - - // Perse areas - HMI_DEBUG("Perse areas"); - json_object *json_cfg; - if (!json_object_object_get_ex(json_obj, "areas", &json_cfg)) + auto re = std::regex(this->role_list); + if (std::regex_match(role, re)) { - HMI_ERROR("Parse Error!!"); - return -1; + HMI_DEBUG("role %s matches layer %s", role.c_str(), this->name.c_str()); + return true; } - - int len = json_object_array_length(json_cfg); - HMI_DEBUG("json_cfg len:%d", len); - HMI_DEBUG("json_cfg dump:%s", json_object_get_string(json_cfg)); - - const char *area; - for (int i = 0; i < len; i++) - { - json_object *json_tmp = json_object_array_get_idx(json_cfg, i); - HMI_DEBUG("> json_tmp dump:%s", json_object_get_string(json_tmp)); - - area = jh::getStringFromJson(json_tmp, "name"); - if (nullptr == area) - { - HMI_ERROR("Parse Error!!"); - return -1; - } - HMI_DEBUG("> area:%s", area); - - json_object *json_rect; - if (!json_object_object_get_ex(json_tmp, "rect", &json_rect)) - { - HMI_ERROR("Parse Error!!"); - return -1; - } - HMI_DEBUG("> json_rect dump:%s", json_object_get_string(json_rect)); - - compositor::rect area_size; - area_size.x = jh::getIntFromJson(json_rect, "x"); - area_size.y = jh::getIntFromJson(json_rect, "y"); - area_size.w = jh::getIntFromJson(json_rect, "w"); - area_size.h = jh::getIntFromJson(json_rect, "h"); - - this->area2size[area] = area_size; - } - - // Check - for (auto itr = this->area2size.begin(); - itr != this->area2size.end(); ++itr) - { - HMI_DEBUG("area:%s x:%d y:%d w:%d h:%d", - itr->first.c_str(), itr->second.x, itr->second.y, - itr->second.w, itr->second.h); - } - - // Release json_object - json_object_put(json_obj); - - return 0; + return false; } -const char* layer_map::kDefaultAreaDb = "{ \ - \"areas\": [ \ - { \ - \"name\": \"fullscreen\", \ - \"rect\": { \ - \"x\": 0, \ - \"y\": 0, \ - \"w\": 1080, \ - \"h\": 1920 \ - } \ - }, \ - { \ - \"name\": \"normal.full\", \ - \"rect\": { \ - \"x\": 0, \ - \"y\": 218, \ - \"w\": 1080, \ - \"h\": 1488 \ - } \ - }, \ - { \ - \"name\": \"split.main\", \ - \"rect\": { \ - \"x\": 0, \ - \"y\": 218, \ - \"w\": 1080, \ - \"h\": 744 \ - } \ - }, \ - { \ - \"name\": \"split.sub\", \ - \"rect\": { \ - \"x\": 0, \ - \"y\": 962, \ - \"w\": 1080, \ - \"h\": 744 \ - } \ - }, \ - { \ - \"name\": \"software_keyboard\", \ - \"rect\": { \ - \"x\": 0, \ - \"y\": 962, \ - \"w\": 1080, \ - \"h\": 744 \ - } \ - }, \ - { \ - \"name\": \"restriction.normal\", \ - \"rect\": { \ - \"x\": 0, \ - \"y\": 218, \ - \"w\": 1080, \ - \"h\": 1488 \ - } \ - }, \ - { \ - \"name\": \"restriction.split.main\", \ - \"rect\": { \ - \"x\": 0, \ - \"y\": 218, \ - \"w\": 1080, \ - \"h\": 744 \ - } \ - }, \ - { \ - \"name\": \"restriction.split.sub\", \ - \"rect\": { \ - \"x\": 0, \ - \"y\": 962, \ - \"w\": 1080, \ - \"h\": 744 \ - } \ - }, \ - { \ - \"name\": \"on_screen\", \ - \"rect\": { \ - \"x\": 0, \ - \"y\": 218, \ - \"w\": 1080, \ - \"h\": 1488 \ - } \ - } \ - ] \ -}"; - } // namespace wm diff --git a/src/wm_layer.hpp b/src/wm_layer.hpp index 4dd4616..1d9435b 100644 --- a/src/wm_layer.hpp +++ b/src/wm_layer.hpp @@ -14,145 +14,40 @@ * limitations under the License. */ -#ifndef WM_LAYERS_H -#define WM_LAYERS_H +#ifndef WM_LAYER_HPP +#define WM_LAYER_HPP #include +#include +#include +#include +#include "wm_error.hpp" -#include "../include/json.hpp" -#include "layout.hpp" -#include "result.hpp" -#include "wayland_ivi_wm.hpp" +struct json_object; namespace wm { -struct layer +class WMLayer { - using json = nlohmann::json; - + public: + explicit WMLayer(json_object* j); + ~WMLayer() = default; // A more or less descriptive name? + const std::string& layerName(){ return this->role_list;} + unsigned layerID(){ return this->layer_id;} + const std::string& roleList(); + bool hasRole(const std::string& role); + private: std::string name = ""; // The actual layer ID - int layer_id = -1; - // The rectangular region surfaces are allowed to draw on - // this layer. - compositor::rect rect; + int layer_id = 0; + // Specify a role prefix for surfaces that should be // put on this layer. - std::string role; - - mutable struct LayoutState state; - - explicit layer(nlohmann::json const &j); - - json to_json() const; + std::string role_list; }; -struct layer_map -{ - using json = nlohmann::json; - - using storage_type = std::map; - using layers_type = std::vector; - using role_to_layer_map = std::vector>; - using addsurf_layer_map = std::map; - - storage_type mapping; // map surface_id to layer - layers_type layers; // the actual layer IDs we have - int main_surface; - std::string main_surface_name; - role_to_layer_map roles; - addsurf_layer_map surfaces; // additional surfaces on layers - - optional get_layer_id(int surface_id); - optional get_layer_id(std::string const &role); - optional get_layout_state(int surface_id) - { - int layer_id = *this->get_layer_id(surface_id); - auto i = this->mapping.find(layer_id); - return i == this->mapping.end() - ? nullopt - : optional(&i->second.state); - } - optional get_layer(int layer_id) - { - auto i = this->mapping.find(layer_id); - return i == this->mapping.end() ? nullopt - : optional(i->second); - } - - layers_type::size_type get_layers_count() const - { - return this->layers.size(); - } - - void add_surface(int surface_id, int layer_id) - { - this->surfaces[surface_id] = layer_id; - } - - void remove_surface(int surface_id) - { - this->surfaces.erase(surface_id); - } - - json to_json() const; - void setupArea(double scaling); - compositor::rect getAreaSize(const std::string &area); - int loadAreaDb(); - - private: - std::unordered_map area2size; - - static const char *kDefaultAreaDb; -}; - -struct result to_layer_map(nlohmann::json const &j); - -static const nlohmann::json default_layers_json = { - {"main_surface", { - {"surface_role", "HomeScreen"} - }}, - {"mappings", { - { - {"role", "^HomeScreen$"}, - {"name", "HomeScreen"}, - {"layer_id", 1000}, - {"area", { - {"type", "full"} - }} - }, - { - {"role", "MediaPlayer|Radio|Phone|Navigation|HVAC|Settings|Dashboard|POI|Mixer"}, - {"name", "apps"}, - {"layer_id", 1001}, - {"area", { - {"type", "rect"}, - {"rect", { - {"x", 0}, - {"y", 218}, - {"width", -1}, - {"height", -433} - }} - }} - }, - { - {"role", "^OnScreen.*"}, - {"name", "popups"}, - {"layer_id", 9999}, - {"area", { - {"type", "rect"}, - {"rect", { - {"x", 0}, - {"y", 760}, - {"width", -1}, - {"height", 400} - }} - }} - } - }} -}; } // namespace wm -#endif // WM_LAYERS_H +#endif // WM_LAYER_HPP diff --git a/src/wm_layer_control.cpp b/src/wm_layer_control.cpp new file mode 100644 index 0000000..951c840 --- /dev/null +++ b/src/wm_layer_control.cpp @@ -0,0 +1,594 @@ +/* + * Copyright (c) 2017 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include "wm_layer_control.hpp" +#include "wm_layer.hpp" +#include "wm_client.hpp" +#include "request.hpp" +#include "json_helper.hpp" + +#define LC_AREA_PATH "/etc/areas.db" +#define LC_LAYER_SETTING_PATH "/etc/layers.json" +#define LC_DEFAULT_AREA "fullscreen" +#define BACK_GROUND_LAYER "BackGroundLayer" + +using std::string; +using std::vector; +using std::shared_ptr; + +namespace wm { + +LayerControl* g_lc_ctxt; + +static void createCallback_static(ilmObjectType object, + t_ilm_uint id, + t_ilm_bool created, + void* data) +{ + static_cast(data)->dispatchCreateEvent(object, id, created); +} + +static void surfaceCallback_static(t_ilm_surface surface, + struct ilmSurfaceProperties* surface_prop, + t_ilm_notification_mask mask) +{ + g_lc_ctxt->dispatchSurfacePropChangeEvent(surface, surface_prop, mask); +} + +static void layerCallback_static(t_ilm_layer layer, + struct ilmLayerProperties* layer_prop, + t_ilm_notification_mask mask) +{ + g_lc_ctxt->dispatchLayerPropChangeEvent(layer, layer_prop, mask); +} + +LayerControl::LayerControl(const std::string& root) +{ + string area_path = root + LC_AREA_PATH; + string layer_path= root + LC_LAYER_SETTING_PATH; + // load layers.setting.json + WMError ret = this->loadLayerSetting(layer_path); + assert(ret == WMError::SUCCESS); + // load areas.json + ret = this->loadAreaDb(area_path); + assert(ret == WMError::SUCCESS); +} + +WMError LayerControl::init(const LayerControlCallbacks& cb) +{ + HMI_DEBUG("Initialize of ilm library and display"); + t_ilm_uint num = 0; + t_ilm_uint *ids; + int cnt = 0; + ilmErrorTypes rc = ilm_init(); + + while (rc != ILM_SUCCESS) + { + cnt++; + if (20 <= cnt) + { + HMI_ERROR("Could not connect to compositor"); + goto lc_init_error; + } + HMI_ERROR("Wait to start weston ..."); + sleep(1); + rc = ilm_init(); + } + if(rc != ILM_SUCCESS) goto lc_init_error; + + // Get current screen setting + rc = ilm_getScreenIDs(&num, &ids); + + if(rc != ILM_SUCCESS) goto lc_init_error; + + for(unsigned i = 0; i < num; i++) + { + HMI_INFO("get screen: %d", ids[i]); + } + // Currently, 0 is only available + this->screenID = ids[0]; + + rc = ilm_getPropertiesOfScreen(this->screenID, &this->screen_prop); + + if(rc != ILM_SUCCESS) goto lc_init_error; + + // Register Callback to Window Manager and from ILM + this->cb = cb; + ilm_registerNotification(createCallback_static, this); + + return WMError::SUCCESS; + +lc_init_error: + HMI_ERROR("Failed to initialize. Terminate WM"); + + return WMError::FAIL; +} + +unsigned LayerControl::getLayerID(const string& role) +{ + unsigned ret = 0; + for(const auto& l: this->wm_layers) + { + if(l->hasRole(role)) + { + ret = l->layerID(); + } + } + return ret; +} + +void LayerControl::addSurface(unsigned surface, unsigned layer) +{ + ilm_layerAddSurface(layer, surface); + ilm_commitChanges(); +} + +void LayerControl::createLayers() +{ + for(const auto &layer : this->wm_layers) + { + unsigned id = layer->layerID(); + HMI_INFO("create new ID :%d", id); + struct rect rct = this->area2size[LC_DEFAULT_AREA]; + ilm_layerCreateWithDimension(&id, rct.w, rct.h); + //ilm_layerSetSourceRectangle(id, rct.x, rct.y, rct.w, rct.h); + ilm_layerSetDestinationRectangle(id, this->offset_x, this->offset_y, rct.w, rct.h); + ilm_layerSetOpacity(id, 1.0); + ilm_layerSetVisibility(id, ILM_TRUE); + ilm_commitChanges(); + /* auto wm_layer = getWMLayer(id); + wm_layer->addLayerToState(id); */ + } + this->renderLayers(); +} + +shared_ptr LayerControl::getWMLayer(unsigned layer) +{ + unsigned uuid = this->lid2wmlid[layer]; + return this->wm_layers[uuid]; +} + +std::shared_ptr LayerControl::getWMLayer(std::string layer_name) +{ + for(auto &l : this->wm_layers) + { + if(l->layerName() == layer_name) + { + return l; + } + } + return nullptr; +} + +struct rect LayerControl::getAreaSize(const std::string& area) +{ + return area2size[area]; +} + +void LayerControl::setupArea(const rectangle& base_rct, double scaling) +{ + this->scaling = scaling; + this->offset_x = base_rct.left(); + this->offset_y = base_rct.top(); + + for (auto &i : this->area2size) + { + i.second.x = static_cast(scaling * i.second.x + 0.5); + i.second.y = static_cast(scaling * i.second.y + 0.5); + i.second.w = static_cast(scaling * i.second.w + 0.5); + i.second.h = static_cast(scaling * i.second.h + 0.5); + + HMI_DEBUG("area:%s size(after) : x:%d y:%d w:%d h:%d", + i.first.c_str(), i.second.x, i.second.y, i.second.w, i.second.h); + } +} + +Screen LayerControl::getScreenInfo() +{ + return Screen(this->screen_prop.screenWidth, this->screen_prop.screenHeight); +} + +double LayerControl::scale() +{ + return this->scaling; +} + +WMError LayerControl::renderLayers() +{ + HMI_INFO("Commit change"); + WMError rc = WMError::SUCCESS; + + // Create render order + t_ilm_layer* id_array = new t_ilm_layer[this->wm_layers.size()]; + if(id_array == nullptr) + { + HMI_WARNING("short memory"); + return WMError::FAIL; + } + int count = 0; + for(const auto& i : this->wm_layers) + { + id_array[count] = i->layerID(); + ++count; + } + + // Display + ilmErrorTypes ret = ilm_displaySetRenderOrder(this->screenID, id_array, this->wm_layers.size()); + if(ret != ILM_SUCCESS) + { + rc = WMError::FAIL; + } + ilm_commitChanges(); + delete id_array; + return rc; +} + +WMError LayerControl::setXDGSurfaceOriginSize(unsigned surface) +{ + WMError ret = WMError::NOT_REGISTERED; + ilmSurfaceProperties prop; + ilmErrorTypes rc = ilm_getPropertiesOfSurface(surface, &prop); + if(rc == ILM_SUCCESS) + { + HMI_INFO("xdg surface info %d, %d", prop.origSourceWidth, prop.origSourceHeight); + ilm_surfaceSetSourceRectangle(surface, 0, 0, prop.origSourceWidth, prop.origSourceHeight); + ret = WMError::SUCCESS; + } + return ret; +} + +WMError LayerControl::loadLayerSetting(const string &path) +{ + HMI_DEBUG("loading WMLayer(Application Containers) Setting from %s", path); + + json_object *json_obj, *json_cfg; + int ret = jh::inputJsonFilie(path.c_str(), &json_obj); + if (0 > ret) + { + HMI_ERROR("Could not open %s", path.c_str()); + return WMError::FAIL; + } + HMI_INFO("json_obj dump:%s", json_object_get_string(json_obj)); + + if (!json_object_object_get_ex(json_obj, "mappings", &json_cfg)) + { + HMI_ERROR("Parse Error!!"); + return WMError::FAIL; + } + + int len = json_object_array_length(json_cfg); + HMI_DEBUG("json_cfg len:%d", len); + + for (int i = 0; i < len; i++) + { + json_object *json_tmp = json_object_array_get_idx(json_cfg, i); + HMI_DEBUG("> json_tmp dump:%s", json_object_get_string(json_tmp)); + + this->wm_layers.emplace_back(std::make_shared(json_tmp)); + } + json_object_put(json_obj); + + return WMError::SUCCESS; +} + +WMError LayerControl::loadAreaDb(const std::string& path) +{ + // Load area.db + json_object *json_obj; + int ret = jh::inputJsonFilie(path.c_str(), &json_obj); + if (0 > ret) + { + HMI_ERROR("Could not open %s", path.c_str()); + return WMError::FAIL; + } + HMI_INFO("json_obj dump:%s", json_object_get_string(json_obj)); + + // Perse areas + json_object *json_cfg; + if (!json_object_object_get_ex(json_obj, "areas", &json_cfg)) + { + HMI_ERROR("Parse Error!!"); + return WMError::FAIL; + } + + int len = json_object_array_length(json_cfg); + HMI_DEBUG("json_cfg len:%d", len); + + const char *area; + for (int i = 0; i < len; i++) + { + json_object *json_tmp = json_object_array_get_idx(json_cfg, i); + HMI_DEBUG("> json_tmp dump:%s", json_object_get_string(json_tmp)); + + area = jh::getStringFromJson(json_tmp, "name"); + if (nullptr == area) + { + HMI_ERROR("Parse Error!!"); + return WMError::FAIL; + } + HMI_DEBUG("> area:%s", area); + + json_object *json_rect; + if (!json_object_object_get_ex(json_tmp, "rect", &json_rect)) + { + HMI_ERROR("Parse Error!!"); + return WMError::FAIL; + } + HMI_DEBUG("> json_rect dump:%s", json_object_get_string(json_rect)); + + struct rect area_size; + area_size.x = jh::getIntFromJson(json_rect, "x"); + area_size.y = jh::getIntFromJson(json_rect, "y"); + area_size.w = jh::getIntFromJson(json_rect, "w"); + area_size.h = jh::getIntFromJson(json_rect, "h"); + + this->area2size[area] = area_size; + } + + // Check + for (const auto& itr : this->area2size) + { + HMI_DEBUG("area:%s x:%d y:%d w:%d h:%d", + itr.first.c_str(), itr.second.x, itr.second.y, + itr.second.w, itr.second.h); + } + + // Release json_object + json_object_put(json_obj); + + return WMError::SUCCESS; +} + +WMError LayerControl::layoutChange(const WMAction& action) +{ + if (action.visible == TaskVisible::INVISIBLE) + { + // Visibility is not change -> no redraw is required + return WMError::SUCCESS; + } + if(action.client == nullptr) + { + HMI_SEQ_ERROR(action.req_num, "client may vanish"); + return WMError::NOT_REGISTERED; + } + unsigned surface = action.client->surfaceID(action.role); + + auto rect = this->getAreaSize(action.area); + HMI_DEBUG("Set layout %d, %d, %d, %d",rect.x, rect.y, rect.w, rect.h); + ilm_commitChanges(); + ilm_surfaceSetDestinationRectangle(surface, rect.x, rect.y, rect.w, rect.h); + ilm_commitChanges(); + + return WMError::SUCCESS; +} + +WMError LayerControl::visibilityChange(const WMAction& action) +{ + WMError ret = WMError::FAIL; + if(action.client == nullptr) + { + HMI_SEQ_ERROR(action.req_num, "client may vanish"); + return WMError::NOT_REGISTERED; + } + + if (action.visible == TaskVisible::VISIBLE) + { + ret = this->makeVisible(action.client, action.role); + } + else if (action.visible == TaskVisible::INVISIBLE) + { + ret = this->makeInvisible(action.client, action.role); + } + ilm_commitChanges(); + return ret; +} + +void LayerControl::dispatchCreateEvent(ilmObjectType object, unsigned id, bool created) +{ + if (ILM_SURFACE == object) + { + if (created) + { + ilmSurfaceProperties sp; + ilmErrorTypes rc; + rc = ilm_getPropertiesOfSurface(id, &sp); + if(rc != ILM_SUCCESS) + { + HMI_ERROR("Failed to get surface %d property due to %d", id, ilm_getError()); + return; + } + this->cb.surfaceCreated(sp.creatorPid, id); + ilm_surfaceAddNotification(id, surfaceCallback_static); + ilm_surfaceSetType(id, ILM_SURFACETYPE_DESKTOP); + } + else + { + this->cb.surfaceDestroyed(id); + } + } + if (ILM_LAYER == object) + { + if(created) + { + ilm_layerAddNotification(id, layerCallback_static); + } + else + { + // Ignore here. Nothing to do currently. + // Process of application dead is handled by Window Manager + // from binder notification + } + } +} + +void LayerControl::dispatchSurfacePropChangeEvent(unsigned id, + struct ilmSurfaceProperties* sprop, + t_ilm_notification_mask mask) +{ + /* + ILM_NOTIFICATION_CONTENT_AVAILABLE & ILM_NOTIFICATION_CONTENT_REMOVED + are not handled here, handled in create/destroy event + */ + if (ILM_NOTIFICATION_VISIBILITY & mask) + { + HMI_DEBUG("surface %d turns visibility %d", id, sprop->visibility); + } + if (ILM_NOTIFICATION_OPACITY & mask) + { + HMI_DEBUG("surface %d turns opacity %f", id, sprop->opacity); + } + if (ILM_NOTIFICATION_SOURCE_RECT & mask) + { + HMI_DEBUG("surface %d source rect changes", id); + } + if (ILM_NOTIFICATION_DEST_RECT & mask) + { + HMI_DEBUG("surface %d dest rect changes", id); + } + if (ILM_NOTIFICATION_CONFIGURED & mask) + { + HMI_DEBUG("surface %d size %d, %d, %d, %d", id, + sprop->sourceX, sprop->sourceY, sprop->origSourceWidth, sprop->origSourceHeight); + ilm_surfaceSetSourceRectangle(id, 0, 0, sprop->origSourceWidth, sprop->origSourceHeight); + } +} + +void LayerControl::dispatchLayerPropChangeEvent(unsigned id, + struct ilmLayerProperties* lprop, + t_ilm_notification_mask mask) +{ + if (ILM_NOTIFICATION_VISIBILITY & mask) + { + HMI_DEBUG("layer %d turns visibility %d", id, lprop->visibility); + } + if (ILM_NOTIFICATION_OPACITY & mask) + { + HMI_DEBUG("layer %d turns opacity %f", id, lprop->opacity); + } + if (ILM_NOTIFICATION_SOURCE_RECT & mask) + { + HMI_DEBUG("layer %d source rect changes", id); + } + if (ILM_NOTIFICATION_DEST_RECT & mask) + { + HMI_DEBUG("layer %d dest rect changes", id); + } +} + +WMError LayerControl::makeVisible(const shared_ptr client, const string& role) +{ + WMError ret = WMError::SUCCESS; + // Don't check here the client is not nullptr + unsigned surface = client->surfaceID(role); + + this->moveForeGround(client, role); + + ilm_surfaceSetVisibility(surface, ILM_TRUE); + + return ret; +} + +WMError LayerControl::makeInvisible(const shared_ptr client, const string& role) +{ + WMError ret = WMError::SUCCESS; + unsigned surface = client->surfaceID(role); // Don't check here the client is not nullptr + + bool mv_ok = this->moveBackGround(client, role); + + if(!mv_ok) + { + HMI_INFO("make invisible client %s", client->appID().c_str()); + ilm_surfaceSetVisibility(surface, ILM_FALSE); + } + + return ret; +} + +bool LayerControl::moveBackGround(const shared_ptr client, const string& role) +{ + bool ret = false; + const char* label = role.c_str(); + + if ((0 == strcmp(label, "radio")) || + (0 == strcmp(label, "music")) || + (0 == strcmp(label, "video")) || + (0 == strcmp(label, "map"))) + { + unsigned surface = client->surfaceID(role); + this->surface_bg.push_back(surface); + auto bg = this->getWMLayer(BACK_GROUND_LAYER); + auto layer = 0; + for(const auto& l : this->wm_layers) + { + if(l->hasRole(role)) + { + layer = l->layerID(); + ilm_layerRemoveSurface(layer, surface); + ilm_layerAddSurface(bg->layerID(), surface); + ret = true; + break; + } + } + } + ilm_commitChanges(); + return ret; +} + +bool LayerControl::moveForeGround(const shared_ptr client, const string& role) +{ + bool ret = false; + const char* label = role.c_str(); + + // Move foreground from foreground layer + if ((0 == strcmp(label, "radio")) || + (0 == strcmp(label, "music")) || + (0 == strcmp(label, "video")) || + (0 == strcmp(label, "map"))) + { + for (auto i = surface_bg.begin(); i != surface_bg.end(); ++i) + { + if (client->surfaceID(role) == *i) + { + // Remove id + unsigned surface = *i; + + this->surface_bg.erase(i); + + // Remove from BG layer (999) + HMI_DEBUG("wm", "Remove %s(%d) from BG layer", label, surface); + auto bg = this->getWMLayer(BACK_GROUND_LAYER); + unsigned layer = 0; + for(const auto& l : this->wm_layers) + { + if(l->hasRole(role)) + { + layer = l->layerID(); + break; + } + } + ilm_layerRemoveSurface(bg->layerID(), surface); + ilm_layerAddSurface(layer, surface); + ret = true; + break; + } + } + } + ilm_commitChanges(); + return ret; +} + +} // namespace wm \ No newline at end of file diff --git a/src/wm_layer_control.hpp b/src/wm_layer_control.hpp new file mode 100644 index 0000000..5244bf5 --- /dev/null +++ b/src/wm_layer_control.hpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2017 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include "wm_error.hpp" +#include "util.hpp" + +namespace wm { + +class Screen { + public: + Screen(unsigned w, unsigned h) : _width(w), _height(h){} + unsigned width() { return _width; } + unsigned height() { return _height; } + private: + unsigned _width; + unsigned _height; + unsigned _pysical_width = 0; + unsigned _pysical_height = 0; +}; + +class LayerControlCallbacks { + public: + LayerControlCallbacks() {}; + ~LayerControlCallbacks() = default; + LayerControlCallbacks(const LayerControlCallbacks &obj) = default; + + // callback functions + std::function surfaceCreated; + std::function surfaceDestroyed; + /* + std::function layerCreated; + std::function layerDestroyed; + */ +}; + +class WMLayer; +class LayerState; +class WMAction; +class WMClient; + +class LayerControl +{ + public: + explicit LayerControl(const std::string& root); + ~LayerControl() = default; + WMError init(const LayerControlCallbacks& cb); + void createLayers(); + unsigned getLayerID(const std::string& role); + std::shared_ptr getWMLayer(unsigned layer); + std::shared_ptr getWMLayer(std::string layer_name); + struct rect getAreaSize(const std::string& area); + void setupArea(const rectangle& base_rct, double scaling); + Screen getScreenInfo(); + double scale(); + WMError renderLayers(); + WMError setXDGSurfaceOriginSize(unsigned surface); + WMError layoutChange(const WMAction& action); + WMError visibilityChange(const WMAction &action); + void addSurface(unsigned surface, unsigned layer); + + // Don't use this function. + void dispatchCreateEvent(ilmObjectType object, unsigned id, bool created); + void dispatchSurfacePropChangeEvent(unsigned id, struct ilmSurfaceProperties*, t_ilm_notification_mask); + void dispatchLayerPropChangeEvent(unsigned id, struct ilmLayerProperties*, t_ilm_notification_mask); + + private: + WMError makeVisible(const std::shared_ptr client, const std::string& role); + WMError makeInvisible(const std::shared_ptr client, const std::string& role); + bool moveForeGround(const std::shared_ptr client, const std::string& role); + bool moveBackGround(const std::shared_ptr client, const std::string& role); + WMError loadLayerSetting(const std::string& path); + WMError loadAreaDb(const std::string& path); + + std::vector surface_bg; // For CES demo + std::vector> wm_layers; + std::unordered_map lid2wmlid; + std::unordered_map area2size; + unsigned screenID; + struct ilmScreenProperties screen_prop; + double scaling; + int offset_x; + int offset_y; + LayerControlCallbacks cb; +}; + +} // namespace wm \ No newline at end of file -- cgit 1.2.3-korg