1 /*****************************************************************
2 * gmerlin - a general purpose multimedia framework and applications
3 *
4 * Copyright (c) 2001 - 2011 Members of the Gmerlin project
5 * gmerlin-general@lists.sourceforge.net
6 * http://gmerlin.sourceforge.net
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * *****************************************************************/
21
22 #include <string.h>
23
24 #include <config.h>
25 #include <gmerlin/translation.h>
26 #include <gmerlin/pluginregistry.h>
27 #include <gmerlin/cfg_dialog.h>
28
29 #include <gtk/gtk.h>
30 #include <gdk/gdkkeysyms.h>
31 #include <gui_gtk/aboutwindow.h>
32 #include <gui_gtk/gtkutils.h>
33 #include <gui_gtk/audio.h>
34 #include <gui_gtk/plugin.h>
35 #include <gui_gtk/logwindow.h>
36 #include <gmerlin/utils.h>
37 #include <gmerlin/visualize.h>
38
39 #include <gdk/gdkx.h>
40
41 #include <gmerlin/log.h>
42 #define LOG_DOMAIN "gmerlin_visualizer"
43
44 #define TOOLBAR_TRIGGER_KEY (1<<0)
45 #define TOOLBAR_TRIGGER_MOUSE (1<<1)
46
47 #define TOOLBAR_LOCATION_TOP 0
48 #define TOOLBAR_LOCATION_BOTTOM 1
49
50 extern void
51 gtk_decorated_window_move_resize_window(GtkWindow*, int, int, int, int);
52
53
54 typedef struct
55 {
56 GtkWidget * window;
57 GtkWidget * box;
58 GtkWidget * socket;
59 } window_t;
60
61 typedef struct
62 {
63 GtkWidget * window;
64 bg_gtk_plugin_widget_single_t * ra_plugins;
65 bg_gtk_plugin_widget_single_t * ov_plugins;
66 GtkWidget * close_button;
67 } plugin_window_t;
68
69 typedef struct
70 {
71 GtkWidget * config_button;
72 GtkWidget * quit_button;
73 GtkWidget * plugin_button;
74 GtkWidget * restart_button;
75 GtkWidget * log_button;
76 GtkWidget * about_button;
77 GtkWidget * help_button;
78
79 guint log_id;
80 guint about_id;
81
82 GtkWidget * fullscreen_button;
83 GtkWidget * nofullscreen_button;
84
85 GtkWidget * toolbar; /* A GtkEventBox actually... */
86 GtkWidget * fps;
87
88 bg_gtk_plugin_widget_single_t * vis_plugins;
89
90 /* Windows are created by gtk and the x11 plugin
91 is embedded inside after */
92
93 window_t normal_window;
94 window_t fullscreen_window;
95
96 window_t *current_window;
97
98 plugin_window_t plugin_window;
99
100 bg_gtk_vumeter_t * vumeter;
101
102 /* Core stuff */
103
104 gavl_audio_frame_t * audio_frame;
105 gavl_audio_format_t audio_format;
106
107 bg_visualizer_t * visualizer;
108
109 bg_plugin_registry_t * plugin_reg;
110 bg_cfg_registry_t * cfg_reg;
111
112 bg_plugin_handle_t * ra_handle;
113 bg_recorder_plugin_t * ra_plugin;
114
115 const bg_plugin_info_t * ov_info;
116 const bg_plugin_info_t * ra_info;
117 /* Config stuff */
118
119 // bg_cfg_section_t * vumeter_section;
120 bg_cfg_section_t * visualizer_section;
121 bg_cfg_section_t * general_section;
122 bg_cfg_section_t * log_section;
123 bg_dialog_t * cfg_dialog;
124
125 int audio_open;
126 int vis_open;
127
128 int mouse_in_toolbar;
129 int do_hide_toolbar;
130 int toolbar_visible;
131
132 int toolbar_location;
133 int toolbar_trigger;
134
135 int x, y, width, height;
136
137 bg_gtk_log_window_t * log_window;
138
139 bg_ov_callbacks_t cb;
140 } visualizer_t;
141
configure_callback(GtkWidget * w,GdkEventConfigure * event,gpointer data)142 static gboolean configure_callback(GtkWidget * w, GdkEventConfigure *event,
143 gpointer data)
144 {
145 visualizer_t * win;
146
147 win = (visualizer_t*)data;
148 win->x = event->x;
149 win->y = event->y;
150 win->width = event->width;
151 win->height = event->height;
152 gdk_window_get_root_origin(win->current_window->window->window,
153 &win->x, &win->y);
154 return FALSE;
155 }
156
157
get_display_string(visualizer_t * v)158 static char * get_display_string(visualizer_t * v)
159 {
160 char * ret;
161 GdkDisplay * dpy;
162 /* Get the display string */
163
164 gtk_widget_realize(v->normal_window.socket);
165 gtk_widget_realize(v->fullscreen_window.socket);
166 dpy = gdk_display_get_default();
167
168 // ret = bg_sprintf("%s:%08lx:%08lx", gdk_display_get_name(dpy),
169 // GDK_WINDOW_XID(v->normal_window.window->window),
170 // GDK_WINDOW_XID(v->fullscreen_window.window->window));
171
172 ret =
173 bg_sprintf("%s:%08lx:%08lx", gdk_display_get_name(dpy),
174 (long unsigned int)gtk_socket_get_id(GTK_SOCKET(v->normal_window.socket)),
175 (long unsigned int)gtk_socket_get_id(GTK_SOCKET(v->fullscreen_window.socket)));
176
177 return ret;
178 }
179
hide_toolbar(visualizer_t * v)180 static void hide_toolbar(visualizer_t * v)
181 {
182 gtk_widget_hide(v->toolbar);
183 v->toolbar_visible = 0;
184 }
185
toolbar_timeout(void * data)186 static gboolean toolbar_timeout(void * data)
187 {
188 visualizer_t * v;
189 v = (visualizer_t *)data;
190 if(!v->toolbar_visible)
191 return TRUE;
192
193 /* Maybe the toolbar will be hidden next time */
194 if(!v->do_hide_toolbar)
195 {
196 v->do_hide_toolbar = 1;
197 return TRUE;
198 }
199
200 if(!v->mouse_in_toolbar)
201 {
202 hide_toolbar(v);
203 }
204 return TRUE;
205 }
206
fps_timeout(void * data)207 static gboolean fps_timeout(void * data)
208 {
209 float fps;
210 char * tmp_string;
211 visualizer_t * v;
212 v = (visualizer_t *)data;
213
214 if(!v->toolbar_visible || !v->audio_open)
215 return TRUE;
216
217 fps = bg_visualizer_get_fps(v->visualizer);
218 if(fps >= 0.0)
219 {
220 tmp_string = bg_sprintf("Fps: %.2f", fps);
221 gtk_label_set_text(GTK_LABEL(v->fps), tmp_string);
222 free(tmp_string);
223 }
224
225 return TRUE;
226 }
227
show_toolbar(visualizer_t * v)228 static void show_toolbar(visualizer_t * v)
229 {
230 if(!v->toolbar_visible)
231 {
232 gtk_widget_show(v->toolbar);
233 v->toolbar_visible = 1;
234 }
235 v->do_hide_toolbar = 0;
236 }
237
attach_toolbar(visualizer_t * v,window_t * win)238 static void attach_toolbar(visualizer_t * v, window_t * win)
239 {
240 if(v->toolbar_location == TOOLBAR_LOCATION_TOP)
241 gtk_box_pack_start(GTK_BOX(win->box), v->toolbar,
242 FALSE, FALSE, 0);
243 else
244 gtk_box_pack_end(GTK_BOX(win->box), v->toolbar,
245 FALSE, FALSE, 0);
246
247
248 }
249
toggle_fullscreen(visualizer_t * v)250 static void toggle_fullscreen(visualizer_t * v)
251 {
252 if(v->current_window == &v->normal_window)
253 {
254 /* Reparent toolbar */
255 gtk_container_remove(GTK_CONTAINER(v->normal_window.box),
256 v->toolbar);
257 attach_toolbar(v, &v->fullscreen_window);
258 /* Hide normal window, show fullscreen window */
259 gtk_widget_show(v->fullscreen_window.window);
260 gtk_widget_hide(v->normal_window.window);
261
262 gtk_window_fullscreen(GTK_WINDOW(v->fullscreen_window.window));
263 /* Update toolbar */
264 gtk_widget_show(v->nofullscreen_button);
265 gtk_widget_hide(v->fullscreen_button);
266
267 gtk_widget_hide(v->config_button);
268 gtk_widget_hide(v->plugin_button);
269
270 bg_gtk_plugin_widget_single_show_buttons(v->vis_plugins, 0);
271
272 v->current_window = &v->fullscreen_window;
273 }
274 else
275 {
276 /* Reparent toolbar */
277 gtk_container_remove(GTK_CONTAINER(v->fullscreen_window.box),
278 v->toolbar);
279 attach_toolbar(v, &v->normal_window);
280
281 /* Hide normal window, show fullscreen window */
282 gtk_widget_show(v->normal_window.window);
283 gtk_widget_hide(v->fullscreen_window.window);
284
285 /* Update toolbar */
286 gtk_widget_show(v->fullscreen_button);
287 gtk_widget_hide(v->nofullscreen_button);
288
289 gtk_widget_show(v->config_button);
290 gtk_widget_show(v->plugin_button);
291 bg_gtk_plugin_widget_single_show_buttons(v->vis_plugins, 1);
292
293 v->current_window = &v->normal_window;
294 }
295 hide_toolbar(v);
296 v->mouse_in_toolbar = 0;
297 }
298
open_audio(visualizer_t * v)299 static void open_audio(visualizer_t * v)
300 {
301 int i;
302 int was_open;
303 gavl_time_t delay_time = GAVL_TIME_SCALE / 20; /* 50 ms */
304 memset(&v->audio_format, 0, sizeof(v->audio_format));
305 v->audio_format.num_channels = 2;
306 v->audio_format.samplerate = 44100;
307 v->audio_format.sample_format = GAVL_SAMPLE_S16;
308 gavl_set_channel_setup(&v->audio_format);
309
310 if(v->audio_frame)
311 {
312 gavl_audio_frame_destroy(v->audio_frame);
313 v->ra_plugin->close(v->ra_handle->priv);
314 v->audio_frame = NULL;
315 bg_plugin_unref(v->ra_handle);
316 was_open = 1;
317 }
318 else
319 was_open = 0;
320
321 v->audio_open = 0;
322
323 v->ra_handle = bg_plugin_load(v->plugin_reg,
324 v->ra_info);
325 v->ra_plugin = (bg_recorder_plugin_t*)(v->ra_handle->plugin);
326
327 /* The soundcard might be busy from last time,
328 give the kernel some time to free the device */
329
330 if(!v->ra_plugin->open(v->ra_handle->priv, &v->audio_format, NULL))
331 {
332 if(!was_open)
333 {
334 bg_log(BG_LOG_ERROR, LOG_DOMAIN,
335 "Opening audio device failed, fix settings and click restart");
336 gtk_label_set_text(GTK_LABEL(v->fps), TR("No audio"));
337 return;
338 }
339 for(i = 0; i < 20; i++)
340 {
341 gavl_time_delay(&delay_time);
342
343 if(v->ra_plugin->open(v->ra_handle->priv, &v->audio_format, NULL))
344 {
345 v->audio_open = 1;
346 break;
347 }
348 }
349 }
350 else
351 v->audio_open = 1;
352
353 if(v->audio_open)
354 {
355 v->audio_frame = gavl_audio_frame_create(&v->audio_format);
356 bg_gtk_vumeter_set_format(v->vumeter, &v->audio_format);
357 }
358 else
359 {
360 bg_log(BG_LOG_ERROR, LOG_DOMAIN,
361 "Opening audio device failed, fix settings and click restart");
362 gtk_label_set_text(GTK_LABEL(v->fps), TR("No audio"));
363 }
364 }
365
open_vis(visualizer_t * v)366 static void open_vis(visualizer_t * v)
367 {
368 char * display_string = get_display_string(v);
369 bg_visualizer_open_id(v->visualizer, &v->audio_format,
370 v->ov_info, display_string);
371 free(display_string);
372
373
374 v->vis_open = 1;
375 }
376
close_vis(visualizer_t * v)377 static void close_vis(visualizer_t * v)
378 {
379 bg_visualizer_close(v->visualizer);
380 v->vis_open = 0;
381 }
382
grab_notify_callback(GtkWidget * widget,gboolean was_grabbed,gpointer data)383 static void grab_notify_callback(GtkWidget *widget,
384 gboolean was_grabbed,
385 gpointer data)
386 {
387 visualizer_t * win = (visualizer_t*)data;
388 if(!was_grabbed)
389 {
390 bg_gtk_widget_set_can_focus(win->current_window->socket, TRUE);
391 gtk_widget_grab_focus(win->current_window->socket);
392 }
393 }
394
about_window_close_callback(bg_gtk_about_window_t * win,void * data)395 static void about_window_close_callback(bg_gtk_about_window_t* win, void* data)
396 {
397 visualizer_t * v;
398
399 v = (visualizer_t*)data;
400 gtk_widget_set_sensitive(v->about_button, 1);
401 }
402
button_callback(GtkWidget * w,gpointer data)403 static void button_callback(GtkWidget * w, gpointer data)
404 {
405 visualizer_t * win = (visualizer_t*)data;
406
407 if((w == win->quit_button) ||
408 (w == win->normal_window.window))
409 gtk_main_quit();
410 else if(w == win->config_button)
411 bg_dialog_show(win->cfg_dialog, win->current_window->window);
412 else if((w == win->fullscreen_button) ||
413 (w == win->nofullscreen_button))
414 toggle_fullscreen(win);
415 else if(w == win->plugin_button)
416 {
417 gtk_widget_show(win->plugin_window.window);
418 gtk_widget_set_sensitive(win->plugin_button, 0);
419 }
420 else if(w == win->restart_button)
421 {
422 if(win->vis_open)
423 {
424 close_vis(win);
425 open_audio(win);
426 open_vis(win);
427 hide_toolbar(win);
428 }
429 }
430 else if(w == win->log_button)
431 {
432 gtk_widget_set_sensitive(win->log_button, 0);
433 bg_gtk_log_window_show(win->log_window);
434 }
435 else if(w == win->about_button)
436 {
437 gtk_widget_set_sensitive(win->about_button, 0);
438 bg_gtk_about_window_create("Gmerlin visualizer", VERSION,
439 "visualizer_icon.png",
440 about_window_close_callback,
441 win);
442 }
443 else if(w == win->help_button)
444 bg_display_html_help("userguide/Visualizer.html");
445 }
446
plug_removed_callback(GtkWidget * w,gpointer data)447 static gboolean plug_removed_callback(GtkWidget * w, gpointer data)
448 {
449 /* Reuse socket */
450 return TRUE;
451 }
452
plug_added_callback(GtkWidget * w,gpointer data)453 static void plug_added_callback(GtkWidget * w, gpointer data)
454 {
455 visualizer_t * v;
456 v = (visualizer_t *)data;
457 gtk_widget_hide(v->toolbar);
458
459 /* Seems that this is switched off, when an earlier client exited */
460 bg_gtk_widget_set_can_focus(w, TRUE);
461 gtk_widget_grab_focus(w);
462 }
463
464 static gboolean
delete_callback(GtkWidget * w,GdkEventAny * evt,gpointer data)465 delete_callback(GtkWidget * w,
466 GdkEventAny * evt, gpointer data)
467 {
468 button_callback(w, data);
469 return TRUE;
470 }
471
472
plugin_window_button_callback(GtkWidget * w,gpointer data)473 static void plugin_window_button_callback(GtkWidget * w, gpointer data)
474 {
475 visualizer_t * v;
476 v = (visualizer_t *)data;
477 gtk_widget_set_sensitive(v->plugin_button, 1);
478 gtk_widget_hide(v->plugin_window.window);
479 }
480
plugin_window_delete_callback(GtkWidget * w,GdkEventAny * evt,gpointer data)481 static gboolean plugin_window_delete_callback(GtkWidget * w,
482 GdkEventAny * evt,
483 gpointer data)
484 {
485 plugin_window_button_callback(w, data);
486 return TRUE;
487 }
488
set_ra_plugin(const bg_plugin_info_t * plugin,void * data)489 static void set_ra_plugin(const bg_plugin_info_t * plugin,
490 void * data)
491 {
492 visualizer_t * v = (visualizer_t*)data;
493 bg_plugin_registry_set_default(v->plugin_reg, BG_PLUGIN_RECORDER_AUDIO, BG_PLUGIN_RECORDER,
494 plugin->name);
495
496 v->ra_info = plugin;
497 bg_log(BG_LOG_INFO, LOG_DOMAIN,
498 "Changed recording plugin to %s", v->ra_info->long_name);
499 close_vis(v);
500 open_audio(v);
501 open_vis(v);
502 }
503
504
plugin_window_init(plugin_window_t * win,visualizer_t * v)505 static void plugin_window_init(plugin_window_t * win, visualizer_t * v)
506 {
507 int row = 0, num_columns = 4;
508 GtkWidget * table;
509 win->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
510 gtk_window_set_modal(GTK_WINDOW(win->window), TRUE);
511 gtk_window_set_transient_for(GTK_WINDOW(win->window),
512 GTK_WINDOW(v->normal_window.window));
513
514 win->ra_plugins =
515 bg_gtk_plugin_widget_single_create(TR("Audio recorder"),
516 v->plugin_reg,
517 BG_PLUGIN_RECORDER_AUDIO,
518 BG_PLUGIN_ALL);
519
520 bg_gtk_plugin_widget_single_set_change_callback(win->ra_plugins,
521 set_ra_plugin,
522 v);
523
524 win->ov_plugins =
525 bg_gtk_plugin_widget_single_create(TR("Video output"),
526 v->plugin_reg,
527 BG_PLUGIN_OUTPUT_VIDEO,
528 BG_PLUGIN_ALL);
529
530 win->close_button = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
531 g_signal_connect(win->close_button, "clicked",
532 G_CALLBACK(plugin_window_button_callback),
533 v);
534 g_signal_connect(win->window, "delete-event",
535 G_CALLBACK(plugin_window_delete_callback),
536 v);
537
538 gtk_widget_show(win->close_button);
539
540 table = gtk_table_new(3, num_columns, 0);
541 gtk_table_set_row_spacings(GTK_TABLE(table), 5);
542 gtk_table_set_col_spacings(GTK_TABLE(table), 5);
543 gtk_container_set_border_width(GTK_CONTAINER(table), 5);
544 gtk_window_set_position(GTK_WINDOW(win->window), GTK_WIN_POS_CENTER);
545
546 bg_gtk_plugin_widget_single_attach(win->ra_plugins, table,
547 &row, &num_columns);
548 bg_gtk_plugin_widget_single_attach(win->ov_plugins, table,
549 &row, &num_columns);
550
551 gtk_table_attach(GTK_TABLE(table), win->close_button, 0, num_columns,
552 row, row+1,
553 GTK_SHRINK, GTK_SHRINK, 0, 0);
554
555 gtk_widget_show(table);
556 gtk_container_add(GTK_CONTAINER(win->window), table);
557 }
558
motion_callback(void * data,int x,int y,int mask)559 static int motion_callback(void * data, int x, int y, int mask)
560 {
561 visualizer_t * v = (visualizer_t*)data;
562 if(v->toolbar_trigger & TOOLBAR_TRIGGER_MOUSE)
563 show_toolbar(v);
564 return FALSE;
565 }
566
key_callback(GtkWidget * w,GdkEventKey * evt,gpointer data)567 static gboolean key_callback(GtkWidget * w,
568 GdkEventKey * evt,
569 gpointer data)
570 {
571 visualizer_t * v = (visualizer_t*)data;
572
573 // gtk_widget_show(v->toolbar);
574 // g_timeout_add(2000, toolbar_timeout, v);
575 switch(evt->keyval)
576 {
577 case GDK_Tab:
578 case GDK_f:
579 toggle_fullscreen(v);
580 return TRUE;
581 break;
582 case GDK_Escape:
583 if(v->current_window == &v->fullscreen_window)
584 toggle_fullscreen(v);
585 return TRUE;
586 break;
587 case GDK_Menu:
588 if(v->toolbar_trigger & TOOLBAR_TRIGGER_KEY)
589 show_toolbar(v);
590 return TRUE;
591 break;
592 }
593 return FALSE;
594 }
595
window_motion_callback(GtkWidget * widget,GdkEventMotion * event,gpointer data)596 static gboolean window_motion_callback(GtkWidget *widget,
597 GdkEventMotion *event,
598 gpointer data)
599 {
600 visualizer_t * v = (visualizer_t*)data;
601 if(v->toolbar_trigger & TOOLBAR_TRIGGER_MOUSE)
602 show_toolbar(v);
603 return FALSE;
604 }
605
window_init(visualizer_t * v,window_t * w,int fullscreen)606 static void window_init(visualizer_t * v,
607 window_t * w, int fullscreen)
608 {
609 GtkWidget * table;
610 w->window = bg_gtk_window_new(GTK_WINDOW_TOPLEVEL);
611
612 if(!fullscreen)
613 g_signal_connect(G_OBJECT(w->window), "configure-event",
614 G_CALLBACK(configure_callback), (gpointer)v);
615
616 gtk_window_set_title(GTK_WINDOW(w->window), "Gmerlin visualizer");
617 w->socket = gtk_socket_new();
618 w->box = gtk_vbox_new(0, 0);
619 gtk_widget_show(w->box);
620
621 table = gtk_table_new(1, 1, 0);
622
623 gtk_table_attach_defaults(GTK_TABLE(table),w->socket,
624 0, 1, 0, 1);
625 gtk_table_attach_defaults(GTK_TABLE(table),w->box,
626 0, 1, 0, 1);
627
628 gtk_widget_show(table);
629
630 gtk_widget_set_events(w->window,
631 GDK_POINTER_MOTION_MASK);
632
633 gtk_widget_set_events(w->socket,
634 GDK_KEY_PRESS_MASK |
635 GDK_BUTTON_PRESS_MASK );
636
637 // gtk_window_set_focus_on_map(w->window, 0);
638
639 gtk_container_add(GTK_CONTAINER(w->window), table);
640
641 g_signal_connect(G_OBJECT(w->window), "delete_event",
642 G_CALLBACK(delete_callback),
643 v);
644
645 g_signal_connect(G_OBJECT(w->socket), "plug-removed",
646 G_CALLBACK(plug_removed_callback),
647 v);
648
649 g_signal_connect(G_OBJECT(w->socket), "grab-notify",
650 G_CALLBACK(grab_notify_callback),
651 v);
652
653 g_signal_connect(G_OBJECT(w->socket), "plug-added",
654 G_CALLBACK(plug_added_callback),
655 v);
656
657 g_signal_connect(G_OBJECT(w->socket), "key-press-event",
658 G_CALLBACK(key_callback),
659 v);
660
661 g_signal_connect(G_OBJECT(w->window), "motion-notify-event",
662 G_CALLBACK(window_motion_callback),
663 v);
664
665 gtk_widget_show(w->socket);
666
667 if(fullscreen)
668 gtk_window_fullscreen(GTK_WINDOW(w->window));
669 // else
670 // gtk_widget_set_size_request(w->window, 640, 480);
671
672 }
673
create_pixmap_button(visualizer_t * w,const char * filename,const char * tooltip)674 static GtkWidget * create_pixmap_button(visualizer_t * w,
675 const char * filename,
676 const char * tooltip)
677 {
678 GtkWidget * button;
679 GtkWidget * image;
680 char * path;
681 path = bg_search_file_read("icons", filename);
682 if(path)
683 {
684 image = gtk_image_new_from_file(path);
685 free(path);
686 }
687 else
688 image = gtk_image_new();
689
690 gtk_widget_show(image);
691 button = gtk_button_new();
692 gtk_container_add(GTK_CONTAINER(button), image);
693
694 g_signal_connect(G_OBJECT(button), "clicked",
695 G_CALLBACK(button_callback), w);
696
697 gtk_widget_show(button);
698
699 bg_gtk_tooltips_set_tip(button, tooltip, PACKAGE);
700
701 return button;
702 }
703 #if 0
704 static GtkWidget * create_pixmap_toggle_button(visualizer_t * w,
705 const char * filename,
706 const char * tooltip,
707 guint * id)
708 {
709 GtkWidget * button;
710 GtkWidget * image;
711 char * path;
712 path = bg_search_file_read("icons", filename);
713 if(path)
714 {
715 image = gtk_image_new_from_file(path);
716 free(path);
717 }
718 else
719 image = gtk_image_new();
720
721 gtk_widget_show(image);
722 button = gtk_toggle_button_new();
723 gtk_container_add(GTK_CONTAINER(button), image);
724
725 *id = g_signal_connect(G_OBJECT(button), "toggled",
726 G_CALLBACK(button_callback), w);
727
728 gtk_widget_show(button);
729
730 bg_gtk_tooltips_set_tip(button, tooltip, PACKAGE);
731
732 return button;
733 }
734 #endif
735
set_vis_param(void * data,const char * name,const bg_parameter_value_t * val)736 static void set_vis_param(void * data, const char * name,
737 const bg_parameter_value_t * val)
738 {
739 visualizer_t * v;
740 v = (visualizer_t *)data;
741 bg_visualizer_set_parameter(v->visualizer, name, val);
742
743 if(bg_visualizer_need_restart(v->visualizer) && v->vis_open &&
744 !name)
745 {
746 gtk_widget_hide(v->toolbar);
747 close_vis(v);
748 open_vis(v);
749 }
750 }
751
set_general_parameter(void * data,const char * name,const bg_parameter_value_t * val)752 static void set_general_parameter(void * data, const char * name,
753 const bg_parameter_value_t * val)
754 {
755 visualizer_t * v;
756 int i_tmp;
757 v = (visualizer_t *)data;
758
759 if(!name)
760 return;
761
762 if(!strcmp(name, "toolbar_location"))
763 {
764 if(!strcmp(val->val_str, "top"))
765 i_tmp = TOOLBAR_LOCATION_TOP;
766 else
767 i_tmp = TOOLBAR_LOCATION_BOTTOM;
768
769 if(v->toolbar_location != i_tmp)
770 {
771 v->toolbar_location = i_tmp;
772 /* Reparent toolbar */
773 gtk_container_remove(GTK_CONTAINER(v->current_window->box),
774 v->toolbar);
775 attach_toolbar(v, v->current_window);
776 }
777 }
778 else if(!strcmp(name, "toolbar_trigger"))
779 {
780 if(!strcmp(val->val_str, "mouse"))
781 {
782 v->toolbar_trigger =
783 TOOLBAR_TRIGGER_MOUSE;
784 }
785 else if(!strcmp(val->val_str, "key"))
786 {
787 v->toolbar_trigger = TOOLBAR_TRIGGER_KEY;
788 }
789 else if(!strcmp(val->val_str, "mousekey"))
790 {
791 v->toolbar_trigger =
792 TOOLBAR_TRIGGER_MOUSE |
793 TOOLBAR_TRIGGER_KEY;
794 }
795 }
796 else if(!strcmp(name, "x"))
797 v->x = val->val_i;
798 else if(!strcmp(name, "y"))
799 v->y = val->val_i;
800 else if(!strcmp(name, "width"))
801 v->width = val->val_i;
802 else if(!strcmp(name, "height"))
803 v->height = val->val_i;
804 }
805
get_general_parameter(void * data,const char * name,bg_parameter_value_t * val)806 static int get_general_parameter(void * data, const char * name,
807 bg_parameter_value_t * val)
808 {
809 visualizer_t * v;
810 v = (visualizer_t *)data;
811 if(!strcmp(name, "x"))
812 {
813 val->val_i = v->x;
814 return 1;
815 }
816 else if(!strcmp(name, "y"))
817 {
818 val->val_i = v->y;
819 return 1;
820 }
821 else if(!strcmp(name, "width"))
822 {
823 val->val_i = v->width;
824 return 1;
825 }
826 else if(!strcmp(name, "height"))
827 {
828 val->val_i = v->height;
829 return 1;
830 }
831 return 0;
832 }
833
834 bg_parameter_info_t parameters[] =
835 {
836 {
837 .name = "toolbar_location",
838 .long_name = "Toolbar location",
839 .type = BG_PARAMETER_STRINGLIST,
840 .flags = BG_PARAMETER_SYNC,
841 .val_default = { .val_str = "top" },
842 .multi_names = (char const *[]){ "top", "bottom", NULL },
843 .multi_labels = (char const *[]){ "Top", "Bottom", NULL },
844 },
845 {
846 .name = "toolbar_trigger",
847 .long_name = "Toolbar trigger",
848 .type = BG_PARAMETER_STRINGLIST,
849 .val_default = { .val_str = "mousekey" },
850 .multi_names = (char const *[]){ "mouse", "key", "mousekey", NULL },
851 .multi_labels = (char const *[]){ "Mouse motion",
852 "Menu key", "Mouse motion & Menu key",
853 NULL },
854 },
855 {
856 .name = "x",
857 .long_name = "X",
858 .type = BG_PARAMETER_INT,
859 .flags = BG_PARAMETER_HIDE_DIALOG,
860 },
861 {
862 .name = "y",
863 .long_name = "y",
864 .type = BG_PARAMETER_INT,
865 .flags = BG_PARAMETER_HIDE_DIALOG,
866 },
867 {
868 .name = "width",
869 .long_name = "width",
870 .type = BG_PARAMETER_INT,
871 .flags = BG_PARAMETER_HIDE_DIALOG,
872 },
873 {
874 .name = "height",
875 .long_name = "height",
876 .type = BG_PARAMETER_INT,
877 .flags = BG_PARAMETER_HIDE_DIALOG,
878 },
879 { /* End of parameters */ },
880
881 };
882
create_cfg_dialog(visualizer_t * win)883 static bg_dialog_t * create_cfg_dialog(visualizer_t * win)
884 {
885 const bg_parameter_info_t * info;
886 bg_dialog_t * ret;
887 ret = bg_dialog_create_multi(TR("Visualizer configuration"));
888
889 bg_dialog_add(ret,
890 TR("General"),
891 win->general_section,
892 set_general_parameter,
893 NULL,
894 (void*)(win),
895 parameters);
896
897 info = bg_visualizer_get_parameters(win->visualizer);
898 bg_dialog_add(ret,
899 TR("Visualizer"),
900 win->visualizer_section,
901 set_vis_param,
902 NULL,
903 (void*)(win),
904 info);
905
906 info = bg_gtk_log_window_get_parameters(win->log_window);
907 bg_dialog_add(ret,
908 TR("Log window"),
909 win->log_section,
910 bg_gtk_log_window_set_parameter,
911 NULL,
912 (void*)(win->log_window),
913 info);
914
915 return ret;
916 }
917
918
apply_config(visualizer_t * v)919 static void apply_config(visualizer_t * v)
920 {
921 const bg_parameter_info_t * info;
922
923 info = bg_visualizer_get_parameters(v->visualizer);
924
925 bg_cfg_section_apply(v->visualizer_section, info,
926 bg_visualizer_set_parameter,
927 (void*)(v->visualizer));
928
929 bg_cfg_section_apply(v->general_section, parameters,
930 set_general_parameter,
931 (void*)(v));
932
933 info = bg_gtk_log_window_get_parameters(v->log_window);
934
935 bg_cfg_section_apply(v->log_section, info,
936 bg_gtk_log_window_set_parameter,
937 (void*)(v->log_window));
938
939 }
940
get_config(visualizer_t * v)941 static void get_config(visualizer_t * v)
942 {
943 const bg_parameter_info_t * info;
944
945 bg_cfg_section_get(v->general_section, parameters,
946 get_general_parameter,
947 (void*)(v));
948
949 info = bg_gtk_log_window_get_parameters(v->log_window);
950
951 bg_cfg_section_get(v->log_section, info,
952 bg_gtk_log_window_get_parameter,
953 (void*)(v->log_window));
954
955 }
956
idle_func(void * data)957 static gboolean idle_func(void * data)
958 {
959 visualizer_t * v;
960 v = (visualizer_t *)data;
961 if(v->audio_open)
962 {
963 v->ra_plugin->read_audio(v->ra_handle->priv,
964 v->audio_frame, 0, v->audio_format.samples_per_frame);
965 bg_visualizer_update(v->visualizer, v->audio_frame);
966
967 if(v->toolbar_visible)
968 bg_gtk_vumeter_update(v->vumeter, v->audio_frame);
969
970 // bg_visualizer_update(v->visualizer, v->audio_frame);
971 }
972 return TRUE;
973 }
974
975
crossing_callback(GtkWidget * widget,GdkEventCrossing * event,gpointer data)976 static gboolean crossing_callback(GtkWidget *widget,
977 GdkEventCrossing *event,
978 gpointer data)
979 {
980 visualizer_t * v = (visualizer_t*)data;
981
982 if(event->detail == GDK_NOTIFY_INFERIOR)
983 return FALSE;
984
985 v->mouse_in_toolbar = (event->type == GDK_ENTER_NOTIFY) ? 1 : 0;
986 return FALSE;
987 }
988
set_vis_plugin(const bg_plugin_info_t * plugin,void * data)989 static void set_vis_plugin(const bg_plugin_info_t * plugin,
990 void * data)
991 {
992 visualizer_t * v = (visualizer_t*)data;
993 bg_visualizer_set_vis_plugin(v->visualizer, plugin);
994 bg_plugin_registry_set_default(v->plugin_reg, BG_PLUGIN_VISUALIZATION,
995 BG_PLUGIN_VISUALIZE_FRAME | BG_PLUGIN_VISUALIZE_GL,
996 plugin->name);
997 if(bg_visualizer_need_restart(v->visualizer))
998 {
999 close_vis(v);
1000 open_vis(v);
1001 }
1002 hide_toolbar(v);
1003 }
1004
set_vis_parameter(void * data,const char * name,const bg_parameter_value_t * val)1005 static void set_vis_parameter(void * data, const char * name,
1006 const bg_parameter_value_t * val)
1007 {
1008 visualizer_t * v = (visualizer_t*)data;
1009 bg_visualizer_set_vis_parameter(v->visualizer, name, val);
1010 }
1011
log_close_callback(bg_gtk_log_window_t * w,void * data)1012 static void log_close_callback(bg_gtk_log_window_t * w, void * data)
1013 {
1014 visualizer_t * v = (visualizer_t*)data;
1015 gtk_widget_set_sensitive(v->log_button, 1);
1016 }
1017
visualizer_create()1018 static visualizer_t * visualizer_create()
1019 {
1020 const bg_plugin_info_t * info;
1021 char * tmp_path;
1022 int row, col;
1023
1024 GtkWidget * main_table;
1025 GtkWidget * table;
1026 GtkWidget * box;
1027
1028 visualizer_t * ret;
1029 bg_cfg_section_t * cfg_section;
1030
1031 ret = calloc(1, sizeof(*ret));
1032
1033 ret->cb.motion_callback = motion_callback;
1034 ret->cb.data = ret;
1035
1036 window_init(ret, &ret->normal_window, 0);
1037 window_init(ret, &ret->fullscreen_window, 1);
1038 ret->current_window = &ret->normal_window;
1039
1040 ret->log_window = bg_gtk_log_window_create(log_close_callback, ret,
1041 TR("Gmerlin visualizer"));
1042
1043 ret->config_button =
1044 create_pixmap_button(ret, "config_16.png", TRS("Configure"));
1045 ret->plugin_button =
1046 create_pixmap_button(ret, "plugin_16.png", TRS("Recording and display plugins"));
1047 ret->restart_button =
1048 create_pixmap_button(ret, "refresh_16.png", TRS("Restart visualization"));
1049 ret->quit_button =
1050 create_pixmap_button(ret, "quit_16.png", TRS("Quit"));
1051 ret->fullscreen_button =
1052 create_pixmap_button(ret, "fullscreen_16.png", TRS("Fullscreen mode"));
1053 ret->nofullscreen_button =
1054 create_pixmap_button(ret, "windowed_16.png", TRS("Leave fullscreen mode"));
1055
1056 ret->log_button = create_pixmap_button(ret,
1057 "log_16.png",
1058 TRS("Show log window"));
1059 ret->about_button = create_pixmap_button(ret,
1060 "about_16.png",
1061 TRS("About Gmerlin visualizer"));
1062 ret->help_button = create_pixmap_button(ret,
1063 "help_16.png",
1064 TRS("Launch help in a webwroswer"));
1065
1066 ret->fps = gtk_label_new("Fps: --:--");
1067 gtk_misc_set_alignment(GTK_MISC(ret->fps), 0.0, 0.5);
1068 gtk_widget_show(ret->fps);
1069
1070 gtk_widget_hide(ret->nofullscreen_button);
1071
1072 // bg_gtk_box_pack_start_defaults(GTK_BOX(mainbox),
1073 // bg_gtk_vumeter_get_widget(ret->vumeter));
1074
1075 ret->toolbar = gtk_event_box_new();
1076
1077 gtk_widget_set_events(ret->toolbar,
1078 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
1079
1080 g_signal_connect(G_OBJECT(ret->toolbar), "enter-notify-event",
1081 G_CALLBACK(crossing_callback), (gpointer*)ret);
1082
1083 g_signal_connect(G_OBJECT(ret->toolbar), "leave-notify-event",
1084 G_CALLBACK(crossing_callback), (gpointer*)ret);
1085
1086
1087 g_object_ref(ret->toolbar); /* Must be done for widgets, which get
1088 reparented after */
1089
1090 ret->vumeter = bg_gtk_vumeter_create(2, 0);
1091
1092 /* Create actual objects */
1093
1094 /* Create plugin regsitry */
1095 ret->cfg_reg = bg_cfg_registry_create();
1096 tmp_path = bg_search_file_read("visualizer", "config.xml");
1097 bg_cfg_registry_load(ret->cfg_reg, tmp_path);
1098 if(tmp_path)
1099 free(tmp_path);
1100
1101 cfg_section = bg_cfg_registry_find_section(ret->cfg_reg, "plugins");
1102 ret->plugin_reg = bg_plugin_registry_create(cfg_section);
1103 ret->visualizer = bg_visualizer_create(ret->plugin_reg);
1104
1105 bg_visualizer_set_callbacks(ret->visualizer, &ret->cb);
1106
1107 /* Create vis plugin widget */
1108
1109 ret->vis_plugins =
1110 bg_gtk_plugin_widget_single_create(TR("Visualization"),
1111 ret->plugin_reg,
1112 BG_PLUGIN_VISUALIZATION,
1113 BG_PLUGIN_VISUALIZE_FRAME |
1114 BG_PLUGIN_VISUALIZE_GL);
1115
1116 bg_gtk_plugin_widget_single_set_change_callback(ret->vis_plugins,
1117 set_vis_plugin,
1118 ret);
1119
1120 bg_gtk_plugin_widget_single_set_parameter_callback(ret->vis_plugins,
1121 set_vis_parameter,
1122 ret);
1123
1124 /* Create audio and video plugin widgets */
1125
1126 plugin_window_init(&ret->plugin_window, ret);
1127
1128 /* Get ov info */
1129
1130 ret->ov_info =
1131 bg_gtk_plugin_widget_single_get_plugin(ret->plugin_window.ov_plugins);
1132
1133 /* Load recording plugin */
1134 ret->ra_info =
1135 bg_gtk_plugin_widget_single_get_plugin(ret->plugin_window.ra_plugins);
1136
1137 /* Create config stuff */
1138
1139 ret->visualizer_section =
1140 bg_cfg_registry_find_section(ret->cfg_reg, "visualizer");
1141 ret->general_section =
1142 bg_cfg_registry_find_section(ret->cfg_reg, "general");
1143 ret->log_section =
1144 bg_cfg_registry_find_section(ret->cfg_reg, "log");
1145
1146 ret->cfg_dialog = create_cfg_dialog(ret);
1147
1148
1149
1150 /* Pack everything */
1151
1152 main_table = gtk_table_new(2, 2, 0);
1153
1154 gtk_table_set_row_spacings(GTK_TABLE(main_table), 5);
1155 gtk_table_set_col_spacings(GTK_TABLE(main_table), 5);
1156 gtk_container_set_border_width(GTK_CONTAINER(main_table), 5);
1157
1158 table = gtk_table_new(1, 4, 0);
1159
1160 gtk_table_set_row_spacings(GTK_TABLE(table), 5);
1161 gtk_table_set_col_spacings(GTK_TABLE(table), 5);
1162 gtk_container_set_border_width(GTK_CONTAINER(table), 5);
1163
1164
1165 row = 0;
1166 col = 0;
1167 bg_gtk_plugin_widget_single_attach(ret->vis_plugins,
1168 table,
1169 &row, &col);
1170 gtk_widget_show(table);
1171
1172 gtk_table_attach(GTK_TABLE(main_table), table, 0, 1, 0, 1,
1173 GTK_FILL, GTK_SHRINK, 0, 0);
1174
1175 box = gtk_hbox_new(0, 0);
1176 gtk_box_pack_start(GTK_BOX(box), ret->plugin_button,
1177 FALSE, FALSE, 0);
1178 gtk_box_pack_start(GTK_BOX(box), ret->config_button,
1179 FALSE, FALSE, 0);
1180 gtk_box_pack_start(GTK_BOX(box), ret->restart_button,
1181 FALSE, FALSE, 0);
1182 gtk_box_pack_start(GTK_BOX(box), ret->fullscreen_button,
1183 FALSE, FALSE, 0);
1184 gtk_box_pack_start(GTK_BOX(box), ret->nofullscreen_button,
1185 FALSE, FALSE, 0);
1186 gtk_box_pack_start(GTK_BOX(box), ret->log_button,
1187 FALSE, FALSE, 0);
1188 gtk_box_pack_start(GTK_BOX(box), ret->about_button,
1189 FALSE, FALSE, 0);
1190 gtk_box_pack_start(GTK_BOX(box), ret->help_button,
1191 FALSE, FALSE, 0);
1192 gtk_box_pack_start(GTK_BOX(box), ret->quit_button,
1193 FALSE, FALSE, 0);
1194 gtk_box_pack_start(GTK_BOX(box), ret->fps, TRUE, TRUE, 5);
1195 gtk_widget_show(box);
1196
1197 gtk_table_attach(GTK_TABLE(main_table), box, 0, 1, 1, 2,
1198 GTK_FILL, GTK_SHRINK, 0, 0);
1199
1200 gtk_table_attach(GTK_TABLE(main_table),
1201 bg_gtk_vumeter_get_widget(ret->vumeter),
1202 1, 2, 0, 2,
1203 GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
1204
1205
1206 gtk_widget_show(main_table);
1207
1208 gtk_container_add(GTK_CONTAINER(ret->toolbar), main_table);
1209
1210 // gtk_widget_show(ret->toolbar);
1211
1212 /* Start with non-fullscreen mode */
1213 attach_toolbar(ret, &ret->normal_window);
1214
1215 apply_config(ret);
1216
1217 /* Get visualization plugin */
1218 info = bg_gtk_plugin_widget_single_get_plugin(ret->vis_plugins);
1219 bg_visualizer_set_vis_plugin(ret->visualizer, info);
1220
1221 /* Initialize stuff */
1222 open_audio(ret);
1223 open_vis(ret);
1224
1225
1226 gtk_widget_show(ret->current_window->window);
1227
1228 if(ret->width && ret->height)
1229 gtk_decorated_window_move_resize_window(GTK_WINDOW(ret->current_window->window),
1230 ret->x, ret->y,
1231 ret->width, ret->height);
1232 else
1233 gtk_decorated_window_move_resize_window(GTK_WINDOW(ret->current_window->window),
1234 100, 100,
1235 640, 480);
1236
1237 while(gdk_events_pending() || gtk_events_pending())
1238 gtk_main_iteration();
1239
1240
1241 g_idle_add(idle_func, ret);
1242
1243 g_timeout_add(3000, toolbar_timeout, ret);
1244 g_timeout_add(1000, fps_timeout, ret);
1245
1246 return ret;
1247 }
1248
visualizer_destroy(visualizer_t * v)1249 static void visualizer_destroy(visualizer_t * v)
1250 {
1251 char * tmp_path;
1252 get_config(v);
1253 tmp_path = bg_search_file_write("visualizer", "config.xml");
1254 bg_cfg_registry_save(v->cfg_reg, tmp_path);
1255 if(tmp_path)
1256 free(tmp_path);
1257 free(v);
1258 }
1259
main(int argc,char ** argv)1260 int main(int argc, char ** argv)
1261 {
1262 visualizer_t * win;
1263
1264 bg_gtk_init(&argc, &argv, "visualizer_icon.png", NULL, NULL);
1265
1266 win = visualizer_create();
1267 gtk_main();
1268
1269 if(win->vis_open)
1270 bg_visualizer_close(win->visualizer);
1271 visualizer_destroy(win);
1272 return 0;
1273 }
1274