samples: add sample-server, sample-client 01/134501/5
authorSung-Jin Park <sj76.park@samsung.com>
Mon, 19 Jun 2017 03:42:28 +0000 (12:42 +0900)
committerJuyeon Lee <juyeonne.lee@samsung.com>
Tue, 20 Jun 2017 01:38:52 +0000 (01:38 +0000)
Change-Id: I9c0af6c6e7a66c8e7141578484539280ca62dd10
Signed-off-by: Sung-Jin Park <sj76.park@samsung.com>
configure.ac
packaging/pepper.spec
src/samples/Makefile.am
src/samples/sample-client.c [new file with mode: 0644]
src/samples/sample-server.c [new file with mode: 0644]
src/samples/xdg-shell-client-protocol.h [new file with mode: 0644]
src/samples/xdg-shell-protocol.c [new file with mode: 0644]

index 47de5db..8494b0e 100644 (file)
@@ -304,6 +304,31 @@ HEADLESS_CLIENT_LIBS="$HEADLESS_CLIENT_LIBS"
 AC_SUBST(HEADLESS_CLIENT_CFLAGS)
 AC_SUBST(HEADLESS_CLIENT_LIBS)
 
+# sample client
+SAMPLE_CLIENT_REQUIRES="wayland-client tizen-extension-client xkbcommon"
+PKG_CHECK_MODULES(SAMPLE_CLIENT, $[SAMPLE_CLIENT_REQUIRES])
+SAMPLE_CLIENT_CFLAGS="$SAMPLE_CLIENT_CFLAGS"
+SAMPLE_CLIENT_LIBS="$SAMPLE_CLIENT_LIBS"
+
+AC_SUBST(SAMPLE_CLIENT_CFLAGS)
+AC_SUBST(SAMPLE_CLIENT_LIBS)
+
+# sample server
+SAMPLE_SERVER_REQUIRES="wayland-server xkbcommon"
+PKG_CHECK_MODULES(SAMPLE_SERVER, [$SAMPLE_SERVER_REQUIRES])
+
+SAMPLE_SERVER_CFLAGS="$PEPPER_DIR $SAMPLE_SERVER_CFLAGS"
+SAMPLE_SERVER_CFLAGS="$PEPPER_EVDEV_DIR $PEPPER_KEYROUTER_DIR $SAMPLE_SERVER_CFLAGS"
+SAMPLE_SERVER_CFLAGS="$PEPPER_XKB_DIR $SAMPLE_SERVER_CFLAGS"
+
+SAMPLE_SERVER_LIBS="$PEPPER_LIB $SAMPLE_SERVER_LIBS"
+SAMPLE_SERVER_LIBS="$PEPPER_EVDEV_LIB $PEPPER_EVDEV_LIBS $SAMPLE_SERVER_LIBS"
+SAMPLE_SERVER_LIBS="$PEPPER_KEYROUTER_LIB $PEPPER_KEYROUTER_LIBS $SAMPLE_SERVER_LIBS"
+SAMPLE_SERVER_LIBS="$PEPPER_XKB_LIB $PEPPER_XKB_LIBS $SAMPLE_SERVER_LIBS"
+
+AC_SUBST(SAMPLE_SERVER_CFLAGS)
+AC_SUBST(SAMPLE_SERVER_LIBS)
+
 # wayland-scanner
 AC_PATH_PROG([wayland_scanner], [wayland-scanner])
 if test x$wayland_scanner = x; then
index 5d6a182..13e9b4e 100644 (file)
@@ -211,6 +211,7 @@ Requires: pepper-tdm
 Requires: pepper-wayland pepper-x11
 Requires: pepper-libinput
 Requires: pepper-keyrouter pepper-evdev
+Requires: pepper-xkb
 
 %description samples
 This package includes samples files.
