--- /dev/null
+Sangjin Lee lsj119@samsung.com
+Sungjin Park sj76.park@samsung.com
+Jeonghyun Kang jhyuni.kang@samsung.com
--- /dev/null
+== 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:
--- /dev/null
+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
--- /dev/null
+SUBDIRS = src
+
+#pkgconfig_DATA =
+
--- /dev/null
+# headless-server
+Pepper-based display server for headless (e.g. Tizen Speaker Profile)
--- /dev/null
+#! /bin/sh
+
+test -n "$srcdir" || srcdir=`dirname "$0"`
+test -n "$srcdir" || srcdir=.
+(
+ cd "$srcdir" &&
+ autoreconf --force -v --install
+) || exit
+test -n "$NOCONFIGURE" || "$srcdir/configure" "$@"
--- /dev/null
+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
--- /dev/null
+#!/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}"
--- /dev/null
+[Unit]
+Description=Path activation for display manager ready service
+After=tmp.mount display-manager.service
+
+[Path]
+PathExists=/run/wayland-0
--- /dev/null
+[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
--- /dev/null
+TBM_DISPLAY_SERVER=1
+WAYLAND_DISPLAY="wayland-0"
+XDG_RUNTIME_DIR=/run
--- /dev/null
+[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
--- /dev/null
+[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/"
--- /dev/null
+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
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_"/>
+ </request>
+</manifest>
--- /dev/null
+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,-)
+
--- /dev/null
+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
--- /dev/null
+/*
+* 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+* 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 */
+
--- /dev/null
+/*
+* 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+* 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;
+}
--- /dev/null
+/*
+* 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);
--- /dev/null
+/*
+* 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");
+}
--- /dev/null
+/*
+* 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;
+}