2 * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
21 #include "window_manager.hpp"
22 #include "json_helper.hpp"
26 #include <afb/afb-binding.h>
27 #include <systemd/sd-event.h>
30 typedef struct WMClientCtxt
34 WMClientCtxt(const char *appName, const char* appRole)
43 wm::WindowManager wmgr;
45 afb_instance() : wmgr() {}
46 ~afb_instance() = default;
51 struct afb_instance *g_afb_instance;
54 int afb_instance::init()
56 return this->wmgr.init();
59 static int _binding_init()
61 HMI_NOTICE("WinMan ver. %s", WINMAN_VERSION_STRING);
63 g_afb_instance = new afb_instance;
65 if (g_afb_instance->init() == -1)
67 HMI_ERROR("Could not connect to compositor");
71 atexit([] { delete g_afb_instance; });
76 delete g_afb_instance;
77 g_afb_instance = nullptr;
81 static int binding_init (afb_api_t api) noexcept
85 return _binding_init();
87 catch (std::exception &e)
89 HMI_ERROR("Uncaught exception in binding_init(): %s", e.what());
94 static void cbRemoveClientCtxt(void *data)
96 WMClientCtxt *ctxt = (WMClientCtxt *)data;
101 HMI_DEBUG("remove app %s", ctxt->name.c_str());
103 // Policy Manager does not know this app was killed,
104 // so notify it by deactivate request.
105 g_afb_instance->wmgr.api_deactivate_window(
106 ctxt->name.c_str(), ctxt->role.c_str(),
107 [](const char *) {});
109 g_afb_instance->wmgr.removeClient(ctxt->name);
113 static void createSecurityContext(afb_req_t req, const char* appid, const char* role)
115 WMClientCtxt *ctxt = (WMClientCtxt *)afb_req_context_get(req);
118 // Create Security Context at first time
119 WMClientCtxt *ctxt = new WMClientCtxt(appid, role);
120 HMI_DEBUG("create session for %s", ctxt->name.c_str());
121 afb_req_session_set_LOA(req, 1);
122 afb_req_context_set(req, ctxt, cbRemoveClientCtxt);
126 void windowmanager_requestsurface(afb_req_t req) noexcept
128 std::lock_guard<std::mutex> guard(binding_m);
129 if (g_afb_instance == nullptr)
131 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
137 const char *a_drawing_name = afb_req_value(req, "drawing_name");
140 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
144 char *appid = afb_req_get_application_id(req);
147 auto ret = g_afb_instance->wmgr.api_request_surface(
148 appid, a_drawing_name);
151 afb_req_fail(req, "failed", ret.unwrap_err());
155 createSecurityContext(req, appid, a_drawing_name);
156 afb_req_success(req, json_object_new_int(ret.unwrap()), "success");
162 afb_req_fail(req, "failed", nullptr);
165 catch (std::exception &e)
167 afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurface: %s", e.what());
172 void windowmanager_requestsurfacexdg(afb_req_t req) noexcept
174 std::lock_guard<std::mutex> guard(binding_m);
175 if (g_afb_instance == nullptr)
177 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
183 json_object *jreq = afb_req_json(req);
185 json_object *j_drawing_name = nullptr;
186 if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
188 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
191 char const *a_drawing_name = json_object_get_string(j_drawing_name);
193 json_object *j_ivi_id = nullptr;
194 if (!json_object_object_get_ex(jreq, "ivi_id", &j_ivi_id))
196 afb_req_fail(req, "failed", "Need char const* argument ivi_id");
199 char const *a_ivi_id = json_object_get_string(j_ivi_id);
200 char *appid = afb_req_get_application_id(req);
203 auto ret = g_afb_instance->wmgr.api_request_surface(
204 appid, a_drawing_name, a_ivi_id);
208 afb_req_fail(req, "failed", ret);
212 createSecurityContext(req, appid, a_drawing_name);
213 afb_req_success(req, NULL, "success");
218 catch (std::exception &e)
220 afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what());
225 void windowmanager_activatewindow(afb_req_t req) noexcept
227 std::lock_guard<std::mutex> guard(binding_m);
228 if (g_afb_instance == nullptr)
230 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
236 const char *a_drawing_name = afb_req_value(req, "drawing_name");
239 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
243 const char *a_drawing_area = afb_req_value(req, "drawing_area");
246 afb_req_fail(req, "failed", "Need char const* argument drawing_area");
250 char* appid = afb_req_get_application_id(req);
253 g_afb_instance->wmgr.api_activate_window(
254 appid, a_drawing_name, a_drawing_area,
255 [&req](const char *errmsg) {
256 if (errmsg != nullptr)
259 afb_req_fail(req, "failed", errmsg);
262 afb_req_success(req, NULL, "success");
267 catch (std::exception &e)
269 HMI_WARNING("failed: Uncaught exception while calling activatesurface: %s", e.what());
270 g_afb_instance->wmgr.exceptionProcessForTransition();
275 void windowmanager_deactivatewindow(afb_req_t req) noexcept
277 std::lock_guard<std::mutex> guard(binding_m);
278 if (g_afb_instance == nullptr)
280 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
286 const char *a_drawing_name = afb_req_value(req, "drawing_name");
289 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
293 char* appid = afb_req_get_application_id(req);
296 g_afb_instance->wmgr.api_deactivate_window(
297 appid, a_drawing_name,
298 [&req](const char *errmsg) {
299 if (errmsg != nullptr)
302 afb_req_fail(req, "failed", errmsg);
305 afb_req_success(req, NULL, "success");
310 catch (std::exception &e)
312 HMI_WARNING("failed: Uncaught exception while calling deactivatesurface: %s", e.what());
313 g_afb_instance->wmgr.exceptionProcessForTransition();
318 void windowmanager_enddraw(afb_req_t req) noexcept
320 std::lock_guard<std::mutex> guard(binding_m);
321 if (g_afb_instance == nullptr)
323 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
329 const char *a_drawing_name = afb_req_value(req, "drawing_name");
332 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
335 afb_req_success(req, NULL, "success");
337 char* appid = afb_req_get_application_id(req);
340 g_afb_instance->wmgr.api_enddraw(appid, a_drawing_name);
344 catch (std::exception &e)
346 HMI_WARNING("failed: Uncaught exception while calling enddraw: %s", e.what());
347 g_afb_instance->wmgr.exceptionProcessForTransition();
352 void windowmanager_getdisplayinfo_thunk(afb_req_t req) noexcept
354 std::lock_guard<std::mutex> guard(binding_m);
355 if (g_afb_instance == nullptr)
357 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
363 auto ret = g_afb_instance->wmgr.api_get_display_info();
366 afb_req_fail(req, "failed", ret.unwrap_err());
370 afb_req_success(req, ret.unwrap(), "success");
372 catch (std::exception &e)
374 afb_req_fail_f(req, "failed", "Uncaught exception while calling getdisplayinfo: %s", e.what());
379 void windowmanager_getareainfo_thunk(afb_req_t req) noexcept
381 std::lock_guard<std::mutex> guard(binding_m);
382 if (g_afb_instance == nullptr)
384 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
390 json_object *jreq = afb_req_json(req);
392 json_object *j_drawing_name = nullptr;
393 if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
395 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
398 char const *a_drawing_name = json_object_get_string(j_drawing_name);
400 auto ret = g_afb_instance->wmgr.api_get_area_info(a_drawing_name);
403 afb_req_fail(req, "failed", ret.unwrap_err());
407 afb_req_success(req, ret.unwrap(), "success");
409 catch (std::exception &e)
411 afb_req_fail_f(req, "failed", "Uncaught exception while calling getareainfo: %s", e.what());
416 void windowmanager_get_area_list(afb_req_t req) noexcept
418 std::lock_guard<std::mutex> guard(binding_m);
419 json_object* ret = g_afb_instance->wmgr.api_get_area_list();
420 afb_req_success(req, ret, nullptr);
423 void windowmanager_change_area_size(afb_req_t req) noexcept
425 std::lock_guard<std::mutex> guard(binding_m);
426 if (g_afb_instance == nullptr)
428 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
432 char* appid = afb_req_get_application_id(req);
435 ChangeAreaReq change_req;
436 change_req.appname = appid;
437 change_req.save = false;
438 json_object *jreq = afb_req_json(req);
439 json_object *jsave, *jareas;
440 HMI_INFO("json_check, %s", json_object_get_string(jreq));
441 if(json_object_object_get_ex(jreq, "save", &jsave))
443 change_req.save = json_object_get_boolean(jsave);
445 if (json_object_object_get_ex(jreq, "areas", &jareas))
447 int size = json_object_array_length(jareas);
448 for(int i = 0; i < size; i++)
450 json_object* elem = json_object_array_get_idx(jareas, i);
452 std::string name = jh::getStringFromJson(elem, "name");
454 if(json_object_object_get_ex(elem, "rect", &jrect))
456 rect.x = jh::getIntFromJson(jrect, "x");
457 rect.y = jh::getIntFromJson(jrect, "y");
458 rect.w = jh::getIntFromJson(jrect, "w");
459 rect.h = jh::getIntFromJson(jrect, "h");
463 HMI_ERROR("bad request @area name :%s", name.c_str());
464 afb_req_fail(req, "failed", "bad request");
467 change_req.area_req[name] = rect;
469 if(change_req.area_req.size() != 0)
471 g_afb_instance->wmgr.api_change_area_size(change_req);
473 afb_req_success(req, nullptr, nullptr);
479 afb_req_fail(req, "failed", nullptr);
483 void windowmanager_wm_subscribe(afb_req_t req) noexcept
485 std::lock_guard<std::mutex> guard(binding_m);
486 if (g_afb_instance == nullptr)
488 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
494 json_object *jreq = afb_req_json(req);
495 json_object *j = nullptr;
496 if (!json_object_object_get_ex(jreq, "event", &j))
498 afb_req_fail(req, "failed", "Need char const* argument event");
501 wm::WindowManager::EventType event_id = (wm::WindowManager::EventType)json_object_get_int(j);
502 bool ret = g_afb_instance->wmgr.api_subscribe(req, event_id);
506 afb_req_fail(req, "failed", "Error: afb_req_subscribe()");
509 afb_req_success(req, NULL, "success");
511 catch (std::exception &e)
513 afb_req_fail_f(req, "failed", "Uncaught exception while calling wm_subscribe: %s", e.what());
518 void windowmanager_ping(afb_req_t req) noexcept
520 std::lock_guard<std::mutex> guard(binding_m);
522 if (g_afb_instance == nullptr)
524 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
529 afb_req_success(req, NULL, "success");
533 void windowmanager_debug_terminate(afb_req_t req) noexcept
535 std::lock_guard<std::mutex> guard(binding_m);
536 if (g_afb_instance == nullptr)
538 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
545 if (getenv("WINMAN_DEBUG_TERMINATE") != nullptr)
547 raise(SIGKILL); // afb-daemon kills it's pgroup using TERM, which
548 // doesn't play well with perf
551 afb_req_success(req, NULL, "success");
553 catch (std::exception &e)
555 afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_terminate: %s", e.what());
560 const afb_verb_t windowmanager_verbs[] = {
561 { .verb = "requestSurface", .callback = windowmanager_requestsurface },
562 { .verb = "requestSurfaceXDG", .callback = windowmanager_requestsurfacexdg },
563 { .verb = "activateWindow", .callback = windowmanager_activatewindow },
564 { .verb = "deactivateWindow", .callback = windowmanager_deactivatewindow },
565 { .verb = "endDraw", .callback = windowmanager_enddraw },
566 { .verb = "getDisplayInfo", .callback = windowmanager_getdisplayinfo_thunk },
567 { .verb = "getAreaInfo", .callback = windowmanager_getareainfo_thunk },
568 { .verb = "changeAreaSize", .callback = windowmanager_change_area_size },
569 { .verb = "getAreaList", .callback = windowmanager_get_area_list },
570 { .verb = "wm_subscribe", .callback = windowmanager_wm_subscribe },
571 { .verb = "ping", .callback = windowmanager_ping },
572 { .verb = "debug_terminate", .callback = windowmanager_debug_terminate },
575 extern "C" const afb_binding_t afbBindingExport = {
576 .api = "windowmanager",
577 .specification = "windowmanager",
578 .info = "windowmanager",
579 .verbs = windowmanager_verbs,
581 .init = binding_init,
584 .provide_class = nullptr,
585 .require_class = nullptr,
586 .require_api = nullptr,