@@ -427,3 +428,4 @@ make %{?_smp_mflags}
 %defattr(-,root,root,-)
 %{_bindir}/*-backend
 %{_bindir}/headless*
+%{_bindir}/sample-*
\ No newline at end of file
index 03d9865..29ac394 100644 (file)
@@ -55,3 +55,15 @@ headless_client_CFLAGS = $(HEADLESS_CLIENT_CFLAGS)
 headless_client_LDADD = $(HEADLESS_CLIENT_LIBS)
 
 headless_client_SOURCES = headless-client.c
+
+bin_PROGRAMS += sample-server sample-client
+
+sample_server_CFLAGS = $(SAMPLE_SERVER_CFLAGS)
+sample_server_LDADD = $(SAMPLE_SERVER_LIBS)
+
+sample_server_SOURCES = sample-server.c
+
+sample_client_CFLAGS = $(SAMPLE_CLIENT_CFLAGS)
+sample_client_LDADD = $(SAMPLE_CLIENT_LIBS)
+
+sample_client_SOURCES = sample-client.c xdg-shell-client-protocol.h xdg-shell-protocol.c
diff --git a/src/samples/sample-client.c b/src/samples/sample-client.c
new file mode 100644 (file)
index 0000000..6728378
--- /dev/null
@@ -0,0 +1,759 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <wayland-client.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <fcntl.h>
+#include <tizen-extension-client-protocol.h>
+#include <xdg-shell-client-protocol.h>
+#include <xkbcommon/xkbcommon.h>
+
+#define DEBUG
+#ifdef DEBUG
+#define TRACE(fmt, ...)        \
+       do { \
+               printf("[sample-client : %s] "fmt, __FUNCTION__, ##__VA_ARGS__); \
+       } while (0)
+#else
+#define TRACE(fmt, ...)
+       do { \
+               ;
+       } while (0)
+#endif
+
+#define ERROR_CHECK(exp, action, fmt, ...) \
+       do { \
+               if (!(exp)) \
+               { \
+                       printf(fmt, ##__VA_ARGS__);     \
+                       action; \
+               } \
+       } while (0)
+
+struct sample_client
+{
+       struct wl_display *display;
+       struct wl_compositor *compositor;
+       struct wl_registry *registry;
+       struct tizen_keyrouter *keyrouter;
+       struct wl_seat *seat;
+       struct wl_keyboard *keyboard;
+       struct wl_pointer *pointer;
+       struct wl_touch *touch;
+
+       struct xdg_shell *shell;
+       struct wl_shm *shm;
+       struct wl_surface *surface;
+       struct xdg_surface *xdg_surface;
+       struct wl_buffer *buffer;
+
+       struct xkb_context *xkb_context;
+       struct xkb_keymap *keymap;
+
+       pid_t pid;
+       void *shm_data;
+};
+
+struct keyrouter_grab_list {
+       int key;
+       int mode;
+       int err;
+};
+
+struct keycode_map
+{
+       xkb_keysym_t keysym;
+       xkb_keycode_t *keycodes;
+       int nkeycodes;
+};
+
+typedef struct keyrouter_grab_list keyrouter_grab_list_t;
+typedef struct sample_client sample_client_t;
+typedef struct keycode_map keycode_map_t;
+
+const int width = 640;
+const int height = 480;
+
+static void
+find_keycode(struct xkb_keymap *keymap, xkb_keycode_t key, void *data)
+{
+       keycode_map_t *found_keycodes = (keycode_map_t *)data;
+       xkb_keysym_t keysym = found_keycodes->keysym;
+       int nsyms = 0;
+       const xkb_keysym_t *syms_out = NULL;
+
+       ERROR_CHECK(keymap, return, "[%s] Invalid keymap !\n", __FUNCTION__);
+
+       nsyms = xkb_keymap_key_get_syms_by_level(keymap, key, 0, 0, &syms_out);
+
+       if (nsyms && syms_out)
+       {
+               if (*syms_out == keysym)
+               {
+                       found_keycodes->nkeycodes++;
+                       found_keycodes->keycodes = realloc(found_keycodes->keycodes, sizeof(int)*found_keycodes->nkeycodes);
+                       found_keycodes->keycodes[found_keycodes->nkeycodes-1] = key;
+               }
+       }
+}
+
+int
+xkb_keycode_from_keysym(struct xkb_keymap *keymap, xkb_keysym_t keysym, xkb_keycode_t **keycodes)
+{
+       keycode_map_t found_keycodes = {0,};
+       found_keycodes.keysym = keysym;
+
+       ERROR_CHECK(keymap, return 0, "[%s] Invalid keymap !\n", __FUNCTION__);
+
+       xkb_keymap_key_for_each(keymap, find_keycode, &found_keycodes);
+
+       *keycodes = found_keycodes.keycodes;
+       return found_keycodes.nkeycodes;
+}
+
+int
+xkb_init(sample_client_t *client)
+{
+       if (!client)
+               return 0;
+
+       client->xkb_context = xkb_context_new(0);
+       ERROR_CHECK(client->xkb_context, return 0, "Failed to get xkb_context\n");
+
+       return 1;
+}
+
+void
+xkb_shutdown(sample_client_t *client)
+{
+       if (!client || !client->xkb_context)
+               return;
+
+       xkb_context_unref(client->xkb_context);
+}
+
+static int
+set_cloexec_or_close(int fd)
+{
+       long flags;
+
+       if (fd == -1)
+               return -1;
+
+       flags = fcntl(fd, F_GETFD);
+
+       if (flags == -1)
+               goto err;
+
+       if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+               goto err;
+
+       return fd;
+
+err:
+       close(fd);
+       return -1;
+}
+
+static int
+create_tmpfile_cloexec(char *tmpname)
+{
+       int fd;
+
+#ifdef HAVE_MKOSTEMP
+       fd = mkostemp(tmpname, O_CLOEXEC);
+
+       if (fd >= 0)
+               unlink(tmpname);
+#else
+       fd = mkstemp(tmpname);
+
+       if (fd >= 0)
+       {
+               fd = set_cloexec_or_close(fd);
+               unlink(tmpname);
+       }
+#endif
+
+       return fd;
+}
+
+int
+os_create_anonymous_file(off_t size)
+{
+       static const char template[] = "/pepper-shared-XXXXXX";
+       const char *path;
+       char *name;
+       int fd;
+       int ret;
+
+       path = getenv("TIZEN_WAYLAND_SHM_DIR");
+
+       if (!path)
+               path = getenv("XDG_RUNTIME_DIR");
+
+       if (!path)
+       {
+               setenv("XDG_RUNTIME_DIR", "/run", 1);
+               path = getenv("XDG_RUNTIME_DIR");
+       }
+
+       if (!path) {
+               errno = ENOENT;
+               return -1;
+       }
+
+       name = malloc(strlen(path) + sizeof(template));
+       if (!name)
+               return -1;
+
+       strncpy(name, path, strlen(path) + 1);
+       strncat(name, template, sizeof(template));
+
+       fd = create_tmpfile_cloexec(name);
+
+       free(name);
+
+       if (fd < 0)
+               return -1;
+
+#ifdef HAVE_POSIX_FALLOCATE
+       ret = posix_fallocate(fd, 0, size);
+       if (ret != 0) {
+               close(fd);
+               errno = ret;
+               return -1;
+       }
+#else
+       ret = ftruncate(fd, size);
+       if (ret < 0) {
+               close(fd);
+               return -1;
+       }
+#endif
+
+       return fd;
+}
+
+static void
+paint_pixels(sample_client_t *client)
+{
+       int n;
+       uint32_t *pixel = client->shm_data;
+
+       for (n =0; n < width*height; n++)
+       {
+               *pixel++ = 0xffff;
+       }
+}
+
+static struct wl_buffer *
+create_buffer(sample_client_t *client)
+{
+       struct wl_shm_pool *pool;
+       int stride = width * 4; // 4 bytes per pixel
+       int size = stride * height;
+       int fd;
+       struct wl_buffer *buff;
+
+       fd = os_create_anonymous_file(size);
+
+       if (fd < 0)
+       {
+               TRACE("... creating a buffer file has been failed: %m\n");
+               exit(1);
+       }
+
+       client->shm_data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+       if (client->shm_data == MAP_FAILED)
+       {
+               TRACE("... mmap failed: %m\n");
+               close(fd);
+               exit(1);
+       }
+
+       pool = wl_shm_create_pool(client->shm, fd, size);
+       buff = wl_shm_pool_create_buffer(pool, 0,       width, height, stride, WL_SHM_FORMAT_XRGB8888);
+       wl_shm_pool_destroy(pool);
+
+       return buff;
+}
+
+static void
+create_window(sample_client_t *client)
+{
+       client->buffer = create_buffer(client);
+
+       wl_surface_attach(client->surface, client->buffer, 0, 0);
+       wl_surface_damage(client->surface, 0, 0, width, height);
+       wl_surface_commit(client->surface);
+}
+
+static void
+shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
+{
+       TRACE("... SHM Format %d\n", format);
+}
+
+struct wl_shm_listener shm_listener = {
+       shm_format
+};
+
+static void
+xdg_shell_ping(void *data, struct xdg_shell *shell, uint32_t serial)
+{
+       (void) data;
+       xdg_shell_pong(shell, serial);
+}
+
+static const struct xdg_shell_listener xdg_shell_listener =
+{
+       xdg_shell_ping,
+};
+
+
+static void
+keygrab_request(struct tizen_keyrouter *tizen_keyrouter, struct wl_surface *surface, uint32_t key, uint32_t mode)
+{
+   tizen_keyrouter_set_keygrab(tizen_keyrouter, surface, key, mode);
+
+   TRACE("... request set_keygrab (key:%d, mode:%d)!\n",  key, mode);
+}
+
+static void pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y)
+{
+   (void) data;
+   (void) wl_pointer;
+   (void) serial;
+   (void) surface;
+   (void) surface_x;
+   (void) surface_y;
+
+   TRACE("... serial=%d, x=%.f, y=%.f\n", serial, wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y));
+}
+
+static void pointer_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface)
+{
+   (void) data;
+   (void) wl_pointer;
+   (void) serial;
+   (void) surface;
+
+   TRACE("... serial=%d\n", serial);
+}
+
+static void pointer_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
+{
+   (void) data;
+   (void) wl_pointer;
+   (void) time;
+   (void) surface_x;
+   (void) surface_y;
+
+   TRACE("... time=%d, x=%.f, y=%.f\n", time, wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y));
+}
+
+static void pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
+{
+   (void) data;
+   (void) wl_pointer;
+   (void) serial;
+   (void) time;
+   (void) button;
+   (void) state;
+
+   TRACE("... serial=%d, time=%d, button=%d, state=%d\n", serial, time, button, state);
+}
+
+static void pointer_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value)
+{
+   (void) data;
+   (void) wl_pointer;
+   (void) time;
+   (void) axis;
+   (void) value;
+
+   TRACE("... time=%d, axis=%d, value=%.f\n", time, axis, wl_fixed_to_double(value));
+}
+
+static void
+keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size)
+{
+       (void) data;
+       (void) keyboard;
+       (void) format;
+       (void) fd;
+       (void) size;
+
+       sample_client_t *client = (sample_client_t *)data;
+       char *map = NULL;
+
+       TRACE("...WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1=%d, WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP=%d\n",
+                                       WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP);
+       TRACE("... format=%d, fd=%d, size=%d\n",  format, fd, size);
+
+       if (!client->xkb_context)
+       {
+               TRACE("... This client failed to make xkb context\n");
+               close(fd);
+               return;
+       }
+
+       if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
+       {
+               TRACE("... Invaild format: %d\n", format);
+               close(fd);
+               return;
+       }
+
+       map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+
+       if (map == MAP_FAILED)
+       {
+               TRACE("... Failed to mmap from fd(%d) size(%d)\n", fd, size);
+               close(fd);
+               return;
+       }
+
+       client->keymap = xkb_map_new_from_string(client->xkb_context, map,
+                              XKB_KEYMAP_FORMAT_TEXT_V1, 0);
+       if (client->keymap)
+               TRACE("... Failed to get keymap from fd(%d)\n", fd);
+
+       munmap(map, size);
+       close(fd);
+}
+
+static void
+keyboard_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys)
+{
+       (void) data;
+       (void) keyboard;
+       (void) serial;
+       (void) surface;
+       (void) keys;
+
+       TRACE("... serial=%d\n",  serial);
+}
+
+static void
+keyboard_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface)
+{
+       (void) data;
+       (void) keyboard;
+       (void) serial;
+       (void) surface;
+
+       TRACE("... serial=%d\n",  serial);
+}
+
+static void
+keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
+{
+       (void) data;
+       (void) keyboard;
+       (void) serial;
+       (void) time;
+       (void) key;
+       (void) state;
+
+       TRACE("... serial=%d, time=%d, key=%d, state=%d\n", serial, time, key, state);
+}
+
+static void
+keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
+{
+       (void) data;
+       (void) keyboard;
+       (void) serial;
+       (void) mods_depressed;
+       (void) mods_latched;
+       (void) mods_locked;
+       (void) group;
+
+       TRACE("... serial=%d, mods_depressed=%d, mods_latched=%d, mods_locked=%d, group=%d\n", serial, mods_depressed, mods_latched, mods_locked, group);
+}
+
+static void
+touch_down(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time, struct wl_surface *surface, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
+{
+       (void) data;
+       (void) wl_touch;
+       (void) serial;
+       (void) time;
+       (void) surface;
+       (void) id;
+       (void) x_w;
+       (void) y_w;
+
+       TRACE("... serial=%d, time=%d, id=%d, x_w=%.f, y_w=%.f\n", serial, time, id, wl_fixed_to_double(x_w), wl_fixed_to_double(y_w));
+}
+
+static void
+touch_up(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time, int32_t id)
+{
+       (void) data;
+       (void) wl_touch;
+       (void) serial;
+       (void) time;
+       (void) id;
+
+       TRACE("... serial=%d, time=%d, id=%d\n",  serial, time, id);
+}
+
+static void
+touch_motion(void *data, struct wl_touch *wl_touch, uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
+{
+       (void) data;
+       (void) wl_touch;
+       (void) time;
+       (void) id;
+       (void) x_w;
+       (void) y_w;
+
+       TRACE("... time=%d, id=%d, x_w=%.f, y_w=%.f\n", time, id, wl_fixed_to_double(x_w), wl_fixed_to_double(y_w));
+}
+
+static void
+touch_frame(void *data, struct wl_touch *wl_touch)
+{
+       (void) data;
+       (void) wl_touch;
+
+       TRACE("...\n");
+}
+
+static void
+touch_cancel(void *data, struct wl_touch *wl_touch)
+{
+       (void) data;
+       (void) wl_touch;
+
+       TRACE("...\n");
+}
+
+/* Define pointer event handlers */
+static const struct wl_pointer_listener pointer_listener = {
+       .enter = pointer_enter,
+       .leave = pointer_leave,
+       .motion = pointer_motion,
+       .button = pointer_button,
+       .axis = pointer_axis
+};
+
+/* Define touch event handlers */
+static const struct wl_touch_listener touch_listener = {
+       .down = touch_down,
+       .up = touch_up,
+       .motion = touch_motion,
+       .frame = touch_frame,
+       .cancel = touch_cancel
+};
+
+/* Define keyboard event handlers */
+static const struct wl_keyboard_listener keyboard_listener = {
+       .keymap = keyboard_keymap,
+       .enter = keyboard_enter,
+       .leave = keyboard_leave,
+       .key = keyboard_key,
+       .modifiers = keyboard_modifiers
+};
+
+static void
+global_registry_add(void * data, struct wl_registry * registry, uint32_t id, const char * interface, uint32_t version)
+{
+       sample_client_t *client = (sample_client_t *)data;
+
+       if (0 == strncmp(interface, "wl_compositor", 13))
+       {
+               client->compositor = wl_registry_bind(client->registry, id, &wl_compositor_interface, 1);
+               if (client->compositor) TRACE("[PID:%d] Succeed to bind wl_compositor_interface !\n", client->pid);
+       }
+       else if (0 == strncmp(interface, "tizen_keyrouter", 12))
+       {
+               client->keyrouter = wl_registry_bind(client->registry, id, &tizen_keyrouter_interface, 1);
+               if (client->keyrouter) TRACE("[PID:%d] Succeed to bind tizen_keyrouter_interface !\n", client->pid);
+       }
+       else if (0 == strncmp(interface, "xdg_shell", 9))
+       {
+               client->shell = wl_registry_bind(client->registry, id, &xdg_shell_interface, 1);
+
+               if (client->shell)
+                       TRACE("[PID:%d] Succeed to bind xdg_shell interface !\n", client->pid);
+
+               xdg_shell_use_unstable_version(client->shell, 5);
+               xdg_shell_add_listener(client->shell, &xdg_shell_listener, client->display);
+       }
+       else if (0 == strncmp(interface, "wl_shm", 6))
+       {
+               client->shm = wl_registry_bind(client->registry, id, &wl_shm_interface, 1);
+               wl_shm_add_listener(client->shm, &shm_listener, NULL);
+
+               if (client->shm)
+                       TRACE("[PID:%d] Succeed to bind wl_shm_interface !\n", client->pid);
+       }
+       else if (0 == strncmp(interface, "wl_seat", 7))
+       {
+               client->seat = wl_registry_bind(client->registry, id, &wl_seat_interface, 1);
+
+               if (client->seat)
+                       TRACE("[PID:%d] Succeed to bind wl_seat_interface !\n", client->pid);
+
+               client->pointer = wl_seat_get_pointer(client->seat);
+               wl_pointer_add_listener(client->pointer, &pointer_listener, client);
+
+               client->keyboard = wl_seat_get_keyboard(client->seat);
+               wl_keyboard_add_listener(client->keyboard, &keyboard_listener, client);
+
+               client->touch = wl_seat_get_touch(client->seat);
+               wl_touch_add_listener(client->touch, &touch_listener, client);
+       }
+       else
+       {
+               TRACE("[PID:%d] An unhandled global object's interface : %s\n", client->pid, interface ? interface : "NULL");
+       }
+}
+
+static void
+global_registry_remove(void * data, struct wl_registry * registry, uint32_t id)
+{
+       sample_client_t *client = (sample_client_t *)data;
+
+       TRACE("[PID:%d] global object (id:0x%x) has been removed !\n", client->pid, id);
+}
+
+static const struct wl_registry_listener registry_listener = {
+    global_registry_add,
+    global_registry_remove
+};
+
+static void
+keygrab_notify(void *data, struct tizen_keyrouter *tizen_keyrouter, struct wl_surface *surface, uint32_t key, uint32_t mode, uint32_t error)
+{
+       TRACE("... key=%d, mode=%d, error=%d\n",  key, mode, error);
+}
+
+static void
+keygrab_notify_list(void *data, struct tizen_keyrouter *tizen_keyrouter, struct wl_surface *surface, struct wl_array *grab_list)
+{
+       TRACE("... list\n");
+}
+
+
+static struct tizen_keyrouter_listener keyrouter_listener = {
+       keygrab_notify,
+       keygrab_notify_list
+};
+
+static void
+do_keygrab(sample_client_t *client, const char *keyname, uint32_t mode)
+{
+       xkb_keysym_t keysym = 0x0;
+       int nkeycodes=0;
+       xkb_keycode_t *keycodes = NULL;
+       int i;
+
+       keysym = xkb_keysym_from_name(keyname, XKB_KEYSYM_NO_FLAGS);
+       nkeycodes = xkb_keycode_from_keysym(client->keymap, keysym, &keycodes);
+
+       for (i=0; i<nkeycodes; i++)
+       {
+               TRACE("%s's keycode is %d (nkeycode: %d)\n", keyname, keycodes[i], nkeycodes);
+               keygrab_request(client->keyrouter, client->surface, keycodes[i], mode);
+       }
+
+       free(keycodes);
+       keycodes = NULL;
+}
+
+int main(int argc, char **argv)
+{
+       int res;
+       sample_client_t *client = NULL;
+
+       const char *use_xdg_shell = NULL;
+       const char *use_keyrouter = NULL;
+
+       use_xdg_shell = getenv("USE_XDG_SHELL");
+       use_keyrouter = getenv("USE_KEYROUTER");
+
+       if (!use_xdg_shell)
+               TRACE("* Note : XDG SHELL can be initialized by setting USE_XDG_SHELL environment variable !\n");
+       if (!use_keyrouter)
+               TRACE("* Note : tizen_keyrouter interface can be initialized by setting USE_KEYROUTER environment variable !\n");
+
+       client = calloc(1, sizeof(sample_client_t));
+       ERROR_CHECK(client, goto shutdown, "Failed to allocate memory for sample client !\n");
+
+       client->pid = getpid();
+       client->display = wl_display_connect(NULL);
+       ERROR_CHECK(client->display, goto shutdown, "[PID:%d] Failed to connect to wayland server !\n", client->pid);
+
+       res = xkb_init(client);
+       ERROR_CHECK(res, goto shutdown, "Failed to init xkb !\n");
+
+       client->registry = wl_display_get_registry(client->display);
+       ERROR_CHECK(client->registry, goto shutdown, "[PID:%d] Failed to get registry !\n", client->pid);
+
+       wl_registry_add_listener(client->registry, &registry_listener, client);
+
+       assert(wl_display_dispatch(client->display) != -1);
+       assert(wl_display_roundtrip(client->display) != -1);
+
+       ERROR_CHECK(client->compositor, goto shutdown, "[PID:%d] Failed to bind to the compositor interface !\n", client->pid);
+
+       if (use_keyrouter)
+               ERROR_CHECK(client->keyrouter, goto shutdown, "[PID:%d] Failed to bind to the keyrouter interface !\n", client->pid);
+
+       if (use_xdg_shell)
+               ERROR_CHECK(client->shell, goto shutdown, "[PID:%d] Failed to bind to the xdg shell interface !\n", client->pid);
+
+       client->surface = wl_compositor_create_surface(client->compositor);
+       ERROR_CHECK(client->surface, goto shutdown, "[PID:%d] can't create surface\n", client->pid);
+
+       if (use_xdg_shell)
+       {
+               client->xdg_surface = xdg_shell_get_xdg_surface(client->shell, client->surface);
+               ERROR_CHECK(client->xdg_surface, goto shutdown, "[PID:%d] can't create shell surface\n", client->pid);
+
+               xdg_surface_set_title(client->xdg_surface, "sample client");
+       }
+
+       create_window(client);
+       paint_pixels(client);
+
+       if (use_keyrouter)
+       {
+               if (0 > tizen_keyrouter_add_listener(client->keyrouter, &keyrouter_listener, NULL))
+               {
+                       TRACE("[PID:%d] Failed on tizen_keyrouter_add_listener !\n", client->pid);
+                       return 0;
+               }
+
+               do_keygrab(client, "XF86Home", TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE);
+       }
+
+       while (wl_display_dispatch(client->display) != -1)
+               ;
+
+       wl_display_disconnect(client->display);
+       client->display = NULL;
+
+       return 0;
+
+shutdown:
+
+       if(!client)
+               return 0;
+
+       xkb_shutdown(client);
+
+       return 0;
+}
+
diff --git a/src/samples/sample-server.c b/src/samples/sample-server.c
new file mode 100644 (file)
index 0000000..641681d
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+* 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-2016 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.h>
+
+#include <pepper-xkb.h>
+#include <pepper-evdev.h>
+#include <pepper-keyrouter.h>
+#include <pepper-input-backend.h>
+
+/* basic pepper objects */
+pepper_xkb_t *xkb = NULL;
+pepper_seat_t *seat = NULL;
+pepper_evdev_t *evdev = NULL;
+pepper_keyrouter_t *keyrouter = NULL;
+pepper_input_device_t *input_device = NULL;
+
+/* event listeners */
+pepper_event_listener_t *listener_seat_add = NULL;
+pepper_event_listener_t *listener_seat_remove = NULL;
+pepper_event_listener_t *listener_input_add = NULL;
+pepper_event_listener_t *listener_input_remove = NULL;
+pepper_event_listener_t *listener_keyboard_add = NULL;
+pepper_event_listener_t *listener_keyboard_event = NULL;
+
+static void
+_handle_keyboard_key(pepper_event_listener_t *listener, pepper_object_t *object, uint32_t id, void *info, void *data)
+{
+       pepper_input_event_t *event;
+
+       PEPPER_CHECK(id == PEPPER_EVENT_KEYBOARD_KEY, return, "%d event will not be handled.\n", id);
+       PEPPER_CHECK(data, return, "Invalid data.\n");
+
+       event = (pepper_input_event_t *)info;
+       event->key +=8;
+
+       PEPPER_TRACE("[%s] keycode:%d, state=%d\n", __FUNCTION__, event->key, event->state);
+
+       /* send key event via keyrouter key event handler */
+       pepper_keyrouter_event_handler(listener, object, id, info, keyrouter);
+}
+
+/* seat keyboard add event handler */
+static void
+_handle_seat_keyboard_add(pepper_event_listener_t *listener, pepper_object_t *object, uint32_t id, void *info, void *data)
+{
+       pepper_keyboard_t *keyboard = NULL;
+
+       PEPPER_CHECK(id == PEPPER_EVENT_SEAT_KEYBOARD_ADD, return, "%d event will not be handled.\n", id);
+
+       keyboard = (pepper_keyboard_t *)info;
+       pepper_xkb_keyboard_set_keymap(xkb, keyboard, NULL);
+
+       listener_keyboard_event = pepper_object_add_event_listener((pepper_object_t *)keyboard,
+                                                               PEPPER_EVENT_KEYBOARD_KEY,
+                                                               0,
+                                                               _handle_keyboard_key,
+                                                               keyboard);
+}
+
+/* seat add event handler */
+static void
+_handle_seat_add(pepper_event_listener_t *listener, pepper_object_t *object, uint32_t id, void *info, void *data)
+{
+       pepper_seat_t *new_seat = (pepper_seat_t *)info;
+
+       PEPPER_TRACE("[%s] seat added. name:%s\n", __FUNCTION__, pepper_seat_get_name(new_seat));
+
+       listener_keyboard_add = pepper_object_add_event_listener((pepper_object_t *)new_seat,
+                                                               PEPPER_EVENT_SEAT_KEYBOARD_ADD,
+                                                               0,
+                                                               _handle_seat_keyboard_add, data);
+}
+
+/* seat remove event handler */
+static void
+_handle_seat_remove(pepper_event_listener_t *listener, pepper_object_t *object, uint32_t id, void *info, void *data)
+{
+       pepper_seat_t *seat = (pepper_seat_t *)info;
+
+       PEPPER_TRACE("[%s] seat removed (name=%s)\n", __FUNCTION__, pepper_seat_get_name(seat));
+
+       /* remove devices belongs to this seat */
+       if (input_device)
+               pepper_seat_remove_input_device(seat, input_device);
+}
+
+/* compositor input device add event handler */
+static void
+_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;
+
+       PEPPER_TRACE("[%s] input device added.\n", __FUNCTION__);
+
+       if (seat)
+               pepper_seat_add_input_device(seat, device);
+}
+
+/* compositor input deviec remove event handler */
+static void
+_handle_input_device_remove(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;
+
+       PEPPER_TRACE("[%s] input device removed.\n", __FUNCTION__);
+
+       if (seat)
+               pepper_seat_remove_input_device(seat, device);
+}
+
+int
+main(int argc, char **argv)
+{
+       uint32_t caps = 0;
+       uint32_t probed = 0;
+       struct wl_display   *display;
+       pepper_compositor_t *compositor;
+       const char* socket_name = NULL;
+
+       if (!getenv("XDG_RUNTIME_DIR"))
+               setenv("XDG_RUNTIME_DIR", "/run", 1);
+
+       socket_name = getenv("WAYLAND_DISPLAY");
+
+       if (!socket_name)
+               socket_name = "wayland-0";
+
+       compositor = pepper_compositor_create(socket_name);
+
+       if (!compositor)
+               return -1;
+
+       display = pepper_compositor_get_display(compositor);
+
+       if (!display)
+       {
+               pepper_compositor_destroy(compositor);
+               return -1;
+       }
+
+       /* create pepper xkb */
+       xkb = pepper_xkb_create();
+       PEPPER_CHECK(xkb, goto shutdown_on_failure, "Failed to create pepper_xkb !\n");
+
+       /* register event listeners */
+       listener_seat_add = pepper_object_add_event_listener((pepper_object_t *)compositor,
+                                               PEPPER_EVENT_COMPOSITOR_SEAT_ADD,
+                                               0, _handle_seat_add, compositor);
+       PEPPER_CHECK(listener_seat_add, goto shutdown_on_failure, "Failed to add seat add listener.\n");
+
+       listener_seat_remove = pepper_object_add_event_listener((pepper_object_t *)compositor,
+                                               PEPPER_EVENT_COMPOSITOR_SEAT_REMOVE,
+                                               0, _handle_seat_remove, compositor);
+       PEPPER_CHECK(listener_seat_add, goto shutdown_on_failure, "Failed to add seat remove listener.\n");
+
+       listener_input_add = pepper_object_add_event_listener((pepper_object_t *)compositor,
+                                               PEPPER_EVENT_COMPOSITOR_INPUT_DEVICE_ADD,
+                                               0, _handle_input_device_add, compositor);
+       PEPPER_CHECK(listener_input_add, goto shutdown_on_failure, "Failed to add input device add listener.\n");
+
+       listener_input_remove = pepper_object_add_event_listener((pepper_object_t *)compositor,
+                                               PEPPER_EVENT_COMPOSITOR_INPUT_DEVICE_REMOVE,
+                                               0, _handle_input_device_remove, compositor);
+       PEPPER_CHECK(listener_input_remove, goto shutdown_on_failure, "Failed to add input device remove listener.\n");
+
+       /* create pepper keyrouter */
+       keyrouter = pepper_keyrouter_create(compositor);
+       PEPPER_CHECK(keyrouter, goto shutdown_on_failure, "Failed to create keyrouter !\n");
+
+       /* create pepper evdev */
+       evdev = pepper_evdev_create(compositor);
+       PEPPER_CHECK(evdev, goto shutdown_on_failure, "Failed to create evdev !\n");
+
+       /* set seat0 as a default seat name */
+       seat = pepper_compositor_add_seat(compositor, "seat0");
+       PEPPER_CHECK(seat, goto shutdown_on_failure, "Failed to add seat !\n");
+
+       /* set keyboard capability by default */
+       caps = WL_SEAT_CAPABILITY_KEYBOARD;
+
+       /* create a default pepper input device */
+       input_device = pepper_input_device_create(compositor, caps, NULL, NULL);
+       PEPPER_CHECK(input_device, goto shutdown_on_failure, "Failed to create input device !\n");
+
+       /* probe evdev input device(s) */
+       probed = pepper_evdev_device_probe(evdev, caps);
+
+       if (!probed)
+               PEPPER_TRACE("No evdev devices have been probed.\n");
+
+       /* Enter main loop. */
+       wl_display_run(display);
+
+shutdown_on_failure:
+
+       if (xkb)
+               pepper_xkb_destroy(xkb);
+
+       if(listener_seat_add)
+               pepper_event_listener_remove(listener_seat_add);
+       if (listener_seat_remove)
+               pepper_event_listener_remove(listener_seat_remove);
+       if (listener_input_add)
+               pepper_event_listener_remove(listener_input_add);
+       if (listener_input_remove)
+               pepper_event_listener_remove(listener_input_remove);
+
+       if (keyrouter)
+               pepper_keyrouter_destroy(keyrouter);
+       if (evdev)
+               pepper_evdev_destroy(evdev);
+       if (input_device)
+               pepper_input_device_destroy(input_device);
+       if (seat)
+               pepper_seat_destroy(seat);
+       if (compositor)
+               pepper_compositor_destroy(compositor);
+
+       return 0;
+}
diff --git a/src/samples/xdg-shell-client-protocol.h b/src/samples/xdg-shell-client-protocol.h
new file mode 100644 (file)
index 0000000..24b92b0
--- /dev/null
@@ -0,0 +1,561 @@
+/* 
+ * Copyright © 2008-2013 Kristian Høgsberg
+ * Copyright © 2013      Rafael Antognolli
+ * Copyright © 2013      Jasper St. Pierre
+ * Copyright © 2010-2013 Intel Corporation
+ * 
+ * Permission to use, copy, modify, distribute, and sell this
+ * software and its documentation for any purpose is hereby granted
+ * without fee, provided that the above copyright notice appear in
+ * all copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * the copyright holders not be used in advertising or publicity
+ * pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied
+ * warranty.
+ * 
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+
+#ifndef XDG_SHELL_CLIENT_PROTOCOL_H
+#define XDG_SHELL_CLIENT_PROTOCOL_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+struct wl_client;
+struct wl_resource;
+
+struct wl_output;
+struct wl_seat;
+struct wl_surface;
+struct xdg_popup;
+struct xdg_shell;
+struct xdg_surface;
+
+extern const struct wl_interface xdg_shell_interface;
+extern const struct wl_interface xdg_surface_interface;
+extern const struct wl_interface xdg_popup_interface;
+
+#ifndef XDG_SHELL_VERSION_ENUM
+#define XDG_SHELL_VERSION_ENUM
+/**
+ * xdg_shell_version - latest protocol version
+ * @XDG_SHELL_VERSION_CURRENT: Always the latest version
+ *
+ * The 'current' member of this enum gives the version of the protocol.
+ * Implementations can compare this to the version they implement using
+ * static_assert to ensure the protocol and implementation versions match.
+ */
+enum xdg_shell_version {
+       XDG_SHELL_VERSION_CURRENT = 5,
+};
+#endif /* XDG_SHELL_VERSION_ENUM */
+
+#ifndef XDG_SHELL_ERROR_ENUM
+#define XDG_SHELL_ERROR_ENUM
+enum xdg_shell_error {
+       XDG_SHELL_ERROR_ROLE = 0,
+       XDG_SHELL_ERROR_DEFUNCT_SURFACES = 1,
+       XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP = 2,
+       XDG_SHELL_ERROR_INVALID_POPUP_PARENT = 3,
+};
+#endif /* XDG_SHELL_ERROR_ENUM */
+
+/**
+ * xdg_shell - create desktop-style surfaces
+ * @ping: check if the client is alive
+ *
+ * xdg_shell allows clients to turn a wl_surface into a "real window"
+ * which can be dragged, resized, stacked, and moved around by the user.
+ * Everything about this interface is suited towards traditional desktop
+ * environments.
+ */
+struct xdg_shell_listener {
+       /**
+        * ping - check if the client is alive
+        * @serial: pass this to the pong request
+        *
+        * The ping event asks the client if it's still alive. Pass the
+        * serial specified in the event back to the compositor by sending
+        * a "pong" request back with the specified serial.
+        *
+        * Compositors can use this to determine if the client is still
+        * alive. It's unspecified what will happen if the client doesn't
+        * respond to the ping request, or in what timeframe. Clients
+        * should try to respond in a reasonable amount of time.
+        *
+        * A compositor is free to ping in any way it wants, but a client
+        * must always respond to any xdg_shell object it created.
+        */
+       void (*ping)(void *data,
+                    struct xdg_shell *xdg_shell,
+                    uint32_t serial);
+};
+
+static inline int
+xdg_shell_add_listener(struct xdg_shell *xdg_shell,
+                      const struct xdg_shell_listener *listener, void *data)
+{
+       return wl_proxy_add_listener((struct wl_proxy *) xdg_shell,
+                                    (void (**)(void)) listener, data);
+}
+
+#define XDG_SHELL_DESTROY      0
+#define XDG_SHELL_USE_UNSTABLE_VERSION 1
+#define XDG_SHELL_GET_XDG_SURFACE      2
+#define XDG_SHELL_GET_XDG_POPUP        3
+#define XDG_SHELL_PONG 4
+
+static inline void
+xdg_shell_set_user_data(struct xdg_shell *xdg_shell, void *user_data)
+{
+       wl_proxy_set_user_data((struct wl_proxy *) xdg_shell, user_data);
+}
+
+static inline void *
+xdg_shell_get_user_data(struct xdg_shell *xdg_shell)
+{
+       return wl_proxy_get_user_data((struct wl_proxy *) xdg_shell);
+}
+
+static inline void
+xdg_shell_destroy(struct xdg_shell *xdg_shell)
+{
+       wl_proxy_marshal((struct wl_proxy *) xdg_shell,
+                        XDG_SHELL_DESTROY);
+
+       wl_proxy_destroy((struct wl_proxy *) xdg_shell);
+}
+
+static inline void
+xdg_shell_use_unstable_version(struct xdg_shell *xdg_shell, int32_t version)
+{
+       wl_proxy_marshal((struct wl_proxy *) xdg_shell,
+                        XDG_SHELL_USE_UNSTABLE_VERSION, version);
+}
+
+static inline struct xdg_surface *
+xdg_shell_get_xdg_surface(struct xdg_shell *xdg_shell, struct wl_surface *surface)
+{
+       struct wl_proxy *id;
+
+       id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_shell,
+                        XDG_SHELL_GET_XDG_SURFACE, &xdg_surface_interface, NULL, surface);
+
+       return (struct xdg_surface *) id;
+}
+
+static inline struct xdg_popup *
+xdg_shell_get_xdg_popup(struct xdg_shell *xdg_shell, struct wl_surface *surface, struct wl_surface *parent, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y)
+{
+       struct wl_proxy *id;
+
+       id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_shell,
+                        XDG_SHELL_GET_XDG_POPUP, &xdg_popup_interface, NULL, surface, parent, seat, serial, x, y);
+
+       return (struct xdg_popup *) id;
+}
+
+static inline void
+xdg_shell_pong(struct xdg_shell *xdg_shell, uint32_t serial)
+{
+       wl_proxy_marshal((struct wl_proxy *) xdg_shell,
+                        XDG_SHELL_PONG, serial);
+}
+
+#ifndef XDG_SURFACE_RESIZE_EDGE_ENUM
+#define XDG_SURFACE_RESIZE_EDGE_ENUM
+/**
+ * xdg_surface_resize_edge - edge values for resizing
+ * @XDG_SURFACE_RESIZE_EDGE_NONE: (none)
+ * @XDG_SURFACE_RESIZE_EDGE_TOP: (none)
+ * @XDG_SURFACE_RESIZE_EDGE_BOTTOM: (none)
+ * @XDG_SURFACE_RESIZE_EDGE_LEFT: (none)
+ * @XDG_SURFACE_RESIZE_EDGE_TOP_LEFT: (none)
+ * @XDG_SURFACE_RESIZE_EDGE_BOTTOM_LEFT: (none)
+ * @XDG_SURFACE_RESIZE_EDGE_RIGHT: (none)
+ * @XDG_SURFACE_RESIZE_EDGE_TOP_RIGHT: (none)
+ * @XDG_SURFACE_RESIZE_EDGE_BOTTOM_RIGHT: (none)
+ *
+ * These values are used to indicate which edge of a surface is being
+ * dragged in a resize operation. The server may use this information to
+ * adapt its behavior, e.g. choose an appropriate cursor image.
+ */
+enum xdg_surface_resize_edge {
+       XDG_SURFACE_RESIZE_EDGE_NONE = 0,
+       XDG_SURFACE_RESIZE_EDGE_TOP = 1,
+       XDG_SURFACE_RESIZE_EDGE_BOTTOM = 2,
+       XDG_SURFACE_RESIZE_EDGE_LEFT = 4,
+       XDG_SURFACE_RESIZE_EDGE_TOP_LEFT = 5,
+       XDG_SURFACE_RESIZE_EDGE_BOTTOM_LEFT = 6,
+       XDG_SURFACE_RESIZE_EDGE_RIGHT = 8,
+       XDG_SURFACE_RESIZE_EDGE_TOP_RIGHT = 9,
+       XDG_SURFACE_RESIZE_EDGE_BOTTOM_RIGHT = 10,
+};
+#endif /* XDG_SURFACE_RESIZE_EDGE_ENUM */
+
+#ifndef XDG_SURFACE_STATE_ENUM
+#define XDG_SURFACE_STATE_ENUM
+/**
+ * xdg_surface_state - types of state on the surface
+ * @XDG_SURFACE_STATE_MAXIMIZED: the surface is maximized
+ * @XDG_SURFACE_STATE_FULLSCREEN: the surface is fullscreen
+ * @XDG_SURFACE_STATE_RESIZING: (none)
+ * @XDG_SURFACE_STATE_ACTIVATED: (none)
+ *
+ * The different state values used on the surface. This is designed for
+ * state values like maximized, fullscreen. It is paired with the configure
+ * event to ensure that both the client and the compositor setting the
+ * state can be synchronized.
+ *
+ * States set in this way are double-buffered. They will get applied on the
+ * next commit.
+ *
+ * Desktop environments may extend this enum by taking up a range of values
+ * and documenting the range they chose in this description. They are not
+ * required to document the values for the range that they chose. Ideally,
+ * any good extensions from a desktop environment should make its way into
+ * standardization into this enum.
+ *
+ * The current reserved ranges are:
+ *
+ * 0x0000 - 0x0FFF: xdg-shell core values, documented below. 0x1000 -
+ * 0x1FFF: GNOME
+ */
+enum xdg_surface_state {
+       XDG_SURFACE_STATE_MAXIMIZED = 1,
+       XDG_SURFACE_STATE_FULLSCREEN = 2,
+       XDG_SURFACE_STATE_RESIZING = 3,
+       XDG_SURFACE_STATE_ACTIVATED = 4,
+};
+#endif /* XDG_SURFACE_STATE_ENUM */
+
+/**
+ * xdg_surface - A desktop window
+ * @configure: suggest a surface change
+ * @close: surface wants to be closed
+ *
+ * An interface that may be implemented by a wl_surface, for
+ * implementations that provide a desktop-style user interface.
+ *
+ * It provides requests to treat surfaces like windows, allowing to set
+ * properties like maximized, fullscreen, minimized, and to move and resize
+ * them, and associate metadata like title and app id.
+ *
+ * The client must call wl_surface.commit on the corresponding wl_surface
+ * for the xdg_surface state to take effect. Prior to committing the new
+ * state, it can set up initial configuration, such as maximizing or
+ * setting a window geometry.
+ *
+ * Even without attaching a buffer the compositor must respond to initial
+ * committed configuration, for instance sending a configure event with
+ * expected window geometry if the client maximized its surface during
+ * initialization.
+ *
+ * For a surface to be mapped by the compositor the client must have
+ * committed both an xdg_surface state and a buffer.
+ */
+struct xdg_surface_listener {
+       /**
+        * configure - suggest a surface change
+        * @width: (none)
+        * @height: (none)
+        * @states: (none)
+        * @serial: (none)
+        *
+        * The configure event asks the client to resize its surface or
+        * to change its state.
+        *
+        * The width and height arguments specify a hint to the window
+        * about how its surface should be resized in window geometry
+        * coordinates. See set_window_geometry.
+        *
+        * If the width or height arguments are zero, it means the client
+        * should decide its own window dimension. This may happen when the
+        * compositor need to configure the state of the surface but
+        * doesn't have any information about any previous or expected
+        * dimension.
+        *
+        * The states listed in the event specify how the width/height
+        * arguments should be interpreted, and possibly how it should be
+        * drawn.
+        *
+        * Clients should arrange their surface for the new size and
+        * states, and then send a ack_configure request with the serial
+        * sent in this configure event at some point before committing the
+        * new surface.
+        *
+        * If the client receives multiple configure events before it can
+        * respond to one, it is free to discard all but the last event it
+        * received.
+        */
+       void (*configure)(void *data,
+                         struct xdg_surface *xdg_surface,
+                         int32_t width,
+                         int32_t height,
+                         struct wl_array *states,
+                         uint32_t serial);
+       /**
+        * close - surface wants to be closed
+        *
+        * The close event is sent by the compositor when the user wants
+        * the surface to be closed. This should be equivalent to the user
+        * clicking the close button in client-side decorations, if your
+        * application has any...
+        *
+        * This is only a request that the user intends to close your
+        * window. The client may choose to ignore this request, or show a
+        * dialog to ask the user to save their data...
+        */
+       void (*close)(void *data,
+                     struct xdg_surface *xdg_surface);
+};
+
+static inline int
+xdg_surface_add_listener(struct xdg_surface *xdg_surface,
+                        const struct xdg_surface_listener *listener, void *data)
+{
+       return wl_proxy_add_listener((struct wl_proxy *) xdg_surface,
+                                    (void (**)(void)) listener, data);
+}
+
+#define XDG_SURFACE_DESTROY    0
+#define XDG_SURFACE_SET_PARENT 1
+#define XDG_SURFACE_SET_TITLE  2
+#define XDG_SURFACE_SET_APP_ID 3
+#define XDG_SURFACE_SHOW_WINDOW_MENU   4
+#define XDG_SURFACE_MOVE       5
+#define XDG_SURFACE_RESIZE     6
+#define XDG_SURFACE_ACK_CONFIGURE      7
+#define XDG_SURFACE_SET_WINDOW_GEOMETRY        8
+#define XDG_SURFACE_SET_MAXIMIZED      9
+#define XDG_SURFACE_UNSET_MAXIMIZED    10
+#define XDG_SURFACE_SET_FULLSCREEN     11
+#define XDG_SURFACE_UNSET_FULLSCREEN   12
+#define XDG_SURFACE_SET_MINIMIZED      13
+
+static inline void
+xdg_surface_set_user_data(struct xdg_surface *xdg_surface, void *user_data)
+{
+       wl_proxy_set_user_data((struct wl_proxy *) xdg_surface, user_data);
+}
+
+static inline void *
+xdg_surface_get_user_data(struct xdg_surface *xdg_surface)
+{
+       return wl_proxy_get_user_data((struct wl_proxy *) xdg_surface);
+}
+
+static inline void
+xdg_surface_destroy(struct xdg_surface *xdg_surface)
+{
+       wl_proxy_marshal((struct wl_proxy *) xdg_surface,
+                        XDG_SURFACE_DESTROY);
+
+       wl_proxy_destroy((struct wl_proxy *) xdg_surface);
+}
+
+static inline void
+xdg_surface_set_parent(struct xdg_surface *xdg_surface, struct xdg_surface *parent)
+{
+       wl_proxy_marshal((struct wl_proxy *) xdg_surface,
+                        XDG_SURFACE_SET_PARENT, parent);
+}
+
+static inline void
+xdg_surface_set_title(struct xdg_surface *xdg_surface, const char *title)
+{
+       wl_proxy_marshal((struct wl_proxy *) xdg_surface,
+                        XDG_SURFACE_SET_TITLE, title);
+}
+
+static inline void
+xdg_surface_set_app_id(struct xdg_surface *xdg_surface, const char *app_id)
+{
+       wl_proxy_marshal((struct wl_proxy *) xdg_surface,
+                        XDG_SURFACE_SET_APP_ID, app_id);
+}
+
+static inline void
+xdg_surface_show_window_menu(struct xdg_surface *xdg_surface, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y)
+{
+       wl_proxy_marshal((struct wl_proxy *) xdg_surface,
+                        XDG_SURFACE_SHOW_WINDOW_MENU, seat, serial, x, y);
+}
+
+static inline void
+xdg_surface_move(struct xdg_surface *xdg_surface, struct wl_seat *seat, uint32_t serial)
+{
+       wl_proxy_marshal((struct wl_proxy *) xdg_surface,
+                        XDG_SURFACE_MOVE, seat, serial);
+}
+
+static inline void
+xdg_surface_resize(struct xdg_surface *xdg_surface, struct wl_seat *seat, uint32_t serial, uint32_t edges)
+{
+       wl_proxy_marshal((struct wl_proxy *) xdg_surface,
+                        XDG_SURFACE_RESIZE, seat, serial, edges);
+}
+
+static inline void
+xdg_surface_ack_configure(struct xdg_surface *xdg_surface, uint32_t serial)
+{
+       wl_proxy_marshal((struct wl_proxy *) xdg_surface,
+                        XDG_SURFACE_ACK_CONFIGURE, serial);
+}
+
+static inline void
+xdg_surface_set_window_geometry(struct xdg_surface *xdg_surface, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+       wl_proxy_marshal((struct wl_proxy *) xdg_surface,
+                        XDG_SURFACE_SET_WINDOW_GEOMETRY, x, y, width, height);
+}
+
+static inline void
+xdg_surface_set_maximized(struct xdg_surface *xdg_surface)
+{
+       wl_proxy_marshal((struct wl_proxy *) xdg_surface,
+                        XDG_SURFACE_SET_MAXIMIZED);
+}
+
+static inline void
+xdg_surface_unset_maximized(struct xdg_surface *xdg_surface)
+{
+       wl_proxy_marshal((struct wl_proxy *) xdg_surface,
+                        XDG_SURFACE_UNSET_MAXIMIZED);
+}
+
+static inline void
+xdg_surface_set_fullscreen(struct xdg_surface *xdg_surface, struct wl_output *output)
+{
+       wl_proxy_marshal((struct wl_proxy *) xdg_surface,
+                        XDG_SURFACE_SET_FULLSCREEN, output);
+}
+
+static inline void
+xdg_surface_unset_fullscreen(struct xdg_surface *xdg_surface)
+{
+       wl_proxy_marshal((struct wl_proxy *) xdg_surface,
+                        XDG_SURFACE_UNSET_FULLSCREEN);
+}
+
+static inline void
+xdg_surface_set_minimized(struct xdg_surface *xdg_surface)
+{
+       wl_proxy_marshal((struct wl_proxy *) xdg_surface,
+                        XDG_SURFACE_SET_MINIMIZED);
+}
+
+/**
+ * xdg_popup - short-lived, popup surfaces for menus
+ * @popup_done: popup interaction is done
+ *
+ * A popup surface is a short-lived, temporary surface that can be used
+ * to implement menus. It takes an explicit grab on the surface that will
+ * be dismissed when the user dismisses the popup. This can be done by the
+ * user clicking outside the surface, using the keyboard, or even locking
+ * the screen through closing the lid or a timeout.
+ *
+ * When the popup is dismissed, a popup_done event will be sent out, and at
+ * the same time the surface will be unmapped. The xdg_popup object is now
+ * inert and cannot be reactivated, so clients should destroy it.
+ * Explicitly destroying the xdg_popup object will also dismiss the popup
+ * and unmap the surface.
+ *
+ * Clients will receive events for all their surfaces during this grab
+ * (which is an "owner-events" grab in X11 parlance). This is done so that
+ * users can navigate through submenus and other "nested" popup windows
+ * without having to dismiss the topmost popup.
+ *
+ * Clients that want to dismiss the popup when another surface of their own
+ * is clicked should dismiss the popup using the destroy request.
+ *
+ * The parent surface must have either an xdg_surface or xdg_popup role.
+ *
+ * Specifying an xdg_popup for the parent means that the popups are nested,
+ * with this popup now being the topmost popup. Nested popups must be
+ * destroyed in the reverse order they were created in, e.g. the only popup
+ * you are allowed to destroy at all times is the topmost one.
+ *
+ * If there is an existing popup when creating a new popup, the parent must
+ * be the current topmost popup.
+ *
+ * A parent surface must be mapped before the new popup is mapped.
+ *
+ * When compositors choose to dismiss a popup, they will likely dismiss
+ * every nested popup as well. When a compositor dismisses popups, it will
+ * follow the same dismissing order as required from the client.
+ *
+ * The x and y arguments passed when creating the popup object specify
+ * where the top left of the popup should be placed, relative to the local
+ * surface coordinates of the parent surface. See xdg_shell.get_xdg_popup.
+ *
+ * The client must call wl_surface.commit on the corresponding wl_surface
+ * for the xdg_popup state to take effect.
+ *
+ * For a surface to be mapped by the compositor the client must have
+ * committed both the xdg_popup state and a buffer.
+ */
+struct xdg_popup_listener {
+       /**
+        * popup_done - popup interaction is done
+        *
+        * The popup_done event is sent out when a popup is dismissed by
+        * the compositor. The client should destroy the xdg_popup object
+        * at this point.
+        */
+       void (*popup_done)(void *data,
+                          struct xdg_popup *xdg_popup);
+};
+
+static inline int
+xdg_popup_add_listener(struct xdg_popup *xdg_popup,
+                      const struct xdg_popup_listener *listener, void *data)
+{
+       return wl_proxy_add_listener((struct wl_proxy *) xdg_popup,
+                                    (void (**)(void)) listener, data);
+}
+
+#define XDG_POPUP_DESTROY      0
+
+static inline void
+xdg_popup_set_user_data(struct xdg_popup *xdg_popup, void *user_data)
+{
+       wl_proxy_set_user_data((struct wl_proxy *) xdg_popup, user_data);
+}
+
+static inline void *
+xdg_popup_get_user_data(struct xdg_popup *xdg_popup)
+{
+       return wl_proxy_get_user_data((struct wl_proxy *) xdg_popup);
+}
+
+static inline void
+xdg_popup_destroy(struct xdg_popup *xdg_popup)
+{
+       wl_proxy_marshal((struct wl_proxy *) xdg_popup,
+                        XDG_POPUP_DESTROY);
+
+       wl_proxy_destroy((struct wl_proxy *) xdg_popup);
+}
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/samples/xdg-shell-protocol.c b/src/samples/xdg-shell-protocol.c
new file mode 100644 (file)
index 0000000..82433ea
--- /dev/null
@@ -0,0 +1,125 @@
+/* 
+ * Copyright © 2008-2013 Kristian Høgsberg
+ * Copyright © 2013      Rafael Antognolli
+ * Copyright © 2013      Jasper St. Pierre
+ * Copyright © 2010-2013 Intel Corporation
+ * 
+ * Permission to use, copy, modify, distribute, and sell this
+ * software and its documentation for any purpose is hereby granted
+ * without fee, provided that the above copyright notice appear in
+ * all copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * the copyright holders not be used in advertising or publicity
+ * pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied
+ * warranty.
+ * 
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+extern const struct wl_interface wl_output_interface;
+extern const struct wl_interface wl_seat_interface;
+extern const struct wl_interface wl_surface_interface;
+extern const struct wl_interface xdg_popup_interface;
+extern const struct wl_interface xdg_surface_interface;
+
+static const struct wl_interface *types[] = {
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       &xdg_surface_interface,
+       &wl_surface_interface,
+       &xdg_popup_interface,
+       &wl_surface_interface,
+       &wl_surface_interface,
+       &wl_seat_interface,
+       NULL,
+       NULL,
+       NULL,
+       &xdg_surface_interface,
+       &wl_seat_interface,
+       NULL,
+       NULL,
+       NULL,
+       &wl_seat_interface,
+       NULL,
+       &wl_seat_interface,
+       NULL,
+       NULL,
+       &wl_output_interface,
+};
+
+static const struct wl_message xdg_shell_requests[] = {
+       { "destroy", "", types + 0 },
+       { "use_unstable_version", "i", types + 0 },
+       { "get_xdg_surface", "no", types + 4 },
+       { "get_xdg_popup", "nooouii", types + 6 },
+       { "pong", "u", types + 0 },
+};
+
+static const struct wl_message xdg_shell_events[] = {
+       { "ping", "u", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface xdg_shell_interface = {
+       "xdg_shell", 1,
+       5, xdg_shell_requests,
+       1, xdg_shell_events,
+};
+
+static const struct wl_message xdg_surface_requests[] = {
+       { "destroy", "", types + 0 },
+       { "set_parent", "?o", types + 13 },
+       { "set_title", "s", types + 0 },
+       { "set_app_id", "s", types + 0 },
+       { "show_window_menu", "ouii", types + 14 },
+       { "move", "ou", types + 18 },
+       { "resize", "ouu", types + 20 },
+       { "ack_configure", "u", types + 0 },
+       { "set_window_geometry", "iiii", types + 0 },
+       { "set_maximized", "", types + 0 },
+       { "unset_maximized", "", types + 0 },
+       { "set_fullscreen", "?o", types + 23 },
+       { "unset_fullscreen", "", types + 0 },
+       { "set_minimized", "", types + 0 },
+};
+
+static const struct wl_message xdg_surface_events[] = {
+       { "configure", "iiau", types + 0 },
+       { "close", "", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface xdg_surface_interface = {
+       "xdg_surface", 1,
+       14, xdg_surface_requests,
+       2, xdg_surface_events,
+};
+
+static const struct wl_message xdg_popup_requests[] = {
+       { "destroy", "", types + 0 },
+};
+
+static const struct wl_message xdg_popup_events[] = {
+       { "popup_done", "", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface xdg_popup_interface = {
+       "xdg_popup", 1,
+       1, xdg_popup_requests,
+       1, xdg_popup_events,
+};
+