summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitreview5
-rw-r--r--COPYING22
-rw-r--r--README.md4
-rw-r--r--include/os-compatibility.h58
-rw-r--r--meson.build126
-rwxr-xr-xscript/agl-activator27
-rw-r--r--src/main.c200
-rw-r--r--src/os-compatibility.c204
8 files changed, 646 insertions, 0 deletions
diff --git a/.gitreview b/.gitreview
new file mode 100644
index 0000000..019a07b
--- /dev/null
+++ b/.gitreview
@@ -0,0 +1,5 @@
+[gerrit]
+host=gerrit.automotivelinux.org
+port=29418
+project=src/agl-shell-activator
+defaultbranch=master
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..fa8f128
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,22 @@
+Copyright 2021 Collabora, Ltd.
+
+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.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..adf1324
--- /dev/null
+++ b/README.md
@@ -0,0 +1,4 @@
+# agl-shell-activator
+
+Simple application that will activate/display another application using
+agl-shell-desktop protocol.
diff --git a/include/os-compatibility.h b/include/os-compatibility.h
new file mode 100644
index 0000000..690f229
--- /dev/null
+++ b/include/os-compatibility.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef OS_COMPATIBILITY_H
+#define OS_COMPATIBILITY_H
+
+#include <sys/types.h>
+
+#ifdef HAVE_EXECINFO_H
+#include <execinfo.h>
+#else
+static inline int
+backtrace(void **buffer, int size)
+{
+ return 0;
+}
+#endif
+
+int
+os_fd_set_cloexec(int fd);
+
+int
+os_socketpair_cloexec(int domain, int type, int protocol, int *sv);
+
+int
+os_epoll_create_cloexec(void);
+
+int
+os_create_anonymous_file(off_t size);
+
+#ifndef HAVE_STRCHRNUL
+char *
+strchrnul(const char *s, int c);
+#endif
+
+#endif /* OS_COMPATIBILITY_H */
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..f03bd47
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,126 @@
+project('agl-shell-activator',
+ 'c',
+ version: '0.0.1',
+ default_options: [
+ 'warning_level=3',
+ 'c_std=gnu99',
+ ],
+ meson_version: '>= 0.50',
+ license: 'MIT/Expat',
+)
+
+pkgconfig = import('pkgconfig')
+cc = meson.get_compiler('c')
+
+add_project_arguments(
+ cc.get_supported_arguments([
+ '-Wno-unused-parameter',
+ '-Wno-pedantic',
+ '-Wextra',
+ '-Werror'
+ ]),
+ language: 'c'
+)
+
+add_project_arguments([
+ '-DPACKAGE_STRING="agl-shell-activator @0@"'.format(meson.project_version()),
+ '-D_GNU_SOURCE',
+ '-D_ALL_SOURCE',
+ ],
+ language: 'c'
+)
+
+optional_libc_funcs = [ 'memfd_create', 'strchrnul' ]
+foreach func: optional_libc_funcs
+ if cc.has_function(func)
+ add_project_arguments('-DHAVE_@0@=1'.format(func.to_upper()), language: 'c')
+ endif
+endforeach
+
+env_modmap = ''
+
+libwayland_dep = dependency('wayland-client')
+agl_compositor_dep = dependency('agl-compositor-0.0.19-protocols')
+
+dep_scanner = dependency('wayland-scanner', native: true)
+prog_scanner = find_program(dep_scanner.get_pkgconfig_variable('wayland_scanner'))
+dep_wp = dependency('wayland-protocols', version: '>= 1.18')
+dir_wp_base = dep_wp.get_pkgconfig_variable('pkgdatadir')
+dir_agl_compositor_base = agl_compositor_dep.get_pkgconfig_variable('pkgdatadir')
+
+protocols = [
+ { 'name': 'agl-shell-desktop', 'source': 'agl-compositor' },
+]
+
+foreach proto: protocols
+ proto_name = proto['name']
+ if proto['source'] == 'internal'
+ base_file = proto_name
+ xml_path = join_paths('protocol', '@0@.xml'.format(base_file))
+ elif proto['source'] == 'wp-stable'
+ base_file = proto_name
+ xml_path = join_paths(dir_wp_base, 'stable', proto_name, '@0@.xml'.format(base_file))
+ elif proto['source'] == 'agl-compositor'
+ base_file = proto_name
+ xml_path = join_paths(dir_agl_compositor_base, '@0@.xml'.format(base_file))
+ else
+ base_file = '@0@-unstable-@1@'.format(proto_name, proto['version'])
+ xml_path = join_paths(dir_wp_base, 'unstable', proto_name, '@0@.xml'.format(base_file))
+ endif
+
+ foreach output_type: [ 'client-header', 'server-header', 'private-code' ]
+ if output_type == 'client-header'
+ output_file = '@0@-client-protocol.h'.format(base_file)
+ elif output_type == 'server-header'
+ output_file = '@0@-server-protocol.h'.format(base_file)
+ else
+ output_file = '@0@-protocol.c'.format(base_file)
+ if dep_scanner.version().version_compare('< 1.14.91')
+ output_type = 'code'
+ endif
+ endif
+
+ var_name = output_file.underscorify()
+ target = custom_target(
+ '@0@ @1@'.format(base_file, output_type),
+ command: [ prog_scanner, output_type, '@INPUT@', '@OUTPUT@' ],
+ input: xml_path,
+ output: output_file,
+ )
+
+ set_variable(var_name, target)
+ endforeach
+endforeach
+
+prefix_path = get_option('prefix')
+binplugin_dir = join_paths(prefix_path, get_option('bindir'))
+common_inc = include_directories('include')
+
+deps_agl_activator = [
+ libwayland_dep,
+]
+
+srcs_agl_activator = [
+ 'src/main.c',
+ agl_shell_desktop_client_protocol_h,
+ agl_shell_desktop_protocol_c,
+]
+
+exe_wth_receiver = executable(
+ 'agl-shell-activator',
+ srcs_agl_activator,
+ include_directories: common_inc,
+ dependencies: deps_agl_activator,
+ install_rpath: binplugin_dir,
+ install: true
+)
+
+cp = find_program('cp')
+script_target = custom_target('install_script',
+ command: [ cp, '@INPUT@', '@OUTPUT@' ],
+ output : 'agl-activator',
+ input : 'script/agl-activator',
+ install : true,
+ install_dir: binplugin_dir,
+)
+
diff --git a/script/agl-activator b/script/agl-activator
new file mode 100755
index 0000000..b8fd20f
--- /dev/null
+++ b/script/agl-activator
@@ -0,0 +1,27 @@
+#!/bin/bash
+#
+# Copyright 2021 Collabora, Ltd.
+#
+# 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.
+#
+
+XDG_RUNTIME_DIR=/run/platform/display /usr/bin/agl-shell-activator $1
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..831bea6
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2021 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include <assert.h>
+
+#include <wayland-client.h>
+#include <wayland-util.h>
+#include "agl-shell-desktop-client-protocol.h"
+
+
+struct display;
+
+struct window_output {
+ struct display *display;
+ struct wl_output *output;
+ struct wl_list link; /** display::output_list */
+};
+
+struct display {
+ struct wl_display *display;
+ struct wl_registry *registry;
+ struct agl_shell_desktop *agl_shell_desktop;
+
+ struct wl_list output_list; /** window_output::link */
+};
+
+static void
+display_handle_geometry(void *data, struct wl_output *wl_output,
+ int x, int y, int physical_width, int physical_height,
+ int subpixel, const char *make, const char *model, int transform)
+{
+}
+
+static void
+display_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags,
+ int width, int height, int refresh)
+{
+}
+
+static void
+display_handle_done(void *data, struct wl_output *wl_output)
+{
+}
+
+static void
+display_handle_scale(void *data, struct wl_output *wl_output, int32_t factor)
+{
+}
+
+static const struct wl_output_listener output_listener = {
+ display_handle_geometry,
+ display_handle_mode,
+ display_handle_done,
+ display_handle_scale,
+};
+
+
+ static void
+display_add_output(struct display *display, uint32_t id)
+{
+ struct window_output *w_output;
+
+ w_output = calloc(1, sizeof(*w_output));
+ w_output->display = display;
+ w_output->output =
+ wl_registry_bind(display->registry, id, &wl_output_interface, 2);
+
+ wl_list_insert(&display->output_list, &w_output->link);
+
+ wl_output_add_listener(w_output->output, &output_listener, display);
+}
+
+static void
+destroy_output(struct window_output *w_output)
+{
+ wl_list_remove(&w_output->link);
+ free(w_output);
+}
+
+static void
+registry_handle_global(void *data, struct wl_registry *registry,
+ uint32_t id, const char *interface, uint32_t version)
+{
+ struct display *d = data;
+
+ if (strcmp(interface, "agl_shell_desktop") == 0) {
+ d->agl_shell_desktop =
+ wl_registry_bind(registry, id, &agl_shell_desktop_interface, 1);
+ } else if (strcmp(interface, "wl_output") == 0) {
+ display_add_output(d, id);
+ }
+}
+
+static void
+registry_handle_global_remove(void *data, struct wl_registry *registry,
+ uint32_t name)
+{
+
+}
+
+static const struct wl_registry_listener registry_listener = {
+ registry_handle_global,
+ registry_handle_global_remove
+};
+
+static struct display *
+create_display(void)
+{
+ struct display *display;
+
+ display = malloc(sizeof *display);
+ if (display == NULL) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ wl_list_init(&display->output_list);
+ display->display = wl_display_connect(NULL);
+ assert(display->display);
+
+ display->registry = wl_display_get_registry(display->display);
+
+ wl_registry_add_listener(display->registry, &registry_listener, display);
+ wl_display_roundtrip(display->display);
+
+ if (display->agl_shell_desktop == NULL) {
+ fprintf(stderr, "No agl_shell_desktop extension present\n");
+ }
+
+ wl_display_roundtrip(display->display);
+ return display;
+}
+
+static void
+destroy_display(struct display *display)
+{
+ struct window_output *w_output, *w_output_next;
+
+ wl_list_for_each_safe(w_output, w_output_next, &display->output_list, link)
+ destroy_output(w_output);
+
+ wl_registry_destroy(display->registry);
+
+ wl_display_flush(display->display);
+ wl_display_disconnect(display->display);
+
+ free(display);
+}
+
+int main(int argc, char *argv[])
+{
+ struct display *display;
+ const char *app_id = NULL;
+ struct window_output *w_output;
+
+ if (argc < 2) {
+ exit(EXIT_FAILURE);
+ }
+
+ display = create_display();
+
+ /* the app has to be already started, or not already active */
+ app_id = argv[1];
+ if (app_id && strlen(app_id) == 0)
+ exit(EXIT_FAILURE);
+
+ /* pick the first one available */
+ w_output = wl_container_of(display->output_list.prev, w_output, link);
+ agl_shell_desktop_activate_app(display->agl_shell_desktop, app_id,
+ NULL, w_output->output);
+
+ destroy_display(display);
+ return 0;
+}
diff --git a/src/os-compatibility.c b/src/os-compatibility.c
new file mode 100644
index 0000000..d9502e5
--- /dev/null
+++ b/src/os-compatibility.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * 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 <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/epoll.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "os-compatibility.h"
+
+int
+os_fd_set_cloexec(int fd)
+{
+ long flags;
+
+ if (fd == -1)
+ return -1;
+
+ flags = fcntl(fd, F_GETFD);
+ if (flags == -1)
+ return -1;
+
+ if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+ return -1;
+
+ return 0;
+}
+
+static int
+set_cloexec_or_close(int fd)
+{
+ if (os_fd_set_cloexec(fd) != 0) {
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+
+int
+os_socketpair_cloexec(int domain, int type, int protocol, int *sv)
+{
+ int ret;
+
+#ifdef SOCK_CLOEXEC
+ ret = socketpair(domain, type | SOCK_CLOEXEC, protocol, sv);
+ if (ret == 0 || errno != EINVAL)
+ return ret;
+#endif
+
+ ret = socketpair(domain, type, protocol, sv);
+ if (ret < 0)
+ return ret;
+
+ sv[0] = set_cloexec_or_close(sv[0]);
+ sv[1] = set_cloexec_or_close(sv[1]);
+
+ if (sv[0] != -1 && sv[1] != -1)
+ return 0;
+
+ close(sv[0]);
+ close(sv[1]);
+ return -1;
+}
+
+int
+os_epoll_create_cloexec(void)
+{
+ int fd;
+
+#ifdef EPOLL_CLOEXEC
+ fd = epoll_create1(EPOLL_CLOEXEC);
+ if (fd >= 0)
+ return fd;
+ if (errno != EINVAL)
+ return -1;
+#endif
+
+ fd = epoll_create(1);
+ return set_cloexec_or_close(fd);
+}
+
+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;
+}
+
+/*
+ * Create a new, unique, anonymous file of the given size, and
+ * return the file descriptor for it. The file descriptor is set
+ * CLOEXEC. The file is immediately suitable for mmap()'ing
+ * the given size at offset zero.
+ *
+ * The file should not have a permanent backing store like a disk,
+ * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
+ *
+ * The file name is deleted from the file system.
+ *
+ * The file is suitable for buffer sharing between processes by
+ * transmitting the file descriptor over Unix sockets using the
+ * SCM_RIGHTS methods.
+ *
+ * If the C library implements posix_fallocate(), it is used to
+ * guarantee that disk space is available for the file at the
+ * given size. If disk space is insufficent, errno is set to ENOSPC.
+ * If posix_fallocate() is not supported, program may receive
+ * SIGBUS on accessing mmap()'ed file contents instead.
+ */
+int
+os_create_anonymous_file(off_t size)
+{
+ static const char template[] = "/weston-shared-XXXXXX";
+ const char *path;
+ char *name;
+ int fd;
+ int ret;
+
+ path = getenv("XDG_RUNTIME_DIR");
+ if (!path) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ name = malloc(strlen(path) + sizeof(template));
+ if (!name)
+ return -1;
+
+ strcpy(name, path);
+ strcat(name, 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;
+}
+
+#ifndef HAVE_STRCHRNUL
+char *
+strchrnul(const char *s, int c)
+{
+ while (*s && *s != c)
+ s++;
+ return (char *)s;
+}
+#endif