Initial version of headless-server accepted/tizen_5.5_unified accepted/tizen_5.5_unified_mobile_hotfix accepted/tizen_5.5_unified_wearable_hotfix accepted/tizen_6.0_unified accepted/tizen_6.0_unified_hotfix import tizen_5.5 tizen_5.5_mobile_hotfix tizen_5.5_tv tizen_5.5_wearable_hotfix tizen_6.0_hotfix accepted/tizen/5.5/unified/20191031.020308 accepted/tizen/5.5/unified/mobile/hotfix/20201027.080110 accepted/tizen/5.5/unified/wearable/hotfix/20201027.111134 accepted/tizen/6.0/unified/20201030.113934 accepted/tizen/6.0/unified/hotfix/20201103.002057 accepted/tizen/unified/20190805.104341 submit/tizen/20190805.064108 submit/tizen_5.5/20191031.000005 submit/tizen_5.5_mobile_hotfix/20201026.185105 submit/tizen_5.5_wearable_hotfix/20201026.184305 submit/tizen_6.0/20201029.205105 submit/tizen_6.0_hotfix/20201102.192505 submit/tizen_6.0_hotfix/20201103.114805 tizen_5.5.m2_release tizen_6.0.m2_release
authorSung-Jin Park <sj76.park@samsung.com>
Mon, 5 Aug 2019 06:25:18 +0000 (15:25 +0900)
committerSung-Jin Park <sj76.park@samsung.com>
Mon, 5 Aug 2019 06:25:18 +0000 (15:25 +0900)
- Ref revision : b83ac3bcee706dd9043136f603596bbad9d16f46

