4 #include <gst/interfaces/xoverlay.h>
7 #include <clutter-gst/clutter-gst.h>
8 #include <clutter-gtk/clutter-gtk.h>
9 #include <clutter/clutter.h>
10 #include <clutter/x11/clutter-x11.h>
15 typedef struct windows_s
{
17 ClutterActor
*stages
[2];
24 bus_call(GstBus
* bus
, GstMessage
*msg
, gpointer data
)
26 windows_t
*w
= (windows_t
*)data
;
27 if (GST_MESSAGE_TYPE(msg
) == GST_MESSAGE_ELEMENT
&&
28 gst_structure_has_name(msg
->structure
, "prepare-xwindow-id")){
29 g_print("Got prepare-xwindow-id msg\n");
30 for (int i
= 0; i
< 2; i
++){
31 clutter_x11_set_stage_foreign(CLUTTER_STAGE(w
->stages
[i
]), w
->windows
[i
]);
37 toggle_fullscreen(GtkWidget
*widget
){
38 GdkWindowState state
= gdk_window_get_state(GDK_WINDOW(widget
->window
));
39 if (state
== GDK_WINDOW_STATE_FULLSCREEN
){
40 gtk_window_unfullscreen(GTK_WINDOW(widget
));
43 gtk_window_fullscreen(GTK_WINDOW(widget
));
49 key_press_event_cb(GtkWidget
*widget
, GdkEventKey
*event
, gpointer data
)
51 g_print("got key %c\n", event
->keyval
);
52 switch (event
->keyval
){
54 toggle_fullscreen(widget
);
57 g_signal_emit_by_name(widget
, "destroy");
65 void destroy_cb(GtkWidget
* widget
, gpointer data
)
67 GMainLoop
*loop
= (GMainLoop
*) data
;
68 g_print("Window destroyed\n");
69 g_main_loop_quit(loop
);
73 video_widget_realize_cb (GtkWidget
* widget
, gpointer data
)
75 windows_t
*w
= (windows_t
*)data
;
77 w
->windows
[w
->n
] = GDK_WINDOW_XID(GDK_WINDOW(widget
->window
));
80 g_print("wtf, there seem to be %d windows!\n", w
->n
);
88 set_up_window(GMainLoop
*loop
, GtkWidget
*window
){
89 static const GdkColor black
= {0, 0, 0, 0};
90 gtk_window_set_default_size(GTK_WINDOW(window
), WIDTH
, HEIGHT
);
92 //gtk_window_fullscreen(GTK_WINDOW(widget));
93 //GdkScreen *screen = gdk_display_get_screen(0|1);
94 //gtk_window_set_screen(GTK_WINDOW(window), screen);
96 // attach key press signal to key press callback
97 gtk_widget_set_events(window
, GDK_KEY_PRESS_MASK
);
98 g_signal_connect(G_OBJECT(window
), "key-press-event", G_CALLBACK(key_press_event_cb
), NULL
);
99 g_signal_connect(G_OBJECT(window
), "destroy", G_CALLBACK(destroy_cb
), loop
);
101 gtk_widget_modify_bg(window
, GTK_STATE_NORMAL
, &black
);
102 gtk_widget_show_all(window
);
108 static const ClutterColor black
= {0, 0, 0, 255};
109 ClutterActor
*stage
= clutter_stage_get_default();
110 clutter_stage_set_color(CLUTTER_STAGE(stage
), &black
);
111 clutter_stage_set_fullscreen(CLUTTER_STAGE(stage
), TRUE
);
112 clutter_stage_hide_cursor(CLUTTER_STAGE(stage
));
117 gint
main (gint argc
, gchar
*argv
[])
120 gst_init (&argc
, &argv
);
121 gtk_init(&argc
, &argv
);
122 clutter_init(&argc
, &argv
);
124 /* herein we count windows and map them to sinks */
128 GMainLoop
*loop
= g_main_loop_new(NULL
, FALSE
);
129 GtkWidget
*window1
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
130 GtkWidget
*window2
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
131 g_signal_connect (window1
, "realize",
132 G_CALLBACK (video_widget_realize_cb
), &windows
);
133 g_signal_connect (window2
, "realize",
134 G_CALLBACK (video_widget_realize_cb
), &windows
);
136 /* Make a timeline */
137 ClutterTimeline
*timeline
= clutter_timeline_new(1000);
138 g_object_set(timeline
, "loop", TRUE
, NULL
);
140 ClutterActor
*stage1
= new_stage();
141 ClutterTexture
*texture1
= g_object_new (CLUTTER_TYPE_TEXTURE
,
143 "disable-slicing", TRUE
,
145 GstElement
*sink1
= clutter_gst_video_sink_new(CLUTTER_TEXTURE(texture1
));
147 ClutterActor
*stage2
= new_stage();
148 ClutterTexture
*texture2
= g_object_new (CLUTTER_TYPE_TEXTURE
,
150 "disable-slicing", TRUE
,
152 GstElement
*sink2
= clutter_gst_video_sink_new(CLUTTER_TEXTURE(texture2
));
155 /*To avoid flickering on show, you should call gtk_widget_show() or
156 gtk_widget_realize() before calling clutter_actor_show() */
158 //GstElement *sink1 = gst_element_factory_make("ximagesink", "sink1");
159 //GstElement *sink2 = gst_element_factory_make("ximagesink", "sink2");
161 GstElement
*pipeline
= (GstElement
*)make_dual_pipeline(sink1
, sink2
);
163 windows
.sinks
[0] = sink1
;
164 windows
.sinks
[1] = sink2
;
165 windows
.stages
[0] = stage1
;
166 windows
.stages
[1] = stage2
;
168 set_up_window(loop
, window1
);
169 set_up_window(loop
, window2
);
171 GstBus
*bus
= gst_pipeline_get_bus(GST_PIPELINE(pipeline
));
172 gst_bus_add_watch(bus
, (GstBusFunc
)bus_call
, &windows
);
173 gst_object_unref(bus
);
175 gst_element_set_state(pipeline
, GST_STATE_PLAYING
);
176 /* start the timeline */
177 clutter_timeline_start(timeline
);
178 clutter_group_add(CLUTTER_GROUP(stage1
), texture1
);
179 clutter_group_add(CLUTTER_GROUP(stage2
), texture2
);
180 clutter_actor_show_all(stage1
);
181 clutter_actor_show_all(stage2
);
183 g_main_loop_run(loop
);
185 gst_element_set_state (pipeline
, GST_STATE_NULL
);
186 gst_object_unref (pipeline
);