summaryrefslogtreecommitdiffstats
path: root/homescreen/src/settingswidget.cpp
blob: 1629bf035c4789308075d8344fdaf0e1c70c8881 (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
/*
 * Copyright (C) 2016, 2017 Mentor Graphics Development (Deutschland) GmbH
 *
 * 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 "settingswidget.h"
#include "ui_settingswidget.h"
#include <QSettings>
#include <include/daynightmode.hpp>

SettingsWidget::SettingsWidget(QWidget *parent) :
    QWidget(parent),
    mp_ui(new Ui::SettingsWidget),
    mp_translator(0)
{
    // no window decoration
    setWindowFlags(Qt::FramelessWindowHint);

    // multi-language support
    mp_translator = new QTranslator();
    mp_translator->load("homescreen_en_US.qm", ":/translations"); // TODO: read from system
    QApplication::instance()->installTranslator(mp_translator);

    mp_ui->setupUi(this);

    mp_ui->comboBox_language->addItem(QString("English"), QVariant("homescreen_en_US.qm")); // TODO: make this configurable
    mp_ui->comboBox_language->addItem(QString("Deutsch"), QVariant("homescreen_de_DE.qm"));
    mp_ui->comboBox_language->addItem(QString("日本語"), QVariant("homescreen_ja_JP.qm"));

    mp_ui->comboBox_colorScheme->addItem(QString("Default"), QVariant("default")); // TODO: make this configurable
    mp_ui->comboBox_colorScheme->addItem(QString("Demo 1"), QVariant("demo1"));
    mp_ui->comboBox_colorScheme->addItem(QString("Demo 2"), QVariant("demo2"));

    QSettings settings;
    mp_ui->comboBox_language->setCurrentIndex(settings.value("systemsettings/language", 0).toInt());
    mp_ui->comboBox_colorScheme->setCurrentIndex(settings.value("systemsettings/colorschemeindex", 0).toInt());
}

SettingsWidget::~SettingsWidget()
{
    delete mp_translator;
    delete mp_ui;
}

void SettingsWidget::updateColorScheme()
{
    QSettings settings;
    QSettings settings_cs(QApplication::applicationDirPath() +
                          "/colorschemes/" +
                          settings.value("systemsettings/colorscheme", "default").toString() +
                          "/" +
                          QString::number(settings.value("systemsettings/proximityobjectdetected", false).toBool()) +
                          "/" +
                          QString::number(settings.value("systemsettings/daynightmode", SystemDayNight::DAYNIGHTMODE_DAY).toInt()) +
                          ".ini",
                          QSettings::IniFormat);

    mp_ui->widget_background->setStyleSheet(settings_cs.value("SettingsWidget/widget_background_css").toString());
    mp_ui->comboBox_language->setStyleSheet(settings_cs.value("SettingsWidget/comboBox_language_css").toString());
    mp_ui->comboBox_colorScheme->setStyleSheet(settings_cs.value("SettingsWidget/comboBox_colorScheme_css").toString());
    mp_ui->widget_settingsIcon->setStyleSheet(settings_cs.value("SettingsWidget/widget_settingsIcon_css").toString());
}

void SettingsWidget::changeEvent(QEvent* event)
{
    if (QEvent::LanguageChange == event->type())
    {
        mp_ui->retranslateUi(this);
    }

    QWidget::changeEvent(event);
}

void SettingsWidget::on_comboBox_language_currentIndexChanged(const QString &)
{
    if (0 != mp_translator)
        mp_translator->load(mp_ui->comboBox_language->currentData().toString(), ":/translations");

    QSettings settings;
    settings.setValue("systemsettings/language", mp_ui->comboBox_language->currentIndex());
}

void SettingsWidget::on_comboBox_colorScheme_currentIndexChanged(const QString &)
{
    QSettings settings;
    settings.setValue("systemsettings/colorscheme", mp_ui->comboBox_colorScheme->currentData().toString());
    settings.setValue("systemsettings/colorschemeindex", mp_ui->comboBox_colorScheme->currentIndex());
    // make sure that everything is written to the settings file before continuing
    settings.sync();

    emit colorSchemeChanged();
}
} /* 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 */ }
/*
 * 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 <cassert>
#include <cctype>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <atomic>
#include <map>
#include <mutex>
#include <set>
#include <queue>

#include <unistd.h>

#include <systemd/sd-event.h>

#include <pthread.h>

extern "C" {
#include <afb/afb-ws-client.h>
#include <afb/afb-wsj1.h>
}

#define UNUSED(x) (void)(x)

/**
 * @class LibWindowmanager::Impl
 */
class LibWindowmanager::Impl {
    friend class LibWindowmanager;

    const std::vector<std::string> kListEventName{
      std::string("active"),
      std::string("inactive"),
      std::string("visible"),
      std::string("invisible"),
      std::string("syncdraw"),
      std::string("flushdraw")
    };

