CasildaCompositor: add socketpair support
- Add casilda_compositor_get_client_socket_fd() - Add casilda_compositor_spawn_async() Closes issue #8 "Investigate using WAYLAND_SOCKET"
This commit is contained in:
parent
0185440702
commit
1b8efba708
3 changed files with 183 additions and 47 deletions
|
|
@ -1,33 +1,47 @@
|
|||
#include <gtk/gtk.h>
|
||||
#include "casilda-compositor.h"
|
||||
|
||||
/* Do not listen on any socket by default */
|
||||
gchar *socket = NULL;
|
||||
|
||||
|
||||
static void
|
||||
activate (GtkApplication *app,
|
||||
G_GNUC_UNUSED gpointer user_data)
|
||||
activate (GtkApplication *app, G_GNUC_UNUSED gpointer user_data)
|
||||
{
|
||||
CasildaCompositor *compositor;
|
||||
GtkWidget *window;
|
||||
g_autofree char *socket = NULL;
|
||||
|
||||
window = gtk_application_window_new (app);
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Compositor");
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Casilda Compositor");
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
|
||||
|
||||
socket = g_build_path (G_DIR_SEPARATOR_S, g_get_tmp_dir (),
|
||||
"casilda-example.sock", NULL);
|
||||
if (socket)
|
||||
g_message ("Listening on %s", socket);
|
||||
else
|
||||
g_message ("Not listening in any socket, you can pass a socket path as parameter");
|
||||
|
||||
compositor = casilda_compositor_new (socket);
|
||||
gtk_window_set_child (GTK_WINDOW (window), GTK_WIDGET (compositor));
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
|
||||
gchar *argv[2] = {
|
||||
"/usr/bin/gtk4-demo",
|
||||
NULL
|
||||
};
|
||||
|
||||
casilda_compositor_spawn_async (compositor, NULL, argv, NULL, G_SPAWN_DEFAULT, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
g_autoptr(GtkApplication) app = NULL;
|
||||
|
||||
app = gtk_application_new ("org.gnome.casilda.compositor", G_APPLICATION_DEFAULT_FLAGS);
|
||||
app = gtk_application_new ("ar.xjuan.casilda.Example", G_APPLICATION_DEFAULT_FLAGS);
|
||||
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
|
||||
|
||||
return g_application_run (G_APPLICATION (app), argc, argv);
|
||||
if (argc >= 2)
|
||||
socket = argv[1];
|
||||
|
||||
return g_application_run (G_APPLICATION (app), 0, NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@
|
|||
#define ENABLE_GL_DEBUG 0
|
||||
#define ENABLE_BORDERS 0
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <epoxy/egl.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
#include <wayland-server-core.h>
|
||||
|
|
@ -162,9 +164,10 @@ typedef struct
|
|||
GdkTexture *cursor_gdk_texture;
|
||||
GdkCursor *cursor_gdk_cursor;
|
||||
|
||||
struct sockaddr_un abstract_socket;
|
||||
|
||||
/* GObject properties */
|
||||
gchar *socket;
|
||||
gboolean owns_socket;
|
||||
} CasildaCompositorPrivate;
|
||||
|
||||
|
||||
|
|
@ -1675,14 +1678,6 @@ casilda_compositor_finalize (GObject *object)
|
|||
CasildaCompositorPrivate *priv = GET_PRIVATE (object);
|
||||
|
||||
g_clear_pointer (&priv->toplevel_state, g_hash_table_destroy);
|
||||
|
||||
if (priv->owns_socket)
|
||||
{
|
||||
priv->owns_socket = FALSE;
|
||||
g_autofree char *socket_path = g_path_get_basename (priv->socket);
|
||||
g_unlink (priv->socket);
|
||||
g_rmdir (socket_path);
|
||||
}
|
||||
g_clear_pointer (&priv->socket, g_free);
|
||||
|
||||
wl_display_destroy_clients (priv->wl_display);
|
||||
|
|
@ -1713,7 +1708,6 @@ casilda_compositor_set_property (GObject *object,
|
|||
{
|
||||
case PROP_SOCKET:
|
||||
g_set_str (&priv->socket, g_value_get_string (value));
|
||||
priv->owns_socket = priv->socket != NULL;
|
||||
break;
|
||||
|
||||
case PROP_BG_COLOR:
|
||||
|
|
@ -1807,9 +1801,12 @@ casilda_compositor_class_init (CasildaCompositorClass *klass)
|
|||
*
|
||||
* Wayland socket the compositor will listen on.
|
||||
*
|
||||
* If NULL you can still use WAYLAND_SOCKET with an fd returned by
|
||||
* casilda_compositor_get_client_socket_fd() instead of setting up WAYLAND_DISPLAY.
|
||||
*
|
||||
*/
|
||||
properties[PROP_SOCKET] =
|
||||
g_param_spec_string ("socket", "", "", NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
|
||||
g_param_spec_string ("socket", "", "", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
/**
|
||||
* CasildaCompositor:bg-color:
|
||||
|
|
@ -1824,13 +1821,6 @@ casilda_compositor_class_init (CasildaCompositorClass *klass)
|
|||
g_object_class_install_properties (object_class, N_PROPERTIES, properties);
|
||||
}
|
||||
|
||||
|
||||
CasildaCompositor *
|
||||
casilda_compositor_new (const gchar *socket)
|
||||
{
|
||||
return g_object_new (CASILDA_COMPOSITOR_TYPE, "socket", socket, NULL);
|
||||
}
|
||||
|
||||
/* wlroots */
|
||||
|
||||
static void
|
||||
|
|
@ -2235,15 +2225,6 @@ server_request_activate (struct wl_listener *listener, void *data)
|
|||
}
|
||||
}
|
||||
|
||||
static gchar *
|
||||
casilda_compositor_get_socket (void)
|
||||
{
|
||||
g_autofree char *tmp = g_dir_make_tmp ("casilda-compositor-XXXXXX", NULL);
|
||||
g_autofree char *retval = g_build_filename (tmp, "wayland.sock", NULL);
|
||||
|
||||
return g_steal_pointer (&retval);
|
||||
}
|
||||
|
||||
#if ENABLE_GL_DEBUG
|
||||
static void GLAPIENTRY
|
||||
on_gl_message_callback (G_GNUC_UNUSED GLenum source,
|
||||
|
|
@ -2388,21 +2369,150 @@ casilda_compositor_wlr_init (CasildaCompositorPrivate *priv)
|
|||
/* Configure seat */
|
||||
priv->seat = wlr_seat_create (priv->wl_display, "seat0");
|
||||
priv->request_set_selection.notify = seat_request_set_selection;
|
||||
wl_signal_add (&priv->seat->events.request_set_selection,
|
||||
&priv->request_set_selection);
|
||||
wl_signal_add (&priv->seat->events.request_set_selection, &priv->request_set_selection);
|
||||
|
||||
wlr_seat_set_capabilities (priv->seat,
|
||||
WL_SEAT_CAPABILITY_POINTER |
|
||||
WL_SEAT_CAPABILITY_KEYBOARD);
|
||||
wlr_seat_set_capabilities (priv->seat, WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_KEYBOARD);
|
||||
|
||||
if (!priv->socket)
|
||||
{
|
||||
priv->socket = casilda_compositor_get_socket ();
|
||||
priv->owns_socket = TRUE;
|
||||
}
|
||||
return;
|
||||
|
||||
if (wl_display_add_socket (priv->wl_display, priv->socket) != 0)
|
||||
if (wl_display_add_socket (priv->wl_display, priv->socket))
|
||||
g_warning ("Error adding socket file %s", priv->socket);
|
||||
else
|
||||
g_info ("Listening on %s", priv->socket);
|
||||
}
|
||||
|
||||
|
||||
/* Public API */
|
||||
|
||||
CasildaCompositor *
|
||||
casilda_compositor_new (const gchar *socket)
|
||||
{
|
||||
return g_object_new (CASILDA_COMPOSITOR_TYPE, "socket", socket, NULL);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* casilda_compositor_get_client_socket_fd:
|
||||
* @compositor: a `CasildaCompositor`
|
||||
*
|
||||
* Create a client socket file descriptor connected to this compositor ready to use by passing it to a client with
|
||||
* WAYLAND_SOCKET environment variable.
|
||||
*
|
||||
* Returns: a socket FD connected to the compositor
|
||||
*/
|
||||
int
|
||||
casilda_compositor_get_client_socket_fd (CasildaCompositor *compositor)
|
||||
{
|
||||
g_return_val_if_fail (CASILDA_IS_COMPOSITOR (compositor), -1);
|
||||
|
||||
CasildaCompositorPrivate *priv = GET_PRIVATE (compositor);
|
||||
gint fds[2] = {0, };
|
||||
|
||||
if (socketpair (AF_UNIX, SOCK_STREAM, 0, fds))
|
||||
{
|
||||
g_warning ("Could not create a UNIX socketpair");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!wl_client_create (priv->wl_display, fds[0]))
|
||||
{
|
||||
g_warning ("Could not add socketpair to display");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fds[1];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* casilda_compositor_spawn_async:
|
||||
* @compositor: a `CasildaCompositor`
|
||||
* @working_directory: (type filename) (nullable): child's current working directory, or %NULL to inherit parent's
|
||||
* @argv: (array zero-terminated=1) (element-type filename): child's argument vector
|
||||
* @envp: (array zero-terminated=1) (element-type filename) (nullable): child's environment, or %NULL to inherit parent's
|
||||
* @flags: flags from #GSpawnFlags
|
||||
* @child_setup: (scope async) (closure user_data) (nullable): function to run in the child just before `exec()`
|
||||
* @user_data: user data for @child_setup
|
||||
* @child_pid: (out) (optional): return location for child process reference, or %NULL
|
||||
* @error: return location for error
|
||||
*
|
||||
* Executes a child program asynchronously with the right environment to automatically connect to this compositor.
|
||||
*
|
||||
* See g_spawn_async_with_pipes_and_fds() for a full description; this function simply calls
|
||||
* g_spawn_async_with_pipes_and_fds() without any pipes and with WAYLAND_DISPLAY set to `CasildaCompositor::socket` or
|
||||
* a fd already connected to the compositor and set to WAYLAND_SOCKET if its NULL.
|
||||
*
|
||||
* Please note GDK_BACKEND, WAYLAND_DISPLAY and WAYLAND_SOCKET are set by this function they are ignored from %envp and
|
||||
* DISPLAY is removed to avoid clients try to connect using X11
|
||||
*
|
||||
* Returns: TRUE on success, FALSE if error is set.
|
||||
*/
|
||||
gboolean
|
||||
casilda_compositor_spawn_async (CasildaCompositor *compositor,
|
||||
const gchar *working_directory,
|
||||
gchar **argv,
|
||||
gchar **envp,
|
||||
GSpawnFlags flags,
|
||||
GSpawnChildSetupFunc child_setup,
|
||||
gpointer user_data,
|
||||
GPid *child_pid,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (CASILDA_IS_COMPOSITOR (compositor), FALSE);
|
||||
|
||||
CasildaCompositorPrivate *priv = GET_PRIVATE (compositor);
|
||||
g_autoptr(GStrvBuilder) builder = g_strv_builder_new ();
|
||||
g_autofree gchar *wayland_socket = NULL;
|
||||
g_auto(GStrv) environ = NULL;
|
||||
GStrv source_env = NULL;
|
||||
gint fd;
|
||||
|
||||
if (envp)
|
||||
source_env = envp;
|
||||
else
|
||||
source_env = environ = g_get_environ();
|
||||
|
||||
/* Build environment */
|
||||
for (gint i = 0; source_env[i]; i++)
|
||||
{
|
||||
if (g_str_has_prefix (source_env[i], "DISPLAY="))
|
||||
continue;
|
||||
if (g_str_has_prefix (source_env[i], "GDK_BACKEND="))
|
||||
continue;
|
||||
if (g_str_has_prefix (source_env[i], "WAYLAND_DISPLAY="))
|
||||
continue;
|
||||
if (g_str_has_prefix (source_env[i], "WAYLAND_SOCKET="))
|
||||
continue;
|
||||
|
||||
g_strv_builder_add (builder, source_env[i]);
|
||||
}
|
||||
|
||||
/* Force GTK apps to wayland backend */
|
||||
g_strv_builder_add (builder, "GDK_BACKEND=wayland");
|
||||
|
||||
if (priv->socket)
|
||||
wayland_socket = g_strdup_printf("WAYLAND_DISPLAY=%s", priv->socket);
|
||||
else
|
||||
{
|
||||
fd = casilda_compositor_get_client_socket_fd (compositor);
|
||||
wayland_socket = g_strdup_printf("WAYLAND_SOCKET=%d", fd);
|
||||
}
|
||||
|
||||
/* Add wayland socket env var */
|
||||
g_strv_builder_add (builder, wayland_socket);
|
||||
|
||||
g_auto(GStrv) env = g_strv_builder_end (builder);
|
||||
|
||||
return g_spawn_async_with_pipes_and_fds (working_directory,
|
||||
(const gchar* const* ) argv,
|
||||
(const gchar* const* ) env,
|
||||
flags,
|
||||
child_setup,
|
||||
user_data,
|
||||
-1, -1, -1,
|
||||
&fd, &fd, priv->socket ? 0 : 1,
|
||||
child_pid,
|
||||
NULL, NULL, NULL,
|
||||
error);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,3 +31,15 @@
|
|||
G_DECLARE_FINAL_TYPE (CasildaCompositor, casilda_compositor, CASILDA, COMPOSITOR, GtkWidget)
|
||||
|
||||
CasildaCompositor *casilda_compositor_new (const gchar *socket);
|
||||
|
||||
int casilda_compositor_get_client_socket_fd (CasildaCompositor *compositor);
|
||||
|
||||
gboolean casilda_compositor_spawn_async (CasildaCompositor *compositor,
|
||||
const gchar *working_directory,
|
||||
gchar **argv,
|
||||
gchar **envp,
|
||||
GSpawnFlags flags,
|
||||
GSpawnChildSetupFunc child_setup,
|
||||
gpointer user_data,
|
||||
GPid *child_pid,
|
||||
GError **error);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue