Commit 47e6e733 authored by Benjamin Berg's avatar Benjamin Berg
Browse files

portal: Rework cancellation, reworking error reporting and adding X fallback

With this gnome-screencast will fall back to trying to use a simple
ximagesrc rather than the portal if the portal API is missing.
parent 63166e79
......@@ -5,13 +5,10 @@ project('gnome-screencast', 'c', version: '0.1.0',
gnome = import('gnome')
i18n = import('i18n')
have_screencast_portal = get_option('screencast_portal')
config_h = configuration_data()
config_h.set_quoted('PACKAGE_VERSION', meson.project_version())
config_h.set_quoted('GETTEXT_PACKAGE', 'gnome-screencast')
config_h.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir')))
config_h.set10('HAVE_SCREENCAST_PORTAL', have_screencast_portal)
configure_file(
output: 'gnome-screencast-config.h',
configuration: config_h,
......
option('screencast_portal',
type: 'boolean',
value: true,
description: 'Use the screencast portal, if unset uses X11 image source'
)
......@@ -27,9 +27,7 @@
#include <gst/gst.h>
#if HAVE_SCREENCAST_PORTAL
#include "screencast-portal.h"
#endif
struct _GnomeScreencastWindow
{
......@@ -38,9 +36,8 @@ struct _GnomeScreencastWindow
ScreencastMetaProvider *meta_provider;
ScreencastWFDP2PRegistry *wfd_p2p_registry;
#if HAVE_SCREENCAST_PORTAL
ScreencastPortal *portal;
#endif
gboolean use_x11;
GCancellable *cancellable;
......@@ -71,11 +68,11 @@ sink_create_source_cb (GnomeScreencastWindow * self, ScreencastSink * sink)
GstElement *src, *dst, *res;
bin = GST_BIN (gst_bin_new ("screencast source bin"));
#if HAVE_SCREENCAST_PORTAL
src = screencast_portal_get_source (self->portal);
#else
src = gst_element_factory_make ("ximagesrc", "X11 screencast source");
#endif
g_debug ("use x11: %d", self->use_x11);
if (self->use_x11)
src = gst_element_factory_make ("ximagesrc", "X11 screencast source");
else
src = screencast_portal_get_source (self->portal);
gst_bin_add (bin, src);
dst = gst_element_factory_make ("intervideosink", "inter video sink");
......@@ -176,13 +173,11 @@ find_sink_list_row_activated_cb (GnomeScreencastWindow *self, ScreencastSinkRow
{
ScreencastSink *sink;
#if HAVE_SCREENCAST_PORTAL
if (!self->portal)
if (!self->portal && ! self->use_x11)
{
g_warning ("Cannot start streaming right now as we don't have a portal!");
return;
}
#endif
g_assert (SCREENCAST_IS_SINK_ROW (row));
......@@ -244,7 +239,6 @@ gnome_screencast_window_class_init (GnomeScreencastWindowClass *klass)
gtk_widget_class_bind_template_child (widget_class, GnomeScreencastWindow, error_return);
}
#if HAVE_SCREENCAST_PORTAL
static void
screencast_portal_init_async_cb (GObject *source_object,
GAsyncResult *res,
......@@ -260,9 +254,17 @@ screencast_portal_init_async_cb (GObject *source_object,
{
g_warning ("Error initing screencast portal: %s", error->message);
/* XXX: This is fatal! */
window = GNOME_SCREENCAST_WINDOW (user_data);
gtk_widget_destroy (GTK_WIDGET (window));
/* If this the error was for an unknown method, then we likely
* don't have a gnome-shell or it does not support the screen casting
* portal.
* In this case we assume that an xvimagesrc is usable, in all other
* cases it is a fatal error. */
if (!g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD))
gtk_widget_destroy (GTK_WIDGET (window));
else
window->use_x11 = TRUE;
}
g_object_unref (source_object);
......@@ -272,7 +274,6 @@ screencast_portal_init_async_cb (GObject *source_object,
window = GNOME_SCREENCAST_WINDOW (user_data);
window->portal = SCREENCAST_PORTAL (source_object);
}
#endif
static void
stream_stop_clicked_cb (GnomeScreencastWindow *self)
......@@ -286,9 +287,7 @@ stream_stop_clicked_cb (GnomeScreencastWindow *self)
static void
gnome_screencast_window_init (GnomeScreencastWindow *self)
{
#if HAVE_SCREENCAST_PORTAL
ScreencastPortal *portal;
#endif
gtk_widget_init_template (GTK_WIDGET (self));
self->meta_provider = screencast_meta_provider_new ();
......@@ -332,12 +331,10 @@ gnome_screencast_window_init (GnomeScreencastWindow *self)
self,
G_CONNECT_SWAPPED);
#if HAVE_SCREENCAST_PORTAL
portal = screencast_portal_new ();
g_async_initable_init_async (G_ASYNC_INITABLE (portal),
G_PRIORITY_LOW,
self->cancellable,
screencast_portal_init_async_cb,
self);
#endif
}
......@@ -15,12 +15,9 @@ gnome_screencast_sources = [
'screencast-wfd-p2p-registry.c',
'screencast-dummy-provider.c',
'screencast-dummy-wfd-sink.c',
'screencast-portal.c',
]
if have_screencast_portal
gnome_screencast_sources += [ 'screencast-portal.c' ]
endif
enum_headers = files('screencast-sink.h')
gnome_screencast_sources += gnome.mkenums_simple(
......
......@@ -13,6 +13,8 @@ struct _ScreencastPortal
gint portal_signal_id;
GDBusProxy *screencast;
guint32 stream_node_id;
GCancellable *cancellable;
};
static void screencast_portal_async_initable_iface_init (GAsyncInitableIface *iface);
......@@ -90,15 +92,20 @@ init_check_dbus_error (GObject *source_object,
&error);
if (result == NULL)
{
GCancellable *cancellable;
g_warning ("Error calling DBus method during Screencast portal initialization: %s",
error->message);
/* Do nothing if the operation was cancelled, the task was likely
* already returned from elsewhere. */
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
ScreencastPortal *self = SCREENCAST_PORTAL (g_task_get_source_object (task));
cancellable = g_task_get_cancellable (task);
g_cancellable_cancel (cancellable);
g_warning ("Error calling DBus method during Screencast portal initialization: %s",
error->message);
g_task_return_error (task, g_steal_pointer (&error));
g_object_unref (task);
g_cancellable_cancel (self->cancellable);
g_task_return_error (task, g_steal_pointer (&error));
g_object_unref (task);
}
}
}
......@@ -132,7 +139,7 @@ portal_start_response_received (GDBusConnection *connection,
g_task_return_new_error (task,
G_IO_ERROR,
G_IO_ERROR_FAILED,
"Failed to create portal sesssion");
"Failed to create portal session");
g_object_unref (task);
return;
}
......@@ -220,7 +227,7 @@ portal_select_source_response_received (GDBusConnection *connection,
g_variant_builder_end (&builder),
G_DBUS_CALL_FLAGS_NONE,
1000,
g_task_get_cancellable (task),
self->cancellable,
init_check_dbus_error,
task);
}
......@@ -287,7 +294,7 @@ portal_create_session_response_received (GDBusConnection *connection,
g_variant_builder_end (&builder),
G_DBUS_CALL_FLAGS_NONE,
1000,
g_task_get_cancellable (task),
self->cancellable,
init_check_dbus_error,
task);
}
......@@ -314,7 +321,7 @@ on_portal_screencast_proxy_acquired (GObject *source_object,
if (screencast == NULL)
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
g_warning ("Could not get session bus: %s", error->message);
g_warning ("Could not create screencast portal proxy: %s", error->message);
g_task_return_error (task, g_steal_pointer (&error));
return;
......@@ -339,7 +346,7 @@ on_portal_screencast_proxy_acquired (GObject *source_object,
NULL);
g_variant_builder_open (&builder, "a{sv}");
g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_add (&builder, "{sv}", "session_handle_token", g_variant_new_string (session_token));
g_variant_builder_add (&builder, "{sv}", "handle_token", g_variant_new_string (token));
g_variant_builder_close (&builder);
......@@ -349,7 +356,7 @@ on_portal_screencast_proxy_acquired (GObject *source_object,
g_variant_builder_end (&builder),
G_DBUS_CALL_FLAGS_NONE,
1000,
g_task_get_cancellable (task),
self->cancellable,
init_check_dbus_error,
task);
}
......@@ -361,6 +368,25 @@ screencast_portal_async_initable_iface_init (GAsyncInitableIface *iface)
iface->init_finish = screencast_portal_async_initable_init_finish;
}
static void
init_cancelable_cancelled_cb (GTask *task, GCancellable *external)
{
ScreencastPortal *self = SCREENCAST_PORTAL (g_task_get_source_object (task));
/* Ensure no further callbacks are called. */
if (self->portal_signal_id)
{
g_dbus_connection_signal_unsubscribe (g_dbus_proxy_get_connection (self->screencast),
self->portal_signal_id);
self->portal_signal_id = 0;
}
/* Cancel the task and return it immediately. */
g_cancellable_cancel (self->cancellable);
g_task_return_error_if_cancelled (task);
g_object_unref (task);
}
static void
screencast_portal_async_initable_init_async (GAsyncInitable *initable,
int io_priority,
......@@ -369,19 +395,20 @@ screencast_portal_async_initable_init_async (GAsyncInitable *initable,
gpointer user_data)
{
ScreencastPortal *self = SCREENCAST_PORTAL (initable);
g_autoptr(GCancellable) internal_cancellable = NULL;
//g_autoptr(GTask) task = NULL;
GTask *task = NULL;
task = g_task_new (initable, cancellable, callback, user_data);
self->cancellable = g_cancellable_new ();
if (cancellable)
g_signal_connect_object (cancellable,
"cancelled",
(GCallback) init_cancelable_cancelled_cb,
self->cancellable,
G_CONNECT_SWAPPED);
/* Use an internal cancellable if we did not get one. */
if (!cancellable)
{
internal_cancellable = g_cancellable_new ();
cancellable = internal_cancellable;
}
if (g_cancellable_is_cancelled (cancellable))
g_cancellable_cancel (self->cancellable);
task = g_task_new (initable, cancellable, callback, user_data);
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
......@@ -389,7 +416,7 @@ screencast_portal_async_initable_init_async (GAsyncInitable *initable,
"org.freedesktop.portal.Desktop",
"/org/freedesktop/portal/desktop",
SCREEN_CAST_IFACE,
cancellable,
self->cancellable,
on_portal_screencast_proxy_acquired,
task);
}
......@@ -415,6 +442,9 @@ screencast_portal_finalize (GObject *object)
G_OBJECT_CLASS (screencast_portal_parent_class)->finalize (object);
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->cancellable);
g_clear_pointer (&self->session_handle, g_free);
if (self->portal_signal_id)
{
......
......@@ -297,7 +297,7 @@ wfd_video_codec_new_from_desc (gint native, const gchar *descr)
native_res = resolution_table_lookup (native & 0x7, native >> 3);
if (native_res)
res->native = wfd_resolution_copy (native_res);
res->native = wfd_resolution_copy ((WfdResolution*) native_res);
return g_steal_pointer (&res);
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment