diff options
-rw-r--r-- | CMakeLists.txt | 6 | ||||
-rw-r--r-- | libwindowmanager/CMakeLists.txt | 85 | ||||
-rw-r--r-- | libwindowmanager/doc/CMakeLists.txt | 4 | ||||
-rw-r--r-- | libwindowmanager/doc/GNUmakefile | 7 | ||||
-rw-r--r-- | libwindowmanager/doc/LibWindowmanager.md | 250 | ||||
-rw-r--r-- | libwindowmanager/doc/LibWindowmanager.txt | 238 | ||||
-rw-r--r-- | libwindowmanager/libwindowmanager.cpp | 498 | ||||
-rw-r--r-- | libwindowmanager/libwindowmanager.h | 58 | ||||
-rw-r--r-- | windowmanager.pc.in | 12 |
9 files changed, 0 insertions, 1158 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index ec3759b..0b2d47b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,15 +79,9 @@ set(SANITIZER_MODE "none" CACHE STRING "Build using a specific sanitizer (e.g. ' set(LINK_LIBCXX OFF CACHE BOOL "Link against LLVMs libc++") -add_subdirectory(libwindowmanager) add_subdirectory(scripts) add_subdirectory(src) -configure_file(windowmanager.pc.in windowmanager.pc @ONLY) -INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/windowmanager.pc - DESTINATION - ${CMAKE_INSTALL_LIBDIR}/pkgconfig) - install( FILES layers.json DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/windowmanager diff --git a/libwindowmanager/CMakeLists.txt b/libwindowmanager/CMakeLists.txt deleted file mode 100644 index a1c28c8..0000000 --- a/libwindowmanager/CMakeLists.txt +++ /dev/null @@ -1,85 +0,0 @@ -# -# 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(FindPkgConfig) - -pkg_check_modules(AFB REQUIRED libafbwsc) -pkg_check_modules(SD REQUIRED libsystemd>=222) - -set(TARGET_LIBWM windowmanager) - -add_library(${TARGET_LIBWM} SHARED - libwindowmanager.cpp - libwindowmanager.h) - -target_include_directories(${TARGET_LIBWM} - PRIVATE - ${AFB_INCLUDE_DIRS} - ${SD_INCLUDE_DIRS}) - -target_link_libraries(${TARGET_LIBWM} - PUBLIC - -lpthread - ${AFB_LIBRARIES} - ${SD_LIBRARIES}) - -target_compile_definitions(${TARGET_LIBWM} - PRIVATE - _GNU_SOURCE) # XXX should I define this here?! - -if(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Release") - target_compile_definitions(${TARGET_LIBWM} - PRIVATE - _GLIBCXX_DEBUG) -endif() - -target_compile_options(${TARGET_LIBWM} - PRIVATE - -Wall -Wextra -Wno-unused-parameter -Wno-comment) - -set_target_properties(${TARGET_LIBWM} - PROPERTIES - # INTERPROCEDURAL_OPTIMIZATION ON - CXX_EXTENSIONS OFF - CXX_STANDARD 14 - CXX_STANDARD_REQUIRED ON) - -if (LINK_LIBCXX) - set_target_properties(${TARGET_LIBWM} - PROPERTIES - LINK_FLAGS "-lc++") -endif() - -if (NOT ${SANITIZER_MODE} STREQUAL "none" AND NOT ${SANITIZER_MODE} STREQUAL "") - target_compile_options(${TARGET_LIBWM} - PRIVATE - -fsanitize=${SANITIZER_MODE} -g -fno-omit-frame-pointer) - set_target_properties(${TARGET_LIBWM} - PROPERTIES - LINK_FLAGS "-fsanitize=${SANITIZER_MODE} -g") -endif() - -install( - TARGETS ${TARGET_LIBWM} - DESTINATION ${CMAKE_INSTALL_LIBDIR} - COMPONENT "runtime") - -install( - FILES libwindowmanager.h - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - COMPONENT "development") - -add_subdirectory(doc) diff --git a/libwindowmanager/doc/CMakeLists.txt b/libwindowmanager/doc/CMakeLists.txt deleted file mode 100644 index da59a0c..0000000 --- a/libwindowmanager/doc/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -install( - FILES LibWindowmanager.md - DESTINATION ${CMAKE_INSTALL_DOCDIR} - COMPONENT "development") diff --git a/libwindowmanager/doc/GNUmakefile b/libwindowmanager/doc/GNUmakefile deleted file mode 100644 index d878cc4..0000000 --- a/libwindowmanager/doc/GNUmakefile +++ /dev/null @@ -1,7 +0,0 @@ -all: LibWindowmanager.html - -LibWindowmanager.html: LibWindowmanager.txt - asciidoc -a max-width=55em $^ - -clean: - rm -f LibWindowmanager.html diff --git a/libwindowmanager/doc/LibWindowmanager.md b/libwindowmanager/doc/LibWindowmanager.md deleted file mode 100644 index b855081..0000000 --- a/libwindowmanager/doc/LibWindowmanager.md +++ /dev/null @@ -1,250 +0,0 @@ -Introduction -============ - -The LibWindowmanager library provides a simple interface to manipulate and -query the state of the window manager application framework binding. -It is needs to be integrated and called from the client application. - -Intended audience ------------------ - -This document is intended to be useful to application developers. - -Scope of this Document ----------------------- - -This document describes the singleton class interface to the *Window -Manager* binding service. - -class LibWindowmanager -=============== - -This is the public interface of the class `LibWindowmanager`. Private members -and methods are not reproduced as they will not affect usage of the -class by client applications. - - class LibWindowmanager - { - public: - static LibWindowmanager &instance(); - - int init(int port, char const *token); - - // WM API - int requestSurface(const char *label); - int activateSurface(const char *label); - int deactivateSurface(const char *label); - int endDraw(const char *label); - - enum EventType { - Event_Active, - Event_Inactive, - Event_Visible, - Event_Invisible, - Event_SyncDraw, - Event_FlushDraw, - }; - - void set_event_handler(enum EventType et, - std::function<void(char const *label)> f); - }; - -Errors ------- - -Methods returning an `int` signal successful operation when returning -`0`. In case of an error, an error value is returned as a negative errno -value. E.g. `-EINVAL` to signal that some input value was invalid. - -Additionally, logging of error messages is done on the standard error -file descriptor to help debugging the issue. - -Labels ------- - -Surface labels are any valid strings. For `requestSurface()` these -strings must match the *Window Manager* configuration in order to be -allowed to be displayed on one layer or the other. For all other calls -the label must match the exact name of a requested surface. - -Methods -------- - -### LibWindowmanager::init(port, token) - -Initialize the Binding communication. - -The `token` parameter is a string consisting of only alphanumeric characters. -If these conditions are not met, the LibWindowmanager instance will not initialize, -i.e. this call will return `-EINVAL`. - -The `port` parameter is the port the afb daemon is listening on, an -invalid port will lead to a failure of the call and return `-EINVAL`. - -### LibWindowmanager::requestSurface(label) - -This method requests a surface with the label given from the *Window -Manager*. It will return `0` for a successful surface request, and -`-errno` on failure. Additionally, on the standard error, messages are -logged to help debgging the issue. - -### LibWindowmanager::activateSurface(label) - -This method is mainly intended for *manager* applications that control -other applications (think an application manager or the *HomeScreen*). -It instructs the window manager to activate the surface with the given -*label*. - -This method only is effective after the actual window or surface was -created by the application. - -### LibWindowmanager::deactivateSurface(label) - -This method is mainly intended for *manager* applications that control -other applications. It instructs the window manager to deactivate the -surface associated with the given label. Note, that deactivating a -surface also means to implicitly activate another (the last active or if -not available *main surface* or *HomeScreen*.) - -This method only is effective after the actual window or surface was -created by the application. - -### LibWindowmanager::endDraw(label) - -This function is called from a client application when it is done -drawing its surface content. - -It is not crucial to make this call at every time a drawing is finished -- it is mainly intended to allow the window manager to synchronize -drawing in case of layout switch. The exact semantics are explained in -the next [Events](#_events) Section. - -### LibWindowmanager::set\_event\_handler(et, func) - -This method needs to be used to register event handlers for the WM -events described in the EventType enum. Only one hendler for each -EventType is possible, i.e. if it is called multiple times with the same -EventType the previous handler will be replaced. - -The `func` handler functions will receive the label of the surface this -event is targeted at. - -See Section [Events](#_events) for mor detailed information about event -delivery to client applications. - -Usage ------ - -### Initialization of LibWindowmanager - -Before usage of the LibWindowmanager, the method `init()` must be -called once, it will return `-errno` in case of en error and log -diagnostic messages to stderr. - -### Request a surface - -When creating a surface with *Qt* - it is necessary to request a surface -from the WM, internally this will communicate with the window manager -binding. Only after `requestSurface()` was successful, a surface should -be created. - -This is also true for *QML* aplications, where only after the -`requestSurface()` should the load of the resource be done. The method -returns `0` after the surface was requested successfully. - -#### Workings of requestSurface() - -`LibWindowmanager::requestSurface()` calls the AFB binding verb -`requestsurface` of the `windowmanager` API. This API call will return a -numeric ID to be used when creating the surface. This ID is never -explicitly returned to the client application, instead, it is set in the -application environment in order for *Qt* to then use it when creating -the surface. - -With the current *Qt* implementation this means, that only one surface -will be available to client applications, as subsequent windows will -increment this numeric ID internally - which then will lead to IDs that -cannot be known by the window manager as there is no direct -communication from *Qt* to the WM. - -Events ------- - -Events are a way for the *Window Manager* to propagate information to -client applications. It was vital for the project to implement a number -of events, that mirror functionality that is already present in the -wayland protocol. - -All events have the surface `label` as argument - a way to enable future -multi-surface applications. - -As already stated above, this is currently not possible with the way -*Qt* implements its surface ID setting. - -### Active and Inactive Events - -These events signal an application that it was activated or deactivated -respectively. Usually this means it was switched visible - which means -the surface will now be on the screen and therefor continue to render. - -### Visible and Invisible - -These events signal an application that it was switched to be visible or -invisible respectively. These events too are handled implicitly through -the wayland protocol by means of `wl_surface::enter` and -`wl_surface::leave` events to the client. - -### SyncDraw and FlushDraw - -These events instruct applications that they should redraw their surface -contents - again, this is handled implicitly by the wayland protocol. - -`SyncDraw` is sent to the application when it has to redraw its surface. - -`FlushDraw` is sent to the application when it should swap its buffers, -that is *signal* the compositor that its surface contains new content. - -Example Use Case ----------------- - -In order to enable application to use the `WM` surface registration -function the above described steps need to be implemented. - -As a minimal example the usage and initialization can look like the -following. - - // Assume a program argc and argv. - QGuiApplication app(argc, argv); - - auto &wm = LibWindowmanager::instance(); - - // initialize the LibWindowmanager binding. - if(wm.init(1234, "wmtest") != 0) { - exit(EXIT_FAILURE); - } - - // Request a surface label from the WM. - char const *surface_label = "AppMediaPlayer"; - if (wm.requestSurface(surface_label) != 0) { - exit(EXIT_FAILURE); - } - - // Register an Active event handler. - wm.set_event_handler(Event_Active, - [](char const *label) { - qDebug() << "Surface" << label << "got activated"; - }); - - // Initialize application window - // ... - - // request to activate the surface, this should usually - // not be done by the client application. - if (wm.activateSurface(surface_label) != 0) { - fprintf(stderr, "Could not activate the surface\n"); - exit(EXIT_FAILURE); - } - - // e.g. exec the qt application - app.exec(); - diff --git a/libwindowmanager/doc/LibWindowmanager.txt b/libwindowmanager/doc/LibWindowmanager.txt deleted file mode 100644 index 87394af..0000000 --- a/libwindowmanager/doc/LibWindowmanager.txt +++ /dev/null @@ -1,238 +0,0 @@ -= LibWindowmanager Library User Guide -:doctype: book -:toc: -:icons: -:data-uri: -:lang: en -:encoding: utf-8 - -== Introduction -The LibWindowmanager library provides a simple interface to manipulate and -query the state of the window manager application framework binding. -It is needs to be integrated and called from the client application. - -=== Intended audience -This document is intended to be useful to application developers. - -=== Scope of this Document -This document describes the singleton class interface to the _Window -Manager_ binding service. - -== class LibWindowmanager -This is the public interface of the class `LibWindowmanager`. Private members -and methods are not reproduced as they will not affect usage of the -class by client applications. - ---------------------------- -class LibWindowmanager -{ -public: - static LibWindowmanager &instance(); - - int init(int port, char const *token); - - // WM API - int requestSurface(const char *label); - int activateSurface(const char *label); - int deactivateSurface(const char *label); - int endDraw(const char *label); - - enum EventType { - Event_Active, - Event_Inactive, - Event_Visible, - Event_Invisible, - Event_SyncDraw, - Event_FlushDraw, - }; - - void set_event_handler(enum EventType et, - std::function<void(char const *label)> f); -}; ---------------------------- - -=== Errors -Methods returning an `int` signal successful operation when returning -`0`. In case of an error, an error value is returned as a negative errno -value. E.g. `-EINVAL` to signal that some input value was invalid. - -Additionally, logging of error messages is done on the standard error -file descriptor to help debugging the issue. - -=== Labels -Surface labels are any valid strings. For `requestSurface()` these strings -must match the _Window Manager_ configuration in order to be allowed to -be displayed on one layer or the other. For all other calls the label -must match the exact name of a requested surface. - -=== Methods - -==== LibWindowmanager::init(port, token) -Initialize the Binding communication. - -The `token` parameter is a string consisting of only alphanumeric characters. -If these conditions are not met, the LibWindowmanager instance will not initialize, -i.e. this call will return `-EINVAL`. - -The `port` parameter is the port the afb daemon is listening on, -an invalid port will lead to a failure of the call and return `-EINVAL`. - -==== LibWindowmanager::requestSurface(label) -This method requests a surface with the label given from the _Window -Manager_. It will return `0` for a successful surface request, and -`-errno` on failure. Additionally, on the standard error, messages are -logged to help debgging the issue. - -==== LibWindowmanager::activateSurface(label) -This method is mainly intended for _manager_ applications that control -other applications (think an application manager or the _HomeScreen_). It -instructs the window manager to activate the surface with the given -_label_. - -This method only is effective after the actual window or surface was -created by the application. - -==== LibWindowmanager::deactivateSurface(label) -This method is mainly intended for _manager_ applications that control -other applications. It instructs the window manager to deactivate the -surface associated with the given label. Note, that deactivating a -surface also means to implicitly activate another (the last active or -if not available _main surface_ or _HomeScreen_.) - -This method only is effective after the actual window or surface was -created by the application. - -==== LibWindowmanager::endDraw(label) -This function is called from a client application when it is done -drawing its surface content. - -It is not crucial to make this call at every time a drawing is finished - -it is mainly intended to allow the window manager to synchronize drawing -in case of layout switch. The exact semantics are explained in the next -<<_events,Events>> Section. - -==== LibWindowmanager::set_event_handler(et, func) -This method needs to be used to register event handlers for the WM -events described in the EventType enum. Only one hendler for each -EventType is possible, i.e. if it is called multiple times with the same -EventType the previous handler will be replaced. - -The `func` handler functions will receive the label of the surface this -event is targeted at. - -See Section <<_events,Events>> for mor detailed information about event -delivery to client applications. - -=== Usage - -==== Initialization of LibWindowmanager -Before usage of the LibWindowmanager, the method `init()` must be -called once, it will return `-errno` in case of en error and log diagnostic -messages to stderr. - -==== Request a surface -When creating a surface with _Qt_ - it is necessary to request a surface -from the WM, internally this will communicate with the window manager -binding. Only after `requestSurface()` was successful, a surface should -be created. - -This is also true for _QML_ aplications, where only after the -`requestSurface()` should the load of the resource be done. The method -returns `0` after the surface was requested successfully. - -===== Workings of requestSurface() -`LibWindowmanager::requestSurface()` calls the AFB binding verb -`requestsurface` of the `windowmanager` API. This API call will return a -numeric ID to be used when creating the surface. This ID is never -explicitly returned to the client application, instead, it is set in the -application environment in order for _Qt_ to then use it when creating the -surface. - -.Remarks -******************************** -With the current _Qt_ implementation this means, that only one surface -will be available to client applications, as subsequent windows will -increment this numeric ID internally - which then will lead to IDs that -cannot be known by the window manager as there is no direct -communication from _Qt_ to the WM. -******************************** - -=== Events -Events are a way for the _Window Manager_ to propagate information to -client applications. It was vital for the project to implement a number -of events, that mirror functionality that is already present in the -wayland protocol. - -All events have the surface `label` as argument - a way to enable future -multi-surface applications. - -.Remarks -************************** -As already stated above, this is currently not possible with the way -_Qt_ implements its surface ID setting. -************************** - -==== Active and Inactive Events -These events signal an application that it was activated or deactivated -respectively. Usually this means it was switched visible - which means -the surface will now be on the screen and therefor continue to render. - -==== Visible and Invisible -These events signal an application that it was switched to be visible or -invisible respectively. These events too are handled implicitly through -the wayland protocol by means of `wl_surface::enter` and -`wl_surface::leave` events to the client. - -==== SyncDraw and FlushDraw -These events instruct applications that they should redraw their surface -contents - again, this is handled implicitly by the wayland protocol. - -`SyncDraw` is sent to the application when it has to redraw its surface. - -`FlushDraw` is sent to the application when it should swap its buffers, -that is _signal_ the compositor that its surface contains new content. - -=== Example Use Case -In order to enable application to use the `WM` surface registration -function the above described steps need to be implemented. - -As a minimal example the usage and initialization can look like the -following. - ------------------------ - // Assume a program argc and argv. - QGuiApplication app(argc, argv); - - auto &wm = LibWindowmanager::instance(); - - // initialize the LibWindowmanager binding. - if(wm.init(1234, "wmtest") != 0) { - exit(EXIT_FAILURE); - } - - // Request a surface label from the WM. - char const *surface_label = "AppMediaPlayer"; - if (wm.requestSurface(surface_label) != 0) { - exit(EXIT_FAILURE); - } - - // Register an Active event handler. - wm.set_event_handler(Event_Active, - [](char const *label) { - qDebug() << "Surface" << label << "got activated"; - }); - - // Initialize application window - // ... - - // request to activate the surface, this should usually - // not be done by the client application. - if (wm.activateSurface(surface_label) != 0) { - fprintf(stderr, "Could not activate the surface\n"); - exit(EXIT_FAILURE); - } - - // e.g. exec the qt application - app.exec(); - -// vim:set ft=asciidoc tw=72: diff --git a/libwindowmanager/libwindowmanager.cpp b/libwindowmanager/libwindowmanager.cpp deleted file mode 100644 index c5a1062..0000000 --- a/libwindowmanager/libwindowmanager.cpp +++ /dev/null @@ -1,498 +0,0 @@ -/* - * 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 <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 <json-c/json.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 { - friend class LibWindowmanager; - - // This is the LibWindowmanager interface impl - int init(int port, char const *token); - - // WM API - int requestSurface(const char *label); - int activateSurface(const char *label); - int deactivateSurface(const char *label); - int endDraw(const char *label); - - 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, char const *label); -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))) { - return; - } - - reinterpret_cast<LibWindowmanager::Impl *>(closure)->event( - event, json_object_get_string( - json_object_object_get(afb_wsj1_msg_object_j(msg), "data"))); -} - -/* called when wsj1 hangsup */ -void onHangup(void *closure, afb_wsj1 *wsj1) { - TRACE(); - UNUSED(closure); - UNUSED(wsj1); - fputs("Hangup, the WindowManager vanished\n", stderr); - exit(1); // XXX: there should be something ... *better* here. -} - -constexpr struct afb_wsj1_itf itf = { - onHangup, onCall, onEvent, -}; - -// XXX: I am not sure this is the right thing to do though... -std::recursive_mutex dispatch_mutex; - -json_object *drawing_name_json_argument(char const *label) { - json_object *j = json_object_new_object(); - json_object_object_add(j, "drawing_name", json_object_new_string(label)); - return j; -} - -} // namespace - -// _ ___ _ _ _ -// ___| | __ _ ___ ___ |_ _|_ __ ___ _ __ | | (_)_ __ ___ _ __ | | -// / __| |/ _` / __/ __| | || '_ ` _ \| '_ \| | | | '_ ` _ \| '_ \| | -// | (__| | (_| \__ \__ \ | || | | | | | |_) | | | | | | | | | |_) | | -// \___|_|\__,_|___/___/ |___|_| |_| |_| .__/|_| |_|_| |_| |_| .__/|_| -// |_| |_| -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(); - char *uribuf = nullptr; - int rc = -1; - - if (this->loop != nullptr && this->wsj1 != nullptr) { - fputs("LibWindowmanager instance is already initialized!\n", stderr); - rc = -EALREADY; - goto fail; - } - - if (token == nullptr) { - fputs("Token is invalid\n", stderr); - rc = -EINVAL; - goto fail; - } - - if (port < 1 || port > 0xffff) { - fputs("Port is invalid\n", stderr); - rc = -EINVAL; - goto fail; - } - - /* get the default event loop */ - rc = sd_event_default(&this->loop); - if (rc < 0) { - fprintf(stderr, "Connection to default event loop failed: %s\n", - 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; - fprintf(stderr, "Connection to %s failed: %m\n", uribuf); - rc = -errno; - goto fail; - } - - this->runEventLoop(); - - return 0; - -fail: - return rc; -} - -int LibWindowmanager::Impl::requestSurface(const char *label) { - TRACE(); - - if (this->labels.find(label) != this->labels.end()) { - fputs("Surface label already known!\n", stderr); - return -EINVAL; - } - - json_object *j = drawing_name_json_argument(label); - - int rc = -1; - /* send the request */ - int rc2 = - this->api_call("RequestSurface", j, [&rc](bool ok, json_object *j) { - if (ok) { - int id = - json_object_get_int(json_object_object_get(j, "response")); - char *buf; - asprintf(&buf, "%d", id); - printf("setenv(\"QT_IVI_SURFACE_ID\", %s, 1)\n", buf); - if (setenv("QT_IVI_SURFACE_ID", buf, 1) != 0) { - fprintf(stderr, "putenv failed: %m\n"); - rc = -errno; - } else { - rc = 0; // Single point of success - } - } else { - fprintf(stderr, "Could not get surface ID from WM: %s\n", - j != nullptr ? json_object_to_json_string_ext( - j, JSON_C_TO_STRING_PRETTY) - : "no-info"); - rc = -EINVAL; - } - }); - - if (rc2 < 0) { - rc = rc2; - } - - if (rc >= 0) { - this->labels.insert(this->labels.end(), label); - } - - return rc; -} - -int LibWindowmanager::Impl::activateSurface(const char *label) { - TRACE(); - json_object *j = drawing_name_json_argument(label); - return this->api_call("ActivateSurface", j, [](bool ok, json_object *j) { - if (!ok) { - fprintf(stderr, "API Call activate_surface() failed: %s\n", - j != nullptr ? json_object_to_json_string_ext( - j, JSON_C_TO_STRING_PRETTY) - : "no-info"); - } - }); -} - -int LibWindowmanager::Impl::deactivateSurface(const char *label) { - TRACE(); - json_object *j = drawing_name_json_argument(label); - return this->api_call("DeactivateSurface", j, [](bool ok, json_object *j) { - if (!ok) { - fprintf(stderr, "API Call deactivate_surface() failed: %s\n", - j != nullptr ? json_object_to_json_string_ext( - j, JSON_C_TO_STRING_PRETTY) - : "no-info"); - } - }); -} - -int LibWindowmanager::Impl::endDraw(const char *label) { - TRACE(); - json_object *j = drawing_name_json_argument(label); - return this->api_call("EndDraw", j, [](bool ok, json_object *j) { - if (!ok) { - fprintf(stderr, "API Call endDraw() failed: %s\n", - j != nullptr ? json_object_to_json_string_ext( - j, JSON_C_TO_STRING_PRETTY) - : "no-info"); - } - }); -} - -void LibWindowmanager::Impl::set_event_handler( - enum EventType et, std::function<void(char const *)> func) { - TRACE(); - - if (et >= 1 && et <= 6) { // Yeah ... just go with it! - 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 - -static void _on_reply_static(void *closure, struct afb_wsj1_msg *msg) -{ - // nop -} - - -/// 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)) { - // 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) { - fprintf( - stderr, "calling %s/%s(%s) failed: %m\n", wmAPI, verb, - json_object_to_json_string_ext(object, JSON_C_TO_STRING_PRETTY)); - // Call the reply handler regardless with a NULL json_object* - onReply(false, nullptr); - } - - return rc; -} - -void LibWindowmanager::Impl::event(char const *et, char const *label) { - TRACE(); - auto oet = make_event_type(et); - if (!oet.first) { - fprintf(stderr, "Unknown event type string '%s'\n", et); - return; - } - - auto i = this->handlers.find(oet.second); - if (i != this->handlers.end()) { - if (this->labels.find(label) != this->labels.end()) { - i->second(label); - } - } -} - -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; - } -} - -// _ _ _____ ____ ____ _ _ _ -// ___| | __ _ ___ ___ / \ | ___| __ ) / ___| (_) ___ _ __ | |_ -// / __| |/ _` / __/ __| / _ \ | |_ | _ \| | | | |/ _ \ '_ \| __| -// | (__| | (_| \__ \__ \ / ___ \| _| | |_) | |___| | | __/ | | | |_ -// \___|_|\__,_|___/___/ /_/ \_\_| |____/ \____|_|_|\___|_| |_|\__| -// -int LibWindowmanager::init(int port, char const *token) { - return this->d->init(port, token); -} - -int LibWindowmanager::requestSurface(const char *label) { - return this->d->requestSurface(label); -} - -int LibWindowmanager::activateSurface(const char *label) { - return this->d->activateSurface(label); -} - -int LibWindowmanager::deactivateSurface(const char *label) { - return this->d->deactivateSurface(label); -} - -int LibWindowmanager::endDraw(const char *label) { return this->d->endDraw(label); } - -void LibWindowmanager::set_event_handler(enum EventType et, - std::function<void(char const *label)> f) { - return this->d->set_event_handler(et, std::move(f)); -} - -LibWindowmanager::LibWindowmanager() : d(new Impl) {} - -LibWindowmanager::~LibWindowmanager() { delete d; } diff --git a/libwindowmanager/libwindowmanager.h b/libwindowmanager/libwindowmanager.h deleted file mode 100644 index 6c13763..0000000 --- a/libwindowmanager/libwindowmanager.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - */ - -#ifndef LIBWINDOWMANAGER_H -#define LIBWINDOWMANAGER_H - -#include <functional> - -class LibWindowmanager { -public: - LibWindowmanager(); - ~LibWindowmanager(); - - LibWindowmanager(const LibWindowmanager &) = delete; - LibWindowmanager &operator=(const LibWindowmanager &) = delete; - - using handler_fun = std::function<void(const char *)>; - - enum EventType { - Event_Active = 1, - Event_Inactive, - - Event_Visible, - Event_Invisible, - - Event_SyncDraw, - Event_FlushDraw, - }; - - int init(int port, char const *token); - - // WM API - int requestSurface(const char *label); - int activateSurface(const char *label); - int deactivateSurface(const char *label); - int endDraw(const char *label); - - void set_event_handler(enum EventType et, handler_fun f); - - struct Impl; - -private: - Impl *const d; -}; -#endif // LIBWINDOWMANAGER_H diff --git a/windowmanager.pc.in b/windowmanager.pc.in deleted file mode 100644 index 52e6f04..0000000 --- a/windowmanager.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -includedir=@PROJECT_INCLUDEDIR@ -libdir=@PROJECT_LIBDIR@ -binding_install_dir=@binding_install_dir@ - -Name: @PROJECT_PRETTY_NAME@ -Description: @PROJECT_DESCRIPTION@ -Version: @PROJECT_VERSION@ -URL: @PROJECT_URL@ - -Requires: json-c afb-daemon -Cflags: -I${includedir} -Libs: -L${libdir} -lwindowmanager |