From: Sung-Jin Park Date: Mon, 19 Jun 2017 03:42:28 +0000 (+0900) Subject: samples: add sample-server, sample-client X-Git-Tag: submit/tizen/20170628.060900~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=51eb64edd4ca6ba6d68ab2d8cd745325ffbbd160;p=platform%2Fcore%2Fuifw%2Fpepper.git samples: add sample-server, sample-client Change-Id: I9c0af6c6e7a66c8e7141578484539280ca62dd10 Signed-off-by: Sung-Jin Park --- diff --git a/configure.ac b/configure.ac index 47de5db..8494b0e 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/packaging/pepper.spec b/packaging/pepper.spec index 5d6a182..13e9b4e 100644 --- a/packaging/pepper.spec +++ b/packaging/pepper.spec @@ -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 diff --git a/src/samples/Makefile.am b/src/samples/Makefile.am index 03d9865..29ac394 100644 --- a/src/samples/Makefile.am +++ b/src/samples/Makefile.am @@ -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 index 0000000..6728378 --- /dev/null +++ b/src/samples/sample-client.c @@ -0,0 +1,759 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; ikeyrouter, 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, ®istry_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 index 0000000..641681d --- /dev/null +++ b/src/samples/sample-server.c @@ -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 + +#include +#include +#include +#include + +/* 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 index 0000000..24b92b0 --- /dev/null +++ b/src/samples/xdg-shell-client-protocol.h @@ -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 +#include +#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 index 0000000..82433ea --- /dev/null +++ b/src/samples/xdg-shell-protocol.c @@ -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 +#include +#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, +}; +