1ca948788910c6cdbeb917c0a7f21ffb734d176f
[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 }
47 *page_status, page_status_t;
48
49 static GtkWidget *this_page_get_widget( page );
50
51 /** Show the status associated to a unit.
52 */
53
54 static char* status_to_text( mvcp_status status )
55 {
56 switch( status->status )
57 {
58 case unit_offline: return "offline"; break;
59 case unit_undefined: return "undefined"; break;
60 case unit_not_loaded: return "unloaded"; break;
61 case unit_stopped: return "stopped"; break;
62 case unit_playing: return "playing"; break;
63 case unit_paused: return "paused"; break;
64 case unit_disconnected: return "disconnect"; break;
65 case unit_unknown: return "unknown"; break;
66 }
67 return "unknown";
68 }
69
70 static int show_status( page_status this, mvcp_status status )
71 {
72 GtkWidget *widget = this_page_get_widget( ( page )this );
73 char temp[ 1024 ] = "";
74 char temp2[ 1024 ];
75 char label_name[ 256 ];
76 char tc1[12], tc2[12], tc3[12];
77
78 sprintf( temp, "[%s] IN:%s POS:%s OUT:%s %s",
79 status_to_text( status ),
80 frames2tc(status->in, status->fps, tc1),
81 frames2tc(status->position, status->fps, tc2),
82 frames2tc(status->out, status->fps, tc3),
83 status->clip
84 );
85
86 sprintf( label_name, "label_unit_%d", status->unit );
87
88 gdk_threads_enter();
89 widget = lookup_widget( widget, label_name );
90 gtk_label_set_text( GTK_LABEL( widget ), temp );
91 if ( status->unit == dv1394app_get_selected_unit( this->app ) )
92 {
93 sprintf( temp2, "U%d - %s", status->unit, temp );
94 widget = lookup_widget( dv1394app_get_widget( this->app ), "statusbar" );
95 gtk_statusbar_pop( GTK_STATUSBAR( widget ), this->context );
96 gtk_statusbar_push( GTK_STATUSBAR( widget ), this->context, temp2 );
97 dv1394app_show_status( this->app, status );
98 }
99 gdk_flush();
100 gdk_threads_leave();
101
102 return status->unit >= this->count;
103 }
104
105 static void show_units( page_status this, gboolean active )
106 {
107 int index = 0;
108 int index2 = 0;
109
110 GtkWidget *widget;
111 char temp[ 1024 ] = "";
112 char button_name[ 256 ];
113
114 mvcp_units units = NULL;
115 mvcp_unit_entry_t unit;
116 int unit_count = 0;
117
118 mvcp_nodes nodes = NULL;
119 mvcp_node_entry_t node;
120 int node_count = 0;
121
122 if ( active )
123 {
124 units = mvcp_units_init( this->status );
125 unit_count = mvcp_units_count( units );
126 nodes = mvcp_nodes_init( this->status );
127 node_count = mvcp_nodes_count( nodes );
128 this->count = unit_count;
129 }
130
131 gdk_threads_enter();
132
133 for ( index = 0; index < MAX_UNITS; index ++ )
134 {
135 if ( index < unit_count )
136 {
137 mvcp_units_get( units, index, &unit );
138
139 for ( index2 = 0; index2 < node_count; index2 ++ )
140 {
141 mvcp_nodes_get( nodes, index2, &node );
142 if ( !strcmp( node.guid, unit.guid ) )
143 break;
144 }
145
146 if ( index2 < node_count )
147 sprintf( temp, "U%d - %s (%s)", unit.unit, node.name, unit.guid );
148 else
149 sprintf( temp, "U%d - %s", unit.unit, unit.guid );
150
151 sprintf( button_name, "radiobutton_%d", index );
152 widget = lookup_widget( this_page_get_widget( ( page )this ), button_name );
153 gtk_widget_show( widget );
154 gtk_button_set_label( GTK_BUTTON( widget ), temp );
155 sprintf( button_name, "label_unit_%d", index );
156 widget = lookup_widget( this_page_get_widget( ( page )this ), button_name );
157 gtk_widget_show( widget );
158 }
159 else
160 {
161 sprintf( button_name, "radiobutton_%d", index );
162 widget = lookup_widget( this_page_get_widget( ( page )this ), button_name );
163 gtk_widget_hide( widget );
164 sprintf( button_name, "label_unit_%d", index );
165 widget = lookup_widget( this_page_get_widget( ( page )this ), button_name );
166 gtk_widget_hide( widget );
167 }
168 }
169 gdk_flush();
170 gdk_threads_leave();
171
172 mvcp_notifier notifier = mvcp_get_notifier( this->status );
173 mvcp_status_t status;
174
175 for ( index = 0; index < MAX_UNITS; index ++ )
176 {
177 status.unit = index;
178 if ( !active )
179 status.status = unit_disconnected;
180 else
181 mvcp_notifier_get( notifier, &status, index );
182 show_status( this, &status );
183 }
184
185 if ( active )
186 {
187 mvcp_nodes_close( nodes );
188 mvcp_units_close( units );
189 }
190 }
191
192 /** Status monitoring thread.
193 */
194
195 static void *status_thread( void *arg )
196 {
197 page_status this = arg;
198 mvcp_notifier notifier = mvcp_get_notifier( this->status );
199 mvcp_status_t status;
200
201 show_units( this, TRUE );
202
203 while ( !this->terminated )
204 {
205 if ( mvcp_notifier_wait( notifier, &status ) != -1 )
206 {
207 char buf[32];
208
209 if ( status.status == unit_disconnected )
210 {
211 this->app->eof = 0;
212 break;
213 }
214 if ( show_status( this, &status ) )
215 show_units( this, TRUE );
216 if ( !this->app->eof && mvcp_unit_get( this->app->command, this->app->selected_unit,
217 "eof", buf, sizeof(buf) ) != -1)
218 this->app->eof = buf[0];
219 }
220 }
221
222 show_units( this, FALSE );
223
224 if ( !this->terminated )
225 {
226 GtkWidget *widget = lookup_widget( dv1394app_get_widget( this->app ), "button_disconnect" );
227 gdk_threads_enter();
228 gtk_signal_emit_by_name( GTK_OBJECT( widget ), "clicked" );
229 gdk_threads_leave();
230 }
231
232 return NULL;
233 }
234
235 void on_radiobutton_toggled( GtkToggleButton *togglebutton, gpointer user_data )
236 {
237 page_status this = user_data;
238 dv1394app app = this->app;
239 int index = 0;
240 GtkWidget *widget = this_page_get_widget( ( page )this );
241 for ( index = 0; index < MAX_UNITS; index ++ )
242 {
243 char button_name[ 256 ];
244 sprintf( button_name, "radiobutton_%d", index );
245 if ( lookup_widget( widget, button_name ) == GTK_WIDGET( togglebutton ) )
246 break;
247 }
248 if ( index < MAX_UNITS )
249 {
250 mvcp_status_t status;
251 mvcp_notifier notifier = mvcp_get_notifier( this->status );
252 dv1394app_on_unit_change( app, index );
253 mvcp_notifier_get( notifier, &status, index );
254 gdk_threads_leave( );
255 show_status( this, &status );
256 gdk_threads_enter( );
257 }
258 }
259
260 static GtkWidget *this_page_get_widget( page super )
261 {
262 page_status this = ( page_status )super;
263 if ( this->widget == NULL )
264 this->widget = create_page_status( );
265 return this->widget;
266 }
267
268 static void this_page_get_toolbar_info( page super, GtkIconSize size, GtkWidget **icon, char **label )
269 {
270 *icon = gtk_image_new_from_stock( "gtk-home", size );
271 *label = _("_Units");
272 }
273
274 static void this_page_on_connect( page super )
275 {
276 page_status this = ( page_status )super;
277 if ( this->terminated )
278 {
279 this->terminated = 0;
280 this->status = mvcp_init( dv1394app_get_parser( this->app ) );
281 pthread_create( &this->status_thread, NULL, status_thread, this );
282 }
283 }
284
285 static void this_page_on_disconnect( page super )
286 {
287 page_status this = ( page_status )super;
288 if ( !this->terminated )
289 {
290 GtkWidget *widget;
291 this->terminated = 1;
292 gdk_threads_leave();
293 pthread_join( this->status_thread, NULL );
294 gdk_threads_enter();
295 mvcp_close( this->status );
296 widget = lookup_widget( dv1394app_get_widget( this->app ), "statusbar" );
297 gtk_statusbar_push( GTK_STATUSBAR( widget ), this->context, "Disconnected." );
298 }
299 }
300
301 static void this_page_close( page super )
302 {
303 page_status this = ( page_status )super;
304 if ( this != NULL )
305 free( this );
306 }
307
308 page page_status_init( dv1394app app )
309 {
310 page_status this = calloc( 1, sizeof( page_status_t ) );
311 int index = 0;
312 GtkWidget *widget;
313
314 this->parent.get_widget = this_page_get_widget;
315 this->parent.get_toolbar_info = this_page_get_toolbar_info;
316 this->parent.on_connect = this_page_on_connect;
317 this->parent.on_disconnect = this_page_on_disconnect;
318 this->parent.close = this_page_close;
319 this->app = app;
320 this->terminated = 1;
321
322 for ( index = 0; index < MAX_UNITS; index ++ )
323 {
324 char button_name[ 256 ];
325 sprintf( button_name, "radiobutton_%d", index );
326 widget = lookup_widget( this_page_get_widget( ( page )this ), button_name );
327 gtk_signal_connect( GTK_OBJECT( widget ), "toggled", GTK_SIGNAL_FUNC( on_radiobutton_toggled ), this );
328 }
329
330 widget = lookup_widget( dv1394app_get_widget( this->app ), "statusbar" );
331 this->context = gtk_statusbar_get_context_id( GTK_STATUSBAR( widget ), "info" );
332 gtk_statusbar_push( GTK_STATUSBAR( widget ), this->context, "Disconnected." );
333
334 return ( page )this;
335 }