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 "../include/json.hpp"
22 #include "window_manager.hpp"
23 #include "json_helper.hpp"
24 #include "wayland_ivi_wm.hpp"
28 #include <afb/afb-binding.h>
29 #include <systemd/sd-event.h>
32 typedef struct WMClientCtxt
36 WMClientCtxt(const char *appName, const char* appRole)
45 std::unique_ptr<wl::display> display;
46 wm::WindowManager wmgr;
48 afb_instance() : display{new wl::display}, wmgr{this->display.get()} {}
53 struct afb_instance *g_afb_instance;
56 int afb_instance::init()
58 return this->wmgr.init();
61 int display_event_callback(sd_event_source *evs, int /*fd*/, uint32_t events,
66 if ((events & EPOLLHUP) != 0)
68 HMI_ERROR("wm", "The compositor hung up, dying now.");
69 delete g_afb_instance;
70 g_afb_instance = nullptr;
74 if ((events & EPOLLIN) != 0u)
77 g_afb_instance->wmgr.display->read_events();
78 g_afb_instance->wmgr.set_pending_events();
81 // We want do dispatch pending wayland events from within
83 afb_service_call("windowmanager", "ping", json_object_new_object(),
84 [](void *c, int st, json_object *j) {}, nullptr);
91 sd_event_source_unref(evs);
92 if (getenv("WINMAN_EXIT_ON_HANGUP") != nullptr)
101 HMI_NOTICE("wm", "WinMan ver. %s", WINMAN_VERSION_STRING);
103 if (g_afb_instance != nullptr)
105 HMI_ERROR("wm", "Wayland context already initialized?");
109 if (getenv("XDG_RUNTIME_DIR") == nullptr)
111 HMI_ERROR("wm", "Environment variable XDG_RUNTIME_DIR not set");
116 // wait until wayland compositor starts up.
118 g_afb_instance = new afb_instance;
119 while (!g_afb_instance->display->ok())
124 HMI_ERROR("wm", "Could not connect to compositor");
127 HMI_ERROR("wm", "Wait to start weston ...");
129 delete g_afb_instance;
130 g_afb_instance = new afb_instance;
134 if (g_afb_instance->init() == -1)
136 HMI_ERROR("wm", "Could not connect to compositor");
141 int ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
142 g_afb_instance->display->get_fd(), EPOLLIN,
143 display_event_callback, g_afb_instance);
146 HMI_ERROR("wm", "Could not initialize afb_instance event handler: %d", -ret);
151 atexit([] { delete g_afb_instance; });
156 delete g_afb_instance;
157 g_afb_instance = nullptr;
161 int binding_init() noexcept
165 return _binding_init();
167 catch (std::exception &e)
169 HMI_ERROR("wm", "Uncaught exception in binding_init(): %s", e.what());
174 static void cbRemoveClientCtxt(void *data)
176 WMClientCtxt *ctxt = (WMClientCtxt *)data;
181 HMI_DEBUG("wm", "remove app %s", ctxt->name.c_str());
183 // Policy Manager does not know this app was killed,
184 // so notify it by deactivate request.
185 g_afb_instance->wmgr.api_deactivate_surface(
186 ctxt->name.c_str(), ctxt->role.c_str(),
187 [](const char *) {});
189 g_afb_instance->wmgr.removeClient(ctxt->name);
193 static void createSecurityContext(afb_req req, const char* appid, const char* role)
195 WMClientCtxt *ctxt = (WMClientCtxt *)afb_req_context_get(req);
198 // Create Security Context at first time
199 const char *new_role = g_afb_instance->wmgr.convertRoleOldToNew(role);
200 WMClientCtxt *ctxt = new WMClientCtxt(appid, new_role);
201 HMI_DEBUG("wm", "create session for %s", ctxt->name.c_str());
202 afb_req_session_set_LOA(req, 1);
203 afb_req_context_set(req, ctxt, cbRemoveClientCtxt);
207 void windowmanager_requestsurface(afb_req req) noexcept
209 std::lock_guard<std::mutex> guard(binding_m);
211 if (g_afb_instance == nullptr)
213 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
219 const char *a_drawing_name = afb_req_value(req, "drawing_name");
222 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
226 const char *appid = afb_req_get_application_id(req);
227 auto ret = g_afb_instance->wmgr.api_request_surface(
228 appid, a_drawing_name);
231 afb_req_fail(req, "failed", ret.unwrap_err());
235 createSecurityContext(req, appid, a_drawing_name);
237 afb_req_success(req, json_object_new_int(ret.unwrap()), "success");
239 catch (std::exception &e)
241 afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurface: %s", e.what());
246 void windowmanager_requestsurfacexdg(afb_req req) noexcept
248 std::lock_guard<std::mutex> guard(binding_m);
250 if (g_afb_instance == nullptr)
252 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
258 json_object *jreq = afb_req_json(req);
260 json_object *j_drawing_name = nullptr;
261 if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
263 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
266 char const *a_drawing_name = json_object_get_string(j_drawing_name);
268 json_object *j_ivi_id = nullptr;
269 if (!json_object_object_get_ex(jreq, "ivi_id", &j_ivi_id))
271 afb_req_fail(req, "failed", "Need char const* argument ivi_id");
274 char const *a_ivi_id = json_object_get_string(j_ivi_id);
275 char const *appid = afb_req_get_application_id(req);
276 auto ret = g_afb_instance->wmgr.api_request_surface(
277 appid, a_drawing_name, a_ivi_id);
281 afb_req_fail(req, "failed", ret);
285 createSecurityContext(req, appid, a_drawing_name);
287 afb_req_success(req, NULL, "success");
289 catch (std::exception &e)
291 afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what());
296 void windowmanager_setrole(afb_req req) noexcept
298 std::lock_guard<std::mutex> guard(binding_m);
299 if (g_afb_instance == nullptr)
301 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
307 char const *appid = afb_req_get_application_id(req);
308 json_object *jreq = afb_req_json(req);
310 json_object *j_role = nullptr;
311 if (!json_object_object_get_ex(jreq, "role", &j_role))
313 afb_req_fail(req, "failed", "Need char const* argument role");
316 char const *a_role = json_object_get_string(j_role);
318 json_object *j_pid = nullptr;
319 if (json_object_object_get_ex(jreq, "pid", &j_pid))
321 HMI_DEBUG("wm", "PID is set");
322 char const *a_pid = json_object_get_string(j_pid);
323 pid = std::stol(a_pid);
326 auto ret = g_afb_instance->wmgr.api_set_role(appid, a_role, pid);
329 afb_req_fail(req, "failed", "Couldn't register");
333 createSecurityContext(req, appid, a_role);
335 afb_req_success(req, NULL, "success");
337 catch (std::exception &e)
339 afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what());
344 void windowmanager_activatewindow(afb_req req) noexcept
346 std::lock_guard<std::mutex> guard(binding_m);
348 if (g_afb_instance == nullptr)
350 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
356 const char *a_drawing_name = afb_req_value(req, "drawing_name");
359 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
363 const char *a_drawing_area = afb_req_value(req, "drawing_area");
366 afb_req_fail(req, "failed", "Need char const* argument drawing_area");
370 g_afb_instance->wmgr.api_activate_surface(
371 afb_req_get_application_id(req),
372 a_drawing_name, a_drawing_area,
373 [&req](const char *errmsg) {
374 if (errmsg != nullptr)
376 HMI_ERROR("wm", errmsg);
377 afb_req_fail(req, "failed", errmsg);
380 afb_req_success(req, NULL, "success");
383 catch (std::exception &e)
385 HMI_WARNING("wm", "failed: Uncaught exception while calling activatesurface: %s", e.what());
386 g_afb_instance->wmgr.exceptionProcessForTransition();
391 void windowmanager_deactivatewindow(afb_req req) noexcept
393 std::lock_guard<std::mutex> guard(binding_m);
395 if (g_afb_instance == nullptr)
397 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
403 const char *a_drawing_name = afb_req_value(req, "drawing_name");
406 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
410 g_afb_instance->wmgr.api_deactivate_surface(
411 afb_req_get_application_id(req), a_drawing_name,
412 [&req](const char *errmsg) {
413 if (errmsg != nullptr)
415 HMI_ERROR("wm", errmsg);
416 afb_req_fail(req, "failed", errmsg);
419 afb_req_success(req, NULL, "success");
422 catch (std::exception &e)
424 HMI_WARNING("wm", "failed: Uncaught exception while calling deactivatesurface: %s", e.what());
425 g_afb_instance->wmgr.exceptionProcessForTransition();
430 void windowmanager_enddraw(afb_req req) noexcept
432 std::lock_guard<std::mutex> guard(binding_m);
434 if (g_afb_instance == nullptr)
436 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
442 const char *a_drawing_name = afb_req_value(req, "drawing_name");
445 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
448 afb_req_success(req, NULL, "success");
450 g_afb_instance->wmgr.api_enddraw(
451 afb_req_get_application_id(req), a_drawing_name);
453 catch (std::exception &e)
455 HMI_WARNING("wm", "failed: Uncaught exception while calling enddraw: %s", e.what());
456 g_afb_instance->wmgr.exceptionProcessForTransition();
461 void windowmanager_getdisplayinfo_thunk(afb_req req) noexcept
463 std::lock_guard<std::mutex> guard(binding_m);
465 if (g_afb_instance == nullptr)
467 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
473 auto ret = g_afb_instance->wmgr.api_get_display_info();
476 afb_req_fail(req, "failed", ret.unwrap_err());
480 afb_req_success(req, ret.unwrap(), "success");
482 catch (std::exception &e)
484 afb_req_fail_f(req, "failed", "Uncaught exception while calling getdisplayinfo: %s", e.what());
489 void windowmanager_getareainfo_thunk(afb_req req) noexcept
491 std::lock_guard<std::mutex> guard(binding_m);
493 if (g_afb_instance == nullptr)
495 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
501 json_object *jreq = afb_req_json(req);
503 json_object *j_drawing_name = nullptr;
504 if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
506 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
509 char const *a_drawing_name = json_object_get_string(j_drawing_name);
511 auto ret = g_afb_instance->wmgr.api_get_area_info(a_drawing_name);
514 afb_req_fail(req, "failed", ret.unwrap_err());
518 afb_req_success(req, ret.unwrap(), "success");
520 catch (std::exception &e)
522 afb_req_fail_f(req, "failed", "Uncaught exception while calling getareainfo: %s", e.what());
527 void windowmanager_wm_subscribe(afb_req req) noexcept
529 std::lock_guard<std::mutex> guard(binding_m);
531 if (g_afb_instance == nullptr)
533 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
539 json_object *jreq = afb_req_json(req);
540 json_object *j = nullptr;
541 if (!json_object_object_get_ex(jreq, "event", &j))
543 afb_req_fail(req, "failed", "Need char const* argument event");
546 int event_type = json_object_get_int(j);
547 const char *event_name = g_afb_instance->wmgr.kListEventName[event_type];
548 struct afb_event event = g_afb_instance->wmgr.map_afb_event[event_name];
549 int ret = afb_req_subscribe(req, event);
552 afb_req_fail(req, "failed", "Error: afb_req_subscribe()");
555 afb_req_success(req, NULL, "success");
557 catch (std::exception &e)
559 afb_req_fail_f(req, "failed", "Uncaught exception while calling wm_subscribe: %s", e.what());
564 void windowmanager_list_drawing_names(afb_req req) noexcept
566 std::lock_guard<std::mutex> guard(binding_m);
568 if (g_afb_instance == nullptr)
570 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
577 nlohmann::json j = g_afb_instance->wmgr.id_alloc.name2id;
578 auto ret = wm::Ok(json_tokener_parse(j.dump().c_str()));
581 afb_req_fail(req, "failed", ret.unwrap_err());
585 afb_req_success(req, ret.unwrap(), "success");
587 catch (std::exception &e)
589 afb_req_fail_f(req, "failed", "Uncaught exception while calling list_drawing_names: %s", e.what());
594 void windowmanager_ping(afb_req req) noexcept
596 std::lock_guard<std::mutex> guard(binding_m);
598 if (g_afb_instance == nullptr)
600 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
607 g_afb_instance->wmgr.api_ping();
609 afb_req_success(req, NULL, "success");
611 catch (std::exception &e)
613 afb_req_fail_f(req, "failed", "Uncaught exception while calling ping: %s", e.what());
618 void windowmanager_debug_status(afb_req req) noexcept
620 std::lock_guard<std::mutex> guard(binding_m);
622 if (g_afb_instance == nullptr)
624 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
631 json_object *jr = json_object_new_object();
632 json_object_object_add(jr, "surfaces",
633 to_json(g_afb_instance->wmgr.controller->sprops));
634 json_object_object_add(jr, "layers", to_json(g_afb_instance->wmgr.controller->lprops));
636 afb_req_success(req, jr, "success");
638 catch (std::exception &e)
640 afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_status: %s", e.what());
645 void windowmanager_debug_layers(afb_req req) noexcept
647 std::lock_guard<std::mutex> guard(binding_m);
649 if (g_afb_instance == nullptr)
651 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
657 auto ret = wm::Ok(json_tokener_parse(g_afb_instance->wmgr.layers.to_json().dump().c_str()));
659 afb_req_success(req, ret, "success");
661 catch (std::exception &e)
663 afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_layers: %s", e.what());
668 void windowmanager_debug_surfaces(afb_req req) noexcept
670 std::lock_guard<std::mutex> guard(binding_m);
672 if (g_afb_instance == nullptr)
674 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
681 auto ret = wm::Ok(to_json(g_afb_instance->wmgr.controller->sprops));
684 afb_req_fail(req, "failed", ret.unwrap_err());
688 afb_req_success(req, ret.unwrap(), "success");
690 catch (std::exception &e)
692 afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_surfaces: %s", e.what());
697 void windowmanager_debug_terminate(afb_req req) noexcept
699 std::lock_guard<std::mutex> guard(binding_m);
701 if (g_afb_instance == nullptr)
703 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
710 if (getenv("WINMAN_DEBUG_TERMINATE") != nullptr)
712 raise(SIGKILL); // afb-daemon kills it's pgroup using TERM, which
713 // doesn't play well with perf
716 afb_req_success(req, NULL, "success");
718 catch (std::exception &e)
720 afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_terminate: %s", e.what());
725 const struct afb_verb_v2 windowmanager_verbs[] = {
726 {"requestsurface", windowmanager_requestsurface, nullptr, nullptr, AFB_SESSION_NONE},
727 {"requestsurfacexdg", windowmanager_requestsurfacexdg, nullptr, nullptr, AFB_SESSION_NONE},
728 {"setrole", windowmanager_setrole, nullptr, nullptr, AFB_SESSION_NONE},
729 {"activatewindow", windowmanager_activatewindow, nullptr, nullptr, AFB_SESSION_NONE},
730 {"deactivatewindow", windowmanager_deactivatewindow, nullptr, nullptr, AFB_SESSION_NONE},
731 {"enddraw", windowmanager_enddraw, nullptr, nullptr, AFB_SESSION_NONE},
732 {"getdisplayinfo", windowmanager_getdisplayinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
733 {"getareainfo", windowmanager_getareainfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
734 {"wm_subscribe", windowmanager_wm_subscribe, nullptr, nullptr, AFB_SESSION_NONE},
735 {"list_drawing_names", windowmanager_list_drawing_names, nullptr, nullptr, AFB_SESSION_NONE},
736 {"ping", windowmanager_ping, nullptr, nullptr, AFB_SESSION_NONE},
737 {"debug_status", windowmanager_debug_status, nullptr, nullptr, AFB_SESSION_NONE},
738 {"debug_layers", windowmanager_debug_layers, nullptr, nullptr, AFB_SESSION_NONE},
739 {"debug_surfaces", windowmanager_debug_surfaces, nullptr, nullptr, AFB_SESSION_NONE},
740 {"debug_terminate", windowmanager_debug_terminate, nullptr, nullptr, AFB_SESSION_NONE},
743 extern "C" const struct afb_binding_v2 afbBindingV2 = {
744 "windowmanager", nullptr, nullptr, windowmanager_verbs, nullptr, binding_init, nullptr, 0};