aboutsummaryrefslogtreecommitdiffstats
path: root/src/main.cpp
blob: 6b4fef6698de1bc2eda4d26f65850341ef41fb7f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240

@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #a6e22e } /* Name.Function.Magic */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}
@media (prefers-color-scheme: light) {
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->

<svg
   xmlns:i="&amp;ns_ai;"
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   version="1.1"
   id="Connectivity_Active"
   x="0px"
   y="0px"
   viewBox="0 0 300 300"
   style="enable-background:new 0 0 300 300;"
   xml:space="preserve"
   inkscape:version="0.91 r13725"
   sodipodi:docname="connectivity_active.svg"><metadata
     id="metadata93"><rdf:RDF><cc:Work
         rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
     id="defs91" /><sodipodi:namedview
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1"
     objecttolerance="10"
     gridtolerance="10"
     guidetolerance="10"
     inkscape:pageopacity="0"
     inkscape:pageshadow="2"
     inkscape:window-width="1243"
     inkscape:window-height="824"
     id="namedview89"
     showgrid="false"
     inkscape:zoom="0.78666667"
     inkscape:cx="289.2517"
     inkscape:cy="150"
     inkscape:window-x="0"
     inkscape:window-y="27"
     inkscape:window-maximized="0"
     inkscape:current-layer="Connectivity_Active" /><style
     type="text/css"
     id="style3">
	.st0{fill:url(#SVGID_1_);}
	.st1{opacity:0.4;fill:url(#SVGID_2_);}
	.st2{fill:#FFFFFF;}
	.st3{font-family:'Roboto-Regular';}
	.st4{font-size:25px;}
	.st5{letter-spacing:6;}
	.st6{fill:url(#SVGID_3_);}
	.st7{fill:url(#SVGID_4_);}
	.st8{fill:url(#SVGID_5_);}
	.st9{fill:url(#SVGID_6_);}
	.st10{fill:url(#SVGID_7_);}
	.st11{fill:url(#SVGID_8_);}
</style><switch
     id="switch5"
     transform="matrix(1.3307804,0,0,1.3307804,-62.924861,-27.79036)"><g
       i:extraneous="self"
       id="g7"><linearGradient
         id="SVGID_1_"
         gradientUnits="userSpaceOnUse"
         x1="116.0821"
         y1="254.39191"
         x2="256.53561"
         y2="-133.31841"><stop
           offset="0"
           style="stop-color:#0DF9FF"
           id="stop10" /><stop
           offset="9.208472e-02"
           style="stop-color:#0DF9FF;stop-opacity:0.853"
           id="stop12" /><stop
           offset="0.6264"
           style="stop-color:#0DF9FF;stop-opacity:0"
           id="stop14" /></linearGradient><circle
         class="st0"
         cx="159.8"
         cy="133.60001"
         r="101.9"
         id="circle16"
         style="fill:url(#SVGID_1_)" /><linearGradient
         id="SVGID_2_"
         gradientUnits="userSpaceOnUse"
         x1="-55.796902"
         y1="435.51099"
         x2="216.9304"
         y2="53.692902"><stop
           offset="0.2978"
           style="stop-color:#FFFFFF;stop-opacity:0"
           id="stop19" /><stop
           offset="0.3685"
           style="stop-color:#FAFAFA;stop-opacity:0.1007"
           id="stop21" /><stop
           offset="0.4554"
           style="stop-color:#EBEBEB;stop-opacity:0.2245"
           id="stop23" /><stop
           offset="0.5508"
           style="stop-color:#D2D2D2;stop-opacity:0.3603"
           id="stop25" /><stop
           offset="0.6523"
           style="stop-color:#AFAFAF;stop-opacity:0.5048"
           id="stop27" /><stop
           offset="0.7585"
           style="stop-color:#828282;stop-opacity:0.6562"
           id="stop29" /><stop
           offset="0.8689"
           style="stop-color:#4B4B4B;stop-opacity:0.8133"
           id="stop31" /><stop
           offset="0.9806"
           style="stop-color:#0C0C0C;stop-opacity:0.9724"
           id="stop33" /><stop
           offset="1"
           style="stop-color:#000000"
           id="stop35" /></linearGradient><circle
         class="st1"
         cx="159.8"
         cy="133.60001"
         r="101.9"
         id="circle37"
         style="opacity:0.4;fill:url(#SVGID_2_)" /><g
         id="g39"><g
           id="g41"><
/*
 * 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 <unistd.h>
#include <algorithm>
#include <mutex>
#include <json.h>
#include "window_manager.hpp"
#include "json_helper.hpp"

extern "C"
{
#include <afb/afb-binding.h>
#include <systemd/sd-event.h>
}

typedef struct WMClientCtxt
{
    std::string name;
    std::string role;
    WMClientCtxt(const char *appName, const char* appRole)
    {
        name = appName;
        role = appRole;
    }
} WMClientCtxt;

struct afb_instance
{
    wm::WindowManager wmgr;

    afb_instance() : wmgr() {}
    ~afb_instance() = default;

    int init();
};

struct afb_instance *g_afb_instance;
std::mutex binding_m;

int afb_instance::init()
{
    return this->wmgr.init();
}

int _binding_init()
{
    HMI_NOTICE("WinMan ver. %s", WINMAN_VERSION_STRING);

    g_afb_instance = new afb_instance;

    if (g_afb_instance->init() == -1)
    {
        HMI_ERROR("Could not connect to compositor");
        goto error;
    }

    atexit([] { delete g_afb_instance; });

    return 0;

error:
    delete g_afb_instance;
    g_afb_instance = nullptr;
    return -1;
}

int binding_init() noexcept
{
    try
    {
        return _binding_init();
    }
    catch (std::exception &e)
    {
        HMI_ERROR("Uncaught exception in binding_init(): %s", e.what());
    }
    return -1;
}

static void cbRemoveClientCtxt(void *data)
{
    WMClientCtxt *ctxt = (WMClientCtxt *)data;
    if (ctxt == nullptr)
    {
        return;
    }
    HMI_DEBUG("remove app %s", ctxt->name.c_str());

    // Policy Manager does not know this app was killed,
    // so notify it by deactivate request.
    g_afb_instance->wmgr.api_deactivate_surface(
        ctxt->name.c_str(), ctxt->role.c_str(),
        [](const char *) {});

    g_afb_instance->wmgr.removeClient(ctxt->name);
    delete ctxt;
}

static void createSecurityContext(afb_req req, const char* appid, const char* role)
{
    WMClientCtxt *ctxt = (WMClientCtxt *)afb_req_context_get(req);
    if (!ctxt)
    {
        // Create Security Context at first time
        const char *new_role = g_afb_instance->wmgr.convertRoleOldToNew(role);
        WMClientCtxt *ctxt = new WMClientCtxt(appid, new_role);
        HMI_DEBUG("create session for %s", ctxt->name.c_str());
        afb_req_session_set_LOA(req, 1);
        afb_req_context_set(req, ctxt, cbRemoveClientCtxt);
    }
}

void windowmanager_requestsurface(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);

    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {
        const char *a_drawing_name = afb_req_value(req, "drawing_name");
        if (!a_drawing_name)
        {
            afb_req_fail(req, "failed", "Need char const* argument drawing_name");
            return;
        }

        const char *appid = afb_req_get_application_id(req);
        auto ret = g_afb_instance->wmgr.api_request_surface(
            appid, a_drawing_name);
        if (ret.is_err())
        {
            afb_req_fail(req, "failed", ret.unwrap_err());
            return;
        }

        createSecurityContext(req, appid, a_drawing_name);

        afb_req_success(req, json_object_new_int(ret.unwrap()), "success");
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurface: %s", e.what());
        return;
    }
}

void windowmanager_requestsurfacexdg(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);

    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {
        json_object *jreq = afb_req_json(req);

        json_object *j_drawing_name = nullptr;
        if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
        {
            afb_req_fail(req, "failed", "Need char const* argument drawing_name");
            return;
        }
        char const *a_drawing_name = json_object_get_string(j_drawing_name);

        json_object *j_ivi_id = nullptr;
        if (!json_object_object_get_ex(jreq, "ivi_id", &j_ivi_id))
        {
            afb_req_fail(req, "failed", "Need char const* argument ivi_id");
            return;
        }
        char const *a_ivi_id = json_object_get_string(j_ivi_id);
        char const *appid = afb_req_get_application_id(req);
        auto ret = g_afb_instance->wmgr.api_request_surface(
            appid, a_drawing_name, a_ivi_id);

        if (ret != nullptr)
        {
            afb_req_fail(req, "failed", ret);
            return;
        }

        createSecurityContext(req, appid, a_drawing_name);

        afb_req_success(req, NULL, "success");
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what());
        return;
    }
}

void windowmanager_setrole(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);
    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }
    try
    {
        unsigned pid = 0;
        char const *appid = afb_req_get_application_id(req);
        json_object *jreq = afb_req_json(req);

        json_object *j_role = nullptr;
        if (!json_object_object_get_ex(jreq, "role", &j_role))
        {
            afb_req_fail(req, "failed", "Need char const* argument role");
            return;
        }
        char const *a_role = json_object_get_string(j_role);

        json_object *j_pid = nullptr;
        if (json_object_object_get_ex(jreq, "pid", &j_pid))
        {
            HMI_DEBUG("PID is set");
            char const *a_pid = json_object_get_string(j_pid);
            pid = std::stol(a_pid);
        }

        auto ret = g_afb_instance->wmgr.api_set_role(appid, a_role, pid);
        if (!ret)
        {
            afb_req_fail(req, "failed", "Couldn't register");
            return;
        }

        createSecurityContext(req, appid, a_role);

        afb_req_success(req, NULL, "success");
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what());
        return;
    }
}

void windowmanager_activatewindow(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);

    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {
        const char *a_drawing_name = afb_req_value(req, "drawing_name");
        if (!a_drawing_name)
        {
            afb_req_fail(req, "failed", "Need char const* argument drawing_name");
            return;
        }

        const char *a_drawing_area = afb_req_value(req, "drawing_area");
        if (!a_drawing_area)
        {
            afb_req_fail(req, "failed", "Need char const* argument drawing_area");
            return;
        }

        g_afb_instance->wmgr.api_activate_surface(
            afb_req_get_application_id(req),
            a_drawing_name, a_drawing_area,
            [&req](const char *errmsg) {
                if (errmsg != nullptr)
                {
                    HMI_ERROR(errmsg);
                    afb_req_fail(req, "failed", errmsg);
                    return;
                }
                afb_req_success(req, NULL, "success");
            });
    }
    catch (std::exception &e)
    {
        HMI_WARNING("failed: Uncaught exception while calling activatesurface: %s", e.what());
        g_afb_instance->wmgr.exceptionProcessForTransition();
        return;
    }
}

void windowmanager_deactivatewindow(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);

    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {
        const char *a_drawing_name = afb_req_value(req, "drawing_name");
        if (!a_drawing_name)
        {
            afb_req_fail(req, "failed", "Need char const* argument drawing_name");
            return;
        }

        g_afb_instance->wmgr.api_deactivate_surface(
            afb_req_get_application_id(req), a_drawing_name,
            [&req](const char *errmsg) {
                if (errmsg != nullptr)
                {
                    HMI_ERROR(errmsg);
                    afb_req_fail(req, "failed", errmsg);
                    return;
                }
                afb_req_success(req, NULL, "success");
            });
    }
    catch (std::exception &e)
    {
        HMI_WARNING("failed: Uncaught exception while calling deactivatesurface: %s", e.what());
        g_afb_instance->wmgr.exceptionProcessForTransition();
        return;
    }
}

void windowmanager_enddraw(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);

    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {
        const char *a_drawing_name = afb_req_value(req, "drawing_name");
        if (!a_drawing_name)
        {
            afb_req_fail(req, "failed", "Need char const* argument drawing_name");
            return;
        }
        afb_req_success(req, NULL, "success");

        g_afb_instance->wmgr.api_enddraw(
            afb_req_get_application_id(req), a_drawing_name);
    }
    catch (std::exception &e)
    {
        HMI_WARNING("failed: Uncaught exception while calling enddraw: %s", e.what());
        g_afb_instance->wmgr.exceptionProcessForTransition();
        return;
    }
}

void windowmanager_getdisplayinfo_thunk(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);

    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {
        auto ret = g_afb_instance->wmgr.api_get_display_info();
        if (ret.is_err())
        {
            afb_req_fail(req, "failed", ret.unwrap_err());
            return;
        }

        afb_req_success(req, ret.unwrap(), "success");
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling getdisplayinfo: %s", e.what());
        return;
    }
}

void windowmanager_getareainfo_thunk(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);

    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {
        json_object *jreq = afb_req_json(req);

        json_object *j_drawing_name = nullptr;
        if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
        {
            afb_req_fail(req, "failed", "Need char const* argument drawing_name");
            return;
        }
        char const *a_drawing_name = json_object_get_string(j_drawing_name);

        auto ret = g_afb_instance->wmgr.api_get_area_info(a_drawing_name);
        if (ret.is_err())
        {
            afb_req_fail(req, "failed", ret.unwrap_err());
            return;
        }

        afb_req_success(req, ret.unwrap(), "success");
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling getareainfo: %s", e.what());
        return;
    }
}

void windowmanager_wm_subscribe(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);

    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {
        json_object *jreq = afb_req_json(req);
        json_object *j = nullptr;
        if (!json_object_object_get_ex(jreq, "event", &j))
        {
            afb_req_fail(req, "failed", "Need char const* argument event");
            return;
        }
        int event_type = json_object_get_int(j);
        const char *event_name = g_afb_instance->wmgr.kListEventName[event_type];
        struct afb_event event = g_afb_instance->wmgr.map_afb_event[event_name];
        int ret = afb_req_subscribe(req, event);
        if (ret)
        {
            afb_req_fail(req, "failed", "Error: afb_req_subscribe()");
            return;
        }
        afb_req_success(req, NULL, "success");
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling wm_subscribe: %s", e.what());
        return;
    }
}

void windowmanager_list_drawing_names(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);

    /* if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {

        nlohmann::json j = g_afb_instance->wmgr.id_alloc.name2id;
        auto ret = wm::Ok(json_tokener_parse(j.dump().c_str()));
        if (ret.is_err())
        {
            afb_req_fail(req, "failed", ret.unwrap_err());
            return;
        }

        afb_req_success(req, ret.unwrap(), "success");
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling list_drawing_names: %s", e.what());
        return;
    } */
}

void windowmanager_ping(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);

    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {

        g_afb_instance->wmgr.api_ping();

        afb_req_success(req, NULL, "success");
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling ping: %s", e.what());
        return;
    }
}

void windowmanager_debug_status(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);

    /* if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {

        json_object *jr = json_object_new_object();
        json_object_object_add(jr, "surfaces",
                               to_json(g_afb_instance->wmgr.controller->sprops));
        json_object_object_add(jr, "layers", to_json(g_afb_instance->wmgr.controller->lprops));

        afb_req_success(req, jr, "success");
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_status: %s", e.what());
        return;
    } */
}

void windowmanager_debug_layers(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);

    /* if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {
        auto ret = wm::Ok(json_tokener_parse(g_afb_instance->wmgr.layers.to_json().dump().c_str()));

        afb_req_success(req, ret, "success");
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_layers: %s", e.what());
        return;
    } */
}

void windowmanager_debug_surfaces(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);

    /* if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {

        auto ret = wm::Ok(to_json(g_afb_instance->wmgr.controller->sprops));
        if (ret.is_err())
        {
            afb_req_fail(req, "failed", ret.unwrap_err());
            return;
        }

        afb_req_success(req, ret.unwrap(), "success");
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_surfaces: %s", e.what());
        return;
    } */
}

void windowmanager_debug_terminate(afb_req req) noexcept
{
    std::lock_guard<std::mutex> guard(binding_m);

    if (g_afb_instance == nullptr)
    {
        afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
        return;
    }

    try
    {

        if (getenv("WINMAN_DEBUG_TERMINATE") != nullptr)
        {
            raise(SIGKILL); // afb-daemon kills it's pgroup using TERM, which
                            // doesn't play well with perf
        }

        afb_req_success(req, NULL, "success");
    }
    catch (std::exception &e)
    {
        afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_terminate: %s", e.what());
        return;
    }
}

const struct afb_verb_v2 windowmanager_verbs[] = {
    {"requestsurface", windowmanager_requestsurface, nullptr, nullptr, AFB_SESSION_NONE},
    {"requestsurfacexdg", windowmanager_requestsurfacexdg, nullptr, nullptr, AFB_SESSION_NONE},
    {"setrole", windowmanager_setrole, nullptr, nullptr, AFB_SESSION_NONE},
    {"activatewindow", windowmanager_activatewindow, nullptr, nullptr, AFB_SESSION_NONE},
    {"deactivatewindow", windowmanager_deactivatewindow, nullptr, nullptr, AFB_SESSION_NONE},
    {"enddraw", windowmanager_enddraw, nullptr, nullptr, AFB_SESSION_NONE},
    {"getdisplayinfo", windowmanager_getdisplayinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
    {"getareainfo", windowmanager_getareainfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
    {"wm_subscribe", windowmanager_wm_subscribe, nullptr, nullptr, AFB_SESSION_NONE},
    {"list_drawing_names", windowmanager_list_drawing_names, nullptr, nullptr, AFB_SESSION_NONE},
    {"ping", windowmanager_ping, nullptr, nullptr, AFB_SESSION_NONE},
    {"debug_status", windowmanager_debug_status, nullptr, nullptr, AFB_SESSION_NONE},
    {"debug_layers", windowmanager_debug_layers, nullptr, nullptr, AFB_SESSION_NONE},
    {"debug_surfaces", windowmanager_debug_surfaces, nullptr, nullptr, AFB_SESSION_NONE},
    {"debug_terminate", windowmanager_debug_terminate, nullptr, nullptr, AFB_SESSION_NONE},
    {}};

extern "C" const struct afb_binding_v2 afbBindingV2 = {
    "windowmanager", nullptr, nullptr, windowmanager_verbs, nullptr, binding_init, nullptr, 0};