Convert README to README.rst for Github co-hosting
[sparrow.git] / gtk-clutter-app.c
blobf510950072331f1cc34875a64c49206a9f4a36fc
2 #include <gst/gst.h>
3 #include <gtk/gtk.h>
4 #include <gst/interfaces/xoverlay.h>
5 #include <gdk/gdk.h>
6 #include <gdk/gdkx.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>
13 #include "app.h"
15 typedef struct windows_s {
16 GstElement *sinks[2];
17 ClutterActor *stages[2];
18 XID windows[2];
19 int n;
20 } windows_t;
23 static void
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]);
36 static void
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));
42 else{
43 gtk_window_fullscreen(GTK_WINDOW(widget));
48 static gboolean
49 key_press_event_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
51 g_print("got key %c\n", event->keyval);
52 switch (event->keyval){
53 case 'f':
54 toggle_fullscreen(widget);
55 break;
56 case 'q':
57 g_signal_emit_by_name(widget, "destroy");
58 break;
59 default:
60 break;
62 return TRUE;
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);
72 static void
73 video_widget_realize_cb (GtkWidget * widget, gpointer data)
75 windows_t *w = (windows_t *)data;
76 if (w->n < 2){
77 w->windows[w->n] = GDK_WINDOW_XID(GDK_WINDOW(widget->window));
79 else {
80 g_print("wtf, there seem to be %d windows!\n", w->n);
82 w->n++;
83 return;
87 static void
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);
106 ClutterActor *
107 new_stage(void){
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));
113 return stage;
117 gint main (gint argc, gchar *argv[])
119 /* initialization */
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 */
125 windows_t windows;
126 windows.n = 0;
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,
142 "sync-size", FALSE,
143 "disable-slicing", TRUE,
144 NULL);
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,
149 "sync-size", FALSE,
150 "disable-slicing", TRUE,
151 NULL);
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);
187 return 0;