reset line to avoid duplicating last item
[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 void format_status_string(char* buf, int size, mvcp_status status , char* sep)
72 {
73 char tc1[12], tc2[12], tc3[12];
74
75 snprintf( buf, size,
76 "[%s]%sIN:%s%sPOS:%s%sOUT:%s%s%s%s",
77 status_to_text( status ), sep,
78 frames2tc(status->in, status->fps, tc1), sep,
79 frames2tc(status->position, status->fps, tc2), sep,
80 frames2tc(status->out, status->fps, tc3), sep,
81 status->clip, sep
82 );
83
84 }
85
86 static int show_status( page_status this, mvcp_status status )
87 {
88 GtkWidget *widget = this_page_get_widget( ( page )this );
89 char temp[ 1024 ] = "";
90 char label_name[ 256 ];
91
92 format_status_string(temp, sizeof(temp), status , "\n");
93 sprintf( label_name, "label_unit_%d", status->unit );
94
95 gdk_threads_enter();
96 widget = lookup_widget( widget, label_name );
97 gtk_label_set_text( GTK_LABEL( widget ), temp );
98 if ( status->unit == dv1394app_get_selected_unit( this->app ) )
99 {
100 char tc[12];
101
102 snprintf( temp, sizeof(temp), "U%d - [%s] %s",
103 status->unit,
104 status_to_text( status ),
105 status->clip);
106 widget = lookup_widget( dv1394app_get_widget( this->app ), "statusbar" );
107 gtk_statusbar_pop( GTK_STATUSBAR( widget ), this->context );
108 gtk_statusbar_push( GTK_STATUSBAR( widget ), this->context, temp );
109
110 widget = lookup_widget( dv1394app_get_widget( this->app ), "bbt_label_1a" );
111 snprintf( temp, sizeof(temp), "POS: %s",
112 frames2tc(status->position, status->fps, tc));
113 gtk_label_set_text( GTK_LABEL( widget ), temp );
114
115 widget = lookup_widget( dv1394app_get_widget( this->app ), "bbt_label_1b" );
116 snprintf( temp, sizeof(temp), "REM: %s",
117 frames2tc(status->out - status->position, status->fps, tc));
118 gtk_label_set_text( GTK_LABEL( widget ), temp );
119
120 dv1394app_show_status( this->app, status );
121 }
122 gdk_flush();
123 gdk_threads_leave();
124
125 return status->unit >= this->count;
126 }
127
128 static void show_units( page_status this, gboolean active )
129 {
130 int index = 0;
131 int index2 = 0;
132
133 GtkWidget *widget;
134 char temp[ 1024 ] = "";
135 char button_name[ 256 ];
136
137 mvcp_units units = NULL;
138 mvcp_unit_entry_t unit;
139 int unit_count = 0;
140
141 mvcp_nodes nodes = NULL;
142 mvcp_node_entry_t node;
143 int node_count = 0;
144
145 if ( active )
146 {
147 units = mvcp_units_init( this->status );
148 unit_count = mvcp_units_count( units );
149 nodes = mvcp_nodes_init( this->status );
150 node_count = mvcp_nodes_count( nodes );
151 this->count = unit_count;
152 }
153
154 gdk_threads_enter();
155
156 for ( index = 0; index < MAX_UNITS; index ++ )
157 {
158 if ( index < unit_count )
159 {
160 mvcp_units_get( units, index, &unit );
161
162 for ( index2 = 0; index2 < node_count; index2 ++ )
163 {
164 mvcp_nodes_get( nodes, index2, &node );
165 if ( !strcmp( node.guid, unit.guid ) )
166 break;
167 }
168
169 if ( index2 < node_count )
170 sprintf( temp, "U%d - %s (%s)", unit.unit, node.name, unit.guid );
171 else
172 sprintf( temp, "U%d - %s", unit.unit, unit.guid );
173
174 sprintf( button_name, "radiobutton_%d", index );
175 widget = lookup_widget( this_page_get_widget( ( page )this ), button_name );
176 gtk_widget_show( widget );
177 gtk_button_set_label( GTK_BUTTON( widget ), temp );
178 sprintf( button_name, "label_unit_%d", index );
179 widget = lookup_widget( this_page_get_widget( ( page )this ), button_name );
180 gtk_widget_show( widget );
181 }
182 else
183 {
184 sprintf( button_name, "radiobutton_%d", index );
185 widget = lookup_widget( this_page_get_widget( ( page )this ), button_name );
186 gtk_widget_hide( widget );
187 sprintf( button_name, "label_unit_%d", index );
188 widget = lookup_widget( this_page_get_widget( ( page )this ), button_name );
189 gtk_widget_hide( widget );
190 }
191 }
192 gdk_flush();
193 gdk_threads_leave();
194
195 mvcp_notifier notifier = mvcp_get_notifier( this->status );
196 mvcp_status_t status;
197
198 for ( index = 0; index < MAX_UNITS; index ++ )
199 {
200 status.unit = index;
201 if ( !active )
202 status.status = unit_disconnected;
203 else
204 mvcp_notifier_get( notifier, &status, index );
205 show_status( this, &status );
206 }
207
208 if ( active )
209 {
210 mvcp_nodes_close( nodes );
211 mvcp_units_close( units );
212 }
213 }
214
215 /** Status monitoring thread.
216 */
217
218 static void *status_thread( void *arg )
219 {
220 int i;
221 page_status this = arg;
222 mvcp_notifier notifier = mvcp_get_notifier( this->status );
223 mvcp_status_t status;
224 mvcp_status_t *statuses;
225
226 show_units( this, TRUE );
227
228 statuses = malloc(sizeof(mvcp_status_t) * this->count);
229 memset(statuses, 0, sizeof(mvcp_status_t) * this->count);
230
231 while ( !this->terminated )
232 {
233 char buf[32];
234
235 /* wait for any event from notifier */
236 mvcp_notifier_wait( notifier, &status );
237
238 /* get status for all units */
239 for(i = 0; i < this->count; i++)
240 {
241 mvcp_notifier_get( notifier, &status, i);
242
243 if ( status.status == unit_disconnected )
244 goto break_unit_disconnected;
245
246 if( memcmp(&status, &statuses[i], sizeof(mvcp_status_t)) || !this->app->eof[i])
247 {
248 /* save status */
249 statuses[i] = status;
250
251 /* save eof status */
252 if ( !this->app->eof[i] && mvcp_unit_get( this->app->command, i,
253 "eof", buf, sizeof(buf) ) != -1)
254 this->app->eof[i] = buf[0];
255
256 /* send status update */
257 if ( show_status( this, &status ) )
258 show_units( this, TRUE );
259 }
260 }
261 }
262
263 break_unit_disconnected:
264
265 free(statuses);
266
267 show_units( this, FALSE );
268
269 if ( !this->terminated )
270 {
271 GtkWidget *widget = lookup_widget( dv1394app_get_widget( this->app ), "button_disconnect" );
272 gdk_threads_enter();
273 gtk_signal_emit_by_name( GTK_OBJECT( widget ), "clicked" );
274 gdk_threads_leave();
275 }
276
277 return NULL;
278 }
279
280 void on_radiobutton_toggled( GtkToggleButton *togglebutton, gpointer user_data )
281 {
282 page_status this = user_data;
283 dv1394app app = this->app;
284 int index = 0;
285 GtkWidget *widget = this_page_get_widget( ( page )this );
286 for ( index = 0; index < MAX_UNITS; index ++ )
287 {
288 char button_name[ 256 ];
289 sprintf( button_name, "radiobutton_%d", index );
290 if ( lookup_widget( widget, button_name ) == GTK_WIDGET( togglebutton ) )
291 break;
292 }
293 if ( index < MAX_UNITS )
294 {
295 mvcp_status_t status;
296 mvcp_notifier notifier = mvcp_get_notifier( this->status );
297 dv1394app_on_unit_change( app, index );
298 mvcp_notifier_get( notifier, &status, index );
299 gdk_threads_leave( );
300 show_status( this, &status );
301 gdk_threads_enter( );
302 }
303 }
304
305 static GtkWidget *this_page_get_widget( page super )
306 {
307 page_status this = ( page_status )super;
308 if ( this->widget == NULL )
309 this->widget = this->parent_page->get_widget(this->parent_page);
310 return this->widget;
311 }
312
313 static void this_page_get_toolbar_info( page super, GtkIconSize size, GtkWidget **icon, char **label )
314 {
315 *icon = gtk_image_new_from_stock( "gtk-home", size );
316 *label = _("_Units");
317 }
318
319 static void this_page_on_connect( page super )
320 {
321 page_status this = ( page_status )super;
322 if ( this->terminated )
323 {
324 this->terminated = 0;
325 this->status = mvcp_init( dv1394app_get_parser( this->app ) );
326 pthread_create( &this->status_thread, NULL, status_thread, this );
327 }
328 }
329
330 static void this_page_on_disconnect( page super )
331 {
332 page_status this = ( page_status )super;
333 if ( !this->terminated )
334 {
335 GtkWidget *widget;
336 this->terminated = 1;
337 gdk_threads_leave();
338 pthread_join( this->status_thread, NULL );
339 gdk_threads_enter();
340 mvcp_close( this->status );
341 widget = lookup_widget( dv1394app_get_widget( this->app ), "statusbar" );
342 gtk_statusbar_push( GTK_STATUSBAR( widget ), this->context, "Disconnected." );
343 }
344 }
345
346 static void this_page_close( page super )
347 {
348 page_status this = ( page_status )super;
349 if ( this != NULL )
350 free( this );
351 }
352
353 page page_status_init( dv1394app app, struct page_t *parent_page )
354 {
355 page_status this = calloc( 1, sizeof( page_status_t ) );
356 int index = 0;
357 GtkWidget *widget;
358
359 this->parent_page = parent_page;
360 this->parent.get_widget = this_page_get_widget;
361 this->parent.get_toolbar_info = this_page_get_toolbar_info;
362 this->parent.on_connect = this_page_on_connect;
363 this->parent.on_disconnect = this_page_on_disconnect;
364 this->parent.close = this_page_close;
365 this->app = app;
366 this->terminated = 1;
367
368 for ( index = 0; index < MAX_UNITS; index ++ )
369 {
370 char button_name[ 256 ];
371 sprintf( button_name, "radiobutton_%d", index );
372 widget = lookup_widget( this_page_get_widget( ( page )this ), button_name );
373 gtk_signal_connect( GTK_OBJECT( widget ), "toggled", GTK_SIGNAL_FUNC( on_radiobutton_toggled ), this );
374 }
375
376 widget = lookup_widget( dv1394app_get_widget( this->app ), "statusbar" );
377 this->context = gtk_statusbar_get_context_id( GTK_STATUSBAR( widget ), "info" );
378 gtk_statusbar_push( GTK_STATUSBAR( widget ), this->context, "Disconnected." );
379
380 return ( page )this;
381 }