Support wayland build 11/17811/1
authorSung-jae Park <nicesj.park@samsung.com>
Tue, 11 Mar 2014 06:19:32 +0000 (15:19 +0900)
committerSung-jae Park <nicesj.park@samsung.com>
Tue, 11 Mar 2014 06:19:32 +0000 (15:19 +0900)
Change-Id: I23a880fdcb2d44d9959c2057e49b68448d813efb

CMakeLists.txt
include/livebox.h
packaging/liblivebox-viewer.spec
src/client.c
src/fb.c
src/fb_wayland.c [new file with mode: 0644]
src/livebox.c

index 3dbe5bc..886e1e6 100644 (file)
@@ -9,7 +9,7 @@ SET(INCLUDEDIR "\${prefix}/include/${PROJECT_NAME}")
 SET(VERSION_MAJOR 0)
 SET(VERSION "${VERSION_MAJOR}.0.1")
 
-set(CMAKE_SKIP_BUILD_RPATH true)
+SET(CMAKE_SKIP_BUILD_RPATH true)
 
 INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
 
@@ -20,8 +20,6 @@ pkg_check_modules(pkgs REQUIRED
        glib-2.0
        gio-2.0
        com-core
-       x11
-       xext
        sqlite3
        db-util
        livebox-service
@@ -29,10 +27,46 @@ pkg_check_modules(pkgs REQUIRED
        libtzplatform-config
 )
 
+SET(BUILD_SOURCE
+       src/dlist.c
+       src/livebox.c
+       src/util.c
+       src/desc_parser.c
+       src/master_rpc.c
+       src/client.c
+       src/file_service.c
+       src/conf.c
+)
+
+IF (X11_SUPPORT)
+pkg_check_modules(pkgs_extra REQUIRED
+       x11
+       xext
+)
+
+SET(BUILD_SOURCE
+       ${BUILD_SOURCE}
+       src/fb.c
+)
+ADD_DEFINITIONS("-DHAVE_X11")
+ENDIF (X11_SUPPORT)
+
+IF (WAYLAND_SUPPORT)
+SET(BUILD_SOURCE
+       ${BUILD_SOURCE}
+       src/fb_wayland.c
+)
+ADD_DEFINITIONS("-DHAVE_WAYLAND")
+ENDIF (WAYLAND_SUPPORT)
+
 FOREACH(flag ${pkgs_CFLAGS})
        SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
 ENDFOREACH(flag)
 
+FOREACH(flag ${pkgs_extra_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
 SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -Wall -Werror -Winline -g")
 
 SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
@@ -43,17 +77,12 @@ ADD_DEFINITIONS("-DNDEBUG")
 ADD_DEFINITIONS("-D_USE_ECORE_TIME_GET")
 #ADD_DEFINITIONS("-DFLOG")
 ADD_DEFINITIONS("-DMASTER_PKGNAME=\"data-provider-master\"")
-ADD_LIBRARY(${PROJECT_NAME} SHARED
-       src/dlist.c
-       src/livebox.c
-       src/util.c
-       src/fb.c
-       src/desc_parser.c
-       src/master_rpc.c
-       src/client.c
-       src/file_service.c
-       src/conf.c
-)
+ADD_DEFINITIONS("-DINFO_SOCKET=\"/opt/usr/share/live_magazine/.live.socket\"")
+ADD_DEFINITIONS("-DCLIENT_SOCKET=\"/opt/usr/share/live_magazine/.client.socket\"")
+ADD_DEFINITIONS("-DSLAVE_SOCKET=\"/opt/usr/share/live_magazine/.slave.socket\"")
+ADD_DEFINITIONS("-DSERVICE_SOCKET=\"/opt/usr/share/live_magazine/.service.socket\"")
+ADD_LIBRARY(${PROJECT_NAME} SHARED ${BUILD_SOURCE})
+
 SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${VERSION_MAJOR})
 SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES VERSION ${VERSION})
 TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} "-lpthread")
index 630571c..2706245 100644 (file)
@@ -1712,6 +1712,21 @@ extern int livebox_set_option(enum livebox_option_type option, int state);
  */
 extern int livebox_option(enum livebox_option_type option);
 