    /* Key for json obejct */
    const char *kKeyDrawingName = "drawing_name";
    const char *kKeyDrawingArea = "drawing_area";

    // 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 activateSurface(json_object *object);
    int deactivateSurface(json_object *object);
    int endDraw(json_object *object);

    int getDisplayInfo(json_object *object);
    int getAreaInfo(json_object *in_obj, json_object *out_obj);

    void set_event_handler(enum EventType et, handler_fun func);

    Impl();
    ~Impl();

    struct afb_wsj1 *wsj1;
    struct sd_event *loop;

    std::set<std::string> labels;
    std::map<EventType, handler_fun> handlers;
    std::queue<std::pair<handler_fun, std::string>> handler_queue;

    int api_call(const char *verb, json_object *object,
                 const std::function<void(bool, json_object *)> &onReply);

public:
    void event(char const *et, json_object *object);
private:
    int runEventLoop();
};

namespace {

constexpr const int token_maxlen = 20;
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 *val;
    if (json_object_object_get_ex(afb_wsj1_msg_object_j(msg), "data", &val)) {
        reinterpret_cast<LibWindowmanager::Impl *>(closure)->event(event, val);
    }
    else {
        HMI_ERROR("libwm", "Not found key \"data\"");
    }
}

/* 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() { TRACE(); }

LibWindowmanager::Impl::~Impl() {
    TRACE();
    afb_wsj1_unref(wsj1);
    sd_event_unref(loop);
}

int LibWindowmanager::Impl::init(int port, char const *token) {
    TRACE();
    HMI_DEBUG("libwm", "called");

    char *uribuf = nullptr;
    int rc = -1;

    if (this->loop != nullptr && this->wsj1 != nullptr) {
        HMI_ERROR("libwm", "LibWindowmanager instance is already initialized!");
        rc = -EALREADY;
        goto fail;
    }

    if (token == nullptr) {
        HMI_ERROR("libwm", "Token is invalid");
        rc = -EINVAL;
        goto fail;
    }

    if (port < 1 || port > 0xffff) {
        HMI_ERROR("libwm", "Port is invalid");
        rc = -EINVAL;
        goto fail;
    }

    /* get the default event loop */
    rc = sd_event_default(&this->loop);
    if (rc < 0) {
        HMI_ERROR("libwm", "Connection to default event loop failed: %s",
                strerror(-rc));
        goto fail;
    }

    asprintf(&uribuf, "ws://localhost:%d/api?token=%s", port, token);

    /* connect the websocket wsj1 to the uri given by the first argument */
    this->wsj1 = afb_ws_client_connect_wsj1(
        this->loop, uribuf, const_cast<struct afb_wsj1_itf *>(&itf), this);
    if (this->wsj1 == nullptr) {
        sd_event_unref(this->loop);
        this->loop = nullptr;
        HMI_ERROR("libwm", "Connection to %s failed: %m", uribuf);
        rc = -errno;
        goto fail;
    }

    this->runEventLoop();

    return 0;

fail:
    return rc;
}

