commit 9fb1a5d25f79281977768f5514401162c4f45eff
parent 027bc5b314c3f2e36937956d2d75f5ea2d62b62a
Author: Jacki <jacki@thejackimonster.de>
Date: Wed, 31 Jul 2024 16:46:14 +0200
Link video stream into discourse panel as widget
Signed-off-by: Jacki <jacki@thejackimonster.de>
Diffstat:
5 files changed, 212 insertions(+), 3 deletions(-)
diff --git a/resources/ui/discourse_panel.ui b/resources/ui/discourse_panel.ui
@@ -36,6 +36,7 @@ Author: Tobias Frisch
<property name="width-request">124</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
+ <property name="valign">center</property>
<property name="border-width">8</property>
<property name="orientation">vertical</property>
<property name="spacing">4</property>
diff --git a/src/discourse.c b/src/discourse.c
@@ -176,7 +176,7 @@ _setup_video_gst_pipelines_of_subscription(MESSENGER_DiscourseSubscriptionInfo *
gst_caps_unref(caps);
- gst_element_set_state(info->video_stream_pipeline, GST_STATE_PLAYING);
+ gst_element_set_state(info->video_stream_pipeline, GST_STATE_NULL);
}
}
@@ -373,6 +373,59 @@ discourse_subscription_stream_message(MESSENGER_DiscourseSubscriptionInfo *info,
_stream_video_message(info, message, available);
}
+static gboolean
+discourse_subscription_link_widget(MESSENGER_DiscourseSubscriptionInfo *info,
+ GtkContainer *container,
+ gboolean link)
+{
+ g_assert((info) && (container));
+
+ GtkWidget *widget;
+ if (info->video_stream_sink)
+ g_object_get(info->video_stream_sink, "widget", &widget, NULL);
+ else
+ widget = NULL;
+
+ if (!widget)
+ return FALSE;
+
+ GtkWidget *parent = gtk_widget_get_parent(widget);
+
+ if (parent)
+ {
+ GtkContainer *container = GTK_CONTAINER(parent);
+
+ gst_element_set_state(info->video_stream_pipeline, GST_STATE_NULL);
+
+ gtk_widget_hide(widget);
+ gtk_widget_unrealize(widget);
+
+ gtk_container_remove(
+ container,
+ widget
+ );
+ }
+
+ if (!link)
+ return TRUE;
+
+ gtk_box_pack_start(
+ GTK_BOX(container),
+ widget,
+ true,
+ true,
+ 0
+ );
+
+ g_object_unref(widget);
+ gtk_widget_realize(widget);
+
+ gtk_widget_show_all(GTK_WIDGET(container));
+
+ gst_element_set_state(info->video_stream_pipeline, GST_STATE_PLAYING);
+ return TRUE;
+}
+
static void
_setup_audio_gst_pipelines(MESSENGER_DiscourseInfo *info)
{
@@ -789,3 +842,58 @@ discourse_is_mute(struct GNUNET_CHAT_Discourse *discourse)
return (GST_STATE_PLAYING != state);
}
+
+gboolean
+discourse_link_widget(const struct GNUNET_CHAT_Discourse *discourse,
+ const struct GNUNET_CHAT_Contact *contact,
+ GtkContainer *container)
+{
+ MESSENGER_DiscourseInfo* info = GNUNET_CHAT_discourse_get_user_pointer(discourse);
+
+ if (!info)
+ return FALSE;
+
+ GList *sub = info->subscriptions;
+ MESSENGER_DiscourseSubscriptionInfo *sub_info = NULL;
+
+ while (sub)
+ {
+ sub_info = (MESSENGER_DiscourseSubscriptionInfo*) (sub->data);
+ if (contact == sub_info->contact)
+ break;
+
+ sub = g_list_next(sub);
+ }
+
+ if (!sub_info)
+ return FALSE;
+
+ return discourse_subscription_link_widget(sub_info, container, TRUE);
+}
+
+gboolean
+discourse_unlink_widget(const struct GNUNET_CHAT_Discourse *discourse,
+ const struct GNUNET_CHAT_Contact *contact)
+{
+ MESSENGER_DiscourseInfo* info = GNUNET_CHAT_discourse_get_user_pointer(discourse);
+
+ if (!info)
+ return FALSE;
+
+ GList *sub = info->subscriptions;
+ MESSENGER_DiscourseSubscriptionInfo *sub_info = NULL;
+
+ while (sub)
+ {
+ sub_info = (MESSENGER_DiscourseSubscriptionInfo*) (sub->data);
+ if (contact == sub_info->contact)
+ break;
+
+ sub = g_list_next(sub);
+ }
+
+ if (!sub_info)
+ return FALSE;
+
+ return discourse_subscription_link_widget(sub_info, NULL, FALSE);
+}
diff --git a/src/discourse.h b/src/discourse.h
@@ -29,6 +29,7 @@
#include <glib-2.0/glib.h>
#include <gnunet/gnunet_chat_lib.h>
+#include <gtk-3.0/gtk/gtk.h>
#include <pthread.h>
/**
@@ -185,4 +186,29 @@ discourse_set_mute(struct GNUNET_CHAT_Discourse *discourse,
bool
discourse_is_mute(struct GNUNET_CHAT_Discourse *discourse);
+/**
+ * Links a widget from the video pipeline of a discourse
+ * for a given chat contact to a selected container as
+ * child.
+ *
+ * @param discourse Chat discourse
+ * @param contact Chat contact
+ * @param container Container
+ */
+gboolean
+discourse_link_widget(const struct GNUNET_CHAT_Discourse *discourse,
+ const struct GNUNET_CHAT_Contact *contact,
+ GtkContainer *container);
+
+/**
+ * Unlinks a widget from the video pipeline of a discourse
+ * for a given chat contact from its current parent.
+ *
+ * @param discourse Chat discourse
+ * @param contact Chat contact
+ */
+gboolean
+discourse_unlink_widget(const struct GNUNET_CHAT_Discourse *discourse,
+ const struct GNUNET_CHAT_Contact *contact);
+
#endif /* DISCOURSE_H_ */
diff --git a/src/ui/discourse.c b/src/ui/discourse.c
@@ -24,6 +24,7 @@
#include "discourse.h"
+#include <glib-2.0/glib.h>
#include <gnunet/gnunet_common.h>
#include <gnunet/gnunet_chat_lib.h>
#include <gnunet/gnunet_time_lib.h>
@@ -413,6 +414,7 @@ append_group_contacts(void *cls,
struct IterateDiscourseClosure {
MESSENGER_Application *app;
+ UI_DISCOURSE_Handle *handle;
GtkContainer *container;
};
@@ -433,6 +435,10 @@ iterate_ui_discourse_update_discourse_members(void *cls,
UI_DISCOURSE_PANEL_Handle* panel = ui_discourse_panel_new(closure->app);
ui_discourse_panel_set_contact(panel, contact);
+ GtkWidget *parent = gtk_widget_get_parent(panel->panel_box);
+ if (parent)
+ gtk_container_remove(GTK_CONTAINER(parent), panel->panel_box);
+
gtk_flow_box_insert(flowbox, panel->panel_box, -1);
GtkFlowBoxChild *child = GTK_FLOW_BOX_CHILD(
@@ -466,6 +472,56 @@ iterate_ui_discourse_update_context_discourses(void *cls,
return GNUNET_YES;
}
+struct IterateDiscourseVideoClosure {
+ MESSENGER_Application *app;
+ UI_DISCOURSE_Handle *handle;
+ GList *children;
+};
+
+static enum GNUNET_GenericReturnValue
+iterate_ui_discourse_update_discourse_video(void *cls,
+ const struct GNUNET_CHAT_Discourse *discourse,
+ struct GNUNET_CHAT_Contact *contact)
+{
+ g_assert((cls) && (discourse) && (contact));
+
+ struct IterateDiscourseVideoClosure *closure = (
+ (struct IterateDiscourseVideoClosure*) cls
+ );
+
+ GList *list = closure->children;
+ while (list)
+ {
+ GtkFlowBoxChild *child = GTK_FLOW_BOX_CHILD(list->data);
+
+ UI_DISCOURSE_PANEL_Handle* panel = (UI_DISCOURSE_PANEL_Handle*) (
+ g_object_get_qdata(
+ G_OBJECT(child),
+ closure->app->quarks.ui
+ )
+ );
+
+ if (contact != panel->contact)
+ goto skip_child;
+
+ const gboolean linked = discourse_link_widget(
+ discourse,
+ contact,
+ GTK_CONTAINER(panel->video_box)
+ );
+
+ if (linked)
+ gtk_stack_set_visible_child(panel->panel_stack, panel->video_box);
+ else
+ gtk_stack_set_visible_child(panel->panel_stack, panel->avatar_box);
+
+ skip_child:
+ list = g_list_next(list);
+ }
+
+ return GNUNET_YES;
+}
+
static void
_discourse_update_members(UI_DISCOURSE_Handle *handle)
{
@@ -497,6 +553,7 @@ _discourse_update_members(UI_DISCOURSE_Handle *handle)
struct IterateDiscourseClosure closure;
closure.app = handle->app;
+ closure.handle = handle;
closure.container = GTK_CONTAINER(handle->members_flowbox);
GNUNET_CHAT_context_iterate_discourses(
@@ -504,6 +561,23 @@ _discourse_update_members(UI_DISCOURSE_Handle *handle)
iterate_ui_discourse_update_context_discourses,
&closure
);
+
+ list = gtk_container_get_children(GTK_CONTAINER(handle->members_flowbox));
+ if (list)
+ {
+ struct IterateDiscourseVideoClosure closure_video;
+ closure_video.app = handle->app;
+ closure_video.handle = handle;
+ closure_video.children = list;
+
+ GNUNET_CHAT_discourse_iterate_contacts(
+ handle->video_discourse,
+ iterate_ui_discourse_update_discourse_video,
+ &closure_video
+ );
+
+ g_list_free(list);
+ }
}
static enum GNUNET_GenericReturnValue
diff --git a/src/ui/play_media.c b/src/ui/play_media.c
@@ -249,8 +249,8 @@ _adjust_playing_media_state(UI_PLAY_MEDIA_Handle *handle, gboolean playing)
if (handle->preview_stack)
gtk_stack_set_visible_child(
- handle->preview_stack,
- handle->video_box
+ handle->preview_stack,
+ handle->video_box
);
}