+
+/*!
+ * \brief Set a handler for launching an app for auto-launch feature
+ * \details If a user clicks a box, and the box uses auto-launch option, the launcher_handler will be called.
+ * \remarks N/A
+ * \param[in] launch_handler Handler for launching an app manually
+ * \param[in] data Callback data which will be given a data for launch_handler
+ * \return int
+ * \retval
+ * \pre N/A
+ * \post N/A
+ * \see N/A
+ */
+extern int livebox_set_auto_launch_handler(int (*launch_handler)(struct livebox *handler, const char *appid, void *data), void *data);
+
 /*!
  * \}
  */
index 9921a26..f9f0410 100644 (file)
@@ -1,6 +1,8 @@
+%bcond_with wayland
+
 Name: liblivebox-viewer
 Summary: Library for developing the application
-Version: 0.20.8
+Version: 0.30.0
 Release: 1
 Group: HomeTF/Livebox
 License: Flora
@@ -12,15 +14,19 @@ BuildRequires: pkgconfig(aul)
 BuildRequires: pkgconfig(glib-2.0)
 BuildRequires: pkgconfig(gio-2.0)
 BuildRequires: pkgconfig(com-core)
-BuildRequires: pkgconfig(x11)
-BuildRequires: pkgconfig(xext)
 BuildRequires: pkgconfig(sqlite3)
 BuildRequires: pkgconfig(db-util)
 BuildRequires: pkgconfig(livebox-service)
-BuildRequires: pkgconfig(vconf)
 BuildRequires: pkgconfig(libtzplatform-config)
+BuildRequires: pkgconfig(vconf)
 Requires:      libtzplatform-config
 
+%if %{with wayland}
+%else
+BuildRequires: pkgconfig(x11)
+BuildRequires: pkgconfig(xext)
+%endif
+
 %description
 API for creating a new instance of the livebox and managing its life-cycle.
 
@@ -48,7 +54,16 @@ export CFLAGS="${CFLAGS} -DTIZEN_ENGINEER_MODE"
 export CXXFLAGS="${CXXFLAGS} -DTIZEN_ENGINEER_MODE"
 export FFLAGS="${FFLAGS} -DTIZEN_ENGINEER_MODE"
 %endif
-%cmake .
+
+%if %{with wayland}
+export WAYLAND_SUPPORT=On
+export X11_SUPPORT=Off
+%else
+export WAYLAND_SUPPORT=Off
+export X11_SUPPORT=On
+%endif
+
+%cmake . -DWAYLAND_SUPPORT=${WAYLAND_SUPPORT} -DX11_SUPPORT=${X11_SUPPORT}
 make %{?jobs:-j%jobs}
 
 %install
index 7979b69..fe8f6b6 100644 (file)
@@ -1662,7 +1662,9 @@ static void master_started_cb(keynode_t *node, void *data)
        if (state == 1 && make_connection() == (int)LB_STATUS_SUCCESS) {
                int ret;
                ret = vconf_ignore_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb);
-               DbgPrint("master_started vconf key de-registered [%d]\n", ret);
+               if (ret < 0) {
+                       DbgPrint("master_started vconf key de-registered [%d]\n", ret);
+               }
        }
 }
 
index 1dda034..0e90ad1 100644 (file)
--- a/src/fb.c
+++ b/src/fb.c
@@ -47,6 +47,7 @@ struct fb_info {
        int bufsz;
        void *buffer;
 
+       int pixels;
        int handle;
 };
 
@@ -64,14 +65,12 @@ struct buffer { /*!< Must has to be sync with slave & provider */
 static struct {
        Display *disp;
        int screen;
-       int depth;
        Visual *visual;
        int disp_is_opened;
 } s_info = {
        .disp = NULL,
        .disp_is_opened = 0,
        .screen = -1,
-       .depth = 0,
        .visual = NULL,
 };
 
@@ -87,7 +86,6 @@ int fb_init(void *disp)
                s_info.visual = DefaultVisualOfScreen(screen);
        }
 
-       s_info.depth = sizeof(int); //DefaultDepthOfScreen(screen);
        return 0;
 }
 
@@ -101,13 +99,12 @@ int fb_fini(void)
        s_info.disp_is_opened = 0;
        s_info.visual = NULL;
        s_info.screen = -1;
-       s_info.depth = 0;
        return 0;
 }
 
 static inline void update_fb_size(struct fb_info *info)
 {
-       info->bufsz = info->w * info->h * s_info.depth;
+       info->bufsz = info->w * info->h * info->pixels;
 }
 
 static inline int sync_for_file(struct fb_info *info)
@@ -243,7 +240,7 @@ static inline __attribute__((always_inline)) int sync_for_pixmap(struct fb_info
         * Use the 24 bits Pixmap for Video player
         */
        xim = XShmCreateImage(s_info.disp, s_info.visual,
-                               (s_info.depth << 3), ZPixmap, NULL,
+                               (info->pixels << 3), ZPixmap, NULL,
                                &si,
                                info->w, info->h);
        if (xim == NULL) {
@@ -326,10 +323,12 @@ struct fb_info *fb_create(const char *id, int w, int h)
                return NULL;
        }
 
+       info->pixels = sizeof(int);     /* Use the default pixels(depth) */
+
        if (sscanf(info->id, SCHEMA_SHM "%d", &info->handle) == 1) {
                DbgPrint("SHMID: %d is gotten\n", info->handle);
-       } else if (sscanf(info->id, SCHEMA_PIXMAP "%d", &info->handle) == 1) {
-               DbgPrint("PIXMAP-SHMID: %d is gotten\n", info->handle);
+       } else if (sscanf(info->id, SCHEMA_PIXMAP "%d:%d", &info->handle, &info->pixels) == 2) {
+               DbgPrint("PIXMAP-SHMID: %d is gotten (%d)\n", info->handle, info->pixels);
        } else {
                info->handle = LB_STATUS_ERROR_INVALID;
        }
diff --git a/src/fb_wayland.c b/src/fb_wayland.c
new file mode 100644 (file)
index 0000000..a38eb5f
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ * Copyright 2013  Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/shm.h>
+#include <sys/ipc.h>
+
+#include <dlog.h>
+#include <livebox-errno.h> /* For error code */
+
+#include "debug.h"
+#include "util.h"
+#include "fb.h"
+
+int errno;
+
+struct fb_info {
+       char *id;
+       int w;
+       int h;
+       int bufsz;
+       void *buffer;
+
+       int pixels;
+       int handle;
+};
+
+struct buffer { /*!< Must has to be sync with slave & provider */
+       enum {
+               CREATED = 0x00beef00,
+               DESTROYED = 0x00dead00
+       } state;
+       enum buffer_type type;
+       int refcnt;
+       void *info;
+       char data[];
+};
+
+static struct {
+} s_info = {
+};
+
+int fb_init(void *disp)
+{
+       return 0;
+}
+
+int fb_fini(void)
+{
+       return 0;
+}
+
+static inline void update_fb_size(struct fb_info *info)
+{
+       info->bufsz = info->w * info->h * info->pixels;
+}
+
+static inline int sync_for_file(struct fb_info *info)
+{
+       int fd;
+       struct buffer *buffer;
+
+       buffer = info->buffer;
+
+       if (!buffer) { /* Ignore this sync request */
+               return LB_STATUS_SUCCESS;
+       }
+
+       if (buffer->state != CREATED) {
+               ErrPrint("Invalid state of a FB\n");
+               return LB_STATUS_ERROR_INVALID;
+       }
+
+       if (buffer->type != BUFFER_TYPE_FILE) {
+               ErrPrint("Invalid buffer\n");
+               return LB_STATUS_SUCCESS;
+       }
+
+       fd = open(util_uri_to_path(info->id), O_RDONLY);
+       if (fd < 0) {
+               ErrPrint("Failed to open a file (%s) because of (%s)\n",
+                                       util_uri_to_path(info->id), strerror(errno));
+
+               /*!
+                * \note
+                * But return ZERO, even if we couldn't get a buffer file,
+                * the viewer can draw empty screen.
+                *
+                * and then update it after it gots update events
+                */
+               return LB_STATUS_SUCCESS;
+       }
+
+       if (read(fd, buffer->data, info->bufsz) != info->bufsz) {
+               ErrPrint("read: %s\n", strerror(errno));
+               if (close(fd) < 0) {
+                       ErrPrint("close: %s\n", strerror(errno));
+               }
+
+               /*!
+                * \note
+                * But return ZERO, even if we couldn't get a buffer file,
+                * the viewer can draw empty screen.
+                *
+                * and then update it after it gots update events
+                */
+               return LB_STATUS_SUCCESS;
+       }
+
+       if (close(fd) < 0) {
+               ErrPrint("close: %s\n", strerror(errno));
+       }
+       return LB_STATUS_SUCCESS;
+}
+
+int fb_sync(struct fb_info *info)
+{
+       if (!info) {
+               ErrPrint("FB Handle is not valid\n");
+               return LB_STATUS_ERROR_INVALID;
+       }
+
+       if (!info->id || info->id[0] == '\0') {
+               DbgPrint("Ingore sync\n");
+               return LB_STATUS_SUCCESS;
+       }
+
+       if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) {
+               return sync_for_file(info);
+       } else if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) {
+       } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM))) {
+               /* No need to do sync */ 
+               return LB_STATUS_SUCCESS;
+       }
+
+       return LB_STATUS_ERROR_INVALID;
+}
+
+struct fb_info *fb_create(const char *id, int w, int h)
+{
+       struct fb_info *info;
+
+       if (!id || id[0] == '\0') {
+               ErrPrint("Invalid ID\n");
+               return NULL;
+       }
+
+       info = calloc(1, sizeof(*info));
+       if (!info) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               return NULL;
+       }
+
+       info->id = strdup(id);
+       if (!info->id) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               free(info);
+               return NULL;
+       }
+
+       info->pixels = sizeof(int);     /* Use the default pixels(depth) */
+
+       if (sscanf(info->id, SCHEMA_SHM "%d", &info->handle) == 1) {
+               DbgPrint("SHMID: %d is gotten\n", info->handle);
+       } else if (sscanf(info->id, SCHEMA_PIXMAP "%d:%d", &info->handle, &info->pixels) == 2) {
+               DbgPrint("PIXMAP-SHMID: %d is gotten (%d)\n", info->handle, info->pixels);
+               ErrPrint("Unsupported\n");
+               free(info);
+               return NULL;
+       } else {
+               info->handle = LB_STATUS_ERROR_INVALID;
+       }
+
+       info->bufsz = 0;
+       info->buffer = NULL;
+       info->w = w;
+       info->h = h;
+
+       return info;
+}
+
+int fb_destroy(struct fb_info *info)
+{
+       if (!info) {
+               ErrPrint("Handle is not valid\n");
+               return LB_STATUS_ERROR_INVALID;
+       }
+
+       if (info->buffer) {
+               struct buffer *buffer;
+               buffer = info->buffer;
+
+               buffer->info = NULL;
+       }
+
+       free(info->id);
+       free(info);
+       return LB_STATUS_SUCCESS;
+}
+
+int fb_is_created(struct fb_info *info)
+{
+       if (!info) {
+               ErrPrint("Handle is not valid\n");
+               return 0;
+       }
+
+       if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP)) && info->handle != 0) {
+               return 1;
+       } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM)) && info->handle > 0) {
+               return 1;
+       } else {
+               const char *path;
+               path = util_uri_to_path(info->id);
+               if (path && access(path, F_OK | R_OK) == 0) {
+                       return 1;
+               } else {
+                       ErrPrint("access: %s (%s)\n", strerror(errno), path);
+               }
+       }
+
+       return 0;
+}
+
+void *fb_acquire_buffer(struct fb_info *info)
+{
+       struct buffer *buffer;
+
+       if (!info) {
+               ErrPrint("info == NIL\n");
+               return NULL;
+       }
+
+       if (!info->buffer) {
+               if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) {
+                       ErrPrint("Unsupported Type\n");
+                       return NULL;
+               } else if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) {
+                       update_fb_size(info);
+
+                       buffer = calloc(1, sizeof(*buffer) + info->bufsz);
+                       if (!buffer) {
+                               ErrPrint("Heap: %s\n", strerror(errno));
+                               info->bufsz = 0;
+                               return NULL;
+                       }
+
+                       buffer->type = BUFFER_TYPE_FILE;
+                       buffer->refcnt = 0;
+                       buffer->state = CREATED;
+                       buffer->info = info;
+                       info->buffer = buffer;
+
+                       sync_for_file(info);
+               } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM))) {
+                       buffer = shmat(info->handle, NULL, 0);
+                       if (buffer == (void *)-1) {
+                               ErrPrint("shmat: %s (%d)\n", strerror(errno), info->handle);
+                               return NULL;
+                       }
+
+                       return buffer->data;
+               } else {
+                       ErrPrint("Buffer is not created (%s)\n", info->id);
+                       return NULL;
+               }
+       }
+
+       buffer = info->buffer;
+
+       switch (buffer->type) {
+       case BUFFER_TYPE_FILE:
+               buffer->refcnt++;
+               break;
+       case BUFFER_TYPE_PIXMAP:
+       default:
+               DbgPrint("Unknwon FP: %d\n", buffer->type);
+               break;
+       }
+
+       return buffer->data;
+}
+
+int fb_release_buffer(void *data)
+{
+       struct buffer *buffer;
+
+       if (!data) {
+               ErrPrint("buffer data == NIL\n");
+               return LB_STATUS_ERROR_INVALID;
+       }
+
+       buffer = container_of(data, struct buffer, data);
+
+       if (buffer->state != CREATED) {
+               ErrPrint("Invalid handle\n");
+               return LB_STATUS_ERROR_INVALID;
+       }
+
+       switch (buffer->type) {
+       case BUFFER_TYPE_SHM:
+               if (shmdt(buffer) < 0) {
+                       ErrPrint("shmdt: %s\n", strerror(errno));
+               }
+               break;
+       case BUFFER_TYPE_FILE:
+               buffer->refcnt--;
+               if (buffer->refcnt == 0) {
+                       struct fb_info *info;
+                       info = buffer->info;
+
+                       buffer->state = DESTROYED;
+                       free(buffer);
+
+                       if (info && info->buffer == buffer) {
+                               info->buffer = NULL;
+                       }
+               }
+               break;
+       case BUFFER_TYPE_PIXMAP:
+       default:
+               ErrPrint("Unknwon buffer type\n");
+               break;
+       }
+
+       return LB_STATUS_SUCCESS;
+}
+
+int fb_refcnt(void *data)
+{
+       struct buffer *buffer;
+       struct shmid_ds buf;
+       int ret;
+
+       if (!data) {
+               return LB_STATUS_ERROR_INVALID;
+       }
+
+       buffer = container_of(data, struct buffer, data);
+
+       if (buffer->state != CREATED) {
+               ErrPrint("Invalid handle\n");
+               return LB_STATUS_ERROR_INVALID;
+       }
+
+       switch (buffer->type) {
+       case BUFFER_TYPE_SHM:
+               if (shmctl(buffer->refcnt, IPC_STAT, &buf) < 0) {
+                       ErrPrint("Error: %s\n", strerror(errno));
+                       return LB_STATUS_ERROR_FAULT;
+               }
+
+               ret = buf.shm_nattch;
+               break;
+       case BUFFER_TYPE_FILE:
+               ret = buffer->refcnt;
+               break;
+       case BUFFER_TYPE_PIXMAP:
+       default:
+               ret = LB_STATUS_ERROR_INVALID;
+               break;
+       }
+
+       return ret;
+}
+
+const char *fb_id(struct fb_info *info)
+{
+       return info ? info->id : NULL;
+}
+
+int fb_get_size(struct fb_info *info, int *w, int *h)
+{
+       if (!info) {
+               ErrPrint("Handle is not valid\n");
+               return LB_STATUS_ERROR_INVALID;
+       }
+
+       *w = info->w;
+       *h = info->h;
+       return LB_STATUS_SUCCESS;
+}
+
+int fb_size(struct fb_info *info)
+{
+       if (!info) {
+               return 0;
+       }
+
+       update_fb_size(info);
+
+       return info->bufsz;
+}
+
+int fb_type(struct fb_info *info)
+{
+       struct buffer *buffer;
+
+       if (!info) {
+               return BUFFER_TYPE_ERROR;
+       }
+
+       buffer = info->buffer;
+       if (!buffer) {
+               int type = BUFFER_TYPE_ERROR;
+               /*!
+                * \note
+                * Try to get this from SCHEMA
+                */
+               if (info->id) {
+                       if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) {
+                               type = BUFFER_TYPE_FILE;
+                       } else if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) {
+                               /* Unsupported type */
+                       } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM))) {
+                               type = BUFFER_TYPE_SHM;
+                       }
+               }
+
+               return type;
+       }
+
+       return buffer->type;
+}
+/* End of a file */
index d2dbd36..1d64cf5 100644 (file)
@@ -49,6 +49,8 @@
 FILE *__file_log_fp;
 #endif
 
