summaryrefslogtreecommitdiffstats
path: root/demo3/common/libwindowmanager/src/libwindowmanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'demo3/common/libwindowmanager/src/libwindowmanager.cpp')
-rw-r--r--demo3/common/libwindowmanager/src/libwindowmanager.cpp1218
1 files changed, 1218 insertions, 0 deletions
diff --git a/demo3/common/libwindowmanager/src/libwindowmanager.cpp b/demo3/common/libwindowmanager/src/libwindowmanager.cpp
new file mode 100644
index 0000000..dfc0886
--- /dev/null
+++ b/demo3/common/libwindowmanager/src/libwindowmanager.cpp
@@ -0,0 +1,1218 @@
+/*
+ * 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 "libwindowmanager.h"
+#include "hmi-debug.h"
+
+#include <atomic>
+#include <map>
+#include <mutex>
+#include <set>
+#include <queue>
+#include <unistd.h>
+#include <pthread.h>
+
+extern "C" {
+#include <afb/afb-ws-client.h>
+#include <afb/afb-wsj1.h>
+#include <systemd/sd-event.h>
+}
+
+#define UNUSED(x) (void)(x)
+
+namespace {
+ /* Key for json obejct */
+ static const char g_kKeyDrawingName[] = "drawing_name";
+ static const char g_kKeyDrawingArea[] = "drawing_area";
+ static const char g_kKeyDrawingRect[] = "drawing_rect";
+ static const char g_kKeyResponse[] = "response";
+}
+
+/**
+ * @class LibWindowmanager::Impl
+ */
+class LibWindowmanager::Impl {
+ public:
+
+ Impl();
+ ~Impl();
+
+ // This is the LibWindowmanager interface impl
+ int init(int port, char const *token);
+
+ // WM API
+ int requestSurface(json_object *object);
+ int requestSurfaceXDG(json_object *object);
+ int activateWindow(json_object *object);
+ int deactivateWindow(json_object *object);
+ int endDraw(json_object *object);
+
+ int getDisplayInfo(json_object *object);
+ int getAreaInfo(json_object *in_obj, json_object *out_obj);
+ struct Screen getScreenInfo() {return this->_screen;};
+
+ void set_event_handler(enum EventType et, handler_fun func);
+ void setEventHandler(const WMHandler &wmh);
+
+ int api_call(const char *verb, json_object *object,
+ const std::function<void(bool, json_object *)> &onReply);
+ void event(char const *et, json_object *object);
+ void event(char const *et);
+private:
+ int runEventLoop();
+
+ struct afb_wsj1 *wsj1;
+ struct sd_event *loop;
+
+ std::set<std::string> labels;
+ std::map<EventType, handler_fun> handlers;
+ std::queue<std::pair<handler_fun, std::string>> handler_queue;
+
+ const std::vector<std::string> kListEventName{
+ std::string("active"),
+ std::string("inactive"),
+ std::string("visible"),
+ std::string("invisible"),
+ std::string("syncDraw"),
+ std::string("flushDraw"),
+ std::string("screenUpdated"),
+ std::string("headlampOff"),
+ std::string("headlampOn"),
+ std::string("parkingBrakeOff"),
+ std::string("parkingBrakeOn"),
+ std::string("lightstatusBrakeOff"),
+ std::string("lightstatusBrakeOn"),
+ std::string("carStop"),
+ std::string("carRun"),
+ std::string("error")
+ };
+
+ struct Screen _screen;
+ WMHandler _wmh;
+};
+
+namespace {
+
+constexpr const char *const wmAPI = "windowmanager";
+
+#define CONCAT_(X, Y) X##Y
+#define CONCAT(X, Y) CONCAT_(X, Y)
+
+#ifndef SCOPE_TRACING
+#define TRACE()
+#define TRACEN(N)
+#else
+#define TRACE() \
+ ScopeTrace __attribute__((unused)) CONCAT(trace_scope_, __LINE__)(__func__)
+#define TRACEN(N) \
+ ScopeTrace __attribute__((unused)) CONCAT(named_trace_scope_, __LINE__)(#N)
+
+struct ScopeTrace {
+ thread_local static int indent;
+ char const *f{};
+ explicit ScopeTrace(char const *func) : f(func) {
+ fprintf(stderr, "%*s%s -->\n", 2 * indent++, "", this->f);
+ }
+ ~ScopeTrace() { fprintf(stderr, "%*s%s <--\n", 2 * --indent, "", this->f); }
+};
+thread_local int ScopeTrace::indent = 0;
+#endif
+
+/* called when wsj1 receives a method invocation */
+void onCall(void *closure, const char *api, const char *verb,
+ struct afb_wsj1_msg *msg) {
+ TRACE();
+ UNUSED(closure);
+ UNUSED(verb);
+ UNUSED(api);
+ UNUSED(msg);
+}
+
+/* called when wsj1 receives an event */
+void onEvent(void *closure, const char *event, afb_wsj1_msg *msg) {
+ TRACE();
+ // check API name in event
+ if (0 != strncmp(wmAPI, event, strlen(wmAPI))) {
+ HMI_ERROR("libwm", "Unknown event: %s", event);
+ return;
+ }
+
+ json_object *j, *val;
+ j = afb_wsj1_msg_object_j(msg);
+ if (json_object_object_get_ex(j, "data", &val)) {
+ static_cast<LibWindowmanager::Impl *>(closure)->event(event, val);
+ }
+ else {
+ static_cast<LibWindowmanager::Impl *>(closure)->event(event);
+ }
+}
+
+/* called when wsj1 hangsup */
+void onHangup(void *closure, afb_wsj1 *wsj1) {
+ TRACE();
+ UNUSED(closure);
+ UNUSED(wsj1);
+ HMI_ERROR("libwm", "Hangup, the WindowManager vanished");
+}
+
+constexpr struct afb_wsj1_itf itf = {
+ onHangup, onCall, onEvent,
+};
+
+} // namespace
+
+/**
+ * @class LibWindowmanager::Impl::Impl
+ */
+LibWindowmanager::Impl::Impl()
+ : wsj1{}, loop{}, labels(), handlers(),
+ _screen{0,0,0,0,0.0},
+ _wmh()
+{}
+
+LibWindowmanager::Impl::~Impl() {
+ TRACE();
+ afb_wsj1_unref(wsj1);
+ sd_event_unref(loop);
+}
+
+int LibWindowmanager::Impl::init(int port, char const *token) {
+ TRACE();
+ HMI_DEBUG("libwm", "called");
+
+ char *uribuf = nullptr;
+ int rc = -1;
+
+ if (this->loop != nullptr && this->wsj1 != nullptr) {
+ HMI_ERROR("libwm", "LibWindowmanager instance is already initialized!");
+ rc = -EALREADY;
+ goto fail;
+ }
+
+ if (token == nullptr) {
+ HMI_ERROR("libwm", "Token is invalid");
+ rc = -EINVAL;
+ goto fail;
+ }
+
+ if (port < 1 || port > 0xffff) {
+ HMI_ERROR("libwm", "Port is invalid");
+ rc = -EINVAL;
+ goto fail;
+ }
+
+ /* get the default event loop */
+ rc = sd_event_default(&this->loop);
+ if (rc < 0) {
+ HMI_ERROR("libwm", "Connection to default event loop failed: %s",
+ strerror(-rc));
+ goto fail;
+ }
+
+ asprintf(&uribuf, "ws://localhost:%d/api?token=%s", port, token);
+
+ /* connect the websocket wsj1 to the uri given by the first argument */
+ this->wsj1 = afb_ws_client_connect_wsj1(
+ this->loop, uribuf, const_cast<struct afb_wsj1_itf *>(&itf), this);
+ if (this->wsj1 == nullptr) {
+ sd_event_unref(this->loop);
+ this->loop = nullptr;
+ HMI_ERROR("libwm", "Connection to %s failed: %m", uribuf);
+ rc = -errno;
+ goto fail;
+ }
+
+ this->runEventLoop();
+
+ return 0;
+
+fail:
+ return rc;
+}
+
+int LibWindowmanager::Impl::requestSurface(json_object *object) {
+ TRACE();
+ HMI_DEBUG("libwm", "called");
+
+ json_object *val;
+ const char *tmp_label;
+ if (json_object_object_get_ex(object, g_kKeyDrawingName, &val)) {
+ tmp_label = json_object_get_string(val);
+ }
+ else {
+ HMI_DEBUG("libwm", "Not found key \"%s\"", g_kKeyDrawingName);
+ return -EINVAL;
+ }
+
+ // DrawingName in "object" is overwrited in api_call("RequestSurface")
+ // So it is neccesary to copy it.
+ const char *label = std::string(tmp_label).c_str();
+
+ if (this->labels.find(label) != this->labels.end()) {
+ HMI_ERROR("libwm", "Surface label already known!");
+ return -EINVAL;
+ }
+
+ // Store application name first
+ // because it may not return from setenv
+ HMI_DEBUG("libwm", "Insert application name: %s\n", label);
+ this->labels.insert(this->labels.end(), label);
+
+ int rc = -1;
+ /* send the request */
+ int rc2 =
+ this->api_call("RequestSurface", object, [&rc](bool ok, json_object *j) {
+ if (ok) {
+ json_object *val;
+ if (json_object_object_get_ex(j, g_kKeyResponse, &val)) {
+ rc = json_object_get_int(val);
+ }
+ else {
+ HMI_ERROR("libwm", "Not found key \"response\"");
+ rc = -EINVAL;
+ return;
+ }
+ }
+ });
+
+ if (rc2 < 0) {
+ rc = rc2;
+ }
+
+ if (rc < 0) {
+ HMI_ERROR("libwm", "Erase application name: %s", label);
+ this->labels.erase(label);
+ }
+
+ return rc;
+}
+
+int LibWindowmanager::Impl::requestSurfaceXDG(json_object *object) {
+ TRACE();
+ HMI_DEBUG("libwm", "called");
+
+ json_object *val;
+ const char *tmp_label;
+ if (json_object_object_get_ex(object, g_kKeyDrawingName, &val)) {
+ tmp_label = json_object_get_string(val);
+ }
+ else {
+ HMI_DEBUG("libwm", "Not found key \"%s\"", g_kKeyDrawingName);
+ return -EINVAL;
+ }
+
+ // DrawingName in "object" is overwrited in api_call("RequestSurface")
+ // So it is neccesary to copy it.
+ const char *label = std::string(tmp_label).c_str();
+
+ if (this->labels.find(label) != this->labels.end()) {
+ HMI_ERROR("libwm", "Surface label already known!");
+ return -EINVAL;
+ }
+
+ // Store application name first
+ // because it may not return from setenv
+ HMI_DEBUG("libwm", "Insert application name: %s\n", label);
+ this->labels.insert(this->labels.end(), label);
+
+ /* send the request */
+ int rc = this->api_call("RequestSurfaceXDG", object, [](bool ok, json_object *j) {
+ if (!ok) {
+ HMI_ERROR("libwm", "Could not get surface ID from WM: %s",
+ j != nullptr ? json_object_to_json_string_ext(
+ j, JSON_C_TO_STRING_PRETTY)
+ : "no-info");
+ }
+ });
+
+ if (rc != 0) {
+ HMI_ERROR("libwm", "Erase application name: %s", label);
+ this->labels.erase(label);
+ }
+
+ return rc;
+}
+
+int LibWindowmanager::Impl::activateWindow(json_object *object) {
+ TRACE();
+ HMI_DEBUG("libwm", "called");
+ return this->api_call("ActivateWindow", object, [](bool ok, json_object *j) {
+ if (!ok) {
+ HMI_ERROR("libwm", "API Call activateWindow() failed: %s",
+ j != nullptr ? json_object_to_json_string_ext(
+ j, JSON_C_TO_STRING_PRETTY)
+ : "no-info");
+ }
+ });
+}
+
+int LibWindowmanager::Impl::deactivateWindow(json_object *object) {
+ TRACE();
+ HMI_DEBUG("libwm", "called");
+ return this->api_call("DeactivateWindow", object, [](bool ok, json_object *j) {
+ if (!ok) {
+ HMI_ERROR("libwm", "API Call deactivateWindow() failed: %s",
+ j != nullptr ? json_object_to_json_string_ext(
+ j, JSON_C_TO_STRING_PRETTY)
+ : "no-info");
+ }
+ });
+}
+
+int LibWindowmanager::Impl::endDraw(json_object *object) {
+ TRACE();
+ HMI_DEBUG("libwm", "called");
+ return this->api_call("EndDraw", object, [](bool ok, json_object *j) {
+ if (!ok) {
+ HMI_ERROR("libwm", "API Call endDraw() failed: %s",
+ j != nullptr ? json_object_to_json_string_ext(
+ j, JSON_C_TO_STRING_PRETTY)
+ : "no-info");
+ }
+ });
+}
+
+int LibWindowmanager::Impl::getDisplayInfo(json_object *object) {
+ TRACE();
+ HMI_DEBUG("libwm", "called");
+
+ if (nullptr == object) {
+ HMI_ERROR("libwm", "Argment is NULL!");
+ return -EINVAL;
+ }
+
+ if ((nullptr == this->loop) || (nullptr == this->wsj1)) {
+ HMI_ERROR("libwm", "LibWindowmanager is not initialized!");
+ return -EPERM;
+ }
+
+ int w_px, h_px, w_mm, h_mm;
+ int rc = -1;
+ double scale;
+ /* send the request */
+ int rc2 =
+ this->api_call("GetDisplayInfo", nullptr,
+ [&rc, &w_px, &h_px, &w_mm, &h_mm, &scale](bool ok, json_object *j) {
+ if (ok) {
+ json_object *val;
+ if (json_object_object_get_ex(j, g_kKeyResponse, &val)) {
+ HMI_DEBUG("libwm", "responce:%s", json_object_get_string(val));
+
+ json_object *j_w_px = nullptr;
+ if (!json_object_object_get_ex(val, "width_pixel", &j_w_px)) {
+ HMI_DEBUG("libwm", "Not found key \"width_pixel\"");
+ rc = -EINVAL;
+ return;
+ }
+ w_px = json_object_get_int(j_w_px);
+
+ json_object *j_h_px = nullptr;
+ if (!json_object_object_get_ex(val, "height_pixel", &j_h_px)) {
+ HMI_DEBUG("libwm", "Not found key \"height_pixel\"");
+ rc = -EINVAL;
+ return;
+ }
+ h_px = json_object_get_int(j_h_px);
+
+ json_object *j_w_mm = nullptr;
+ if (!json_object_object_get_ex(val, "width_mm", &j_w_mm)) {
+ HMI_DEBUG("libwm", "Not found key \"width_mm\"");
+ rc = -EINVAL;
+ return;
+ }
+ w_mm = json_object_get_int(j_w_mm);
+
+ json_object *j_h_mm = nullptr;
+ if (!json_object_object_get_ex(val, "height_mm", &j_h_mm)) {
+ HMI_DEBUG("libwm", "Not found key \"height_mm\"");
+ rc = -EINVAL;
+ return;
+ }
+ h_mm = json_object_get_int(j_h_mm);
+
+ json_object *j_scale = nullptr;
+ if (!json_object_object_get_ex(val, "scale", &j_scale)) {
+ HMI_DEBUG("libwm:", "Not found key \"scale\"");
+ scale = 1.0; // for backward compatibility
+ } else {
+ scale = json_object_get_double(j_scale);
+ }
+ rc = 0;
+ }
+ else {
+ HMI_ERROR("libwm", "Not found key \"response\"");
+ rc = -EINVAL;
+ return;
+ }
+ } else {
+ HMI_ERROR("libwm", "Windowmanager-service is not initialized: %s",
+ j != nullptr ? json_object_to_json_string_ext(
+ j, JSON_C_TO_STRING_PRETTY)
+ : "no-info");
+ rc = -EPERM;
+ }
+ });
+
+ if (0 > rc2) {
+ HMI_ERROR("libwm", "api_call() failed");
+ rc = rc2;
+ }
+
+ if (0 == rc) {
+ json_object_object_add(object, "width_pixel", json_object_new_int(w_px));
+ json_object_object_add(object, "height_pixel", json_object_new_int(h_px));
+ json_object_object_add(object, "width_mm", json_object_new_int(w_mm));
+ json_object_object_add(object, "height_mm", json_object_new_int(h_mm));
+ json_object_object_add(object, "scale", json_object_new_double(scale));
+ this->_screen = Screen{
+ static_cast<unsigned long>(w_px),
+ static_cast<unsigned long>(h_px),
+ static_cast<unsigned long>(w_mm),
+ static_cast<unsigned long>(h_mm),
+ scale};
+ }
+
+ return rc;
+}
+
+int LibWindowmanager::Impl::getAreaInfo(json_object *in_obj, json_object *out_obj) {
+ TRACE();
+ HMI_DEBUG("libwm", "called");
+
+ if (nullptr == in_obj) {
+ HMI_ERROR("libwm", "Argment is NULL!");
+ return -EINVAL;
+ }
+
+ if ((nullptr == this->loop) || (nullptr == this->wsj1)) {
+ HMI_ERROR("libwm", "LibWindowmanager is not initialized!");
+ return -EPERM;
+ }
+
+ int x, y, w, h;
+ int rc = -1;
+ /* send the request */
+ int rc2 =
+ this->api_call("GetAreaInfo", in_obj,
+ [&rc, &x, &y, &w, &h](bool ok, json_object *j) {
+ if (ok) {
+ json_object *val;
+ HMI_DEBUG("libwm", "j:%s", json_object_get_string(j));
+ if (json_object_object_get_ex(j, g_kKeyResponse, &val)) {
+ json_object *j_x = nullptr;
+ if (!json_object_object_get_ex(val, "x", &j_x)) {
+ HMI_DEBUG("libwm", "Not found key \"x\"");
+ rc = -EINVAL;
+ return;
+ }
+ x = json_object_get_int(j_x);
+
+ json_object *j_y = nullptr;
+ if (!json_object_object_get_ex(val, "y", &j_y)) {
+ HMI_DEBUG("libwm", "Not found key \"y\"");
+ rc = -EINVAL;
+ return;
+ }
+ y = json_object_get_int(j_y);
+
+ json_object *j_w = nullptr;
+ if (!json_object_object_get_ex(val, "width", &j_w)) {
+ HMI_DEBUG("libwm", "Not found key \"width\"");
+ rc = -EINVAL;
+ return;
+ }
+ w = json_object_get_int(j_w);
+
+ json_object *j_h = nullptr;
+ if (!json_object_object_get_ex(val, "height", &j_h)) {
+ HMI_DEBUG("libwm", "Not found key \"height\"");
+ rc = -EINVAL;
+ return;
+ }
+ h = json_object_get_int(j_h);
+ rc = 0;
+
+ HMI_DEBUG("libwm", "responce:%s", json_object_get_string(val));
+ }
+ else {
+ HMI_ERROR("libwm", "Not found key \"response\"");
+ rc = -EINVAL;
+ return;
+ }
+ } else {
+ HMI_ERROR("libwm", "Could not get area rect: %s",
+ j != nullptr ? json_object_to_json_string_ext(
+ j, JSON_C_TO_STRING_PRETTY)
+ : "no-info");
+ rc = -EINVAL;
+ }
+ });
+
+ if (0 > rc2) {
+ HMI_ERROR("libwm", "api_call() failed");
+ rc = rc2;
+ }
+
+ if (0 == rc) {
+ json_object_object_add(out_obj, "x", json_object_new_int(x));
+ json_object_object_add(out_obj, "y", json_object_new_int(y));
+ json_object_object_add(out_obj, "width", json_object_new_int(w));
+ json_object_object_add(out_obj, "height", json_object_new_int(h));
+ }
+
+ return rc;
+}
+
+static void _on_reply_static(void *closure, struct afb_wsj1_msg *msg)
+{
+}
+
+void LibWindowmanager::Impl::set_event_handler(enum EventType et, handler_fun func) {
+ TRACE();
+ HMI_DEBUG("libwm", "called");
+
+ // Subscribe event
+ struct json_object* j = json_object_new_object();
+ json_object_object_add(j, "event", json_object_new_int(et));
+
+ int ret = afb_wsj1_call_j(this->wsj1, wmAPI, "wm_subscribe", j, _on_reply_static, this);
+ if (0 > ret) {
+ HMI_ERROR("libwm", "Failed to subscribe event: %s", kListEventName[et].c_str());
+ }
+
+ // Set event handler
+ if (et >= Event_Active && et <= Event_Val_Max) {
+ this->handlers[et] = std::move(func);
+ }
+}
+
+namespace {
+std::pair<bool, LibWindowmanager::EventType> make_event_type(char const *et) {
+ // Event have the form "$API/$EVENT", just try to find the first / and
+ // get on with it.
+ char const *et2 = strchr(et, '/');
+ if (et2 != nullptr) {
+ et = et2 + 1;
+ }
+
+#define ET(N, A) \
+ do { \
+ if (strcasecmp(et, N) == 0) \
+ return std::pair<bool, LibWindowmanager::EventType>( \
+ true, CONCAT(LibWindowmanager::Event_, A)); \
+ } while (false)
+
+ ET("active", Active);
+ ET("inactive", Inactive);
+ ET("visible", Visible);
+ ET("invisible", Invisible);
+ ET("syncdraw", SyncDraw);
+ ET("flushdraw", FlushDraw);
+ ET("screenUpdated", ScreenUpdated);
+ ET("headlampOff", HeadlampOff);
+ ET("headlampOn", HeadlampOn);
+ ET("parkingBrakeOff", ParkingBrakeOff);
+ ET("parkingBrakeOn", ParkingBrakeOn);
+ ET("lightstatusBrakeOff", LightstatusBrakeOff);
+ ET("lightstatusBrakeOn", LightstatusBrakeOn);
+ ET("carStop", CarStop);
+ ET("carRun", CarRun);
+ ET("error", Error);
+#undef ET
+
+ return std::pair<bool, LibWindowmanager::EventType>(false,
+ LibWindowmanager::Event_Active);
+}
+} // namespace
+
+/// object will be json_object_put
+int LibWindowmanager::Impl::api_call(
+ const char *verb, json_object *object,
+ const std::function<void(bool, json_object *)> &onReply) {
+ TRACE();
+
+ int rc = 0;
+ if ((0 == strcmp("RequestSurface", verb)) ||
+ (0 == strcmp("GetDisplayInfo", verb)) ||
+ (0 == strcmp("GetAreaInfo", verb))) {
+ // We need to wrap the actual onReply call once in order to
+ // *look* like a normal functions pointer (std::functions<>
+ // with captures cannot convert to function pointers).
+ // Alternatively we could setup a local struct and use it as
+ // closure, but I think it is cleaner this way.
+ int call_rc = 0;
+ std::atomic<bool> returned{};
+ returned.store(false, std::memory_order_relaxed);
+ std::function<void(bool, json_object *)> wrappedOnReply =
+ [&returned, &call_rc, &onReply](bool ok, json_object *j) {
+ TRACEN(wrappedOnReply);
+ call_rc = ok ? 0 : -EINVAL;
+ // We know it failed, but there may be an explanation in the
+ // json object.
+ {
+ TRACEN(onReply);
+ onReply(ok, j);
+ }
+ returned.store(true, std::memory_order_release);
+ };
+
+ // make the actual call, use wrappedOnReply as closure
+ rc = afb_wsj1_call_j(
+ this->wsj1, wmAPI, verb, object,
+ [](void *closure, afb_wsj1_msg *msg) {
+ TRACEN(callClosure);
+ auto *onReply =
+ reinterpret_cast<std::function<void(bool, json_object *)> *>(
+ closure);
+ (*onReply)(!(afb_wsj1_msg_is_reply_ok(msg) == 0),
+ afb_wsj1_msg_object_j(msg));
+ },
+ &wrappedOnReply);
+
+ if (0 == rc) {
+ // We need to wait until "returned" got set, this is necessary
+ // if events get triggered by the call (and would be dispatched before
+ // the actual call-reply).
+ while (!returned.load(std::memory_order_consume)) {
+ sd_event_run(loop, 16);
+ }
+
+ // return the actual API call result
+ rc = call_rc;
+ }
+ }
+ else {
+ rc = afb_wsj1_call_j(this->wsj1, wmAPI, verb, object, _on_reply_static, this);
+ }
+
+ if (rc < 0) {
+ HMI_ERROR("libwm", "calling %s/%s failed: %m", wmAPI, verb);
+ }
+
+ return rc;
+}
+
+void LibWindowmanager::Impl::setEventHandler(const WMHandler &wmh)
+{
+ // Subscribe
+ const char* ev = "event";
+ if(wmh.on_visible != nullptr) {
+ struct json_object* j = json_object_new_object();
+ json_object_object_add(j, ev, json_object_new_int(Event_Visible));
+ struct json_object* j_i = json_object_new_object();
+ json_object_object_add(j_i, ev, json_object_new_int(Event_Invisible));
+
+ int ret = afb_wsj1_call_j(this->wsj1, wmAPI, "wm_subscribe", j, _on_reply_static, this);
+ if (0 > ret) {
+ HMI_ERROR("libwm", "Failed to subscribe event visible");
+ }
+ ret = afb_wsj1_call_j(this->wsj1, wmAPI, "wm_subscribe", j_i, _on_reply_static, this);
+ if (0 > ret) {
+ HMI_ERROR("libwm", "Failed to subscribe event");
+ }
+ }
+
+ if(wmh.on_active != nullptr) {
+ struct json_object* j = json_object_new_object();
+ json_object_object_add(j, ev, json_object_new_int(Event_Active));
+ struct json_object* j_i = json_object_new_object();
+ json_object_object_add(j_i, ev, json_object_new_int(Event_Inactive));
+
+ int ret = afb_wsj1_call_j(this->wsj1, wmAPI, "wm_subscribe", j, _on_reply_static, this);
+ if (0 > ret) {
+ HMI_ERROR("libwm", "Failed to subscribe event active");
+ }
+ ret = afb_wsj1_call_j(this->wsj1, wmAPI, "wm_subscribe", j_i, _on_reply_static, this);
+ if (0 > ret) {
+ HMI_ERROR("libwm", "Failed to subscribe event");
+ }
+ }
+
+ if(wmh.on_sync_draw != nullptr) {
+ struct json_object* j = json_object_new_object();
+ json_object_object_add(j, ev, json_object_new_int(Event_SyncDraw));
+
+ int ret = afb_wsj1_call_j(this->wsj1, wmAPI, "wm_subscribe", j, _on_reply_static, this);
+ if (0 > ret) {
+ HMI_ERROR("libwm", "Failed to subscribe event active");
+ }
+ }
+
+ if(wmh.on_flush_draw != nullptr) {
+ struct json_object* j = json_object_new_object();
+ json_object_object_add(j, ev, json_object_new_int(Event_FlushDraw));
+
+ int ret = afb_wsj1_call_j(this->wsj1, wmAPI, "wm_subscribe", j, _on_reply_static, this);
+ if (0 > ret) {
+ HMI_ERROR("libwm", "Failed to subscribe event active");
+ }
+ }
+
+ if(wmh.on_screen_updated != nullptr) {
+ struct json_object* j = json_object_new_object();
+ json_object_object_add(j, ev, json_object_new_int(Event_ScreenUpdated));
+
+ int ret = afb_wsj1_call_j(this->wsj1, wmAPI, "wm_subscribe", j, _on_reply_static, this);
+ if (0 > ret) {
+ HMI_ERROR("libwm", "Failed to subscribe event active");
+ }
+ }
+
+ if(wmh.on_headlamp_off != nullptr) {
+ struct json_object* j = json_object_new_object();
+ json_object_object_add(j, ev, json_object_new_int(Event_HeadlampOff));
+
+ int ret = afb_wsj1_call_j(this->wsj1, wmAPI, "wm_subscribe", j, _on_reply_static, this);
+ if (0 > ret) {
+ HMI_ERROR("libwm", "Failed to subscribe event active");
+ }
+ }
+
+ if(wmh.on_headlamp_on != nullptr) {
+ struct json_object* j = json_object_new_object();
+ json_object_object_add(j, ev, json_object_new_int(Event_HeadlampOn));
+
+ int ret = afb_wsj1_call_j(this->wsj1, wmAPI, "wm_subscribe", j, _on_reply_static, this);
+ if (0 > ret) {
+ HMI_ERROR("libwm", "Failed to subscribe event active");
+ }
+ }
+
+ if(wmh.on_parking_brake_off != nullptr) {
+ struct json_object* j = json_object_new_object();
+ json_object_object_add(j, ev, json_object_new_int(Event_ParkingBrakeOff));
+
+ int ret = afb_wsj1_call_j(this->wsj1, wmAPI, "wm_subscribe", j, _on_reply_static, this);
+ if (0 > ret) {
+ HMI_ERROR("libwm", "Failed to subscribe event active");
+ }
+ }
+
+ if(wmh.on_parking_brake_on != nullptr) {
+ struct json_object* j = json_object_new_object();
+ json_object_object_add(j, ev, json_object_new_int(Event_ParkingBrakeOn));
+
+ int ret = afb_wsj1_call_j(this->wsj1, wmAPI, "wm_subscribe", j, _on_reply_static, this);
+ if (0 > ret) {
+ HMI_ERROR("libwm", "Failed to subscribe event active");
+ }
+ }
+
+ if(wmh.on_lightstatus_brake_off != nullptr) {
+ struct json_object* j = json_object_new_object();
+ json_object_object_add(j, ev, json_object_new_int(Event_LightstatusBrakeOff));
+
+ int ret = afb_wsj1_call_j(this->wsj1, wmAPI, "wm_subscribe", j, _on_reply_static, this);
+ if (0 > ret) {
+ HMI_ERROR("libwm", "Failed to subscribe event active");
+ }
+ }
+
+ if(wmh.on_lightstatus_brake_on != nullptr) {
+ struct json_object* j = json_object_new_object();
+ json_object_object_add(j, ev, json_object_new_int(Event_LightstatusBrakeOn));
+
+ int ret = afb_wsj1_call_j(this->wsj1, wmAPI, "wm_subscribe", j, _on_reply_static, this);
+ if (0 > ret) {
+ HMI_ERROR("libwm", "Failed to subscribe event active");
+ }
+ }
+
+ if(wmh.on_car_stop != nullptr) {
+ struct json_object* j = json_object_new_object();
+ json_object_object_add(j, ev, json_object_new_int(Event_CarStop));
+
+ int ret = afb_wsj1_call_j(this->wsj1, wmAPI, "wm_subscribe", j, _on_reply_static, this);
+ if (0 > ret) {
+ HMI_ERROR("libwm", "Failed to subscribe event active");
+ }
+ }
+
+ if(wmh.on_car_run != nullptr) {
+ struct json_object* j = json_object_new_object();
+ json_object_object_add(j, ev, json_object_new_int(Event_CarRun));
+
+ int ret = afb_wsj1_call_j(this->wsj1, wmAPI, "wm_subscribe", j, _on_reply_static, this);
+ if (0 > ret) {
+ HMI_ERROR("libwm", "Failed to subscribe event active");
+ }
+ }
+
+ // Register
+ this->_wmh.on_visible = wmh.on_visible;
+ this->_wmh.on_active = wmh.on_active;
+ this->_wmh.on_sync_draw = wmh.on_sync_draw;
+ this->_wmh.on_flush_draw = wmh.on_flush_draw;
+ this->_wmh.on_screen_updated = wmh.on_screen_updated;
+ this->_wmh.on_headlamp_off = wmh.on_headlamp_off;
+ this->_wmh.on_headlamp_on = wmh.on_headlamp_on;
+ this->_wmh.on_parking_brake_off = wmh.on_parking_brake_off;
+ this->_wmh.on_parking_brake_on = wmh.on_parking_brake_on;
+ this->_wmh.on_lightstatus_brake_off = wmh.on_lightstatus_brake_off;
+ this->_wmh.on_lightstatus_brake_on = wmh.on_lightstatus_brake_on;
+ this->_wmh.on_car_stop = wmh.on_car_stop;
+ this->_wmh.on_car_run = wmh.on_car_run;
+}
+
+void LibWindowmanager::Impl::event(char const *et, json_object *object) {
+ TRACE();
+ auto oet = make_event_type(et);
+ if (!oet.first) {
+ HMI_ERROR("libwm", "Unknown event type string '%s'", et);
+ return;
+ }
+ json_object *j_val;
+ std::string role = "";
+ bool emit = false;
+ if(json_object_object_get_ex(object, g_kKeyDrawingName, &j_val)) {
+ role = json_object_get_string(j_val);
+ }
+ if (this->labels.find(role) != this->labels.end()){
+ emit = true;
+ }
+
+ switch(oet.second) {
+ case Event_Active :
+ case Event_Inactive : {
+ bool active = ((oet.second == Event_Active) ? true : false);
+ if(!emit) break;
+ if(this->_wmh.on_active) {
+ return this->_wmh.on_active(role.c_str(), active);
+ }
+ break;
+ }
+ case Event_Visible :
+ case Event_Invisible : {
+ bool visible = ((oet.second == Event_Visible) ? true : false);
+ if(!emit) break;
+ if(this->_wmh.on_visible) {
+ return this->_wmh.on_visible(role.c_str(), visible);
+ }
+ break;
+ }
+ case Event_SyncDraw :
+ if(this->_wmh.on_sync_draw && emit) {
+ json_object_object_get_ex(object, g_kKeyDrawingArea, &j_val);
+ const char* area = json_object_get_string(j_val);
+ json_object *j_rect;
+ json_object_object_get_ex(object, g_kKeyDrawingRect, &j_rect);
+ json_object_object_get_ex(j_rect, "x", &j_val);
+ int x = json_object_get_int(j_val);
+ json_object_object_get_ex(j_rect, "y", &j_val);
+ int y = json_object_get_int(j_val);
+ json_object_object_get_ex(j_rect, "width", &j_val);
+ int w = json_object_get_int(j_val);
+ json_object_object_get_ex(j_rect, "height", &j_val);
+ int h = json_object_get_int(j_val);
+ Rect rect(x, y, w, h);
+ return this->_wmh.on_sync_draw(role.c_str(), area, rect);
+ }
+ break;
+ case Event_FlushDraw :
+ if(this->_wmh.on_flush_draw && emit) {
+ return this->_wmh.on_flush_draw(role.c_str());
+ }
+ break;
+ case Event_ScreenUpdated :
+ if(this->_wmh.on_screen_updated) {
+ // emit this case
+ json_object_object_get_ex(object, "ids", &j_val);
+ int len = json_object_array_length(j_val);
+ std::vector<std::string> id_list;
+ for(int i = 0; i < len; i++)
+ {
+ std::string elem = json_object_get_string(json_object_array_get_idx(j_val, i));
+ id_list.push_back(elem);
+ }
+ return this->_wmh.on_screen_updated(id_list);
+ }
+ break;
+ default :
+ break;
+ }
+
+ auto i = this->handlers.find(oet.second);
+ if (i != this->handlers.end()) {
+ json_object *val;
+ const char *label;
+ if (json_object_object_get_ex(object, g_kKeyDrawingName, &val)) {
+ label = json_object_get_string(val);
+ }
+ else {
+ i->second(object);
+ return;
+ }
+
+ if (this->labels.find(label) != this->labels.end()) {
+ i->second(object);
+ }
+ }
+}
+
+void LibWindowmanager::Impl::event(char const *et) {
+ TRACE();
+ auto oet = make_event_type(et);
+ if (!oet.first) {
+ HMI_ERROR("libwm", "Unknown event type string '%s'", et);
+ return;
+ }
+
+ switch(oet.second) {
+ case Event_HeadlampOff:
+ if(this->_wmh.on_headlamp_off) {
+ return this->_wmh.on_headlamp_off(nullptr);
+ }
+ break;
+ case Event_HeadlampOn:
+ if(this->_wmh.on_headlamp_on) {
+ return this->_wmh.on_headlamp_on(nullptr);
+ }
+ break;
+ case Event_ParkingBrakeOff:
+ if(this->_wmh.on_parking_brake_off) {
+ return this->_wmh.on_parking_brake_off(nullptr);
+ }
+ break;
+ case Event_ParkingBrakeOn:
+ if(this->_wmh.on_parking_brake_on) {
+ return this->_wmh.on_parking_brake_on(nullptr);
+ }
+ break;
+ case Event_LightstatusBrakeOff:
+ if(this->_wmh.on_lightstatus_brake_off) {
+ return this->_wmh.on_lightstatus_brake_off(nullptr);
+ }
+ break;
+ case Event_LightstatusBrakeOn:
+ if(this->_wmh.on_lightstatus_brake_on) {
+ return this->_wmh.on_lightstatus_brake_on(nullptr);
+ }
+ break;
+ case Event_CarStop:
+ if(this->_wmh.on_car_stop) {
+ return this->_wmh.on_car_stop(nullptr);
+ }
+ break;
+ case Event_CarRun:
+ if(this->_wmh.on_car_run) {
+ return this->_wmh.on_car_run(nullptr);
+ }
+ break;
+ default :
+ break;
+ }
+
+ auto i = this->handlers.find(oet.second);
+ if (i != this->handlers.end()) {
+ i->second(nullptr);
+ }
+}
+
+static void *event_loop_run(void *args){
+ struct sd_event* loop = (struct sd_event*)(args);
+ for(;;)
+ sd_event_run(loop, 30000000);
+}
+
+int LibWindowmanager::Impl::runEventLoop() {
+ if(this->wsj1 && this->loop)
+ {
+ pthread_t thread_id;
+ int ret = pthread_create(&thread_id, NULL, event_loop_run, this->loop);
+ if(ret != 0)
+ {
+ HMI_ERROR("libwm", "Cannot run eventloop due to error:%d", errno);
+ return -1;
+ }
+ else
+ return thread_id;
+ }
+ else
+ {
+ HMI_ERROR("libwm", "Connecting is not established yet");
+ return -1;
+ }
+}
+
+/**
+ * @class LibWindowmanager
+ */
+int LibWindowmanager::init(int port, char const *token) {
+ int ret = this->d->init(port, token);
+ if(ret == 0) {
+ json_object* j = json_object_new_object();
+ ret = this->getDisplayInfo(j); // return 0 if success
+ json_object_put(j);
+ }
+ return ret;
+}
+
+int LibWindowmanager::init(int port, const std::string &token) {
+ int ret = this->d->init(port, token.c_str());
+ if(ret == 0) {
+ json_object* j = json_object_new_object();
+ ret = this->getDisplayInfo(j); // return 0 if success
+ json_object_put(j);
+ }
+ return ret;
+}
+
+int LibWindowmanager::requestSurface(json_object *object) {
+ return this->d->requestSurface(object);
+}
+
+int LibWindowmanager::requestSurface(const char *role) {
+ json_object* object = json_object_new_object();
+ json_object_object_add(object, kKeyDrawingName, json_object_new_string(role));
+ return this->d->requestSurface(object);
+}
+
+int LibWindowmanager::requestSurfaceXDG(json_object *object) {
+ return this->d->requestSurfaceXDG(object);
+}
+
+int LibWindowmanager::requestSurfaceXDG(const char* role, unsigned ivi_id) {
+ json_object* object = json_object_new_object();
+ json_object_object_add(object, kKeyDrawingName, json_object_new_string(role));
+ json_object_object_add(object, kKeyIviId, json_object_new_int(ivi_id));
+ return this->d->requestSurfaceXDG(object);
+}
+
+int LibWindowmanager::activateWindow(json_object *object) {
+ return this->d->activateWindow(object);
+}
+
+int LibWindowmanager::activateWindow(const char* role, const char* area) {
+ json_object* object = json_object_new_object();
+ json_object_object_add(object, kKeyDrawingName, json_object_new_string(role));
+ json_object_object_add(object, kKeyDrawingArea, json_object_new_string(area));
+ return this->d->activateWindow(object);
+}
+
+int LibWindowmanager::activateWindow(const char* role) {
+ json_object* object = json_object_new_object();
+ json_object_object_add(object, kKeyDrawingName, json_object_new_string(role));
+ json_object_object_add(object, kKeyDrawingArea, json_object_new_string(kDefaultArea.c_str()));
+ return this->d->activateWindow(object);
+}
+
+int LibWindowmanager::deactivateWindow(json_object *object) {
+ return this->d->deactivateWindow(object);
+}
+
+int LibWindowmanager::deactivateWindow(const char* role) {
+ json_object* object = json_object_new_object();
+ json_object_object_add(object, kKeyDrawingName, json_object_new_string(role));
+ return this->d->deactivateWindow(nullptr);
+}
+
+// This API is deprecated, please use new API
+int LibWindowmanager::activateSurface(json_object *object) {
+ return this->activateWindow(object);
+}
+
+// This API is deprecated, please use new API
+int LibWindowmanager::deactivateSurface(json_object *object) {
+ return this->deactivateWindow(object);
+}
+
+int LibWindowmanager::endDraw(json_object *object) {
+ return this->d->endDraw(object);
+}
+
+int LibWindowmanager::endDraw(const char* role) {
+ json_object* object = json_object_new_object();
+ json_object_object_add(object, kKeyDrawingName, json_object_new_string(role));
+ return this->d->endDraw(object);
+}
+
+int LibWindowmanager::getDisplayInfo(json_object *object) {
+ return this->d->getDisplayInfo(object);
+}
+
+int LibWindowmanager::getAreaInfo(json_object *in_obj, json_object *out_obj) {
+ return this->d->getAreaInfo(in_obj, out_obj);
+}
+
+int LibWindowmanager::getAreaInfo(const char *role, Rect *out_rect) {
+ json_object *object = json_object_new_object();
+ json_object *out = json_object_new_object();
+ json_object_object_add(object, this->kKeyDrawingName, json_object_new_string(role));
+ int ret = this->d->getAreaInfo(object, out);
+
+ out_rect->set_left(0);
+ out_rect->set_top(0);
+ out_rect->set_width(0);
+ out_rect->set_height(0);
+
+ if(!ret) {
+ json_object *j_val;
+ json_object *j_rect;
+ json_object_object_get_ex(out, kKeyDrawingRect, &j_rect);
+ if (json_object_object_get_ex(j_rect, "x", &j_val)) {
+ out_rect->set_left(json_object_get_int(j_val));
+ }
+ if (json_object_object_get_ex(j_rect, "y", &j_val)) {
+ out_rect->set_top(json_object_get_int(j_val));
+ }
+ if (json_object_object_get_ex(j_rect, "width", &j_val)) {
+ out_rect->set_width(json_object_get_int(j_val));
+ }
+ if (json_object_object_get_ex(j_rect, "height", &j_val)) {
+ out_rect->set_height(json_object_get_int(j_val));
+ }
+ }
+ return ret;
+}
+
+int LibWindowmanager::getAreaInfo(const char *label, json_object *out_obj) {
+ json_object *object = json_object_new_object();
+ json_object_object_add(object, this->kKeyDrawingName, json_object_new_string(label));
+ return this->d->getAreaInfo(object, out_obj);
+}
+
+void LibWindowmanager::set_event_handler(enum EventType et, handler_fun f) {
+ return this->d->set_event_handler(et, std::move(f));
+}
+
+struct Screen LibWindowmanager::getScreenInfo() {
+ return this->d->getScreenInfo();
+}
+
+void LibWindowmanager::setEventHandler(const WMHandler &wml)
+{
+ return this->d->setEventHandler(wml);
+}
+
+LibWindowmanager::LibWindowmanager() : d(new Impl) {}
+
+LibWindowmanager::~LibWindowmanager() { delete d; }
+
+WMHandler::WMHandler()
+ : on_visible(nullptr),
+ on_active(nullptr),
+ on_sync_draw(nullptr),
+ on_flush_draw(nullptr),
+ on_screen_updated(nullptr),
+ on_headlamp_off(nullptr),
+ on_headlamp_on(nullptr),
+ on_parking_brake_off(nullptr),
+ on_parking_brake_on(nullptr),
+ on_lightstatus_brake_off(nullptr),
+ on_lightstatus_brake_on(nullptr),
+ on_car_stop(nullptr),
+ on_car_run(nullptr)
+{}