join clips and status control to same 'operate' page
[rugen] / src / page_status.c
1 /*
2 * page_status.c -- Status Page Handling
3 * Copyright (C) 2002-2003 Charles Yates <charles.yates@pandora.be>
4 * Copyright (C) 2010 Dan Dennedy <dan@dennedy.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <gtk/gtk.h>
29
30 #include "interface.h"
31 #include "support.h"
32 #include "dv1394app.h"
33 #include "page.h"
34
35 typedef struct
36 {
37 struct page_t parent;
38 dv1394app app;
39 GtkWidget *widget;
40 mvcp status;
41 int terminated;
42 pthread_t status_thread;
43 guint context;
44 int unit;
45 int count;
46 struct page_t *parent_page;
47 }
48 *page_status, page_status_t;
49
50 static GtkWidget *this_page_get_widget( page );
51
52 /** Show the status associated to a unit.
53 */
54
55 static char* status_to_text( mvcp_status status )
56 {
57 switch( status->status )
58 {
59 case unit_offline: return "offline"; break;
60 case unit_undefined: return "undefined"; break;
61 case unit_not_loaded: return "unloaded"; break;
62 case unit_stopped: return "stopped"; break;
63 case unit_playing: return "playing"; break;
64 case unit_paused: return "paused"; break;
65 case unit_disconnected: return "disconnect"; break;
66 case unit_unknown: return "unknown"; break;
67 }
68 return "unknown";
69 }
70
71 static int show_status( page_status this, mvcp_status status )
72 {
73 GtkWidget *widget = this_page_get_widget( ( page )this );
74 char temp[ 1024 ] = "";
75 char temp2[ 1024 ];
76 char label_name[ 256 ];
77 char tc1[12], tc2[12], tc3[12];
78
79 sprintf( temp, "[%s] IN:%s POS:%s OUT:%s %s",
80 status_to_text( status ),
81 frames2tc(status->in, status->fps, tc1),
82 frames2tc(status->position, status->fps, tc2),
83 frames2tc(status->out, status->fps, tc3),
84 status->clip
85 );
86
87 sprintf( label_name, "label_unit_%d", status->unit );
88
89 gdk_threads_enter();
90 widget = lookup_widget( widget, label_name );
91 gtk_label_set_text( GTK_LABEL( widget ), temp );
92 if ( status->unit == dv1394app_get_selected_unit( this->app ) )
93 {
94 sprintf( temp2, "U%d - %s", status->unit, temp );
95 widget = lookup_widget( dv1394app_get_widget( this->app ), "statusbar" );
96 gtk_statusbar_pop( GTK_STATUSBAR( widget ), this->context );
97 gtk_statusbar_push( GTK_STATUSBAR( widget ), this->context, temp2 );
98 dv1394app_show_status( this->app, status );
99 }
100 gdk_flush();
101 gdk_threads_leave();
102
103 return status->unit >= this->count;
104 }
105
106 static void show_units( page_status this, gboolean active )
107 {
108 int index = 0;
109 int index2 = 0;
110
111 GtkWidget *widget;
112 char temp[ 1024 ] = "";
113 char button_name[ 256 ];
114
115 mvcp_units units = NULL;
116 mvcp_unit_entry_t unit;
117 int unit_count = 0;
118
119 mvcp_nodes nodes = NULL;
120 mvcp_node_entry_t node;
121 int node_count = 0;
122
123 if ( active )
124 {
125 units = mvcp_units_init( this->status );
126 unit_count = mvcp_units_count( units );
127 nodes = mvcp_nodes_init( this->status );
128 node_count = mvcp_nodes_count( nodes );
129 this->count = unit_count;
130 }
131
132 gdk_threads_enter();
133
134 for ( index = 0; index < MAX_UNITS; index ++ )
135 {
136 if ( index < unit_count )
137 {
138 mvcp_units_get( units, index, &unit );
139
140 for ( index2 = 0; index2 < node_count; index2 ++ )
141 {
142 mvcp_nodes_get( nodes, index2, &node );
143 if ( !strcmp( node.guid, unit.guid ) )
144 break;
145 }
146
147 if ( index2 < node_count )
148 sprintf( temp, "U%d - %s (%s)", unit.unit, node.name, unit.guid );
149 else
150 sprintf( temp, "U%d - %s", unit.unit, unit.guid );
151
152 sprintf( button_name, "radiobutton_%d", index );
153 widget = lookup_widget( this_page_get_widget( ( page )this ), button_name );
154 gtk_widget_show( widget );
155 gtk_button_set_label( GTK_BUTTON( widget ), temp );
156 sprintf( button_name, "label_unit_%d", index );
157 widget = lookup_widget( this_page_get_widget( ( page )this ), button_name );
158 gtk_widget_show( widget );
159 }
160 else
161 {
162 sprintf( button_name, "radiobutton_%d", index );
163 widget = lookup_widget( this_page_get_widget( ( page )this ), button_name );
164 gtk_widget_hide( widget );
165 sprintf( button_name, "label_unit_%d", index );
166 widget = lookup_widget( this_page_get_widget( ( page )this ), button_name );
167 gtk_widget_hide( widget );
168 }
169 }
170 gdk_flush();
171 gdk_threads_leave();
172
173 mvcp_notifier notifier = mvcp_get_notifier( this->status );
174 mvcp_status_t status;
175
176 for ( index = 0; index < MAX_UNITS; index ++ )
177 {
178 status.unit = index;
179 if ( !active )
180 status.status = unit_disconnected;
181 else
182 mvcp_notifier_get( notifier, &status, index );
183 show_status( this, &status );
184 }
185
186 if ( active )
187 {
188 mvcp_nodes_close( nodes );
189 mvcp_units_close( units );
190 }
191 }
192
193 /** Status monitoring thread.
194 */
195
196 static void *status_thread( void *arg )
197 {
198 page_status this = arg;
199 mvcp_notifier notifier = mvcp_get_notifier( this->status );
200 mvcp_status_t status;
201
202 show_units( this, TRUE );
203
204 while ( !this->terminated )
205 {
206 if ( mvcp_notifier_wait( notifier, &status ) != -1 )
207 {
208 char buf[32];
209
210 if ( status.status == unit_disconnected )
211 {
212 this->app->eof = 0;
213 break;
214 }
215 if ( show_status( this, &status ) )
216 show_units( this, TRUE );
217 if ( !this->app->eof && mvcp_unit_get( this->app->command, this->app->selected_unit,
218 "eof", buf, sizeof(buf) ) != -1)
219 this->app->eof = buf[0];
220 }
221 }
222
223 show_units( this, FALSE );
224
225 if ( !this->terminated )
226 {
227 GtkWidget *widget = lookup_widget( dv1394app_get_widget( this->app ), "button_disconnect" );
228 gdk_threads_enter();
229 gtk_signal_emit_by_name( GTK_OBJECT( widget ), "clicked" );
230 gdk_threads_leave();
231 }
232
233 return NULL;
234 }
235
236 void on_radiobutton_toggled( GtkToggleButton *togglebutton, gpointer user_data )
237 {
238 page_status this = user_data;
239 dv1394app app = this->app;
240 int index = 0;
241 GtkWidget *widget = this_page_get_widget( ( page )this );
242 for ( index = 0; index < MAX_UNITS; index ++ )
243 {
244 char button_name[ 256 ];
245 sprintf( button_name, "radiobutton_%d", index );
246 if ( lookup_widget( widget, button_name ) == GTK_WIDGET( togglebutton ) )
247 break;
248 }
249 if ( index < MAX_UNITS )
250 {
251 mvcp_status_t status;
252 mvcp_notifier notifier = mvcp_get_notifier( this->status );
253 dv1394app_on_unit_change( app, index );
254 mvcp_notifier_get( notifier, &status, index );
255 gdk_threads_leave( );
256 show_status( this, &status );
257 gdk_threads_enter( );
258 }
259 }
260
261 static GtkWidget *this_page_get_widget( page super )
262 {
263 page_status this = ( page_status )super;
264 if ( this->widget == NULL )
265 this->widget = this->parent_page->get_widget(this->parent_page);
266 return this->widget;
267 }
268
269 static void this_page_get_toolbar_info( page super, GtkIconSize size, GtkWidget **icon, char **label )
270 {
271 *icon = gtk_image_new_from_stock( "gtk-home", size );
272 *label = _("_Units");
273 }
274
275 static void this_page_on_connect( page super )
276 {
277 page_status this = ( page_status )super;
278 if ( this->terminated )
279 {
280 this->terminated = 0;
281 this->status = mvcp_init( dv1394app_get_parser( this->app ) );
282 pthread_create( &this->status_thread, NULL, status_thread, this );
283 }
284 }
285
286 static void this_page_on_disconnect( page super )
287 {
288 page_status this = ( page_status )super;
289 if ( !this->terminated )
290 {
291 GtkWidget *widget;
292 this->terminated = 1;
293 gdk_threads_leave();
294 pthread_join( this->status_thread, NULL );
295 gdk_threads_enter();
296 mvcp_close( this->status );
297 widget = lookup_widget( dv1394app_get_widget( this->app ), "statusbar" );
298 gtk_statusbar_push( GTK_STATUSBAR( widget ), this->context, "Disconnected." );
299 }
300 }
301
302 static void this_page_close( page super )
303 {
304 page_status this = ( page_status )super;
305 if ( this != NULL )
306 free( this );
307 }
308
309 page page_status_init( dv1394app app, struct page_t *parent_page )
310 {
311 page_status this = calloc( 1, sizeof( page_status_t ) );
312 int index = 0;
313 GtkWidget *widget;
314
315 this->parent_page = parent_page;
316 this->parent.get_widget = this_page_get_widget;
317 this->parent.get_toolbar_info = this_page_get_toolbar_info;
318 this->parent.on_connect = this_page_on_connect;
319 this->parent.on_disconnect = this_page_on_disconnect;
320 this->parent.close = this_page_close;
321 this->app = app;
322 this->terminated = 1;
323
324 for ( index = 0; index < MAX_UNITS; index ++ )
325 {
326 char button_name[ 256 ];
327 sprintf( button_name, "radiobutton_%d", index );
328 widget = lookup_widget( this_page_get_widget( ( page )this ), button_name );
329 gtk_signal_connect( GTK_OBJECT( widget ), "toggled", GTK_SIGNAL_FUNC( on_radiobutton_toggled ), this );
330 }
331
332 widget = lookup_widget( dv1394app_get_widget( this->app ), "statusbar" );
333 this->context = gtk_statusbar_get_context_id( GTK_STATUSBAR( widget ), "info" );
334 gtk_statusbar_push( GTK_STATUSBAR( widget ), this->context, "Disconnected." );
335
336 return ( page )this;
337 }