+static int default_launch_handler(struct livebox *handler, const char *appid, void *data);
+
 enum event_state {
        INFO_STATE_CALLBACK_IN_IDLE = 0x00,
        INFO_STATE_CALLBACK_IN_PROCESSING = 0x01,
@@ -67,6 +69,11 @@ static struct info {
        enum event_state fault_state;
        guint job_timer;
        struct dlist *job_list;
+
+       struct launch {
+               int (*handler)(struct livebox *handler, const char *appid, void *data);
+               void *data;
+       } launch;
 } s_info = {
        .livebox_list = NULL,
        .event_list = NULL,
@@ -77,6 +84,10 @@ static struct info {
        .fault_state = INFO_STATE_CALLBACK_IN_IDLE,
        .job_timer = 0,
        .job_list = NULL,
+       .launch = {
+               .handler = default_launch_handler,
+               .data = NULL,
+       },
 };
 
 struct cb_info {
@@ -99,6 +110,33 @@ struct fault_info {
 static void lb_pixmap_acquired_cb(struct livebox *handler, const struct packet *result, void *data);
 static void pd_pixmap_acquired_cb(struct livebox *handler, const struct packet *result, void *data);
 
+static int default_launch_handler(struct livebox *handler, const char *appid, void *data)
+{
+       int ret;
+
+       ret = aul_launch_app(appid, NULL);
+       if (ret <= 0) {
+               ErrPrint("Failed to launch an app %s (%d)\n", appid, ret);
+       }
+
+/*
+       service_h service;
+
+       DbgPrint("AUTO_LAUNCH [%s]\n", handler->common->lb.auto_launch);
+
+       ret = service_create(&service);
+       if (ret == SERVICE_ERROR_NONE) {
+               service_set_package(service, handler->common->lb.auto_launch);
+               service_send_launch_request(service, NULL, NULL);
+               service_destroy(service);
+       } else {
+               ErrPrint("Failed to launch an app %s (%d)\n", handler->common->lb.auto_launch, ret);
+       }
+*/
+
+       return ret > 0 ? LB_STATUS_SUCCESS : LB_STATUS_ERROR_FAULT;
+}
+
 static inline void default_create_cb(struct livebox *handler, int ret, void *data)
 {
        DbgPrint("Default created event handler: %d\n", ret);
@@ -2115,23 +2153,11 @@ EAPI int livebox_click(struct livebox *handler, double x, double y)
        }
 
        if (handler->common->lb.auto_launch) {
-/*
-               service_h service;
-
-               DbgPrint("AUTO_LAUNCH [%s]\n", handler->common->lb.auto_launch);
-
-               ret = service_create(&service);
-               if (ret == SERVICE_ERROR_NONE) {
-                       service_set_package(service, handler->common->lb.auto_launch);
-                       service_send_launch_request(service, NULL, NULL);
-                       service_destroy(service);
-               } else {
-                       ErrPrint("Failed to launch an app %s (%d)\n", handler->common->lb.auto_launch, ret);
-               }
-*/
-               ret = aul_launch_app(handler->common->lb.auto_launch, NULL);
-               if (ret <= 0) {
-                       ErrPrint("Failed to launch an app %s (%d)\n", handler->common->lb.auto_launch, ret);
+               if (s_info.launch.handler) {
+                       ret = s_info.launch.handler(handler, handler->common->lb.auto_launch, s_info.launch.data);
+                       if (ret < 0) {
+                               ErrPrint("launch handler app %s (%d)\n", handler->common->lb.auto_launch, ret);
+                       }
                }
        }
 
@@ -4831,4 +4857,12 @@ EAPI int livebox_option(enum livebox_option_type option)
        return ret;
 }
 
+EAPI int livebox_set_auto_launch_handler(int (*launch_handler)(struct livebox *handler, const char *appid, void *data), void *data)
+{
+       s_info.launch.handler = launch_handler;
+       s_info.launch.data = data;
+
+       return LB_STATUS_SUCCESS;
+}
+
 /* End of a file */