/* * 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 #include #include #include #include #include #include extern "C" { #include #include #include } #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 &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 labels; std::map handlers; std::queue> handler_queue; const std::vector 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(closure)->event(event, val); } else { static_cast(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(&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(w_px), static_cast(h_px), static_cast(w_mm), static_cast(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 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( \ 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(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 &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 returned{}; returned.store(false, std::memory_order_relaxed); std::function 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 *>( 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 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) {}