Signed-off-by: Sung-Jin Park <sj76.park@samsung.com>
27 files changed:
AUTHORS [new file with mode: 0644]
CODING_STYLE [new file with mode: 0644]
COPYING [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
README.md [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
data/scripts/winfo [new file with mode: 0644]
data/units/display-manager-ready.path [new file with mode: 0644]
data/units/display-manager-ready.service [new file with mode: 0644]
data/units/display-manager.env [new file with mode: 0644]
data/units/display-manager.service [new file with mode: 0644]
data/units/display-user.service [new file with mode: 0644]
data/units/display_env.sh [new file with mode: 0644]
packaging/headless-server.manifest [new file with mode: 0644]
packaging/headless-server.spec [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/debug/debug.c [new file with mode: 0644]
src/headless_server.c [new file with mode: 0644]
src/headless_server.h [new file with mode: 0644]
src/input/input.c [new file with mode: 0644]
src/output/HL_UI_LED.h [new file with mode: 0644]
src/output/HL_UI_LED_APA102.c [new file with mode: 0644]
src/output/boot_anim.c [new file with mode: 0644]
src/output/output_internal.h [new file with mode: 0644]
src/output/output_led.c [new file with mode: 0644]
src/shell/shell.c [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..21dd7b5
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,3 @@
+Sangjin   Lee  lsj119@samsung.com
+Sungjin   Park sj76.park@samsung.com
+Jeonghyun Kang jhyuni.kang@samsung.com
diff --git a/CODING_STYLE b/CODING_STYLE
new file mode 100644 (file)
index 0000000..57cb29b
--- /dev/null
@@ -0,0 +1,73 @@
+== Coding style ==
+
+You should follow the style of the file you're editing. In general, we
+try to follow the rules below.
+
+- indent with tabs, and a tab is always 4 characters wide
+- opening braces are on the same line as the if statement;
+- no braces in an if-body with just one statement;
+- if one of the branches of an if-else codition has braces, than the
+  other branch should also have braces;
+- there is always an empty line between variable declarations and the
+  code;
+
+static int
+my_function(void)
+{
+   int a = 0;
+
+   if (a)
+      b();
+   else
+      c();
+
+   if (a) {
+      b();
+      c();
+   } else {
+      d();
+   }
+}
+
+- lines should be less than 80 characters wide;
+- when breaking lines with functions calls, the parameters are aligned
+  with the opening parenthesis;
+- when assigning a variable with the result of a function call, if the
+  line would be longer we break it around the equal '=' sign if it makes
+  sense;
+
+   long_variable_name =
+      function_with_a_really_long_name(parameter1, parameter2,
+                   parameter3, parameter4);
+
+   x = function_with_a_really_long_name(parameter1, parameter2,
+                    parameter3, parameter4);
+
+== astyle options ==
+#command line
+#astyle -A8 -t4 -p -z2 -H -k3 -W3 -xC80 -xL -n -r "./*.c"
+#or 
+#astyle -A8t8pz2Hk3W3xC80xLnrf "*.c"
+
+#default style : linux
+--style=linux
+--indent=tab=8
+--indent=force-tab-x=8
+
+#Padding Options
+--pad-oper
+--pad-header
+--align-pointer=name
+--align-reference=name
+
+#Formatting Options
+--max-code-length=80
+--break-after-logical
+
+#Other Options
+--suffix=none
+--recursive
+--lineend=linux
+
+== VI options ==
+TODO:
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..6af77c9
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,31 @@
+Copyright © 2008-2012 Kristian Høgsberg
+Copyright © 2010-2012 Intel Corporation
+Copyright © 2011 Benjamin Franzke
+Copyright © 2012 Collabora, Ltd.
+Copyright © 2015 S-Core Corporation
+Copyright © 2015-2017 Samsung Electronics co., Ltd. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+---
+
+The above is the version of the MIT "Expat" License used by X.org:
+
+    http://cgit.freedesktop.org/xorg/xserver/tree/COPYING
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..c390ceb
--- /dev/null
@@ -0,0 +1,4 @@
+SUBDIRS = src
+
+#pkgconfig_DATA =
+
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..1eea085
--- /dev/null
+++ b/README.md
@@ -0,0 +1,2 @@
+# headless-server
+Pepper-based display server for headless (e.g. Tizen Speaker Profile)
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..916169a
--- /dev/null
@@ -0,0 +1,9 @@
+#! /bin/sh
+
+test -n "$srcdir" || srcdir=`dirname "$0"`
+test -n "$srcdir" || srcdir=.
+(
+  cd "$srcdir" &&
+  autoreconf --force -v --install
+) || exit
+test -n "$NOCONFIGURE" || "$srcdir/configure" "$@"
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..d8f71d8
--- /dev/null
@@ -0,0 +1,44 @@
+m4_define([hsvr_major], 0)
+m4_define([hsvr_minor], 0)
+m4_define([hsvr_micro], 0)
+
+m4_define([hsvr_version], [hsvr_major.hsvr_minor.hsvr_micro])
+
+AC_PREREQ([2.64])
+AC_INIT([pepper], [pepper_version], [tkq.kim@samsung.com])
+
+AC_SUBST([HSVR_VERSION_MAJOR], [hsvr_major_version])
+AC_SUBST([HSVR_VERSION_MINOR], [hsvr_minor_version])
+AC_SUBST([HSVR_VERSION_MICRO], [hsvr_micro_version])
+AC_SUBST([HSVR_VERSION], [hsvr_version])
+
+AC_CONFIG_HEADERS([config.h])
+AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz subdir-objects])
+AM_SILENT_RULES([yes])
+
+AC_PROG_CC
+
+LT_PREREQ([2.2])
+LT_INIT([disable-static])
+
+if test "x$GCC" = "xyes"; then
+GCC_CFLAGS="-Wall -Wextra -Wno-unused-parameter \
+            -Wno-missing-field-initializers -g -fvisibility=hidden \
+            -Wstrict-prototypes -Wmissing-prototypes -Wsign-compare"
+fi
+AC_SUBST(GCC_CFLAGS)
+
+# headless server
+HEADLESS_SERVER_REQUIRES="pepper pepper-inotify pepper-keyrouter pepper-devicemgr pepper-xkb pepper-evdev xkbcommon capi-system-peripheral-io xdg-shell-unstable-v6-server tizen-extension-server wayland-tbm-server"
+PKG_CHECK_MODULES(HEADLESS_SERVER, $[HEADLESS_SERVER_REQUIRES])
+
+AC_SUBST(HEADLESS_SERVER_CFLAGS)
+AC_SUBST(HEADLESS_SERVER_LIBS)
+
+# Output files
+AC_CONFIG_FILES([
+Makefile
+src/Makefile
+])
+
+AC_OUTPUT
diff --git a/data/scripts/winfo b/data/scripts/winfo
new file mode 100644 (file)
index 0000000..e320655
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+if [ "$XDG_RUNTIME_DIR" = "" ]; then
+       export XDG_RUNTIME_DIR=/run
+fi
+
+WINFO_RUN_DIR="$XDG_RUNTIME_DIR/pepper"
+
+if [ ! -d "$WINFO_RUN_DIR" ]; then
+       echo "Error: no ${WINFO_RUN_DIR} directory exist."
+       exit 1
+fi
+
+cd $WINFO_RUN_DIR
+
+function usage()
+{
+       echo "Usage> # winfo {command}"
+       echo ""
+       echo "   Supported commands:"
+       echo ""
+       echo "     protocol_trace_on (turn on wayland protocol trace)"
+       echo "     protocol_trace_off (turn off wayland protocol trace)"
+       echo "     stdout (redirect STDOUT to a file : /run/pepper/stdout.txt)"
+       echo "     stderr (redirect STDERR to a file : /run/pepper/stderr.txt)"
+       echo "     keygrab_status"
+       echo "     keymap"
+       echo "     topvwins"
+       echo "     connected_clients (display connected clients info : pid, uid, gid, socket fd)"
+       echo "     reslist (display resources info of the connected clients"
+       echo "     help (display this help message)"
+       echo ""
+       echo "   To execute commands, just create/remove/update a file with the commands above."
+       echo "   Please refer to the following examples."
+       echo ""
+       echo "     # winfo protocol_trace_on   : enable event trace"
+       echo "     # winfo protocol_trace_off  : disable event trace"
+       echo "     # winfo stdout              : redirect STDOUT"
+       echo "     # winfo stderr              : redirect STDERR"
+       echo "     # winfo keygrab_status      : display keygrab status"
+       echo "     # winfo keymap              : display keymap"
+       echo "     # winfo topvwins            : display top/visible window stack"
+       echo "     # winfo connected_clients   : display connected clients information"
+       echo "     # winfo reslist             : display each resources information of connected clients"
+       echo "     # winfo help                : display this help message"
+       echo ""
+}
+
+if [ "$1" = "" ]; then
+       usage
+       exit 1
+fi
+
+CMD="$1"
+
+rm -f ${CMD} ; touch ${CMD}
+echo "winfo ${CMD}"
diff --git a/data/units/display-manager-ready.path b/data/units/display-manager-ready.path
new file mode 100644 (file)
index 0000000..24357bd
--- /dev/null
@@ -0,0 +1,6 @@
+[Unit]
+Description=Path activation for display manager ready service
+After=tmp.mount display-manager.service
+
+[Path]
+PathExists=/run/wayland-0
diff --git a/data/units/display-manager-ready.service b/data/units/display-manager-ready.service
new file mode 100644 (file)
index 0000000..00ac10b
--- /dev/null
@@ -0,0 +1,13 @@
+[Unit]
+Description=Headless Display Manager Ready Service
+After=tmp.mount display-manager.service
+
+[Service]
+Type=oneshot
+EnvironmentFile=/etc/sysconfig/display-manager.env
+SmackProcessLabel=System
+ExecStart=/usr/bin/sh -c "while [ ! -e /run/wayland-0 ] ; do /usr/bin/sleep .1 ; done ;/bin/chown -f root:display /run/wayland-0;/bin/chmod 775 /run/wayland-0"
+ExecStartPost=/usr/bin/sh -c "/usr/bin/touch /run/.wm_ready"
+
+[Install]
+WantedBy=graphical.target
diff --git a/data/units/display-manager.env b/data/units/display-manager.env
new file mode 100644 (file)
index 0000000..dc45551
--- /dev/null
@@ -0,0 +1,3 @@
+TBM_DISPLAY_SERVER=1
+WAYLAND_DISPLAY="wayland-0"
+XDG_RUNTIME_DIR=/run
diff --git a/data/units/display-manager.service b/data/units/display-manager.service
new file mode 100644 (file)
index 0000000..5b4663d
--- /dev/null
@@ -0,0 +1,12 @@
+[Unit]
+Description=Headless Display Manager
+
+[Service]
+Type=simple
+EnvironmentFile=/etc/sysconfig/display-manager.env
+SmackProcessLabel=System
+ExecStartPre=/usr/bin/bash -c "/usr/bin/mkdir -p ${XDG_RUNTIME_DIR}/pepper/"
+ExecStart=/usr/bin/headless_server
+
+[Install]
+WantedBy=graphical.target
diff --git a/data/units/display-user.service b/data/units/display-user.service
new file mode 100644 (file)
index 0000000..392df83
--- /dev/null
@@ -0,0 +1,7 @@
+[Unit]
+Description=Creating a link file for user to access display manager socket
+DefaultDependencies=no
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/sh -c "while [ ! -e /run/wayland-0 ] ; do /usr/bin/sleep .1 ; done ;/usr/bin/ln -sf /run/wayland-0 /run/user/%U/"
diff --git a/data/units/display_env.sh b/data/units/display_env.sh
new file mode 100644 (file)
index 0000000..6b25629
--- /dev/null
@@ -0,0 +1,8 @@
+if [ "$USER" == "root" ]; then
+        export XDG_RUNTIME_DIR=/run
+else
+        export XDG_RUNTIME_DIR=/run/user/$UID
+fi
+if [ "$WAYALND_DISPLAY" = "" ]; then
+        export WAYLAND_DISPLAY=wayland-0
+fi
diff --git a/packaging/headless-server.manifest b/packaging/headless-server.manifest
new file mode 100644 (file)
index 0000000..017d22d
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+ <request>
+    <domain name="_"/>
+ </request>
+</manifest>
diff --git a/packaging/headless-server.spec b/packaging/headless-server.spec
new file mode 100644 (file)
index 0000000..27894f1
--- /dev/null
@@ -0,0 +1,107 @@
+Name:          headless-server
+Version:       0.0.1
+Release:       0
+Summary:       Display server for headless profile
+License:       MIT
+Group:         Graphics & UI Framework/Wayland Window System
+
+Source:                %{name}-%{version}.tar.xz
+source1001:     %name.manifest
+
+BuildRequires: autoconf > 2.64
+BuildRequires: automake >= 1.11
+BuildRequires: libtool >= 2.2
+BuildRequires:  pkgconfig(pepper)
+BuildRequires:  pkgconfig(pepper-inotify)
+BuildRequires:  pkgconfig(pepper-keyrouter)
+BuildRequires:  pkgconfig(pepper-xkb)
+BuildRequires:  pkgconfig(pepper-devicemgr)
+BuildRequires:  pkgconfig(pepper-evdev)
+BuildRequires:  pkgconfig(xkbcommon)
+BuildRequires:  pkgconfig(wayland-tbm-server)
+BuildRequires:  pkgconfig(tizen-extension-server)
+BuildRequires:  pkgconfig(capi-system-peripheral-io)
+BuildRequires: pkgconfig(xdg-shell-unstable-v6-server)
+BuildRequires: pkgconfig(tizen-extension-server)
+
+Requires: pepper pepper-keyrouter pepper-devicemgr pepper-evdev
+Requires: pepper-xkb xkeyboard-config xkb-tizen-data
+Requires: libtbm
+Requires: capi-system-peripheral-io
+Conflicts: pepper-doctor
+
+%description
+Headless server is a display server for headless profile.
+
+%package devel
+Summary: Development module for headless-server package
+Requires: %{name} = %{version}-%{release}
+
+%description devel
+This package includes developer files common to all packages.
+
+%prep
+%setup -q
+cp %{SOURCE1001} .
+
+%build
+%autogen
+
+make %{?_smp_mflags}
+
+%install
+%make_install
+
+%define display_user display
+%define display_group display
+
+# install system session services
+%__mkdir_p %{buildroot}%{_unitdir}
+install -m 644 data/units/display-manager.service %{buildroot}%{_unitdir}
+install -m 550 data/scripts/* %{buildroot}%{_bindir}
+install -m 644 data/units/display-manager-ready.path %{buildroot}%{_unitdir}
+install -m 644 data/units/display-manager-ready.service %{buildroot}%{_unitdir}
+
+# install user session service
+%__mkdir_p %{buildroot}%{_unitdir_user}
+install -m 644 data/units/display-user.service %{buildroot}%{_unitdir_user}
+
+# install env file and scripts for service
+%__mkdir_p %{buildroot}%{_sysconfdir}/sysconfig
+install -m 0644 data/units/display-manager.env %{buildroot}%{_sysconfdir}/sysconfig
+%__mkdir_p %{buildroot}%{_sysconfdir}/profile.d
+install -m 0644 data/units/display_env.sh %{buildroot}%{_sysconfdir}/profile.d
+
+%post -n %{name} -p /sbin/ldconfig
+%postun -n %{name} -p /sbin/ldconfig
+
+%pre
+# create groups 'display'
+getent group %{display_group} >/dev/null || %{_sbindir}/groupadd -r -o %{display_group}
+# create user 'display'
+getent passwd %{display_user} >/dev/null || %{_sbindir}/useradd -r -g %{display_group} -d /run/display -s /bin/false -c "Display" %{display_user}
+
+# create links within systemd's target(s)
+%__mkdir_p %{_unitdir}/graphical.target.wants/
+%__mkdir_p %{_unitdir_user}/basic.target.wants/
+ln -sf ../display-manager.service %{_unitdir}/graphical.target.wants/
+ln -sf ../display-manager-ready.service %{_unitdir}/graphical.target.wants/
+ln -sf ../display-user.service %{_unitdir_user}/basic.target.wants/
+
+%files
+%manifest %{name}.manifest
+%defattr(-,root,root,-)
+%license COPYING
+%{_bindir}/headless*
+%{_bindir}/winfo
+%{_unitdir}/display-manager-ready.path
+%{_unitdir}/display-manager-ready.service
+%{_unitdir}/display-manager.service
+%{_unitdir_user}/display-user.service
+%config %{_sysconfdir}/sysconfig/display-manager.env
+%config %{_sysconfdir}/profile.d/display_env.sh
+
+%files devel
+%manifest %{name}.manifest
+%defattr(-,root,root,-)
+
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..1cdb324
--- /dev/null
@@ -0,0 +1,14 @@
+bin_PROGRAMS =
+
+bin_PROGRAMS += headless_server
+
+headless_server_CFLAGS = $(HEADLESS_SERVER_CFLAGS)
+headless_server_LDADD  = $(HEADLESS_SERVER_LIBS)
+
+headless_server_SOURCES = headless_server.c \
+                         debug/debug.c \
+                         input/input.c \
+                         output/output_led.c \
+                         output/HL_UI_LED_APA102.c \
+                         output/boot_anim.c \
+                         shell/shell.c
diff --git a/src/debug/debug.c b/src/debug/debug.c
new file mode 100644 (file)
index 0000000..a6761b7
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+* Copyright © 2019 Samsung Electronics co., Ltd. All Rights Reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice (including the next
+* paragraph) shall be included in all copies or substantial portions of the
+* Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <pepper.h>
+#include <wayland-server.h>
+#include <wayland-util.h>
+#include <pepper-inotify.h>
+#include <pepper-keyrouter.h>
+#include <pepper-xkb.h>
+#include <headless_server.h>
+
+#define MAX_CMDS       256
+
+#define STDOUT_REDIR                   "stdout"
+#define STDERR_REDIR                   "stderr"
+#define PROTOCOL_TRACE_ON              "protocol_trace_on"
+#define PROTOCOL_TRACE_OFF             "protocol_trace_off"
+#define KEYGRAB_STATUS                 "keygrab_status"
+#define TOPVWINS                       "topvwins"
+#define CONNECTED_CLIENTS              "connected_clients"
+#define CLIENT_RESOURCES               "reslist"
+#define KEYMAP                         "keymap"
+#define HELP_MSG                       "help"
+
+typedef struct
+{
+       pepper_compositor_t *compositor;
+       pepper_inotify_t *inotify;
+
+       pepper_view_t *top_mapped;
+       pepper_view_t *focus;
+} headless_debug_t;
+
+typedef void (*headless_debug_action_cb_t)(headless_debug_t *hd, void *data);
+
+typedef struct
+{
+   const char *cmds;
+   headless_debug_action_cb_t cb;
+   headless_debug_action_cb_t disable_cb;
+} headless_debug_action_t;
+
+const static int KEY_DEBUG = 0xdeaddeb0;
+extern void wl_debug_server_enable(int enable);
+
+static void
+_headless_debug_usage()
+{
+       fprintf(stdout, "Supported commands:\n\n");
+       fprintf(stdout, "\t %s\n", PROTOCOL_TRACE_ON);
+       fprintf(stdout, "\t %s\n", PROTOCOL_TRACE_OFF);
+       fprintf(stdout, "\t %s\n", STDOUT_REDIR);
+       fprintf(stdout, "\t %s\n", STDERR_REDIR);
+       fprintf(stdout, "\t %s\n", KEYGRAB_STATUS);
+       fprintf(stdout, "\t %s\n", TOPVWINS);
+       fprintf(stdout, "\t %s\n", CONNECTED_CLIENTS);
+       fprintf(stdout, "\t %s\n", CLIENT_RESOURCES);
+       fprintf(stdout, "\t %s\n", KEYMAP);
+       fprintf(stdout, "\t %s\n", HELP_MSG);
+
+       fprintf(stdout, "\nTo execute commands, just create/remove/update a file with the commands above.\n");
+       fprintf(stdout, "Please refer to the following examples.\n\n");
+       fprintf(stdout, "\t # winfo protocol_trace_on\t : enable event trace\n");
+       fprintf(stdout, "\t # winfo event_trace_off\t : disable event trace\n");
+       fprintf(stdout, "\t # winfo stdout\t\t\t : redirect STDOUT\n");
+       fprintf(stdout, "\t # winfo stderr\t\t\t : redirect STDERR\n");
+       fprintf(stdout, "\t # winfo keygrab_status\t\t : display keygrab status\n");
+       fprintf(stdout, "\t # winfo topvwins\t\t : display top/visible window stack\n");
+       fprintf(stdout, "\t # winfo connected_clients\t : display connected clients information\n");
+       fprintf(stdout, "\t # winfo reslist\t\t : display each resources information of connected clients\n");
+       fprintf(stdout, "\t # winfo keymap\t\t : display current xkb keymap\n");
+       fprintf(stdout, "\t # winfo help\t\t\t : display this help message\n");
+}
+
+static void
+_headless_debug_protocol_trace_on(headless_debug_t *hdebug, void *data)
+{
+       (void) hdebug;
+       (void) data;
+       wl_debug_server_enable(1);
+}
+
+static void
+_headless_debug_protocol_trace_off(headless_debug_t *hdebug, void *data)
+{
+       (void) hdebug;
+       (void) data;
+       wl_debug_server_enable(0);
+}
+
+static void
+_headless_debug_dummy(headless_debug_t *hdebug, void *data)
+{
+       (void) hdebug;
+       (void) data;
+       _headless_debug_usage();
+}
+
+static enum wl_iterator_result
+_client_get_resource_itr(struct wl_resource *resource, void *data)
+{
+       int *n_resources = (int *)data;
+
+       PEPPER_TRACE("\t\t [resource][%d] class=%s, id=%u\n", ++(*n_resources), wl_resource_get_class(resource), wl_resource_get_id(resource));
+
+       return WL_ITERATOR_CONTINUE;
+}
+
+static void
+_headless_debug_connected_clients(headless_debug_t *hdebug, void *data)
+{
+       pid_t pid;
+       uid_t uid;
+       gid_t gid;
+
+       int client_fd = -1;
+       uint32_t n_clients = 0;
+       int n_resources = 0;
+
+       struct wl_list *clist = NULL;
+       struct wl_client *client_itr = NULL;
+       pepper_bool_t need_reslist = PEPPER_FALSE;
+
+       const char *cmds = (const char *)data;
+
+       /* check if reslist feature is required */
+       if (cmds && !strncmp(cmds, CLIENT_RESOURCES, MAX_CMDS)) {
+               need_reslist = PEPPER_TRUE;
+       }
+
+       /* get client list which bound wl_compositor global */
+       clist = wl_display_get_client_list(pepper_compositor_get_display(hdebug->compositor));
+       PEPPER_CHECK(clist, return, "Failed to get client list from compositor->display.\n");
+
+       PEPPER_TRACE("========= [Connected clients information] =========\n");
+       wl_client_for_each(client_itr, clist) {
+               n_clients++;
+               client_fd = wl_client_get_fd(client_itr);
+               wl_client_get_credentials(client_itr, &pid, &uid, &gid);
+               PEPPER_TRACE("\t client[%d]: pid=%d, user=%d, group=%d, socket_fd=%d", n_clients, pid, uid, gid, client_fd);
+
+               if (PEPPER_FALSE == need_reslist) {
+                       PEPPER_TRACE("\n");
+                       continue;
+               }
+
+               PEPPER_TRACE("\n");
+               wl_client_for_each_resource(client_itr, _client_get_resource_itr, &n_resources);
+               PEPPER_TRACE("\t\t number of resources = %d\n", n_resources);
+
+               n_resources = 0;
+       }
+
+       if (!n_clients)
+               PEPPER_TRACE("============ [No connected clients] ===========\n\n");
+}
+
+static void
+_headless_debug_redir_stdout(headless_debug_t *hdebug, void *data)
+{
+       (void) hdebug;
+       (void) data;
+
+       int fd = -1;
+       int ret = 0;
+
+       fd = open("/run/pepper/stdout.txt", O_CREAT | O_WRONLY | O_APPEND, S_IWUSR | S_IWGRP);
+
+       if (fd < 0) {
+               PEPPER_TRACE("Failed to open stdout.txt (errno=%s)\n", strerror(errno));
+               return;
+       }
+
+       ret = dup2(fd, 1);
+       close(fd);
+       PEPPER_CHECK(ret >= 0, return, "Failed to redirect STDOUT.\n");
+
+       PEPPER_TRACE("STDOUT has been redirected to stdout.txt.\n");
+}
+
+static void
+_headless_debug_redir_stderr(headless_debug_t *hdebug, void *data)
+{
+       (void) hdebug;
+       (void) data;
+
+       int fd = -1;
+       int ret = 0;
+
+       fd = open("/run/pepper/stderr.txt", O_CREAT | O_WRONLY | O_APPEND, S_IWUSR | S_IWGRP);
+
+       if (fd < 0) {
+               PEPPER_TRACE("Failed to open stderr.txt (errno=%s)\n", strerror(errno));
+               return;
+       }
+
+       ret = dup2(fd, 2);
+       close(fd);
+       PEPPER_CHECK(ret >= 0, return, "Failed to redirect STDERR.\n");
+
+       PEPPER_TRACE("STDERR has been redirected to stderr.txt.\n");
+
+}
+
+static void
+_headless_debug_topvwins(headless_debug_t *hdebug, void *data)
+{
+       (void) data;
+
+       int cnt = 0;
+       int w, h;
+       double x, y;
+       pid_t pid;
+
+       pepper_list_t *l;
+       const pepper_list_t *list;
+       pepper_view_t *view;
+       pepper_surface_t *surface;
+       pepper_view_t *top_visible = NULL;
+
+       PEPPER_CHECK(hdebug, return, "[%s] Invalid headless debug !\n", __FUNCTION__);
+
+       PEPPER_TRACE("No. WinID      RscID       PID     w    h    x    y   Mapped Visible Top Top_Visible Focus\n");
+       PEPPER_TRACE("==========================================================================================\n");
+
+       list = pepper_compositor_get_view_list(hdebug->compositor);
+
+       pepper_list_for_each_list(l,  list) {
+               view = (pepper_view_t *)l->item;
+               PEPPER_CHECK(view, continue, "[%s] Invalid object view:%p\n", __FUNCTION__, view);
+
+               surface = pepper_view_get_surface(view);
+               PEPPER_CHECK(surface, continue, "[%s] Invalid object surface:%p\n", __FUNCTION__, surface);
+
+               cnt++;
+               pepper_view_get_position(view, &x, &y);
+               pepper_view_get_size(view, &w, &h);
+               wl_client_get_credentials(wl_resource_get_client(pepper_surface_get_resource(surface)), &pid, NULL, NULL);
+               if (!top_visible && pepper_surface_get_buffer(surface))
+                       top_visible = view;
+
+               pepper_log("DEBUG", PEPPER_LOG_LEVEL_DEBUG, "%3d 0x%08x 0x%08x %5d %4d %4d %4.0f %4.0f     %s       %s     %s       %s       %s\n",
+                                       cnt, surface, pepper_surface_get_resource(surface), pid, w, h, x, y,
+                                       pepper_view_is_mapped(view) ? "O" : "X",
+                                       pepper_view_is_visible(view) ? "O" : "X",
+                                       (hdebug->top_mapped == view) ? "O" : "X",
+                                       (top_visible == view) ? "O" : "X",
+                                       (hdebug->focus == view) ? "O" : "X");
+       }
+
+       PEPPER_TRACE("==========================================================================================\n");
+}
+
+static void
+_headless_debug_keygrab_status(headless_debug_t *hdebug, void *data)
+{
+       pepper_keyrouter_t *keyrouter;
+
+       keyrouter = headless_input_get_keyrouter(hdebug->compositor);
+       pepper_keyrouter_debug_keygrab_status_print(keyrouter);
+}
+
+static void
+_headless_debug_keymap(headless_debug_t *hdebug, void *data)
+{
+       pepper_xkb_t *xkb;
+
+       int i;
+       int min_keycode, max_keycode, num_mods, num_groups;
+       struct xkb_context *context = NULL;
+       struct xkb_keymap *keymap = NULL;
+       struct xkb_state *state = NULL;
+       xkb_keysym_t sym = XKB_KEY_NoSymbol;
+       char keyname[256] = {0, };
+
+       xkb = headless_input_get_xkb(hdebug->compositor);
+       PEPPER_CHECK(xkb, return, "xkb is not set\n");
+
+       context = pepper_xkb_get_context(xkb);
+       PEPPER_CHECK(context, return, "Current pepper_xkb has no context.\n");
+       keymap = pepper_xkb_get_keymap(xkb);
+       PEPPER_CHECK(keymap, return, "Current pepper_xkb has no keymap.\n");
+       state = pepper_xkb_get_state(xkb);
+       PEPPER_CHECK(state, return, "Current pepper_xkb has no state.\n");
+
+       min_keycode = xkb_keymap_min_keycode(keymap);
+       max_keycode = xkb_keymap_max_keycode(keymap);
+       num_groups = xkb_map_num_groups(keymap);
+       num_mods = xkb_keymap_num_mods(keymap);
+
+       printf("\n");
+       printf("    min keycode: %d\n", min_keycode);
+       printf("    max keycode: %d\n", max_keycode);
+       printf("    num_groups : %d\n", num_groups);
+       printf("    num_mods   : %d\n", num_mods);
+       for (i = 0; i < num_mods; i++) {
+               printf("        [%2d] mod: %s\n", i, xkb_keymap_mod_get_name(keymap, i));
+       }
+
+       printf("\n\n\tkeycode\t\tkeyname\t\t  keysym\t    repeat\n");
+       printf("    ----------------------------------------------------------------------\n");
+
+       for (i = min_keycode; i < (max_keycode + 1); i++) {
+               sym = xkb_state_key_get_one_sym(state, i);
+
+               memset(keyname, 0, sizeof(keyname));
+               xkb_keysym_get_name(sym, keyname, sizeof(keyname));
+
+               if (!strncmp(keyname, "NoSymbol", sizeof("NoSymbol")) && sym == 0x0)
+                       continue;
+
+               printf("\t%4d%-5s%-25s%-20x%-5d\n", i, "", keyname, sym, xkb_keymap_key_repeats(keymap, i));
+       }
+}
+
+static const headless_debug_action_t debug_actions[] =
+{
+       { STDOUT_REDIR,  _headless_debug_redir_stdout, NULL },
+       { STDERR_REDIR,  _headless_debug_redir_stderr, NULL },
+       { PROTOCOL_TRACE_ON,  _headless_debug_protocol_trace_on, _headless_debug_protocol_trace_off },
+       { PROTOCOL_TRACE_OFF, _headless_debug_protocol_trace_off, NULL },
+       { KEYGRAB_STATUS, _headless_debug_keygrab_status, NULL },
+       { TOPVWINS, _headless_debug_topvwins, NULL },
+       { CONNECTED_CLIENTS, _headless_debug_connected_clients, NULL },
+       { CLIENT_RESOURCES, _headless_debug_connected_clients, NULL },
+       { KEYMAP, _headless_debug_keymap, NULL },
+       { HELP_MSG, _headless_debug_dummy, NULL },
+};
+
+static void
+_headless_debug_enable_action(headless_debug_t *hdebug, char *cmds)
+{
+       int n_actions = sizeof(debug_actions)/sizeof(debug_actions[0]);
+
+       for(int n=0 ; n < n_actions ; n++) {
+               if (!strncmp(cmds, debug_actions[n].cmds, MAX_CMDS)) {
+                       PEPPER_TRACE("[%s : %s]\n", __FUNCTION__, debug_actions[n].cmds);
+                       debug_actions[n].cb(hdebug, (void *)debug_actions[n].cmds);
+
+                       break;
+               }
+       }
+}
+
+static void
+_headless_debug_disable_action(headless_debug_t *hdebug, char *cmds)
+{
+       int n_actions = sizeof(debug_actions)/sizeof(debug_actions[0]);
+
+       for(int n=0 ; n < n_actions ; n++) {
+               if (!strncmp(cmds, debug_actions[n].cmds, MAX_CMDS)) {
+                       if (debug_actions[n].disable_cb) {
+                               PEPPER_TRACE("[%s : %s]\n", __FUNCTION__, debug_actions[n].cmds);
+                               debug_actions[n].disable_cb(hdebug, (void *)debug_actions[n].cmds);
+                       }
+
+                       break;
+               }
+       }
+}
+
+static void
+_trace_cb_handle_inotify_event(uint32_t type, pepper_inotify_event_t *ev, void *data)
+{
+       headless_debug_t *hdebug = data;
+       char *file_name = pepper_inotify_event_name_get(ev);
+
+       PEPPER_CHECK(hdebug, return, "Invalid headless debug instance\n");
+
+       switch (type)
+       {
+               case PEPPER_INOTIFY_EVENT_TYPE_CREATE:
+                       _headless_debug_enable_action(hdebug, file_name);
+                       break;
+               case PEPPER_INOTIFY_EVENT_TYPE_REMOVE:
+                       _headless_debug_disable_action(hdebug, file_name);
+                       break;
+               case PEPPER_INOTIFY_EVENT_TYPE_MODIFY:
+                       break;
+               default:
+                       PEPPER_TRACE("[%s] Unhandled event type (%d)\n", __FUNCTION__, type);
+                       break;
+       }
+}
+
+PEPPER_API void
+headless_debug_set_focus_view(pepper_compositor_t *compositor, pepper_view_t *focus_view)
+{
+       headless_debug_t *hdebug = NULL;
+
+       hdebug = (headless_debug_t *)pepper_object_get_user_data((pepper_object_t *) compositor, &KEY_DEBUG);
+       PEPPER_CHECK(hdebug, return, "Invalid headless debug.\n");
+
+       if (hdebug->focus != focus_view) {
+               PEPPER_TRACE("[DEBUG] Focus view has been changed to 0x%x (from 0x%x)\n", focus_view, hdebug->focus);
+               hdebug->focus = focus_view;
+       }
+}
+
+PEPPER_API void
+headless_debug_set_top_view(pepper_compositor_t *compositor, pepper_view_t *top_view)
+{
+       headless_debug_t *hdebug = NULL;
+
+       hdebug = (headless_debug_t *)pepper_object_get_user_data((pepper_object_t *) compositor, &KEY_DEBUG);
+       PEPPER_CHECK(hdebug, return, "Invalid headless debug.\n");
+
+       if (hdebug->top_mapped != top_view) {
+               PEPPER_TRACE("[DEBUG] Top view has been changed to 0x%x (from 0x%x)\n", top_view, hdebug->top_mapped);
+               hdebug->top_mapped = top_view;
+       }
+}
+
+PEPPER_API void
+headless_debug_deinit(pepper_compositor_t * compositor)
+{
+       headless_debug_t *hdebug = NULL;
+
+       hdebug = (headless_debug_t *)pepper_object_get_user_data((pepper_object_t *) compositor, &KEY_DEBUG);
+       PEPPER_CHECK(hdebug, return, "Failed to get headless debug instance\n");
+
+       /* remove the directory watching already */
+       if (hdebug->inotify)
+               pepper_inotify_del(hdebug->inotify, "/run/pepper");
+
+       /* remove inotify */
+       pepper_inotify_destroy(hdebug->inotify);
+       hdebug->inotify = NULL;
+
+       pepper_object_set_user_data((pepper_object_t *)hdebug->compositor, &KEY_DEBUG, NULL, NULL);
+       free(hdebug);
+}
+
+pepper_bool_t
+headless_debug_init(pepper_compositor_t *compositor)
+{
+       int n_actions;
+       headless_debug_t *hdebug = NULL;
+       pepper_inotify_t *inotify = NULL;
+       pepper_bool_t res = PEPPER_FALSE;
+
+       hdebug = (headless_debug_t*)calloc(1, sizeof(headless_debug_t));
+       PEPPER_CHECK(hdebug, goto error, "Failed to alloc for headless debug\n");
+       hdebug->compositor = compositor;
+
+       /* create inotify to watch file(s) for event trace */
+       inotify = pepper_inotify_create(hdebug->compositor, _trace_cb_handle_inotify_event, hdebug);
+       PEPPER_CHECK(inotify, goto error, "Failed to create inotify\n");
+
+       /* add a directory for watching */
+       res = pepper_inotify_add(inotify, "/run/pepper");
+       PEPPER_CHECK(res, goto error, "Failed on pepper_inotify_add()\n");
+
+       hdebug->inotify = inotify;
+       n_actions = sizeof(debug_actions)/sizeof(debug_actions[0]);
+
+       PEPPER_TRACE("[%s] Done (%d actions have been defined.)\n", __FUNCTION__, n_actions);
+
+       pepper_object_set_user_data((pepper_object_t *)compositor, &KEY_DEBUG, hdebug, NULL);
+       return PEPPER_TRUE;
+
+error:
+       headless_debug_deinit(compositor);
+
+       return PEPPER_FALSE;
+}
diff --git a/src/headless_server.c b/src/headless_server.c
new file mode 100644 (file)
index 0000000..dd82f9a
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright © 2019 Samsung Electronics co., Ltd. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#include <pepper.h>
+#include <headless_server.h>
+
+static int
+handle_sigint(int signal_number, void *data)
+{
+       struct wl_display *display = (struct wl_display *)data;
+       wl_display_terminate(display);
+
+       return 0;
+}
+
+static pepper_bool_t
+init_signal(pepper_compositor_t *compositor)
+{
+       struct wl_display *display;
+       struct wl_event_loop *loop;
+       struct wl_event_source *sigint;
+
+       display = pepper_compositor_get_display(compositor);
+       loop = wl_display_get_event_loop(display);
+       sigint = wl_event_loop_add_signal(loop, SIGINT, handle_sigint, display);
+       if (!sigint)
+               return PEPPER_FALSE;
+
+       return PEPPER_TRUE;
+}
+
+int main(int argc, char *argv[])
+{
+       const char *socket_name = NULL;
+       pepper_compositor_t *compositor = NULL;
+       pepper_bool_t ret;
+
+       /* set STDOUT/STDERR bufferless */
+       setvbuf(stdout, NULL, _IONBF, 0);
+       setvbuf(stderr, NULL, _IONBF, 0);
+
+       if (getenv("PEPPER_DLOG_ENABLE")) {
+               PEPPER_TRACE("pepper log will be written to dlog !\n");
+               pepper_log_dlog_enable(1);
+       }
+
+       socket_name = getenv("WAYLAND_DISPLAY");
+
+       if (!socket_name)
+               socket_name = "wayland-0";
+
+       if (!getenv("XDG_RUNTIME_DIR"))
+               setenv("XDG_RUNTIME_DIR", "/run", 1);
+
+       /* create pepper compositir */
+       compositor = pepper_compositor_create(socket_name);
+       PEPPER_CHECK(compositor, return EXIT_FAILURE, "Failed to create compositor !");
+
+       /* Init event trace */
+       ret = headless_debug_init(compositor);
+       PEPPER_CHECK(ret, goto end, "headless_debug_init() failed\n");
+
+       /* Init input for headless */
+       ret = headless_input_init(compositor);
+       PEPPER_CHECK(ret, goto end, "headless_input_init() failed\n");
+
+       /* Init Output */
+       ret = headless_output_init(compositor);
+       PEPPER_CHECK(ret, goto end, "headless_output_init() failed.\n");
+
+       /* Init Shell */
+       ret = headless_shell_init(compositor);
+       PEPPER_CHECK(ret, goto end, "headless_shell_init() failed.\n");
+
+       /* Init Signal for SIGINT */
+       init_signal(compositor);
+
+       /* run event loop */
+       wl_display_run(pepper_compositor_get_display(compositor));
+
+end:
+       /* Deinit Process */
+       headless_shell_deinit(compositor);
+       headless_input_deinit(compositor);
+       headless_output_deinit(compositor);
+       headless_debug_deinit(compositor);
+       pepper_compositor_destroy(compositor);
+
+       return EXIT_SUCCESS;
+}
diff --git a/src/headless_server.h b/src/headless_server.h
new file mode 100644 (file)
index 0000000..d176e6e
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+* Copyright © 2019 Samsung Electronics co., Ltd. All Rights Reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice (including the next
+* paragraph) shall be included in all copies or substantial portions of the
+* Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef HEADLESS_SERVER_H
+#define HEADLESS_SERVER_H
+
+#include <pepper.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* APIs for headless_output */
+PEPPER_API pepper_bool_t headless_output_init(pepper_compositor_t *compositor);
+PEPPER_API void headless_output_deinit(pepper_compositor_t *compositor);
+
+/* APIs for headless_shell */
+PEPPER_API pepper_bool_t headless_shell_init(pepper_compositor_t *compositor);
+PEPPER_API void headless_shell_deinit(pepper_compositor_t *compositor);
+
+/* APIs for headless_input */
+PEPPER_API pepper_bool_t headless_input_init(pepper_compositor_t *compositor);
+PEPPER_API void headless_input_deinit(pepper_compositor_t *compositor);
+PEPPER_API void headless_input_set_focus_view(pepper_compositor_t *compositor, pepper_view_t *view);
+PEPPER_API void headless_input_set_top_view(pepper_compositor_t *compositor, pepper_view_t *view);
+PEPPER_API void *headless_input_get_keyrouter(pepper_compositor_t *compositor);
+PEPPER_API void *headless_input_get_xkb(pepper_compositor_t *compositor);
+
+/* APIs for headless_debug */
+PEPPER_API pepper_bool_t headless_debug_init(pepper_compositor_t *compositor);
+PEPPER_API void headless_debug_deinit(pepper_compositor_t *compositor);
+PEPPER_API void headless_debug_set_focus_view(pepper_compositor_t *compositor, pepper_view_t *view);
+PEPPER_API void headless_debug_set_top_view(pepper_compositor_t *compositor, pepper_view_t *view);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HEADLESS_SERVER_H */
+
diff --git a/src/input/input.c b/src/input/input.c
new file mode 100644 (file)
index 0000000..d831e3e
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+* Copyright © 2019 Samsung Electronics co., Ltd. All Rights Reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice (including the next
+* paragraph) shall be included in all copies or substantial portions of the
+* Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*/
+
+#include <pepper-evdev.h>
+#include <pepper-input-backend.h>
+#include <pepper-keyrouter.h>
+#include <pepper-devicemgr.h>
+#include <pepper-xkb.h>
+#include <pepper-inotify.h>
+
+typedef struct
+{
+       pepper_compositor_t *compositor;
+       pepper_seat_t *seat;
+       pepper_evdev_t *evdev;
+       pepper_keyboard_t *keyboard;
+       pepper_input_device_t *default_device;
+       pepper_inotify_t *inotify;
+
+       pepper_view_t *focus_view;
+       pepper_view_t *top_view;
+
+       pepper_keyrouter_t *keyrouter;
+       pepper_devicemgr_t *devicemgr;
+       pepper_xkb_t *xkb;
+
+       pepper_event_listener_t *listener_seat_keyboard_key;
+       pepper_event_listener_t *listener_seat_keyboard_add;
+       pepper_event_listener_t *listener_seat_add;
+       pepper_event_listener_t *listener_input_device_add;
+
+       uint32_t ndevices;
+} headless_input_t;
+
+const static int KEY_INPUT = 0xdeadbeaf;
+
+static void headless_input_init_event_listeners(headless_input_t *hi);
+static void headless_input_deinit_event_listeners(headless_input_t *hi);
+
+/* seat keyboard add event handler */
+static void
+_cb_handle_seat_keyboard_add(pepper_event_listener_t *listener, pepper_object_t *object, uint32_t id, void *info, void *data)
+{
+       pepper_event_listener_t *h = NULL;
+       pepper_keyboard_t *keyboard = (pepper_keyboard_t *)info;
+       headless_input_t *hi = (headless_input_t *)data;
+
+       PEPPER_TRACE("[%s] keyboard added\n", __FUNCTION__);
+
+       /* FIXME: without a keymap, ecore wl2 based client must work properly. */
+       //pepper_keyboard_set_keymap_info(keyboard, WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP, -1, 0);
+       pepper_xkb_keyboard_set_keymap(hi->xkb, keyboard, NULL);
+
+       pepper_keyrouter_set_keyboard(hi->keyrouter, keyboard);
+       h = pepper_object_add_event_listener((pepper_object_t *)keyboard, PEPPER_EVENT_KEYBOARD_KEY,
+                                                               0, pepper_keyrouter_event_handler, hi->keyrouter);
+       PEPPER_CHECK(h, goto end, "Failed to add keyboard key listener.\n");
+       hi->listener_seat_keyboard_key = h;
+       hi->keyboard = keyboard;
+
+       return;
+
+end:
+       headless_input_deinit_event_listeners(hi);
+}
+
+/* compositor input device add event handler */
+static void
+_cb_handle_input_device_add(pepper_event_listener_t *listener, pepper_object_t *object, uint32_t id, void *info, void *data)
+{
+       pepper_input_device_t *device = (pepper_input_device_t *)info;
+       headless_input_t *hi = (headless_input_t *)data;
+
+       /* temporary : only add keyboard device to a seat */
+       if (!(WL_SEAT_CAPABILITY_KEYBOARD & pepper_input_device_get_caps(device)))
+               return;
+
+       PEPPER_TRACE("[%s] input device added.\n", __FUNCTION__);
+
+       if (hi->seat)
+               pepper_seat_add_input_device(hi->seat, device);
+}
+
+/* seat add event handler */
+static void
+_cb_handle_seat_add(pepper_event_listener_t *listener, pepper_object_t *object, uint32_t id, void *info, void *data)
+{
+       pepper_event_listener_t *h = NULL;
+       pepper_seat_t *seat = (pepper_seat_t *)info;
+       headless_input_t *hi = (headless_input_t *)data;
+
+       PEPPER_TRACE("[%s] seat added. name:%s\n", __FUNCTION__, pepper_seat_get_name(seat));
+
+       h = pepper_object_add_event_listener((pepper_object_t *)seat, PEPPER_EVENT_SEAT_KEYBOARD_ADD,
+                                                               0, _cb_handle_seat_keyboard_add, hi);
+       PEPPER_CHECK(h, goto end, "Failed to add seat keyboard add listener.\n");
+       hi->listener_seat_keyboard_add = h;
+
+       return;
+
+end:
+       headless_input_deinit_event_listeners(hi);
+}
+
+static void
+_cb_handle_inotify_event(uint32_t type, pepper_inotify_event_t *ev, void *data)
+{
+       headless_input_t *hi = data;
+
+       PEPPER_CHECK(hi, return, "Invalid headless input\n");
+
+       switch (type)
+       {
+               case PEPPER_INOTIFY_EVENT_TYPE_CREATE:
+                       pepper_evdev_device_path_add(hi->evdev, pepper_inotify_event_name_get(ev));
+                       break;
+               case PEPPER_INOTIFY_EVENT_TYPE_REMOVE:
+                       pepper_evdev_device_path_remove(hi->evdev, pepper_inotify_event_name_get(ev));
+                       break;
+               case PEPPER_INOTIFY_EVENT_TYPE_MODIFY:
+                       pepper_evdev_device_path_remove(hi->evdev, pepper_inotify_event_name_get(ev));
+                       pepper_evdev_device_path_add(hi->evdev, pepper_inotify_event_name_get(ev));
+                       break;
+               default:
+                       break;
+       }
+}
+
+PEPPER_API void *
+headless_input_get_keyrouter(pepper_compositor_t *compositor)
+{
+       headless_input_t *hi;
+       hi = pepper_object_get_user_data((pepper_object_t *)compositor, &KEY_INPUT);
+       PEPPER_CHECK(hi, return NULL, "input system is not initialized\n");
+
+       return hi->keyrouter;
+}
+
+PEPPER_API void *
+headless_input_get_xkb(pepper_compositor_t *compositor)
+{
+       headless_input_t *hi;
+       hi = pepper_object_get_user_data((pepper_object_t *)compositor, &KEY_INPUT);
+       PEPPER_CHECK(hi, return NULL, "input system is not initialized\n");
+
+       return hi->xkb;
+}
+
+void
+headless_input_set_focus_view(pepper_compositor_t *compositor, pepper_view_t *focus_view)
+{
+       headless_input_t *hi;
+
+       hi = (headless_input_t *)pepper_object_get_user_data((pepper_object_t *) compositor, &KEY_INPUT);
+       PEPPER_CHECK(hi, return, "Invalid headless input.\n");
+
+       if (hi->focus_view != focus_view)
+       {
+               pepper_keyboard_send_leave(hi->keyboard, hi->focus_view);
+               pepper_keyboard_set_focus(hi->keyboard, focus_view);
+               pepper_keyboard_send_enter(hi->keyboard, focus_view);
+
+               hi->focus_view = focus_view;
+       }
+
+       if (hi->keyrouter)
+               pepper_keyrouter_set_focus_view(hi->keyrouter, focus_view);
+}
+
+void
+headless_input_set_top_view(void *compositor, pepper_view_t *top_view)
+{
+       headless_input_t *hi;
+
+       hi = (headless_input_t *)pepper_object_get_user_data((pepper_object_t *) compositor, &KEY_INPUT);
+       PEPPER_CHECK(hi, return, "Invalid headless input.\n");
+
+       if (hi->top_view == top_view) return;
+
+       hi->top_view = top_view;
+
+       if (hi->keyrouter)
+               pepper_keyrouter_set_top_view(hi->keyrouter, top_view);
+}
+
+static void
+headless_input_init_event_listeners(headless_input_t *hi)
+{
+       pepper_event_listener_t *h = NULL;
+       pepper_object_t *compositor = (pepper_object_t *)hi->compositor;
+
+       /* register event listeners */
+       h = pepper_object_add_event_listener((pepper_object_t *)compositor,
+                                               PEPPER_EVENT_COMPOSITOR_SEAT_ADD, 0, _cb_handle_seat_add, hi);
+       PEPPER_CHECK(h, goto end, "Failed to add seat add listener.\n");
+       hi->listener_seat_add = h;
+
+       h = pepper_object_add_event_listener((pepper_object_t *)compositor,
+                                               PEPPER_EVENT_COMPOSITOR_INPUT_DEVICE_ADD, 0, _cb_handle_input_device_add, hi);
+       PEPPER_CHECK(h, goto end, "Failed to add input device add listener.\n");
+       hi->listener_input_device_add = h;
+
+       return;
+
+end:
+       PEPPER_ERROR("[%s] Failed to init listeners", __FUNCTION__);
+       headless_input_deinit_event_listeners(hi);
+}
+
+static void
+headless_input_deinit_event_listeners(headless_input_t *hi)
+{
+       pepper_event_listener_remove(hi->listener_seat_keyboard_key);
+       pepper_event_listener_remove(hi->listener_seat_keyboard_add);
+       pepper_event_listener_remove(hi->listener_seat_add);
+       pepper_event_listener_remove(hi->listener_input_device_add);
+
+       PEPPER_TRACE("[%s] event listeners have been removed.\n", __FUNCTION__);
+}
+
+static void
+headless_input_deinit_input(headless_input_t *hi)
+{
+       if (hi->inotify)
+       {
+               pepper_inotify_destroy(hi->inotify);
+               hi->inotify = NULL;
+       }
+
+       if (hi->default_device)
+       {
+               pepper_input_device_destroy(hi->default_device);
+               hi->default_device = NULL;
+       }
+
+       pepper_evdev_destroy(hi->evdev);
+
+       if (hi->seat)
+               pepper_seat_destroy(hi->seat);
+
+       hi->seat = NULL;
+       hi->evdev = NULL;
+       hi->ndevices = 0;
+}
+
+static pepper_bool_t
+headless_input_create_input_device(headless_input_t *hi, uint32_t caps)
+{
+       pepper_input_device_t *input_device = NULL;
+
+       /* create a default pepper input device */
+       input_device = pepper_input_device_create(hi->compositor, caps, NULL, hi);
+       PEPPER_CHECK(input_device, return PEPPER_FALSE, "Failed to create a keyboard device !\n");
+
+       hi->default_device = input_device;
+       return PEPPER_TRUE;
+}
+
+static pepper_bool_t
+headless_input_init_input(headless_input_t *hi)
+{
+       uint32_t caps = 0;
+       uint32_t probed = 0;
+       pepper_bool_t res = PEPPER_FALSE;
+       pepper_evdev_t *evdev = NULL;
+       pepper_inotify_t *inotify = NULL;
+
+       /* create pepper evdev */
+       evdev = pepper_evdev_create(hi->compositor);
+       PEPPER_CHECK(evdev, goto end, "Failed to create evdev !\n");
+
+       hi->evdev = evdev;
+
+       /* probe evdev keyboard device(s) */
+       caps |= WL_SEAT_CAPABILITY_KEYBOARD;
+       probed = pepper_evdev_device_probe(evdev, caps);
+
+       if (!probed)
+       {
+               PEPPER_TRACE("No evdev device has been probed. A default key device will be created.\n");
+
+               res = headless_input_create_input_device(hi, caps);
+               PEPPER_CHECK(res,  goto end, "Failed to create any input device(s) !\n");
+
+               probed++;
+       }
+
+       hi->ndevices = probed;
+
+       PEPPER_TRACE("%d evdev device(s) has been found.\n", probed);
+
+       inotify = pepper_inotify_create(hi->compositor, _cb_handle_inotify_event, hi);
+       PEPPER_CHECK(inotify, goto end, "Failed to create inotify\n");
+
+       pepper_inotify_add(inotify, "/dev/input/");
+
+       hi->inotify = inotify;
+
+       return PEPPER_TRUE;
+
+end:
+       pepper_evdev_destroy(evdev);
+
+       return PEPPER_FALSE;
+}
+
+static void
+headless_input_init_modules(headless_input_t *hi)
+{
+       const char *seat_name = NULL;
+       pepper_seat_t *seat = NULL;
+
+       pepper_keyrouter_t *keyrouter = NULL;
+       pepper_devicemgr_t *devicemgr = NULL;
+       pepper_xkb_t *xkb = NULL;
+
+       PEPPER_TRACE("[%s] ... begin\n", __FUNCTION__);
+
+       seat_name = getenv("XDG_SEAT");
+
+       if (!seat_name)
+               seat_name = "seat0";
+
+       /* create a default seat (seat0) */
+       seat = pepper_compositor_add_seat(hi->compositor, seat_name);
+       PEPPER_CHECK(seat, goto end, "Failed to add seat (%s)!\n", seat_name);
+
+       hi->seat = seat;
+
+       /* create pepper xkb */
+       xkb = pepper_xkb_create();
+       PEPPER_CHECK(xkb, goto end, "Failed to create pepper_xkb !\n");
+
+       hi->xkb = xkb;
+
+       /* create pepper keyrouter */
+       keyrouter = pepper_keyrouter_create(hi->compositor);
+       PEPPER_CHECK(keyrouter, goto end, "Failed to create keyrouter !\n");
+
+       hi->keyrouter = keyrouter;
+
+       /* create pepper devicemgr */
+       devicemgr = pepper_devicemgr_create(hi->compositor, hi->seat);
+       PEPPER_CHECK(devicemgr, goto end, "Failed to create devicemgr !\n");
+       pepper_devicemgr_xkb_enable(devicemgr);
+
+       hi->devicemgr = devicemgr;
+
+       PEPPER_TRACE("[%s] ... done\n", __FUNCTION__);
+
+       return;
+end:
+       if (hi->xkb)
+               pepper_xkb_destroy(hi->xkb);
+       if (hi->keyrouter)
+               pepper_keyrouter_destroy(hi->keyrouter);
+       if (hi->devicemgr)
+               pepper_devicemgr_destroy(hi->devicemgr);
+       if (hi->seat)
+               pepper_seat_destroy(hi->seat);
+
+       hi->xkb = NULL;
+       hi->keyrouter = NULL;
+       hi->devicemgr = NULL;
+       hi->seat = NULL;
+}
+
+static void
+headless_input_deinit_modules(headless_input_t *hi)
+{
+       if (hi->xkb)
+               pepper_xkb_destroy(hi->xkb);
+       if (hi->keyrouter)
+               pepper_keyrouter_destroy(hi->keyrouter);
+       if (hi->devicemgr)
+               pepper_devicemgr_destroy(hi->devicemgr);
+
+       hi->xkb = NULL;
+       hi->keyrouter = NULL;
+       hi->devicemgr = NULL;
+}
+
+PEPPER_API void
+headless_input_deinit(pepper_compositor_t * compositor)
+{
+       headless_input_t *hi = NULL;
+
+       hi = (headless_input_t *)pepper_object_get_user_data((pepper_object_t *) compositor, &KEY_INPUT);
+       PEPPER_CHECK(hi, return, "Failed to get headless input instance.\n");
+
+       headless_input_deinit_event_listeners(hi);
+       headless_input_deinit_modules(hi);
+       headless_input_deinit_input(hi);
+
+       pepper_object_set_user_data((pepper_object_t *)hi->compositor, &KEY_INPUT, NULL, NULL);
+       free(hi);
+}
+
+pepper_bool_t
+headless_input_init(pepper_compositor_t *compositor)
+{
+       headless_input_t *hi = NULL;
+       pepper_bool_t init = PEPPER_FALSE;
+
+       hi = (headless_input_t*)calloc(1, sizeof(headless_input_t));
+       PEPPER_CHECK(hi, goto error, "Failed to alloc for input\n");
+       hi->compositor = compositor;
+
+       headless_input_init_event_listeners(hi);
+       headless_input_init_modules(hi);
+       init = headless_input_init_input(hi);
+       PEPPER_CHECK(init, goto error, "headless_input_init_input() failed\n");
+
+       pepper_object_set_user_data((pepper_object_t *)compositor, &KEY_INPUT, hi, NULL);
+
+       return PEPPER_TRUE;
+
+error:
+       headless_input_deinit(compositor);
+
+       return PEPPER_FALSE;
+}
diff --git a/src/output/HL_UI_LED.h b/src/output/HL_UI_LED.h
new file mode 100644 (file)
index 0000000..ea9889f
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright © 2019 Samsung Electronics co., Ltd. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __HL_UI_LED_H__
+#define __HL_UI_LED_H__
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <peripheral_io.h>
+
+#define B_OFF_SET 1
+#define G_OFF_SET 2
+#define R_OFF_SET 3
+
+#define BITRATE 8000000
+
+typedef struct{
+       uint32_t number;
+       peripheral_spi_h hnd_spi;
+       uint8_t  *pixels;
+       uint8_t  brightness;
+}HL_UI_LED;
+
+/**
+ * @brief: Initialise a set of apa102 LEDs
+ *
+ * @param[in] led_num: Number of leds (0-255)
+ *
+ * @returns:  pointer of handler\ Success
+ *            NULL\ Error
+ */
+HL_UI_LED *HL_UI_LED_Init(uint32_t led_num);
+
+/**
+ * @brief: Change the global brightness and fresh
+ *
+ * @param[in] handle: handler of HL_UI_LED
+ * @param[in] brightness: New brightness value
+ */
+void HL_UI_LED_Change_Brightness(HL_UI_LED *handle, uint8_t brightness);
+
+/**
+ * @brief: Get the brightness
+ *
+ * @param[in] handle: handler of HL_UI_LED
+ * @return current brightness value (0-31)
+ */
+int HL_UI_LED_Get_Brightness(HL_UI_LED *handle);
+
+/**
+ * @brief: Set color for a specific pixel by giving R, G and B value separately
+ *
+ * @param[in] handle: handler of HL_UI_LED
+ * @param[in] index: Index of the target led (0-255)
+ * @param[in] red: Intensity of red colour (0-255)
+ * @param[in] green: Intensity of green colour (0-255)
+ * @param[in] blue: Intensity of blue colour (0-255)
+ */
+void HL_UI_LED_Set_Pixel_RGB(HL_UI_LED *handle, uint32_t index, uint8_t red, uint8_t green, uint8_t blue);
+
+/**
+ * @brief: Get colour form a specific pixel for R, G and B separately
+ *
+ * @param[in] handle: handler of HL_UI_LED
+ * @param[in] index: Index of the target led (0-255)
+ * @param[out] red: Intensity of red colour (0-255)
+ * @param[out] green: Intensity of green colour (0-255)
+ * @param[out] blue: Intensity of blue colour (0-255)
+ */
+void HL_UI_LED_Get_Pixel_RGB(HL_UI_LED *handle, uint32_t index, uint8_t *red, uint8_t *green, uint8_t *blue);
+
+/**
+ * @brief: Set color for a specific pixel by using 4byte date
+ *
+ * @param[in] handle: handler of HL_UI_LED
+ * @param[in] index: Index of the target led (0-255)
+ * @param[in] red: Intensity of red colour (0-255)
+ * @param[in] green: Intensity of green colour (0-255)
+ * @param[in] blue: Intensity of blue colour (0-255)
+ *
+ * @example: HL_UI_LED_Get_Pixel_RGB(1, 0xFF0000) sets the 1st LED to red colour
+ */
+void HL_UI_LED_Set_Pixel_4byte(HL_UI_LED *handle, uint32_t index, uint32_t colour);
+
+/**
+ * @brief: Get colour form a specific pixel
+ *
+ * @param[in] handle: handler of HL_UI_LED
+ * @param[in] index: Index of the target led (0-255)
+ *
+ * @returns: 32 bits colour data
+ */
+uint32_t HL_UI_LED_Get_Pixel_4byte(HL_UI_LED *handle, uint32_t index);
+
+/**
+ * @brief: Clear all the pixels
+ *
+ * @param[in] handle: handler of HL_UI_LED
+ */
+void HL_UI_LED_Clear_All(HL_UI_LED *handle);
+
+/**
+ * @brief: Refresh display (After modifing pixel colour)
+ */
+int HL_UI_LED_Refresh(HL_UI_LED *handle);
+
+/**
+ * @brief: Show display (After modifing pixel colour)
+ *
+ * @param[in] handle: handler of HL_UI_LED
+ */
+int HL_UI_LED_Show(HL_UI_LED *handle);
+
+
+/**
+ * @brief: Close SPI file, release memory
+ *
+ * @param[in] handle: handler of HL_UI_LED
+ */
+void HL_UI_LED_Close(HL_UI_LED *handle);
+#endif
diff --git a/src/output/HL_UI_LED_APA102.c b/src/output/HL_UI_LED_APA102.c
new file mode 100644 (file)
index 0000000..63b8c81
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Copyright © 2019 Samsung Electronics co., Ltd. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "HL_UI_LED.h"
+
+#define SUCCESS_FLAG 760302
+#define RETRY_TIMES 3
+
+#define SPI_BUS 0
+#define SPI_DEV 1
+
+HL_UI_LED *
+HL_UI_LED_Init(uint32_t led_num)
+{
+       HL_UI_LED *handle;
+       int count = 0;
+       int ret;
+
+       handle = (HL_UI_LED*)malloc(sizeof(HL_UI_LED));
+       if(handle == NULL)
+       {
+               return NULL;
+       }
+       handle->number = led_num;
+       handle->brightness = 0xFF;
+       handle->pixels = (uint8_t *)malloc(handle->number * 4);
+       if(handle->pixels == NULL)
+       {
+               free(handle);
+               return NULL;
+       }
+
+       while(count < RETRY_TIMES)
+       {
+               if(peripheral_spi_open(SPI_BUS, SPI_DEV, &(handle->hnd_spi)) == 0)
+               {
+                       printf("spi open success!\n");
+                       count = SUCCESS_FLAG;
+                       if((ret = peripheral_spi_set_frequency(handle->hnd_spi, BITRATE)) != 0)
+                       {
+                               printf("Frequency Failed : 0x%x\n", ret);
+                       }
+                       if((ret = peripheral_spi_set_bits_per_word(handle->hnd_spi, 8)) != 0)
+                       {
+                               printf("BIT_WORD Failed : 0x%x\n", ret);
+                       }
+                       if((ret = peripheral_spi_set_bit_order(handle->hnd_spi,PERIPHERAL_SPI_BIT_ORDER_MSB)) != 0)
+                       {
+                               printf("BIT_ORDER Failed : 0x%x\n", ret);
+                       }
+                       if((ret = peripheral_spi_set_mode(handle->hnd_spi,PERIPHERAL_SPI_MODE_1)) != 0)
+                       {
+                               printf("SPI Mode Failed : 0x%x\n", ret);
+                       }
+                       break;
+               }
+               else
+               {
+                       count++;
+                       continue;
+               }
+       }
+       if(count == SUCCESS_FLAG)
+       {
+               HL_UI_LED_Clear_All(handle);
+               return handle;
+       }
+       else
+       {
+               free(handle->pixels);
+               free(handle);
+               return NULL;
+       }
+}
+
+void
+HL_UI_LED_Change_Brightness(HL_UI_LED *handle, uint8_t brightness)
+{
+       if (brightness > 31)
+               handle->brightness = 0xFF;
+       else
+               handle->brightness = 0xE0 | (0x1F & brightness);
+       HL_UI_LED_Refresh(handle);
+}
+
+int
+HL_UI_LED_Get_Brightness(HL_UI_LED *handle)
+{
+       return handle->brightness & 0x1F;
+}
+
+void
+HL_UI_LED_Set_Pixel_RGB(HL_UI_LED *handle, uint32_t index, uint8_t red, uint8_t green, uint8_t blue)
+{
+       if (index < handle->number) {
+               uint8_t *ptr = &(handle->pixels[index * 4]);
+               ptr[R_OFF_SET] = red;
+               ptr[G_OFF_SET] = green;
+               ptr[B_OFF_SET] = blue;
+       }
+}
+
+void
+HL_UI_LED_Get_Pixel_RGB(HL_UI_LED *handle, uint32_t index, uint8_t *red, uint8_t *green, uint8_t *blue)
+{
+       if (index < handle->number) {
+               uint8_t *ptr = &(handle->pixels[index * 4]);
+               *red = ptr[R_OFF_SET];
+               *green = ptr[G_OFF_SET];
+               *blue = ptr[B_OFF_SET];
+       }
+}
+
+void
+HL_UI_LED_Set_Pixel_4byte(HL_UI_LED *handle, uint32_t index, uint32_t colour)
+{
+       uint8_t  r, g, b;
+       uint8_t *ptr = (uint8_t *)&colour;
+       r = ptr[R_OFF_SET];
+       g = ptr[G_OFF_SET];
+       b = ptr[B_OFF_SET];
+       HL_UI_LED_Set_Pixel_RGB(handle, index, r, g, b);
+}
+
+uint32_t
+HL_UI_LED_Get_Pixel_4byte(HL_UI_LED *handle, uint32_t index)
+{
+       uint8_t r=0, g=0, b=0;
+       uint32_t colour = 0;
+       uint8_t *ptr = (uint8_t *)&colour;
+       HL_UI_LED_Get_Pixel_RGB(handle, index, &r, &g, &b);
+       ptr[R_OFF_SET] = r;
+       ptr[G_OFF_SET] = g;
+       ptr[B_OFF_SET] = b;
+       return colour;
+}
+
+void
+HL_UI_LED_Clear_All(HL_UI_LED *handle)
+{
+       uint8_t *ptr;
+       uint32_t i;
+       for(ptr = handle->pixels, i=0; i<handle->number; i++, ptr += 4) {
+               ptr[1] = 0x00;
+               ptr[2] = 0x00;
+               ptr[3] = 0x00;
+       }
+       HL_UI_LED_Refresh(handle);
+}
+
+int
+HL_UI_LED_Refresh(HL_UI_LED *handle)
+{
+       int ret;
+       uint32_t i;
+       uint32_t buf_len = 4 + 4 * handle->number + (handle->number + 15) / 16 + 1;
+       uint8_t *ptr, *qtr;
+       uint8_t *tx = (uint8_t *)malloc(buf_len);
+
+       if( tx == NULL )
+       {
+               return -1;
+       }
+       // start frame
+       for (i = 0; i < 4; i++)
+               *(tx + i) = 0x00;
+
+       // LED data
+       qtr = tx + 4;
+
+       for(ptr = handle->pixels, i=0; i<handle->number; i++, ptr += 4, qtr += 4) {
+               qtr[0] = handle->brightness;
+               qtr[1] = ptr[1];
+               qtr[2] = ptr[2];
+               qtr[3] = ptr[3];
+       }
+
+       // end frame
+       for (i = handle->number * 4 + 4; i < buf_len; i++)
+       {
+               *(tx + i) = 0x00;
+       }
+
+       ret = peripheral_spi_write(handle->hnd_spi, tx, buf_len);
+       free(tx);
+       if (ret != 0)
+       {
+               fprintf(stdout, "[Error] can't send spi message\n");
+               return -2;
+       }
+
+       return 0;
+}
+
+int
+HL_UI_LED_Show(HL_UI_LED *handle)
+{
+       return HL_UI_LED_Refresh(handle);
+}
+
+void
+HL_UI_LED_Close(HL_UI_LED *handle)
+{
+       HL_UI_LED_Clear_All(handle);
+       peripheral_spi_close(handle->hnd_spi);
+
+       if (handle->pixels) {
+               free(handle->pixels);
+       }
+
+       free(handle);
+}
diff --git a/src/output/boot_anim.c b/src/output/boot_anim.c
new file mode 100644 (file)
index 0000000..83ba500
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+* Copyright © 2019 Samsung Electronics co., Ltd. All Rights Reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice (including the next
+* paragraph) shall be included in all copies or substantial portions of the
+* Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tbm_bufmgr.h>
+#include <wayland-tbm-server.h>
+#include <pepper-output-backend.h>
+#include "HL_UI_LED.h"
+#include "output_internal.h"
+
+typedef struct {
+       HL_UI_LED *led;
+
+       struct wl_event_source *source;
+       uint32_t serial;
+       int index;
+
+       pepper_event_listener_t *surface_add_listener;
+} boot_ani_t;
+
+#define ANI_INTERVAL   40      //20ms
+
+static int
+boot_ani_timer_cb(void *data)
+{
+       boot_ani_t *ani = (boot_ani_t *)data;
+       uint8_t r,g,b;
+       uint32_t color;
+
+       if (ani->index == 0) {
+               r = (uint8_t)(rand()%0xFF);
+               g = (uint8_t)(rand()%0xFF);
+               b = (uint8_t)(rand()%0xFF);
+               HL_UI_LED_Set_Pixel_RGB(ani->led, ani->index, r, g, b);
+       } else {
+               color = HL_UI_LED_Get_Pixel_4byte(ani->led, ani->index - 1);
+               HL_UI_LED_Set_Pixel_4byte(ani->led, ani->index, color);
+       }
+
+       HL_UI_LED_Refresh(ani->led);
+
+       ani->serial++;
+       ani->index = (ani->serial)%12;
+
+       wl_event_source_timer_update(ani->source, ANI_INTERVAL);
+
+       return 1;
+}
+
+static void
+boot_ani_surface_add_cb(pepper_event_listener_t *listener,
+                                                                               pepper_object_t *object,
+                                                                               uint32_t id, void *info, void *data)
+{
+       led_output_t *output = (led_output_t *)data;
+
+       boot_ani_stop(output);
+}
+
+void boot_ani_start(led_output_t *output)
+{
+       struct wl_event_loop *loop;
+       boot_ani_t *ani;
+       int ret;
+
+       PEPPER_TRACE("[OUTPUT] start boot-animation\n");
+
+       loop = wl_display_get_event_loop(pepper_compositor_get_display(output->compositor));
+       PEPPER_CHECK(loop, return, "failed to wl_display_get_event_loop()\n");
+
+       ani = (boot_ani_t *)calloc(sizeof(boot_ani_t), 1);
+       PEPPER_CHECK(ani, return, "failed to alloc\n");
+
+       ani->source = wl_event_loop_add_timer(loop, boot_ani_timer_cb, ani);
+       PEPPER_CHECK(ani, goto err, "failed to wl_event_loop_add_timer()\n");
+
+       ret = wl_event_source_timer_update(ani->source, ANI_INTERVAL);
+       PEPPER_CHECK(!ret, goto err, "failed to wl_event_source_timer_update\n");
+
+       ani->surface_add_listener = pepper_object_add_event_listener((pepper_object_t *)output->compositor,
+                                                                                                                                               PEPPER_EVENT_COMPOSITOR_SURFACE_ADD,
+                                                                                                                                               0, boot_ani_surface_add_cb, output);
+
+       ani->led = output->ui_led;
+       output->boot_ani = ani;
+       return;
+err:
+       if (ani) {
+               if (ani->source)
+                       wl_event_source_remove(ani->source);
+
+               free(ani);
+       }
+       return;
+}
+
+void boot_ani_stop(led_output_t *output)
+{
+       boot_ani_t *ani;
+
+       if (!output->boot_ani) return;
+
+       ani = (boot_ani_t *)output->boot_ani;
+
+       HL_UI_LED_Clear_All(ani->led);
+       wl_event_source_remove(ani->source);
+
+       if(ani->surface_add_listener) {
+               pepper_event_listener_remove(ani->surface_add_listener);
+               ani->surface_add_listener = NULL;
+       }
+
+       free(ani);
+
+       output->boot_ani = NULL;
+       return;
+}
diff --git a/src/output/output_internal.h b/src/output/output_internal.h
new file mode 100644 (file)
index 0000000..2bfa286
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+* Copyright © 2019 Samsung Electronics co., Ltd. All Rights Reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice (including the next
+* paragraph) shall be included in all copies or substantial portions of the
+* Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <pepper-output-backend.h>
+
+#define NUM_LED 12
+
+typedef struct {
+       pepper_compositor_t *compositor;
+       pepper_output_t   *output;
+       pepper_plane_t    *plane;
+
+       int num_led;
+       HL_UI_LED *ui_led;
+
+       struct wayland_tbm_server *tbm_server;
+       struct wl_event_source *frame_done;
+
+       pepper_view_t *top_view;
+
+       //For booting animation
+       void *boot_ani;
+}led_output_t;
+
+PEPPER_API void boot_ani_start(led_output_t *output);
+PEPPER_API void boot_ani_stop(led_output_t *output);
diff --git a/src/output/output_led.c b/src/output/output_led.c
new file mode 100644 (file)
index 0000000..8410495
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+* Copyright © 2019 Samsung Electronics co., Ltd. All Rights Reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice (including the next
+* paragraph) shall be included in all copies or substantial portions of the
+* Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tbm_bufmgr.h>
+#include <wayland-tbm-server.h>
+#include <pepper-output-backend.h>
+#include "HL_UI_LED.h"
+#include "output_internal.h"
+
+static const int KEY_OUTPUT;
+static void led_output_add_frame_done(led_output_t *output);
+static void led_output_update(led_output_t *output);
+
+static void
+led_output_destroy(void *data)
+{
+       led_output_t *output = (led_output_t *)data;
+       PEPPER_TRACE("Output Destroy %p base %p\n", output, output->output);
+
+       if (output->ui_led) {
+               HL_UI_LED_Close(output->ui_led);
+               output->ui_led = NULL;
+       }
+
+       if (output->tbm_server) {
+               wayland_tbm_server_deinit(output->tbm_server);
+               output->tbm_server = NULL;
+       }
+}
+
+static int32_t
+led_output_get_subpixel_order(void *o)
+{
+       return 0;
+}
+
+static const char *
+led_output_get_maker_name(void *o)
+{
+       return "PePPer LED";
+}
+
+static const char *
+led_output_get_model_name(void *o)
+{
+       return "PePPer LED";
+}
+
+static int
+led_output_get_mode_count(void *o)
+{
+       return 1;
+}
+
+static void
+led_output_get_mode(void *o, int index, pepper_output_mode_t *mode)
+{
+       led_output_t *output = (led_output_t *)o;
+
+       PEPPER_TRACE("[OUTPUT]\n");
+
+       if (index != 0)
+               return;
+
+       mode->flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+       mode->w = output->num_led;
+       mode->h = output->num_led;
+       mode->refresh = 60000;
+}
+
+static pepper_bool_t
+led_output_set_mode(void *o, const pepper_output_mode_t *mode)
+{
+       return PEPPER_FALSE;
+}
+
+static void
+led_output_assign_planes(void *o, const pepper_list_t *view_list)
+{
+       led_output_t *output = (led_output_t *)o;
+       pepper_list_t *l;
+       pepper_view_t *view, *top_view = NULL;
+
+       PEPPER_TRACE("[OUTPUT] Assign plane\n");
+       pepper_list_for_each_list(l, view_list) {
+               view = (pepper_view_t*)l->item;
+
+               if (pepper_view_is_mapped(view) && pepper_view_is_visible(view)) {
+                       top_view = view;
+                       break;
+               }
+       }
+
+       if (output->top_view != top_view)
+               PEPPER_TRACE("\tTop-View is changed(%p -> %p)\n", output->top_view, top_view);
+
+       output->top_view = top_view;
+}
+
+static void
+led_output_start_repaint_loop(void *o)
+{
+       led_output_t *output = (led_output_t *)o;
+       struct timespec     ts;
+
+       PEPPER_TRACE("[OUTPUT] Start reapint loop\n");
+       pepper_compositor_get_time(output->compositor, &ts);
+       pepper_output_finish_frame(output->output, &ts);
+}
+
+static void
+led_output_repaint(void *o, const pepper_list_t *plane_list)
+{
+       pepper_list_t *l;
+       pepper_plane_t *plane;
+       led_output_t *output = (led_output_t *)o;
+
+       PEPPER_TRACE("[OUTPUT] Repaint\n");
+
+       pepper_list_for_each_list(l, plane_list) {
+               plane = (pepper_plane_t *)l->item;
+               pepper_plane_clear_damage_region(plane);
+       }
+
+       led_output_update(output);
+       led_output_add_frame_done(output);
+}
+
+static void
+led_output_attach_surface(void *o, pepper_surface_t *surface, int *w, int *h)
+{
+       *w = 10;
+       *h = 10;
+       PEPPER_TRACE("[OUTPUT] attach surface:%p\n", surface);
+}
+
+static void
+led_output_flush_surface_damage(void *o, pepper_surface_t *surface, pepper_bool_t *keep_buffer)
+{
+       *keep_buffer = PEPPER_TRUE;
+       PEPPER_TRACE("[OUTPUT] flush_surface_damage surface:%p\n", surface);
+}
+
+struct pepper_output_backend led_output_backend = {
+       led_output_destroy,
+
+       led_output_get_subpixel_order,
+       led_output_get_maker_name,
+       led_output_get_model_name,
+
+       led_output_get_mode_count,
+       led_output_get_mode,
+       led_output_set_mode,
+
+       led_output_assign_planes,
+       led_output_start_repaint_loop,
+       led_output_repaint,
+       led_output_attach_surface,
+       led_output_flush_surface_damage,
+};
+
+static void
+led_output_update_led(led_output_t *output, unsigned char *data)
+{
+       int i;
+       uint8_t *ptr = (uint8_t *)data;
+
+       if (data == NULL) {
+               PEPPER_TRACE("[OUTPUT] update LED to empty\n");
+               HL_UI_LED_Clear_All(output->ui_led);
+               return;
+       }
+
+       for(i=0; i<output->num_led; i++) {
+               HL_UI_LED_Set_Pixel_RGB(output->ui_led, i, ptr[R_OFF_SET], ptr[G_OFF_SET], ptr[B_OFF_SET]);
+               ptr += 4;
+       }
+
+       HL_UI_LED_Refresh(output->ui_led);
+}
+
+static void
+led_output_update(led_output_t *output)
+{
+       pepper_buffer_t *buf;
+       pepper_surface_t *surface;
+       struct wl_resource *buf_res;
+       tbm_surface_h tbm_surface;
+       tbm_surface_info_s info;
+       int ret;
+
+       if (!output->top_view) {
+               if (!output->ui_led)
+                       PEPPER_TRACE("[UPDATE LED] Empty Display\n");
+               else
+                       led_output_update_led(output, NULL);
+
+               return;
+       }
+
+       surface = pepper_view_get_surface(output->top_view);
+       PEPPER_CHECK(surface, return, "fail to get a surafce from a view(%p)\n", output->top_view);
+
+       buf = pepper_surface_get_buffer(surface);
+       PEPPER_CHECK(buf, return, "fail to get a pepper_buffer from a surface(%p)\n", surface);
+
+       buf_res = pepper_buffer_get_resource(buf);
+       tbm_surface = wayland_tbm_server_get_surface(NULL, buf_res);
+       PEPPER_CHECK(tbm_surface, return, "fail to get a tbm_surface from a pepper_buffer(%p)\n", buf);
+
+       ret = tbm_surface_map(tbm_surface, TBM_SURF_OPTION_READ, &info);
+       PEPPER_CHECK(ret == TBM_SURFACE_ERROR_NONE, return, "fail to map the tbm_surface\n");
+
+       if (!output->ui_led)
+               PEPPER_TRACE("[UPDATE LED] %s\n", (char*)info.planes[0].ptr);
+       else
+               led_output_update_led(output, info.planes[0].ptr);
+
+       tbm_surface_unmap(tbm_surface);
+}
+
+static void
+led_output_cb_frame_done(void *data)
+{
+       led_output_t *output = (led_output_t *)data;
+
+       PEPPER_TRACE("[OUTPUT] frame_done %p\n", output);
+       output->frame_done = NULL;
+
+       pepper_output_finish_frame(output->output, NULL);
+}
+
+static void
+led_output_add_frame_done(led_output_t *output)
+{
+       struct wl_event_loop *loop;
+
+       PEPPER_TRACE("[OUTPUT] Add idle for frame(output:%p, frame_done:%p)\n", output, output->frame_done);
+
+       if (!output || output->frame_done) {
+               PEPPER_TRACE("[OUTPUT] skip add frame_done\n");
+               return;
+       }
+
+       loop = wl_display_get_event_loop(pepper_compositor_get_display(output->compositor));
+       PEPPER_CHECK(loop, return, "[OUTPUT] fail to get event loop\n");
+
+       output->frame_done = wl_event_loop_add_idle(loop, led_output_cb_frame_done, output);
+       PEPPER_CHECK(output->frame_done, return, "[OUTPUT] fail to add idle\n");
+}
+
+static void
+pepper_output_bind_display(led_output_t *output)
+{
+       tbm_bufmgr bufmgr = NULL;
+
+       PEPPER_CHECK(getenv("TBM_DISPLAY_SERVER"), return, "[TBM] run the subcompoitor mode\n");
+
+       bufmgr = wayland_tbm_server_get_bufmgr(output->tbm_server);
+       PEPPER_CHECK(bufmgr, return, "fail to get tbm_bufmgr\n");
+
+       if (!tbm_bufmgr_bind_native_display(bufmgr, (void *)pepper_compositor_get_display(output->compositor)))
+       {
+               PEPPER_CHECK(0, return, "fail to tbm_bufmgr_bind_native_display\n");
+       }
+
+       return;
+}
+
+pepper_bool_t
+headless_output_init(pepper_compositor_t *compositor)
+{
+       led_output_t *output = (led_output_t*)calloc(sizeof(led_output_t), 1);
+
+       PEPPER_TRACE("Output Init\n");
+
+       if (!output) {
+               PEPPER_ERROR("Failed to allocate memory in %s\n", __FUNCTION__);
+               goto error;
+       }
+
+       output->compositor = compositor;
+       output->tbm_server = wayland_tbm_server_init(pepper_compositor_get_display(compositor), NULL, -1, 0);
+       PEPPER_CHECK(output->tbm_server, goto error, "failed to wayland_tbm_server_init.\n");
+
+       pepper_output_bind_display(output);
+
+       output->num_led = NUM_LED;
+       output->ui_led = HL_UI_LED_Init(output->num_led);
+       if (output->ui_led) HL_UI_LED_Change_Brightness(output->ui_led, 0x1);
+
+       if (!output->ui_led)
+               PEPPER_ERROR("HL_UI_LED_Init() failed.\n");
+       else
+               boot_ani_start(output);
+
+       output->output = pepper_compositor_add_output(compositor,
+                       &led_output_backend, "led_output",
+                       output,  WL_OUTPUT_TRANSFORM_NORMAL, 1);
+       PEPPER_CHECK(output->output, goto error, "pepper_compositor_add_output() failed.\n");
+
+       output->plane = pepper_output_add_plane(output->output, NULL);
+       PEPPER_CHECK(output->plane, goto error, "pepper_output_add_plane() failed.\n");
+
+       pepper_object_set_user_data((pepper_object_t *)compositor,
+                       &KEY_OUTPUT, output, NULL);
+       PEPPER_TRACE("\t Add Output %p, base %p\n", output, output->output);
+       PEPPER_TRACE("\t Add Output %p, plane %p\n", output, output->plane);
+       PEPPER_TRACE("\t Userdata %p\n", pepper_object_get_user_data((pepper_object_t *)compositor,&KEY_OUTPUT));
+       return PEPPER_TRUE;
+
+error:
+       if (output->ui_led)
+               HL_UI_LED_Close(output->ui_led);
+
+       if (output->tbm_server)
+               wayland_tbm_server_deinit(output->tbm_server);
+
+       if (output->output)
+               pepper_output_destroy(output->output);
+
+       if (output)
+               free(output);
+       return PEPPER_FALSE;
+}
+
+void
+headless_output_deinit(pepper_compositor_t *compositor)
+{
+       led_output_t *output;
+
+
+       output = pepper_object_get_user_data((pepper_object_t *)compositor, &KEY_OUTPUT);
+
+       if (output) {
+               pepper_object_set_user_data((pepper_object_t *)compositor, &KEY_OUTPUT, NULL, NULL);
+
+               if (output->boot_ani) {
+                       boot_ani_stop(output);
+               }
+
+               pepper_output_destroy(output->output);
+               led_output_destroy(output);
+
+               free(output);
+       }
+
+       PEPPER_TRACE("Output Deinit ... DONE\n");
+}
diff --git a/src/shell/shell.c b/src/shell/shell.c
new file mode 100644 (file)
index 0000000..75e5ddc
--- /dev/null
@@ -0,0 +1,1331 @@
+/*
+* Copyright © 2019 Samsung Electronics co., Ltd. All Rights Reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice (including the next
+* paragraph) shall be included in all copies or substantial portions of the
+* Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <pepper.h>
+#include <pepper-output-backend.h>
+#include <xdg-shell-unstable-v6-server-protocol.h>
+#include <tizen-extension-server-protocol.h>
+
+#include "headless_server.h"
+
+#define UPDATE_SURFACE_TYPE    0               //update the surface_type(map. unmap)
+#define SET_UPDATE(x, type)    (x |= ((uint32_t)(1<<type)))
+#define IS_UPDATE(x, type)     (!!(x & ((uint32_t)(1<<type))))
+
+typedef enum {
+       HEADLESS_SURFACE_NONE,
+       HEADLESS_SURFACE_TOPLEVEL,
+       HEADLESS_SURFACE_POPUP
+} headless_surface_type_t;
+
+typedef struct HEADLESS_SHELL headless_shell_t;
+typedef struct HEADLESS_SHELL_SURFACE headless_shell_surface_t;
+
+struct HEADLESS_SHELL{
+       pepper_compositor_t *compositor;
+       struct wl_global *zxdg_shell;
+       struct wl_global *tizen_policy;
+       struct wl_event_source *cb_idle;
+
+       pepper_view_t *focus;
+       pepper_view_t *top_mapped;
+       pepper_view_t *top_visible;
+
+       pepper_event_listener_t *surface_add_listener;
+       pepper_event_listener_t *surface_remove_listener;
+       pepper_event_listener_t *view_remove_listener;
+};
+
+struct HEADLESS_SHELL_SURFACE{
+       headless_shell_t *hs_shell;
+       pepper_surface_t *surface;
+       pepper_view_t *view;
+       uint32_t        updates;
+       uint8_t         visibility;
+
+       headless_surface_type_t surface_type;
+       struct wl_resource *zxdg_shell_surface;
+       struct wl_resource *zxdg_surface;       /*resource of toplevel, popup and etc*/
+       struct wl_resource *tizen_visibility;
+       uint32_t last_ack_configure;
+
+       pepper_bool_t skip_focus;
+
+       pepper_event_listener_t *cb_commit;
+};
+
+static void
+headless_shell_cb_surface_commit(pepper_event_listener_t *listener,
+                                                                               pepper_object_t *object,
+                                                                               uint32_t id, void *info, void *data);
+static void
+headless_shell_add_idle(headless_shell_t *shell);
+
+
+static void
+headless_shell_send_visiblity(pepper_view_t *view, uint8_t visibility);
+
+const static int KEY_SHELL = 0;
+
+static void
+zxdg_toplevel_cb_resource_destroy(struct wl_resource *resource)
+{
+       headless_shell_surface_t *hs_surface = (headless_shell_surface_t *)wl_resource_get_user_data(resource);
+
+       PEPPER_CHECK(hs_surface, return, "fail to get headless_surface.\n");
+       PEPPER_CHECK((hs_surface->surface_type == HEADLESS_SURFACE_TOPLEVEL), return, "Invalid surface type.\n");
+       PEPPER_CHECK((hs_surface->zxdg_surface == resource), return, "Invalid surface.");
+
+       PEPPER_TRACE("[SHELL] zxdg_toplevel_cb_resource_destroy: view:%p, hs_surface:%p\n", hs_surface->view, hs_surface);
+
+       if (hs_surface->view) {
+               pepper_view_unmap(hs_surface->view);
+               headless_shell_add_idle(hs_surface->hs_shell);
+       }
+
+       hs_surface->surface_type = HEADLESS_SURFACE_NONE;
+       hs_surface->zxdg_surface = NULL;
+       SET_UPDATE(hs_surface->updates, UPDATE_SURFACE_TYPE);
+}
+
+static void
+zxdg_toplevel_cb_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static void
+zxdg_toplevel_cb_parent_set(struct wl_client *client,
+                           struct wl_resource *resource,
+                           struct wl_resource *res_parent)
+{
+}
+
+static void
+zxdg_toplevel_cb_title_set(struct wl_client *client,
+                          struct wl_resource *resource,
+                          const char *title)
+{
+}
+
+static void
+zxdg_toplevel_cb_app_id_set(struct wl_client *client,
+                           struct wl_resource *resource,
+                           const char *app_id)
+{
+}
+
+static void
+zxdg_toplevel_cb_win_menu_show(struct wl_client *client,
+                              struct wl_resource *resource,
+                              struct wl_resource *res_seat,
+                              uint32_t serial,
+                              int32_t x,
+                              int32_t y)
+{
+}
+
+static void
+zxdg_toplevel_cb_move(struct wl_client *client,
+                     struct wl_resource *resource,
+                     struct wl_resource *res_seat,
+                     uint32_t serial)
+{
+}
+
+static void
+zxdg_toplevel_cb_resize(struct wl_client *client,
+                       struct wl_resource *resource,
+                       struct wl_resource *res_seat,
+                       uint32_t serial,
+                       uint32_t edges)
+{
+}
+
+static void
+zxdg_toplevel_cb_max_size_set(struct wl_client *client,
+                             struct wl_resource *resource,
+                             int32_t w,
+                             int32_t h)
+{
+}
+
+static void
+zxdg_toplevel_cb_min_size_set(struct wl_client *client,
+                             struct wl_resource *resource,
+                             int32_t w,
+                             int32_t h)
+{
+}
+
+static void
+zxdg_toplevel_cb_maximized_set(struct wl_client *client, struct wl_resource *resource)
+{
+}
+
+static void
+zxdg_toplevel_cb_maximized_unset(struct wl_client *client, struct wl_resource *resource)
+{
+}
+
+static void
+zxdg_toplevel_cb_fullscreen_set(struct wl_client *client,
+                               struct wl_resource *resource,
+                               struct wl_resource *res_output)
+{
+}
+
+static void
+zxdg_toplevel_cb_fullscreen_unset(struct wl_client *client, struct wl_resource *resource)
+{
+}
+
+static void
+zxdg_toplevel_cb_minimized_set(struct wl_client *client, struct wl_resource *resource)
+{
+}
+
+static const struct zxdg_toplevel_v6_interface zxdg_toplevel_interface =
+{
+       zxdg_toplevel_cb_destroy,
+       zxdg_toplevel_cb_parent_set,
+       zxdg_toplevel_cb_title_set,
+       zxdg_toplevel_cb_app_id_set,
+       zxdg_toplevel_cb_win_menu_show,
+       zxdg_toplevel_cb_move,
+       zxdg_toplevel_cb_resize,
+       zxdg_toplevel_cb_max_size_set,
+       zxdg_toplevel_cb_min_size_set,
+       zxdg_toplevel_cb_maximized_set,
+       zxdg_toplevel_cb_maximized_unset,
+       zxdg_toplevel_cb_fullscreen_set,
+       zxdg_toplevel_cb_fullscreen_unset,
+       zxdg_toplevel_cb_minimized_set
+};
+
+static void
+zxdg_popup_cb_resource_destroy(struct wl_resource *resource)
+{
+       headless_shell_surface_t *hs_surface = (headless_shell_surface_t *)wl_resource_get_user_data(resource);
+
+       PEPPER_CHECK(hs_surface, return, "fail to get headless_surface.\n");
+       PEPPER_CHECK((hs_surface->surface_type == HEADLESS_SURFACE_POPUP), return, "Invalid surface type.\n");
+       PEPPER_CHECK((hs_surface->zxdg_surface == resource), return, "Invalid surface.");
+
+       hs_surface->surface_type = HEADLESS_SURFACE_NONE;
+       hs_surface->zxdg_surface = NULL;
+       SET_UPDATE(hs_surface->updates, UPDATE_SURFACE_TYPE);
+}
+
+static void
+zxdg_popup_cb_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static void
+zxdg_popup_cb_grab(struct wl_client *client,
+                  struct wl_resource *resource,
+                  struct wl_resource *res_seat,
+                  uint32_t serial)
+{
+}
+
+static const struct zxdg_popup_v6_interface zxdg_popup_interface =
+{
+       zxdg_popup_cb_destroy,
+       zxdg_popup_cb_grab
+};
+
+static void
+zxdg_surface_cb_resource_destroy(struct wl_resource *resource)
+{
+       headless_shell_surface_t *hs_surface;
+
+       hs_surface = wl_resource_get_user_data(resource);
+       PEPPER_CHECK(hs_surface, return, "fail to get hs_surface\n");
+
+       PEPPER_TRACE("[SHELL] zxdg_surface_cb_resource_destroy: hs_surface:%p view:%p\n", hs_surface, hs_surface->view);
+
+       if (hs_surface->view) {
+               pepper_view_destroy(hs_surface->view);
+               hs_surface->view = NULL;
+       }
+
+       if (hs_surface->cb_commit) {
+               pepper_event_listener_remove(hs_surface->cb_commit);
+               hs_surface->cb_commit = NULL;
+       }
+
+       hs_surface->zxdg_shell_surface = NULL;
+       hs_surface->skip_focus = PEPPER_FALSE;
+       hs_surface->visibility = TIZEN_VISIBILITY_VISIBILITY_FULLY_OBSCURED;
+
+       SET_UPDATE(hs_surface->updates, UPDATE_SURFACE_TYPE);
+       headless_shell_add_idle(hs_surface->hs_shell);
+}
+
+static void
+zxdg_surface_cb_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static void
+zxdg_surface_cb_toplevel_get(struct wl_client *client, struct wl_resource *resource, uint32_t id)
+{
+       headless_shell_surface_t *hs_surface = (headless_shell_surface_t *)wl_resource_get_user_data(resource);
+       struct wl_resource *new_res;
+
+       PEPPER_CHECK(hs_surface, return, "fail to get headless_surface\n");
+       PEPPER_CHECK((hs_surface->zxdg_surface == NULL), return, "alwreay assign zdg_surface:%p role:%d\n", hs_surface->zxdg_surface, hs_surface->surface_type);
+
+       new_res = wl_resource_create(client, &zxdg_toplevel_v6_interface, 1, id);
+       if (!new_res) {
+               PEPPER_ERROR("fail to create zxdg_toplevel");
+               wl_resource_post_no_memory(resource);
+               return;
+       }
+
+       wl_resource_set_implementation(new_res,
+                       &zxdg_toplevel_interface,
+                       hs_surface,
+                       zxdg_toplevel_cb_resource_destroy);
+
+       hs_surface->surface_type = HEADLESS_SURFACE_TOPLEVEL;
+       hs_surface->zxdg_surface = new_res;
+
+       SET_UPDATE(hs_surface->updates, UPDATE_SURFACE_TYPE);
+}
+
+static void
+zxdg_surface_cb_popup_get(struct wl_client *client,
+                                                                       struct wl_resource *resource,
+                                                                       uint32_t id,
+                                                                       struct wl_resource *res_parent,
+                                                                       struct wl_resource *res_pos)
+{
+       headless_shell_surface_t *hs_surface = (headless_shell_surface_t *)wl_resource_get_user_data(resource);
+       struct wl_resource *new_res;
+
+       PEPPER_CHECK(hs_surface, return, "fail to get headless_surface\n");
+       PEPPER_CHECK((hs_surface->zxdg_surface == NULL), return, "alwreay assign zdg_surface:%p role:%d\n", hs_surface->zxdg_surface, hs_surface->surface_type);
+
+       new_res = wl_resource_create(client, &zxdg_popup_v6_interface, 1, id);
+       if (!new_res) {
+               PEPPER_ERROR("fail to create popup");
+               wl_resource_post_no_memory(resource);
+               return;
+       }
+
+       wl_resource_set_implementation(new_res,
+                                 &zxdg_popup_interface,
+                                 hs_surface,
+                                 zxdg_popup_cb_resource_destroy);
+
+       hs_surface->surface_type = HEADLESS_SURFACE_POPUP;
+       hs_surface->zxdg_surface = new_res;
+
+       SET_UPDATE(hs_surface->updates, UPDATE_SURFACE_TYPE);
+}
+
+static void
+zxdg_surface_cb_win_geometry_set(struct wl_client *client,
+                                   struct wl_resource *resource,
+                                   int32_t x,
+                                   int32_t y,
+                                   int32_t w,
+                                   int32_t h)
+{
+}
+
+static void
+zxdg_surface_cb_configure_ack(struct wl_client *client, struct wl_resource *resource, uint32_t serial)
+{
+       headless_shell_surface_t *hs_surface;
+
+       hs_surface = wl_resource_get_user_data(resource);
+       PEPPER_CHECK(hs_surface, return, "fail to get headless_shell_surface\n");
+
+       hs_surface->last_ack_configure = serial;
+}
+
+static const struct zxdg_surface_v6_interface zxdg_surface_interface =
+{
+       zxdg_surface_cb_destroy,
+       zxdg_surface_cb_toplevel_get,
+       zxdg_surface_cb_popup_get,
+       zxdg_surface_cb_win_geometry_set,
+       zxdg_surface_cb_configure_ack
+};
+
+static void
+zxdg_positioner_cb_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static void
+zxdg_positioner_cb_size_set(struct wl_client *client,
+                           struct wl_resource *resource,
+                           int32_t w, int32_t h)
+{
+}
+
+static void
+zxdg_positioner_cb_anchor_rect_set(struct wl_client *client,
+                                  struct wl_resource *resource,
+                                  int32_t x, int32_t y, int32_t w, int32_t h)
+{
+}
+
+static void
+zxdg_positioner_cb_anchor_set(struct wl_client *client,
+                             struct wl_resource *resource,
+                             enum zxdg_positioner_v6_anchor anchor)
+{
+}
+
+static void
+zxdg_positioner_cb_gravity_set(struct wl_client *client,
+                              struct wl_resource *resource,
+                              enum zxdg_positioner_v6_gravity gravity)
+{
+}
+
+static void
+zxdg_positioner_cb_constraint_adjustment_set(struct wl_client *client,
+                                            struct wl_resource *resource,
+                                            enum zxdg_positioner_v6_constraint_adjustment constraint_adjustment)
+{
+}
+
+static void
+zxdg_positioner_cb_offset_set(struct wl_client *client,
+                             struct wl_resource *resource,
+                             int32_t x, int32_t y)
+{
+}
+
+static const struct zxdg_positioner_v6_interface zxdg_positioner_interface =
+{
+       zxdg_positioner_cb_destroy,
+       zxdg_positioner_cb_size_set,
+       zxdg_positioner_cb_anchor_rect_set,
+       zxdg_positioner_cb_anchor_set,
+       zxdg_positioner_cb_gravity_set,
+       zxdg_positioner_cb_constraint_adjustment_set,
+       zxdg_positioner_cb_offset_set,
+};
+
+static void
+zxdg_shell_cb_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+       PEPPER_TRACE("Destroy zxdg_shell\n");
+
+       wl_resource_destroy(resource);
+}
+
+static void
+zxdg_shell_cb_positioner_create(struct wl_client *client, struct wl_resource *resource, uint32_t id)
+{
+       struct wl_resource *new_res;
+
+       PEPPER_TRACE("Create zxdg_positoiner\n");
+
+       new_res = wl_resource_create(client, &zxdg_positioner_v6_interface, 1, id);
+       if (!new_res)
+       {
+               PEPPER_ERROR("fail to create zxdg_positioner\n");
+               wl_resource_post_no_memory(resource);
+               return;
+       }
+
+       wl_resource_set_implementation(new_res, &zxdg_positioner_interface, NULL, NULL);
+}
+
+static void
+zxdg_shell_cb_surface_get(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *wsurface)
+{
+       headless_shell_t *hs;
+       headless_shell_surface_t *hs_surface = NULL;
+       pepper_surface_t *psurface;
+       const char *role;
+
+       hs = wl_resource_get_user_data(resource);
+       if (!hs) {
+               PEPPER_ERROR("fail to get headless_shell\n");
+               wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
+                               "failed to get headless shell");
+               return;
+       }
+
+       psurface = wl_resource_get_user_data(wsurface);
+       PEPPER_CHECK(psurface, goto error, "faile to get pepper_surface\n");
+
+       hs_surface = (headless_shell_surface_t *)pepper_object_get_user_data((pepper_object_t *)psurface, wsurface);
+       if (!hs_surface) {
+               PEPPER_ERROR("fail to get headless_shell_surface_t: %p key:%p\n", psurface, wsurface);
+               wl_resource_post_no_memory(resource);
+               return;
+       }
+
+       hs_surface->zxdg_shell_surface = wl_resource_create(client, &zxdg_surface_v6_interface, 1, id);
+       if (!hs_surface->zxdg_shell_surface) {
+               PEPPER_ERROR("fail to create the zxdg_surface\n");
+               wl_resource_post_no_memory(resource);
+               goto error;
+       }
+
+       wl_resource_set_implementation(hs_surface->zxdg_shell_surface,
+                       &zxdg_surface_interface,
+                       hs_surface,
+                       zxdg_surface_cb_resource_destroy);
+
+       hs_surface->view = pepper_compositor_add_view(hs->compositor);
+       if (!hs_surface->view) {
+               PEPPER_ERROR("fail to create the pepper_view\n");
+               wl_resource_post_no_memory(resource);
+               goto error;
+       }
+
+       if (!pepper_view_set_surface(hs_surface->view, psurface)) {
+               PEPPER_ERROR("fail to set surface\n");
+               wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
+                               "Assign set psurface to pview");
+               goto error;
+       }
+
+       hs_surface->cb_commit = pepper_object_add_event_listener((pepper_object_t *)psurface,
+                                                                                                                       PEPPER_EVENT_SURFACE_COMMIT, 0, headless_shell_cb_surface_commit, hs_surface);
+
+       role = pepper_surface_get_role(psurface);
+       if (!role) {
+               if (!pepper_surface_set_role(psurface, "xdg_surface")) {
+                       PEPPER_ERROR("fail to set role\n");
+                       wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
+                                       "Assign \"xdg_surface\" to wl_surface failed\n");
+                       goto error;
+               }
+       } else {
+               PEPPER_CHECK(!strcmp(role, "xdg_surface"), goto error, "surface has alweady role %s\n", role);
+       }
+
+       PEPPER_TRACE("[SHELL] create zxdg_surface:%p, pview:%p, psurface:%p\n",
+                       hs_surface->zxdg_shell_surface,
+                       hs_surface->view,
+                       psurface);
+
+       return;
+error:
+       if (hs_surface) {
+               if (hs_surface->view) {
+                       pepper_view_destroy(hs_surface->view);
+                       hs_surface->view = NULL;
+               }
+
+               if (hs_surface->zxdg_shell_surface) {
+                       wl_resource_destroy(hs_surface->zxdg_shell_surface);
+                       hs_surface->zxdg_shell_surface = NULL;
+               }
+       }
+}
+
+static void
+zxdg_shell_cb_pong(struct wl_client *client, struct wl_resource *resource, uint32_t serial)
+{
+
+}
+
+static const struct zxdg_shell_v6_interface zxdg_shell_interface =
+{
+       zxdg_shell_cb_destroy,
+       zxdg_shell_cb_positioner_create,
+       zxdg_shell_cb_surface_get,
+       zxdg_shell_cb_pong
+};
+
+static void
+zxdg_shell_cb_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+       struct wl_resource *resource;
+       headless_shell_t *hs = (headless_shell_t *)data;
+
+       PEPPER_TRACE("Bind zxdg_shell\n");
+
+       /* Create resource for zxdg_shell_v6 */
+       resource = wl_resource_create(client,
+                       &zxdg_shell_v6_interface,
+                       version,
+                       id);
+       PEPPER_CHECK(resource, goto err_shell, "fail to create the zxdg_shell_v6\n");
+
+       wl_resource_set_implementation(resource, &zxdg_shell_interface, hs, NULL);
+
+       return;
+err_shell:
+       wl_resource_destroy(resource);
+       wl_client_post_no_memory(client);
+}
+
+static pepper_bool_t
+zxdg_init(headless_shell_t *shell)
+{
+       struct wl_display *display;
+
+       display = pepper_compositor_get_display(shell->compositor);
+
+       shell->zxdg_shell = wl_global_create(display, &zxdg_shell_v6_interface, 1, shell, zxdg_shell_cb_bind);
+       PEPPER_CHECK(shell->zxdg_shell, return PEPPER_FALSE, "fail to create zxdg_shell\n");
+
+       return PEPPER_TRUE;
+}
+
+void
+zxdg_deinit(headless_shell_t *shell)
+{
+       if (shell->zxdg_shell)
+               wl_global_destroy(shell->zxdg_shell);
+}
+
+static void
+tizen_visibility_cb_destroy(struct wl_client *client, struct wl_resource *res_tzvis)
+{
+       wl_resource_destroy(res_tzvis);
+}
+
+static const struct tizen_visibility_interface tizen_visibility =
+{
+       tizen_visibility_cb_destroy
+};
+
+static void
+tizen_visibility_cb_vis_destroy(struct wl_resource *res_tzvis)
+{
+       headless_shell_surface_t *hs_surface = (headless_shell_surface_t *)wl_resource_get_user_data(res_tzvis);
+
+       PEPPER_CHECK(hs_surface, return, "[SHELL] cannot get headless_shell_surface_t\n");
+       hs_surface->tizen_visibility = NULL;
+}
+
+static void
+tizen_position_cb_destroy(struct wl_client *client, struct wl_resource *res_tzpos)
+{
+   wl_resource_destroy(res_tzpos);
+}
+
+static void
+tizen_position_cb_set(struct wl_client *client, struct wl_resource *res_tzpos, int32_t x, int32_t y)
+{
+}
+
+static const struct tizen_position_interface tizen_position =
+{
+   tizen_position_cb_destroy,
+   tizen_position_cb_set,
+};
+
+static void
+tizen_position_cb_pos_destroy(struct wl_resource *res_tzpos)
+{
+}
+
+static void
+tizen_policy_cb_vis_get(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surf)
+{
+       pepper_surface_t *psurface;
+       headless_shell_surface_t *hs_surface;
+       struct wl_resource *new_res;
+
+       psurface = wl_resource_get_user_data(surf);
+       PEPPER_CHECK(psurface, return, "fail to get pepper_surface_t\n");
+
+       hs_surface = pepper_object_get_user_data((pepper_object_t *)psurface, surf);
+       PEPPER_CHECK(hs_surface, return, "fail to get headless_shell_surface\n");
+
+       new_res = wl_resource_create(client, &tizen_visibility_interface, 5, id);
+       if (!new_res) {
+               PEPPER_ERROR("fail to create tizen_visibility");
+               wl_resource_post_no_memory(resource);
+               return;
+       }
+
+       wl_resource_set_implementation(new_res,
+                       &tizen_visibility,
+                       hs_surface,
+                       tizen_visibility_cb_vis_destroy);
+
+       hs_surface->tizen_visibility = new_res;
+
+       if (hs_surface->visibility != TIZEN_VISIBILITY_VISIBILITY_FULLY_OBSCURED)
+               tizen_visibility_send_notify(hs_surface->tizen_visibility, hs_surface->visibility);
+}
+
+static void
+tizen_policy_cb_pos_get(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surf)
+{
+       struct wl_resource *new_res;
+
+       new_res = wl_resource_create(client, &tizen_position_interface, 1, id);
+       if (!new_res) {
+               PEPPER_ERROR("fail to create tizen_visibility");
+               wl_resource_post_no_memory(resource);
+               return;
+       }
+
+       wl_resource_set_implementation(new_res,
+                       &tizen_position,
+                       NULL,
+                       tizen_position_cb_pos_destroy);
+}
+
+static void
+tizen_policy_cb_activate(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surf)
+{
+       pepper_surface_t *psurface;
+       headless_shell_surface_t *hs_surface;
+
+       psurface = wl_resource_get_user_data(surf);
+       PEPPER_CHECK(psurface, return, "fail to get pepper_surface_t\n");
+
+       hs_surface = pepper_object_get_user_data((pepper_object_t *)psurface, surf);
+       PEPPER_CHECK(hs_surface, return, "fail to get headless_shell_surface\n");
+       PEPPER_CHECK(hs_surface->view, return, "invalid view from headless_shell_surface\n");
+
+       pepper_view_stack_top(hs_surface->view, PEPPER_TRUE);
+
+       headless_shell_add_idle(hs_surface->hs_shell);
+}
+
+static void
+tizen_policy_cb_activate_below_by_res_id(struct wl_client *client, struct wl_resource *resource,  uint32_t res_id, uint32_t below_res_id)
+{
+}
+
+static void
+tizen_policy_cb_raise(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surf)
+{
+}
+
+static void
+tizen_policy_cb_lower(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surf)
+{
+}
+
+static void
+tizen_policy_cb_lower_by_res_id(struct wl_client *client, struct wl_resource *resource,  uint32_t res_id)
+{
+}
+
+static void
+tizen_policy_cb_focus_skip_set(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surf)
+{
+       pepper_surface_t *psurface;
+       headless_shell_surface_t *hs_surface;
+
+       psurface = wl_resource_get_user_data(surf);
+       PEPPER_CHECK(psurface, return, "fail to get pepper_surface_t\n");
+
+       hs_surface = pepper_object_get_user_data((pepper_object_t *)psurface, surf);
+       PEPPER_CHECK(hs_surface, return, "fail to get headless_shell_surface\n");
+
+       hs_surface->skip_focus = PEPPER_TRUE;
+}
+
+static void
+tizen_policy_cb_focus_skip_unset(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surf)
+{
+       pepper_surface_t *psurface;
+       headless_shell_surface_t *hs_surface;
+
+       psurface = wl_resource_get_user_data(surf);
+       PEPPER_CHECK(psurface, return, "fail to get pepper_surface_t\n");
+
+       hs_surface = pepper_object_get_user_data((pepper_object_t *)psurface, surf);
+       PEPPER_CHECK(hs_surface, return, "fail to get headless_shell_surface\n");
+
+       hs_surface->skip_focus = PEPPER_FALSE;
+}
+
+static void
+tizen_policy_cb_role_set(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surf, const char *role)
+{
+}
+
+static void
+tizen_policy_cb_type_set(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surf, uint32_t type)
+{
+}
+
+static void
+tizen_policy_cb_conformant_set(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surf)
+{
+}
+
+static void
+tizen_policy_cb_conformant_unset(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surf)
+{
+}
+
+static void
+tizen_policy_cb_conformant_get(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surf)
+{
+   tizen_policy_send_conformant(resource, surf, 0);
+}
+
+static void
+tizen_policy_cb_notilv_set(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surf, int32_t lv)
+{
+}
+
+static void
+tizen_policy_cb_transient_for_set(struct wl_client *client, struct wl_resource *resource, uint32_t child_id, uint32_t parent_id)
+{
+}
+
+static void
+tizen_policy_cb_transient_for_unset(struct wl_client *client, struct wl_resource *resource, uint32_t child_id)
+{
+   tizen_policy_send_transient_for_done(resource, child_id);
+}
+
+static void
+tizen_policy_cb_win_scrmode_set(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surf, uint32_t mode)
+{
+   tizen_policy_send_window_screen_mode_done
+     (resource, surf, mode, TIZEN_POLICY_ERROR_STATE_NONE);
+}
+
+static void
+tizen_policy_cb_subsurf_place_below_parent(struct wl_client *client, struct wl_resource *resource, struct wl_resource *subsurf)
+{
+}
+
+static void
+tizen_policy_cb_subsurf_stand_alone_set(struct wl_client *client, struct wl_resource *resource, struct wl_resource *subsurf)
+{
+}
+
+static void
+tizen_policy_cb_subsurface_get(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface, uint32_t parent_id)
+{
+       wl_client_post_implementation_error(client, "Headless server not support tizen_subsurface\n");
+}
+
+static void
+tizen_policy_cb_opaque_state_set(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, int32_t state)
+{
+}
+
+static void
+tizen_policy_cb_iconify(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surf)
+{
+}
+
+static void
+tizen_policy_cb_uniconify(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surf)
+{
+}
+
+static void
+tizen_policy_cb_aux_hint_add(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surf, int32_t id, const char *name, const char *value)
+{
+}
+
+static void
+tizen_policy_cb_aux_hint_change(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surf, int32_t id, const char *value)
+{
+}
+
+static void
+tizen_policy_cb_aux_hint_del(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surf, int32_t id)
+{
+}
+
+static void
+tizen_policy_cb_supported_aux_hints_get(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surf)
+{
+}
+
+static void
+tizen_policy_cb_background_state_set(struct wl_client *client, struct wl_resource *resource, uint32_t pid)
+{
+}
+
+static void
+tizen_policy_cb_background_state_unset(struct wl_client *client, struct wl_resource *resource, uint32_t pid)
+{
+}
+
+static void
+tizen_policy_cb_floating_mode_set(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surf)
+{
+}
+
+static void
+tizen_policy_cb_floating_mode_unset(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surf)
+{
+}
+
+static void
+tizen_policy_cb_stack_mode_set(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surf, uint32_t mode)
+{
+}
+
+static void
+tizen_policy_cb_activate_above_by_res_id(struct wl_client *client, struct wl_resource *resource,  uint32_t res_id, uint32_t above_res_id)
+{
+}
+
+static void
+tizen_policy_cb_subsurf_watcher_get(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface)
+{
+       wl_client_post_implementation_error(client, "Headless server not support tizen_subsurface\n");
+}
+
+static void
+tizen_policy_cb_parent_set(struct wl_client *client, struct wl_resource *resource, struct wl_resource *child, struct wl_resource *parent)
+{
+}
+
+static void
+tizen_policy_cb_ack_conformant_region(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, uint32_t serial)
+{
+}
+
+static void
+tizen_policy_cb_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+   wl_resource_destroy(resource);
+}
+
+static void
+tizen_policy_cb_has_video(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, uint32_t has)
+{
+}
+
+static const struct tizen_policy_interface tizen_policy_iface =
+{
+   tizen_policy_cb_vis_get,
+   tizen_policy_cb_pos_get,
+   tizen_policy_cb_activate,
+   tizen_policy_cb_activate_below_by_res_id,
+   tizen_policy_cb_raise,
+   tizen_policy_cb_lower,
+   tizen_policy_cb_lower_by_res_id,
+   tizen_policy_cb_focus_skip_set,
+   tizen_policy_cb_focus_skip_unset,
+   tizen_policy_cb_role_set,
+   tizen_policy_cb_type_set,
+   tizen_policy_cb_conformant_set,
+   tizen_policy_cb_conformant_unset,
+   tizen_policy_cb_conformant_get,
+   tizen_policy_cb_notilv_set,
+   tizen_policy_cb_transient_for_set,
+   tizen_policy_cb_transient_for_unset,
+   tizen_policy_cb_win_scrmode_set,
+   tizen_policy_cb_subsurf_place_below_parent,
+   tizen_policy_cb_subsurf_stand_alone_set,
+   tizen_policy_cb_subsurface_get,
+   tizen_policy_cb_opaque_state_set,
+   tizen_policy_cb_iconify,
+   tizen_policy_cb_uniconify,
+   tizen_policy_cb_aux_hint_add,
+   tizen_policy_cb_aux_hint_change,
+   tizen_policy_cb_aux_hint_del,
+   tizen_policy_cb_supported_aux_hints_get,
+   tizen_policy_cb_background_state_set,
+   tizen_policy_cb_background_state_unset,
+   tizen_policy_cb_floating_mode_set,
+   tizen_policy_cb_floating_mode_unset,
+   tizen_policy_cb_stack_mode_set,
+   tizen_policy_cb_activate_above_by_res_id,
+   tizen_policy_cb_subsurf_watcher_get,
+   tizen_policy_cb_parent_set,
+   tizen_policy_cb_ack_conformant_region,
+   tizen_policy_cb_destroy,
+   tizen_policy_cb_has_video,
+};
+
+static void
+tizen_policy_cb_unbind(struct wl_resource *resource)
+{
+       headless_shell_t *shell = (headless_shell_t *)wl_resource_get_user_data(resource);
+
+       shell->tizen_policy = NULL;
+}
+
+static void
+tizen_policy_cb_bind(struct wl_client *client, void *data, uint32_t ver, uint32_t id)
+{
+       headless_shell_t *shell = (headless_shell_t *)data;
+       struct wl_resource *resource;
+
+       PEPPER_CHECK(shell, goto err, "data is NULL\n");
+
+       resource = wl_resource_create(client,
+                                                                       &tizen_policy_interface,
+                                                                       ver,
+                                                                       id);
+       PEPPER_CHECK(resource, goto err, "fail to create tizen_policy\n");
+
+       wl_resource_set_implementation(resource,
+                                                                       &tizen_policy_iface,
+                                                                       shell,
+                                                                       tizen_policy_cb_unbind);
+       return;
+
+err:
+       wl_client_post_no_memory(client);
+}
+
+static pepper_bool_t
+tizen_policy_init(headless_shell_t *shell)
+{
+       struct wl_display *display;
+
+       display = pepper_compositor_get_display(shell->compositor);
+
+       shell->tizen_policy = wl_global_create(display, &tizen_policy_interface, 7, shell, tizen_policy_cb_bind);
+       PEPPER_CHECK(shell->tizen_policy, return PEPPER_FALSE, "faile to create tizen_policy\n");
+
+       return PEPPER_TRUE;
+}
+
+void
+tizen_policy_deinit(headless_shell_t *shell)
+{
+       if (shell->tizen_policy)
+               wl_global_destroy(shell->tizen_policy);
+}
+
+static void
+headless_shell_send_visiblity(pepper_view_t *view, uint8_t visibility)
+{
+       pepper_surface_t *surface;
+       headless_shell_surface_t *hs_surface;
+
+       if (view == NULL) return;
+
+       surface = pepper_view_get_surface(view);
+       PEPPER_CHECK(surface, return, "[SHELL] Invalid object surface:%p\n", surface);
+
+       hs_surface = pepper_object_get_user_data((pepper_object_t *)surface, pepper_surface_get_resource(surface));
+       PEPPER_CHECK(hs_surface, return, "[SHELL] Invalid object headless_surface:%p\n", hs_surface);
+
+       if (hs_surface->visibility == visibility) {
+               PEPPER_TRACE("[SHELL] Same Visibility hs_surface:%p, visibility:%d\n", hs_surface, visibility);
+               return;
+       }
+
+       if (hs_surface->tizen_visibility)
+               tizen_visibility_send_notify(hs_surface->tizen_visibility, visibility);
+
+       hs_surface->visibility = visibility;
+       PEPPER_TRACE("[SHELL] Set Visibility hs_surface:%p, visibility:%d\n", hs_surface, visibility);
+}
+
+static void
+headless_shell_cb_idle(void *data)
+{
+       headless_shell_t *hs_shell = (headless_shell_t *)data;
+       const pepper_list_t *list;
+       pepper_list_t *l;
+       pepper_view_t *view;
+       pepper_surface_t *surface;
+       headless_shell_surface_t *hs_surface;
+
+       pepper_view_t *focus = NULL, *top = NULL, *top_visible = NULL;
+
+       PEPPER_TRACE("[SHELL] Enter Idle\n");
+       list = pepper_compositor_get_view_list(hs_shell->compositor);
+
+       pepper_list_for_each_list(l,  list) {
+               view = (pepper_view_t *)l->item;
+               PEPPER_CHECK(view, continue, "[SHELL] idle_cb, Invalid object view:%p\n", view);
+
+               surface = pepper_view_get_surface(view);
+               PEPPER_CHECK(surface, continue, "[SHELL] idle_cb, Invalid object surface:%p\n", surface);
+
+               hs_surface = pepper_object_get_user_data((pepper_object_t *)surface, pepper_surface_get_resource(surface));
+               PEPPER_CHECK(hs_surface, continue, "[SHELL] idle_cb, Invalid object headless_surface:%p\n", hs_surface);
+
+               if (!pepper_view_is_mapped(view)) {
+                       headless_shell_send_visiblity(view, TIZEN_VISIBILITY_VISIBILITY_FULLY_OBSCURED);
+                       continue;
+               }
+
+               if (!top)
+                       top = view;
+
+               if (!focus && !hs_surface->skip_focus)
+                       focus = view;
+
+               if (!top_visible && pepper_surface_get_buffer(surface))
+                       top_visible = view;
+
+               if (top && focus && top_visible)
+                       break;
+       }
+
+       if (top != hs_shell->top_mapped) {
+               const pepper_list_t *l;
+               pepper_list_t *ll;
+
+               PEPPER_TRACE("[SHELL] IDLE : top-view change: %p to %p\n", hs_shell->top_mapped , top);
+               hs_shell->top_mapped = top;
+               headless_input_set_top_view(hs_shell->compositor, hs_shell->top_mapped);
+               headless_debug_set_top_view(hs_shell->compositor, hs_shell->top_mapped);
+
+               /*Force update the output*/
+               l = pepper_compositor_get_output_list(hs_shell->compositor);
+               pepper_list_for_each_list(ll, l) {
+                       pepper_output_add_damage_region((pepper_output_t *)ll->item, NULL);
+               }
+       }
+
+       if (focus != hs_shell->focus) {
+               PEPPER_TRACE("[SHELL] IDLE : focus-view change: %p to %p\n", hs_shell->focus , focus);
+               hs_shell->focus = focus;
+               headless_input_set_focus_view(hs_shell->compositor, hs_shell->focus);
+               headless_debug_set_focus_view(hs_shell->compositor, hs_shell->focus);
+       }
+
+       if (top_visible != hs_shell->top_visible) {
+               PEPPER_TRACE("[SHELL] IDLE : visible-view change: %p to %p\n", hs_shell->top_visible, top_visible);
+               headless_shell_send_visiblity(hs_shell->top_visible, TIZEN_VISIBILITY_VISIBILITY_FULLY_OBSCURED);
+               headless_shell_send_visiblity(top_visible, TIZEN_VISIBILITY_VISIBILITY_UNOBSCURED);
+               hs_shell->top_visible = top_visible;
+       }
+
+       hs_shell->cb_idle = NULL;
+}
+
+static void
+headless_shell_cb_surface_commit(pepper_event_listener_t *listener,
+                                                                               pepper_object_t *object,
+                                                                               uint32_t id, void *info, void *data)
+{
+       headless_shell_surface_t * hs_surface = (headless_shell_surface_t *)data;
+
+       PEPPER_CHECK(((pepper_object_t *)hs_surface->surface == object), return, "Invalid object\n");
+
+       /*TODO
+       1. Check the changes(buffer, map status...)
+       */
+       if (IS_UPDATE(hs_surface->updates, UPDATE_SURFACE_TYPE)) {
+               if (hs_surface->surface_type != HEADLESS_SURFACE_NONE)
+                       pepper_view_map(hs_surface->view);
+               else
+                       pepper_view_unmap(hs_surface->view);
+
+               PEPPER_TRACE("Surface type change. view:%p, type:%d, res:%p\n", hs_surface->view, hs_surface->surface_type, hs_surface->zxdg_surface);
+       }
+
+       hs_surface->updates = 0;
+
+       headless_shell_add_idle(hs_surface->hs_shell);
+}
+
+static void
+headless_shell_cb_surface_free(void *data)
+{
+       headless_shell_surface_t *surface = (headless_shell_surface_t *)data;
+
+       PEPPER_TRACE("[SHELL] hs_surface free surface:%p, view:%p, zxdg_shell_surface:%p, zxdg_surface:%p\n",
+                                       surface->surface, surface->view,
+                                       surface->zxdg_shell_surface, surface->zxdg_surface);
+
+       free(surface);
+}
+
+static void
+headless_shell_cb_surface_add(pepper_event_listener_t *listener,
+                                                                               pepper_object_t *object,
+                                                                               uint32_t id, void *info, void *data)
+{
+       headless_shell_surface_t *hs_surface;
+       pepper_surface_t *surface = (pepper_surface_t *)info;
+
+       hs_surface = (headless_shell_surface_t*)calloc(sizeof(headless_shell_surface_t), 1);
+       PEPPER_CHECK(hs_surface, return, "fail to alloc for headless_shell_surface\n");
+
+       hs_surface->hs_shell = (headless_shell_t *)data;
+       hs_surface->surface = (pepper_surface_t *)surface;
+       hs_surface->visibility = TIZEN_VISIBILITY_VISIBILITY_FULLY_OBSCURED;
+
+       pepper_object_set_user_data((pepper_object_t *)surface,
+                                                               pepper_surface_get_resource(surface),
+                                                               hs_surface,
+                                                               headless_shell_cb_surface_free);
+       PEPPER_TRACE("[SHELL] surface_Add: pepper_surface:%, headless_shell:%p to p\n", surface, hs_surface);
+}
+
+static void
+headless_shell_cb_surface_remove(pepper_event_listener_t *listener,
+                                                                               pepper_object_t *object,
+                                                                               uint32_t id, void *info, void *data)
+{
+       headless_shell_surface_t *hs_surface;
+       pepper_surface_t *surface = (pepper_surface_t *)info;
+
+       hs_surface = pepper_object_get_user_data((pepper_object_t *)surface, pepper_surface_get_resource(surface));
+       PEPPER_TRACE("[SHELL] surface_remove: pepper_surface:%p, headless_shell:%p\n", object, hs_surface);
+
+       if (hs_surface->zxdg_surface) {
+               wl_resource_set_user_data(hs_surface->zxdg_surface, NULL);
+               hs_surface->zxdg_surface = NULL;
+       }
+
+       if (hs_surface->zxdg_shell_surface) {
+               wl_resource_set_user_data(hs_surface->zxdg_shell_surface, NULL);
+               hs_surface->zxdg_shell_surface = NULL;
+       }
+
+       if (hs_surface->view) {
+               pepper_view_destroy(hs_surface->view);
+               hs_surface->view = NULL;
+       }
+
+       SET_UPDATE(hs_surface->updates, UPDATE_SURFACE_TYPE);
+       headless_shell_add_idle(hs_surface->hs_shell);
+}
+
+static void
+headless_shell_cb_view_remove(pepper_event_listener_t *listener,
+                                                                               pepper_object_t *object,
+                                                                               uint32_t id, void *info, void *data)
+{
+       pepper_view_t *view = (pepper_view_t *)info;
+       headless_shell_t *shell = (headless_shell_t *)data;
+
+       if (view == shell->top_mapped)
+               shell->top_mapped = NULL;
+
+       if (view == shell->top_visible)
+               shell->top_visible = NULL;
+
+       if (view == shell->focus)
+               shell->focus = NULL;
+
+       headless_shell_add_idle(shell);
+}
+
+static void
+headless_shell_add_idle(headless_shell_t *shell)
+{
+       struct wl_event_loop *loop;
+
+       if (!shell || shell->cb_idle)
+               return;
+
+       loop = wl_display_get_event_loop(pepper_compositor_get_display(shell->compositor));
+       PEPPER_CHECK(loop, return, "fail to get event loop\n");
+
+       shell->cb_idle = wl_event_loop_add_idle(loop, headless_shell_cb_idle, shell);
+       PEPPER_CHECK(shell->cb_idle, return, "fail to add idle\n");
+}
+
+static void
+headless_shell_init_listeners(headless_shell_t *shell)
+{
+       shell->surface_add_listener = pepper_object_add_event_listener((pepper_object_t *)shell->compositor,
+                                                                                                                                       PEPPER_EVENT_COMPOSITOR_SURFACE_ADD,
+                                                                                                                                       0, headless_shell_cb_surface_add, shell);
+
+       shell->surface_remove_listener = pepper_object_add_event_listener((pepper_object_t *)shell->compositor,
+                                                                                                                                               PEPPER_EVENT_COMPOSITOR_SURFACE_REMOVE,
+                                                                                                                                               0, headless_shell_cb_surface_remove, shell);
+
+       shell->view_remove_listener = pepper_object_add_event_listener((pepper_object_t *)shell->compositor,
+                                                                                                                                               PEPPER_EVENT_COMPOSITOR_VIEW_REMOVE,
+                                                                                                                                               0, headless_shell_cb_view_remove, shell);
+}
+
+static void
+headless_shell_deinit_listeners(headless_shell_t *shell)
+{
+       pepper_event_listener_remove(shell->surface_add_listener);
+       pepper_event_listener_remove(shell->surface_remove_listener);
+       pepper_event_listener_remove(shell->view_remove_listener);
+}
+
+static void
+headless_shell_destroy(headless_shell_t *shell)
+{
+       if (!shell)
+               return;
+
+       if (shell->cb_idle)
+               wl_event_source_remove(shell->cb_idle);
+
+       headless_shell_deinit_listeners(shell);
+       zxdg_deinit(shell);
+       tizen_policy_deinit(shell);
+}
+
+void
+headless_shell_deinit(pepper_compositor_t *compositor)
+{
+       headless_shell_t *shell;
+
+       PEPPER_CHECK(compositor, return, "compositor is NULL\n");
+
+       shell = (headless_shell_t *)pepper_object_get_user_data((pepper_object_t *)compositor, &KEY_SHELL);
+       PEPPER_CHECK(shell, return, "shell is NULL\n");
+
+       headless_shell_destroy(shell);
+
+       pepper_object_set_user_data((pepper_object_t *)shell->compositor, &KEY_SHELL, NULL, NULL);
+       free(shell);
+}
+
+pepper_bool_t
+headless_shell_init(pepper_compositor_t *compositor)
+{
+       headless_shell_t *shell;
+
+       shell = (headless_shell_t*)calloc(sizeof(headless_shell_t), 1);
+       PEPPER_CHECK(shell, goto error, "fail to alloc for shell\n");
+       shell->compositor = compositor;
+
+       headless_shell_init_listeners(shell);
+       PEPPER_CHECK(zxdg_init(shell), goto error, "zxdg_init() failed\n");
+       PEPPER_CHECK(tizen_policy_init(shell), goto error, "tizen_policy_init() failed\n");
+
+       pepper_object_set_user_data((pepper_object_t *)compositor, &KEY_SHELL, shell, NULL);
+
+       return PEPPER_TRUE;
+
+error:
+       if (shell) {
+               headless_shell_destroy(shell);
+               free(shell);
+       }
+       return PEPPER_FALSE;
+}