int LibWindowmanager::Impl::requestSurface(json_object *object) {
    TRACE();
    HMI_DEBUG("libwm", "called");

    json_object *val;
    const char *tmp_label;
    if (json_object_object_get_ex(object, this->kKeyDrawingName, &val)) {
        tmp_label = json_object_get_string(val);
    }
    else {
        HMI_DEBUG("libwm", "Not found key \"%s\"", this->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, "response", &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, this->kKeyDrawingName, &val)) {
        tmp_label = json_object_get_string(val);
    }
    else {
        HMI_DEBUG("libwm", "Not found key \"%s\"", this->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::activateSurface(json_object *object) {
    TRACE();
    HMI_DEBUG("libwm", "called");
    return this->api_call("ActivateSurface", object, [](bool ok, json_object *j) {
        if (!ok) {
            HMI_ERROR("libwm", "API Call activate_surface() failed: %s",
                    j != nullptr ? json_object_to_json_string_ext(
                                       j, JSON_C_TO_STRING_PRETTY)
                  : "no-info");
        }
    });
}

int LibWindowmanager::Impl::deactivateSurface(json_object *object) {
    TRACE();
    HMI_DEBUG("libwm", "called");
    return this->api_call("DeactivateSurface", object, [](bool ok, json_object *j) {
        if (!ok) {
            HMI_ERROR("libwm", "API Call deactivate_surface() 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;
    /* send the request */
    int rc2 =
        this->api_call("GetDisplayInfo", nullptr,
                       [&rc, &w_px, &h_px, &w_mm, &h_mm](bool ok, json_object *j) {
            if (ok) {
                json_object *val;
                if (json_object_object_get_ex(j, "response", &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);
                    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));
    }

    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, "response", &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_FlushDraw) {
        this->handlers[et] = std::move(func);
    }
}

namespace {
std::pair<bool, LibWindowmanager::EventType> make_event_type(char const *et) {
    // Event have the form "$API/$EVENT", just try to find the first / and
    // get on with it.
    char const *et2 = strchr(et, '/');
    if (et2 != nullptr) {
        et = et2 + 1;
    }

#define ET(N, A)                                               \
    do {                                                       \
        if (strcasecmp(et, N) == 0)                            \
            return std::pair<bool, LibWindowmanager::EventType>( \
                true, CONCAT(LibWindowmanager::Event_, A));           \
    } while (false)

    ET("active", Active);
    ET("inactive", Inactive);
    ET("visible", Visible);
    ET("invisible", Invisible);
    ET("syncdraw", SyncDraw);
    ET("flushdraw", FlushDraw);
#undef ET

    return std::pair<bool, LibWindowmanager::EventType>(false,
                                                      LibWindowmanager::Event_Active);
}
}  // namespace

/// object will be json_object_put
int LibWindowmanager::Impl::api_call(
    const char *verb, json_object *object,
    const std::function<void(bool, json_object *)> &onReply) {
    TRACE();

    int rc = 0;
    if ((0 == strcmp("RequestSurface", verb)) ||
        (0 == strcmp("GetDisplayInfo", verb)) ||
        (0 == strcmp("GetAreaInfo", verb))) {
        // We need to wrap the actual onReply call once in order to
        // *look* like a normal functions pointer (std::functions<>
        // with captures cannot convert to function pointers).
        // Alternatively we could setup a local struct and use it as
        // closure, but I think it is cleaner this way.
        int call_rc = 0;
        std::atomic<bool> returned{};
        returned.store(false, std::memory_order_relaxed);
        std::function<void(bool, json_object *)> wrappedOnReply =
            [&returned, &call_rc, &onReply](bool ok, json_object *j) {
                TRACEN(wrappedOnReply);
                call_rc = ok ? 0 : -EINVAL;
                // We know it failed, but there may be an explanation in the
                // json object.
                {
                    TRACEN(onReply);
                    onReply(ok, j);
                }
                returned.store(true, std::memory_order_release);
            };

        // make the actual call, use wrappedOnReply as closure
        rc = afb_wsj1_call_j(
            this->wsj1, wmAPI, verb, object,
            [](void *closure, afb_wsj1_msg *msg) {
                TRACEN(callClosure);
                auto *onReply =
                    reinterpret_cast<std::function<void(bool, json_object *)> *>(
                        closure);
                (*onReply)(!(afb_wsj1_msg_is_reply_ok(msg) == 0),
                           afb_wsj1_msg_object_j(msg));
            },
            &wrappedOnReply);

        if (0 == rc) {
            // We need to wait until "returned" got set, this is necessary
            // if events get triggered by the call (and would be dispatched before
            // the actual call-reply).
            while (!returned.load(std::memory_order_consume)) {
                sd_event_run(loop, 16);
            }

            // return the actual API call result
            rc = call_rc;
        }
    }
    else {
        rc = afb_wsj1_call_j(this->wsj1, wmAPI, verb, object, _on_reply_static, this);
    }

    if (rc < 0) {
        HMI_ERROR("libwm", "calling %s/%s failed: %m", wmAPI, verb);
    }

    return rc;
}

void LibWindowmanager::Impl::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;
    }

    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, this->kKeyDrawingName, &val)) {
            label = json_object_get_string(val);
        }
        else {
            HMI_ERROR("libwm", "Not found key \"%s\"\n", this->kKeyDrawingName);
            return;
        }

        if (this->labels.find(label) != this->labels.end()) {
            i->second(object);
        }else if (i->first == Event_Visible || i->first == Event_Invisible){
            i->second(object);
        }
    }
}

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)
        {
            printf("Cannot run eventloop due to error:%d", errno);
            return -1;
        }
        else
            return thread_id;
        }
    else
    {
        printf("Connecting is not established yet");
        return -1;
    }
}

/**
 * @class LibWindowmanager
 */
int LibWindowmanager::init(int port, char const *token) {
    return this->d->init(port, token);
}

int LibWindowmanager::requestSurface(json_object *object) {
    return this->d->requestSurface(object);
}

int LibWindowmanager::requestSurfaceXDG(json_object *object) {
    return this->d->requestSurfaceXDG(object);
}

int LibWindowmanager::activateSurface(json_object *object) {
    return this->d->activateSurface(object);
}

int LibWindowmanager::deactivateSurface(json_object *object) {
    return this->d->deactivateSurface(object);
}

int LibWindowmanager::endDraw(json_object *object) {
    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 *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));
}

LibWindowmanager::LibWindowmanager() : d(new Impl) {}

LibWindowmanager::~LibWindowmanager() { delete d; }