expanded gamma lut, with floor
[sparrow.git] / gtk-app.c
blob9e6830ca5dfeafae981fc31c3ac900483ec0acf5
1 /*
2 initially based on an example by Tristan Matthews
3 http://tristanswork.blogspot.com/2008/09/fullscreen-video-in-gstreamer-with-gtk.html
4 */
5 #include <gst/gst.h>
6 #include <gtk/gtk.h>
7 #include <gst/interfaces/xoverlay.h>
8 #include <gdk/gdk.h>
9 #include <gdk/gdkx.h>
10 #include "gtk-app.h"
13 static GstPipeline *
14 make_multi_pipeline(windows_t *windows, int count)
16 GstPipeline *pipeline = GST_PIPELINE(gst_pipeline_new("sparrow_pipeline"));
17 GstElement *tee = pre_tee_pipeline(pipeline);
18 char *reload = NULL;
19 char *save = NULL;
20 int i;
21 for (i = 0; i < count; i++){
22 GstElement *sink = windows->sinks[i];
23 //args are:
24 //(pipeline, tee, sink, int rngseed, int colour, timer flag, int debug flag)
25 /* timer should only run on one of them. colour >= 3 is undefined */
26 int debug = option_debug == i;
27 int timer = option_timer == i;
28 if (option_reload != NULL){
29 if (option_reload[i] == NULL){
30 g_critical("You can't reload some screens and not others!");
31 exit(1);
33 reload = option_reload[i];
35 if (option_save && option_save[i]){
36 save = option_save[i];
38 post_tee_pipeline(pipeline, tee, sink, i, i + 1, timer, debug, save, reload);
40 if (option_avi){
41 /*add a branch saving the video to a file */
42 mjpeg_branch(pipeline, tee);
45 return pipeline;
49 static void
50 bus_call(GstBus * bus, GstMessage *msg, gpointer data)
52 windows_t *windows = (windows_t *)data;
53 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ELEMENT &&
54 gst_structure_has_name(msg->structure, "prepare-xwindow-id")){
55 g_print("Got prepare-xwindow-id msg. option screens: %d\n", option_screens);
56 for (int i = 0; i < option_screens; i++){
57 gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(windows->sinks[i]),
58 windows->xwindows[i]);
59 g_print("connected sink %d to window %lu\n", i, windows->xwindows[i]);
60 hide_mouse(windows->gtk_windows[i]);
65 static void
66 toggle_fullscreen(GtkWidget *widget){
67 GdkWindowState state = gdk_window_get_state(GDK_WINDOW(widget->window));
68 if (state == GDK_WINDOW_STATE_FULLSCREEN){
69 gtk_window_unfullscreen(GTK_WINDOW(widget));
71 else{
72 gtk_window_fullscreen(GTK_WINDOW(widget));
76 static gboolean
77 key_press_event_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
79 g_print("got key %c\n", event->keyval);
80 switch (event->keyval){
81 case 'f':
82 toggle_fullscreen(widget);
83 break;
84 case 'q':
85 g_signal_emit_by_name(widget, "destroy");
86 break;
87 default:
88 break;
90 return TRUE;
93 void destroy_cb(GtkWidget * widget, gpointer data)
95 GMainLoop *loop = (GMainLoop*) data;
96 g_print("Window destroyed\n");
97 g_main_loop_quit(loop);
100 static void
101 video_widget_realize_cb(GtkWidget *widget, gpointer data)
103 windows_t *windows = (windows_t *)data;
104 int r = windows->realised;
105 if (r < MAX_SCREENS){
106 windows->xwindows[r] = GDK_WINDOW_XID(GDK_WINDOW(widget->window));
107 g_print("realised window %d with XID %lu\n", r, windows->xwindows[r]);
109 else {
110 g_print("wtf, there seem to be %d windows!\n", r);
112 windows->realised++;
113 hide_mouse(widget);
117 static void
118 set_up_window(GMainLoop *loop, GtkWidget *window, int screen_no){
119 static const GdkColor black = {0, 0, 0, 0};
120 gtk_window_set_default_size(GTK_WINDOW(window), WIDTH, HEIGHT);
122 if (option_fullscreen){
123 gtk_window_fullscreen(GTK_WINDOW(window));
126 /*if more than one screen is requested, set the screen number.
127 otherwise let it fall were it falls */
128 if (option_screens > 1 || option_first_screen){
129 GdkScreen * screen = gdk_screen_get_default();
130 int width = gdk_screen_get_width(screen);
131 /* XXX placment heuristic is crap */
132 gtk_window_move(GTK_WINDOW(window),
133 (width / 2 * screen_no + 200) % width, 50);
136 // attach key press signal to key press callback
137 gtk_widget_set_events(window, GDK_KEY_PRESS_MASK);
138 g_signal_connect(G_OBJECT(window), "key-press-event", G_CALLBACK(key_press_event_cb), NULL);
139 g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy_cb), loop);
141 gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &black);
142 gtk_widget_show_all(window);
143 hide_mouse(window);
147 gint main (gint argc, gchar *argv[])
149 //initialise threads before any gtk stuff (because not using gtk_init)
150 g_thread_init(NULL);
151 /*this is more complicated than plain gtk_init/gst_init, so that options from
152 all over can be gathered and presented together.
154 GOptionGroup *gst_opts = gst_init_get_option_group();
155 GOptionGroup *gtk_opts = gtk_get_option_group(TRUE);
156 GOptionContext *ctx = g_option_context_new("...!");
157 g_option_context_add_main_entries(ctx, entries, NULL);
158 g_option_context_add_group(ctx, gst_opts);
159 g_option_context_add_group(ctx, gtk_opts);
160 GError *error = NULL;
161 if (!g_option_context_parse(ctx, &argc, &argv, &error)){
162 g_print ("Error initializing: %s\n", GST_STR_NULL(error->message));
163 exit (1);
165 g_option_context_free(ctx);
167 GMainLoop *loop = g_main_loop_new(NULL, FALSE);
169 windows_t windows;
170 windows.realised = 0;
172 int i;
173 for (i = 0; i < option_screens; i++){
174 GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
175 g_signal_connect(window, "realize",
176 G_CALLBACK(video_widget_realize_cb), &windows);
177 /* set up sink here */
178 GstElement *sink = gst_element_factory_make("ximagesink", NULL);
179 set_up_window(loop, window, i + option_first_screen);
180 windows.gtk_windows[i] = window;
181 windows.sinks[i] = sink;
184 GstElement *pipeline = (GstElement *)make_multi_pipeline(&windows, option_screens);
186 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
187 gst_bus_add_watch(bus, (GstBusFunc)bus_call, &windows);
188 gst_object_unref(bus);
190 gst_element_set_state(pipeline, GST_STATE_PLAYING);
192 g_main_loop_run(loop);
194 gst_element_set_state (pipeline, GST_STATE_NULL);
195 gst_object_unref (pipeline);
196 return 0;