main: rename g_wayland to g_afb_instance
[staging/windowmanager.git] / src / main.cpp
index e78b42f..d4da785 100644 (file)
@@ -1,35 +1,63 @@
+#include "json_helper.hpp"
 #include "util.hpp"
 #include "wayland.hpp"
 
 #include <algorithm>
 #include <json.h>
 
-#define AFB_BINDING_VERSION 2
-
 extern "C" {
 #include <afb/afb-binding.h>
 #include <systemd/sd-event.h>
 }
 
-#include <json.hpp>
-
-using json = nlohmann::json;
-
 namespace {
-struct wayland {
+struct afb_instance {
    std::unique_ptr<wl::display> display;
    std::unique_ptr<genivi::controller> controller;
    std::vector<std::unique_ptr<wl::output>> outputs;
-   sd_event_source *event_source;
 
-   wayland()
-      : display(new wl::display),
-        controller(nullptr),
-        outputs(),
-        event_source{} {}
+   wm::App app;
+
+   afb_instance() : display{new wl::display}, controller{nullptr}, outputs{}, app{} {}
+
+   int init();
 };
 
-struct wayland *g_wayland;
+struct afb_instance *g_afb_instance;
+
+int afb_instance::init() {
+   if (!this->display->ok()) {
+      return -1;
+   }
+
+   this->display->r.add_global_handler("wl_output", [](wl_registry *r,
+                                                       uint32_t name,
+                                                       uint32_t v) {
+      g_afb_instance->outputs.emplace_back(std::make_unique<wl::output>(r, name, v));
+   });
+
+   this->display->r.add_global_handler(
+      "ivi_controller", [](wl_registry *r, uint32_t name, uint32_t v) {
+         g_afb_instance->controller =
+            std::make_unique<genivi::controller>(r, name, v);
+
+         // XXX: This protocol needs the output, so lets just add our mapping
+         // here...
+         g_afb_instance->controller->add_proxy_to_id_mapping(
+            g_afb_instance->outputs.back()->proxy.get(),
+            wl_proxy_get_id(reinterpret_cast<struct wl_proxy *>(
+               g_afb_instance->outputs.back()->proxy.get())));
+      });
+
+   // First level objects
+   this->display->roundtrip();
+   // Second level objects
+   this->display->roundtrip();
+   // Third level objects
+   this->display->roundtrip();
+
+   return 0;
+}
 
 //  _       _ _       _                         _    ____
 // (_)_ __ (_) |_    | | __ _ _   _  ___  _   _| |_ / /\ \
@@ -38,17 +66,17 @@ struct wayland *g_wayland;
 // |_|_| |_|_|\__|___|_|\__,_|\__, |\___/ \__,_|\__| |  | |
 //              |_____|       |___/                 \_\/_/
 char const *init_layout() {
-   if (!g_wayland->controller) {
+   if (!g_afb_instance->controller) {
       return "ivi_controller global not available";
    }
 
-   if (g_wayland->outputs.empty()) {
+   if (g_afb_instance->outputs.empty()) {
       return "no output was set up!";
    }
 
-   auto &c = g_wayland->controller;
+   auto &c = g_afb_instance->controller;
 
-   auto &o = g_wayland->outputs.front();
+   auto &o = g_afb_instance->outputs.front();
    auto &s = c->screens.begin()->second;
    auto &layers = c->layers;
 
@@ -79,11 +107,41 @@ char const *init_layout() {
 
    c->commit_changes();
 
-   g_wayland->display->flush();
+   g_afb_instance->display->flush();
 
    return nullptr;
 }
 
+int display_event_callback(sd_event_source *evs, int fd, uint32_t events,
+                           void *data) {
+   if ((events & EPOLLHUP) != 0) {
+      logerror("The compositor hung up, dying now.");
+      delete g_afb_instance;
+      g_afb_instance = nullptr;
+      goto error;
+   }
+
+   if (events & EPOLLIN) {
+      int ret = g_afb_instance->display->dispatch();
+      if (ret == -1) {
+         logerror("wl_display_dipatch() returned error %d",
+                   g_afb_instance->display->get_error());
+         goto error;
+      }
+      g_afb_instance->display->flush();
+
+      // execute pending tasks, that is layout changes etc.
+      g_afb_instance->controller->execute_pending();
+      g_afb_instance->display->roundtrip();
+   }
+
+   return 0;
+
+error:
+   sd_event_source_unref(evs);
+   return -1;
+}
+
 //  _     _           _ _                 _       _ _    ____
 // | |__ (_)_ __   __| (_)_ __   __ _    (_)_ __ (_) |_ / /\ \
 // | '_ \| | '_ \ / _` | | '_ \ / _` |   | | '_ \| | __| |  | |
@@ -93,88 +151,52 @@ char const *init_layout() {
 int binding_init_() {
    lognotice("WinMan ver. %s", WINMAN_VERSION_STRING);
 
-   if (g_wayland != nullptr) {
-      AFB_ERROR("Wayland context already initialized?");
-      return -1;
+   if (g_afb_instance != nullptr) {
+      logerror("Wayland context already initialized?");
+      return 0;
    }
 
    if (getenv("XDG_RUNTIME_DIR") == nullptr) {
-      AFB_ERROR("Environment variable XDG_RUNTIME_DIR not set");
-      return -1;
+      logerror("Environment variable XDG_RUNTIME_DIR not set");
+      goto error;
    }
 
-   g_wayland = new wayland;
-   if (!g_wayland->display->ok()) {
-      AFB_ERROR("Could not connect to compositor");
-      return -1;
+   g_afb_instance = new afb_instance;
+   if (g_afb_instance->init() == -1) {
+      logerror("Could not connect to compositor");
+      goto error;
    }
 
-   auto &d = g_wayland->display;
-   d->r.add_global_handler("wl_output", [](wl_registry *r, uint32_t name,
-                                           uint32_t v) {
-      g_wayland->outputs.emplace_back(std::make_unique<wl::output>(r, name, v));
-   });
-
-   d->r.add_global_handler("ivi_controller", [](wl_registry *r, uint32_t name,
-                                                uint32_t v) {
-      g_wayland->controller = std::make_unique<genivi::controller>(r, name, v);
-
-      // XXX: This protocol needs the output, so lets just add our mapping
-      // here...
-      g_wayland->controller->add_proxy_to_id_mapping(
-         g_wayland->outputs.back()->proxy.get(),
-         wl_proxy_get_id(reinterpret_cast<struct wl_proxy *>(
-            g_wayland->outputs.back()->proxy.get())));
-   });
-
-   // First level objects
-   d->roundtrip();
-   // Second level objects
-   d->roundtrip();
-   // Third level objects
-   d->roundtrip();
-
    if (char const *e = init_layout()) {
-      AFB_ERROR("Could not init layout: %s", e);
-      return -1;
+      logerror("Could not init layout: %s", e);
+      goto error;
    }
 
-   sd_event *ev = afb_daemon_get_event_loop();
-   sd_event_add_io(
-      ev, &g_wayland->event_source, g_wayland->display->get_fd(),
-      EPOLLIN | EPOLLHUP,
-      [](sd_event_source *evs, int fd, uint32_t events, void *data) {
-         if ((events & EPOLLHUP) != 0) {
-            sd_event_source_unref(evs);
-            delete g_wayland;
-            g_wayland = nullptr;
-            return 1;
-         }
-
-         if (events & EPOLLIN) {
-            int ret = g_wayland->display->dispatch();
-            g_wayland->display->flush();
-
-            // execute pending tasks, that is layout changes etc.
-            g_wayland->controller->execute_pending();
-            g_wayland->display->roundtrip();
-            return ret == -1 ? -1 : 0;
-         }
-
-         return 0;
-      },
-      g_wayland);
+   {
+      int ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
+                                g_afb_instance->display->get_fd(), EPOLLIN,
+                                display_event_callback, g_afb_instance);
+      if (ret < 0) {
+         logerror("Could not initialize afb_instance event handler: %d", -ret);
+         goto error;
+      }
+   }
 
-   atexit([] { delete g_wayland; });
+   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) {
-      AFB_ERROR("Uncaught exception in binding_init(): %s", e.what());
+      logerror("Uncaught exception in binding_init(): %s", e.what());
    }
    return -1;
 }
@@ -185,51 +207,84 @@ int binding_init() noexcept {
 // | (_| |  __/ |_) | |_| | (_| |   \__ \ || (_| | |_| |_| \__ \ |  | |
 //  \__,_|\___|_.__/ \__,_|\__, |___|___/\__\__,_|\__|\__,_|___/ |  | |
 //                         |___/_____|                          \_\/_/
-void debug_status(struct afb_req req) noexcept {
+void debug_status(struct afb_req req) {
    // Quick and dirty, dump current surfaces and layers
    AFB_REQ_DEBUG(req, "status");
 
-   if (g_wayland == nullptr) {
-      afb_req_fail(req, "failed",
-                   "Binding not initialized, did the compositor die?");
+   auto o = json_object_new_object();
+   json_object_object_add(o, "surfaces",
+                          to_json(g_afb_instance->controller->sprops));
+   json_object_object_add(o, "layers", to_json(g_afb_instance->controller->lprops));
+//   json_object_object_add(o, "screens",
+//                          to_json(g_afb_instance->controller->screens));
+
+   afb_req_success(req, o, "status");
+}
+
+void debug_surfaces(afb_req req) {
+   afb_req_success(req, to_json(g_afb_instance->controller->sprops), "surfaces");
+}
+
+void debug_layers(afb_req req) {
+   afb_req_success(req, to_json(g_afb_instance->controller->lprops), "layers");
+}
+
+// Dummy register_surface implementation
+void register_surface(afb_req req) {
+   AFB_DEBUG("register_surface");
+
+   auto jo = afb_req_json(req);
+   json_object *jappid;
+   if (! json_object_object_get_ex(jo, "appid", &jappid)) {
+      afb_req_fail(req, "failed", "register_surface needs 'appid' integer argument");
       return;
    }
 
-   try {
-      json j;
-
-      if (!g_wayland->controller->surfaces.empty()) {
-         auto js = json::array();
-         for (auto const &i : g_wayland->controller->surfaces) {
-            auto const &r = i.second->dst_rect;
-            auto const &s = i.second->size;
-            js.push_back({{"id", i.first},
-                          {"size", {s.w, s.h}},
-                          {"dst_rect", {r.w, r.h, r.x, r.y}}});
-         }
-         j["surfaces"] = js;
-      }
+   json_object *jsurfid;
+   if (! json_object_object_get_ex(jo, "surfaceid", &jsurfid)) {
+      afb_req_fail(req, "failed", "register_surface needs 'surfaceid' integer argument");
+      return;
+   }
 
-      if (!g_wayland->controller->layers.empty()) {
-         auto js = json::array();
-         for (auto const &i : g_wayland->controller->layers) {
-            auto const &r = i.second->dst_rect;
-            auto const &s = i.second->size;
-            js.push_back({{"id", i.first},
-                          {"size", {s.w, s.h}},
-                          {"dst_rect", {r.w, r.h, r.x, r.y}}});
-         }
-         j["layers"] = js;
-      }
+   int32_t appid = json_object_get_int(jappid);
+   int32_t surfid = json_object_get_int(jsurfid);
 
-      afb_req_success(req, json_tokener_parse(j.dump().c_str()), "status");
-   } catch (std::exception &e) {
-      afb_req_fail_f(req, "failed", "Uncaught exception: %s", e.what());
+   if (appid < 0 || appid > 0xff) {
+      afb_req_fail(req, "failed", "invalid appid");
+      return;
    }
+
+   if (surfid < 0 || surfid > 0xffff) {
+      afb_req_fail(req, "failed", "invalid surfaceid");
+      return;
+   }
+
+   lognotice("register_surface, got appid %d and surfaceid %d", appid, surfid);
+
+   afb_req_success(req, json_object_new_int((appid << 16) + surfid), "success");
 }
 
+#define WRAP(F)                                                             \
+   [](afb_req req) noexcept {                                               \
+      if (g_afb_instance == nullptr) {                                           \
+         afb_req_fail(req, "failed",                                        \
+                      "Binding not initialized, did the compositor die?");  \
+         return;                                                            \
+      }                                                                     \
+      try {                                                                 \
+         F(req);                                                            \
+      } catch (std::exception & e) {                                        \
+         afb_req_fail_f(req, "failed", "Uncaught exception: %s", e.what()); \
+      }                                                                     \
+   }
+
 const struct afb_verb_v2 verbs[] = {
-   {"status", debug_status, NULL, NULL, AFB_SESSION_NONE_V2}, {},
+   {"debug::status", WRAP(debug_status), NULL, NULL, AFB_SESSION_NONE_V2},
+   {"debug::layers", WRAP(debug_layers), NULL, NULL, AFB_SESSION_NONE_V2},
+   {"debug::surfaces", WRAP(debug_surfaces), NULL, NULL, AFB_SESSION_NONE_V2},
+
+   {"register_surface", WRAP(register_surface), NULL, NULL, AFB_SESSION_NONE_V2},
+   {}
 };
 }  // namespace