1 /*****************************************************************************
2 * maemo.c : Maemo plugin for VLC
3 *****************************************************************************
4 * Copyright (C) 2008 the VideoLAN team
7 * Authors: Antoine Lejeune <phytos@videolan.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
30 #include <vlc_common.h>
31 #include <vlc_plugin.h>
32 #include <vlc_interface.h>
33 #include <vlc_window.h>
35 #include <hildon/hildon-program.h>
36 #include <hildon/hildon-banner.h>
41 #include "maemo_callbacks.h"
42 #include "maemo_input.h"
43 #include "maemo_interface.h"
45 /*****************************************************************************
47 *****************************************************************************/
48 static int Open ( vlc_object_t * );
49 static void Close ( vlc_object_t * );
50 static void Run ( intf_thread_t * );
51 static gboolean should_die ( gpointer );
52 static int OpenWindow ( vlc_object_t * );
53 static void CloseWindow ( vlc_object_t * );
54 static int ControlWindow ( vout_window_t *, int, va_list );
55 static void* request_video ( intf_thread_t *, vout_thread_t * );
56 static void release_video ( intf_thread_t * );
57 static gboolean video_widget_ready ( gpointer data );
59 /*****************************************************************************
61 *****************************************************************************/
63 set_shortname( "Maemo" );
64 set_description( N_("Maemo hildon interface") );
65 set_category( CAT_INTERFACE );
66 set_subcategory( SUBCAT_INTERFACE_MAIN );
67 set_capability( "interface", 70 );
68 set_callbacks( Open, Close );
69 add_shortcut( "maemo" );
72 set_capability( "vout_window", 50 );
73 set_callbacks( OpenWindow, CloseWindow );
76 /*****************************************************************************
78 *****************************************************************************/
79 static int Open( vlc_object_t *p_this )
81 intf_thread_t *p_intf = (intf_thread_t *)p_this;
83 /* Allocate instance and initialize some members */
84 p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
85 if( p_intf->p_sys == NULL )
87 msg_Err( p_intf, "out of memory" );
93 p_intf->p_sys->p_playlist = pl_Hold( p_intf );
94 p_intf->p_sys->p_input = NULL;
95 p_intf->p_sys->p_vout = NULL;
97 p_intf->p_sys->p_main_window = NULL;
98 p_intf->p_sys->p_video_window = NULL;
100 vlc_spin_init( &p_intf->p_sys->event_lock );
101 vlc_mutex_init( &p_intf->p_sys->p_video_mutex );
102 vlc_cond_init( &p_intf->p_sys->p_video_cond );
107 static void Close( vlc_object_t *p_this )
109 intf_thread_t *p_intf = (intf_thread_t *)p_this;
111 vlc_object_release( p_intf->p_sys->p_playlist );
113 vlc_spin_destroy( &p_intf->p_sys->event_lock );
115 /* Destroy structure */
116 free( p_intf->p_sys );
119 /*****************************************************************************
120 * Initialize and launch the interface
121 *****************************************************************************/
122 static void Run( intf_thread_t *p_intf )
124 char *p_args[] = { "", NULL };
125 char **pp_args = p_args;
128 HildonProgram *program;
129 HildonWindow *window;
130 GtkWidget *main_vbox;
134 GtkWidget *bottom_hbox;
135 GtkWidget *play_button;
136 GtkWidget *prev_button;
137 GtkWidget *next_button;
138 GtkWidget *stop_button;
141 gtk_init( &i_args, &pp_args );
143 program = HILDON_PROGRAM( hildon_program_get_instance() );
144 g_set_application_name( "VLC Media Player" );
146 window = HILDON_WINDOW( hildon_window_new() );
147 hildon_program_add_window( program, window );
148 gtk_object_set_data( GTK_OBJECT( window ),
150 p_intf->p_sys->p_main_window = window;
153 char *psz_rc_file = NULL;
154 if( asprintf( &psz_rc_file, "%s/maemo/vlc_intf.rc",
155 config_GetDataDir() ) != -1 )
157 gtk_rc_parse( psz_rc_file );
161 // We create the main vertical box
162 main_vbox = gtk_vbox_new( FALSE, 0 );
163 gtk_container_add( GTK_CONTAINER( window ), main_vbox );
165 tabs = gtk_notebook_new();
166 p_intf->p_sys->p_tabs = tabs;
167 gtk_notebook_set_tab_pos( GTK_NOTEBOOK( tabs ), GTK_POS_LEFT );
168 gtk_notebook_set_show_border( GTK_NOTEBOOK( tabs ), FALSE );
169 gtk_box_pack_start( GTK_BOX( main_vbox ), tabs, TRUE, TRUE, 0 );
171 // We put first the embedded video
172 video = gtk_event_box_new();
173 gtk_notebook_append_page( GTK_NOTEBOOK( tabs ),
175 gtk_image_new_from_stock( "vlc",
176 GTK_ICON_SIZE_DIALOG ) );
177 gtk_notebook_set_tab_label_packing( GTK_NOTEBOOK( tabs ),
180 create_playlist( p_intf );
182 // We put the horizontal box which contains all the buttons
183 bottom_hbox = gtk_hbox_new( FALSE, 0 );
185 // We create the buttons
186 play_button = gtk_button_new();
187 gtk_button_set_image( GTK_BUTTON( play_button ),
188 gtk_image_new_from_stock( "vlc-play", GTK_ICON_SIZE_BUTTON ) );
189 gtk_widget_set_size_request( play_button, 60, 60);
190 p_intf->p_sys->p_play_button = play_button;
191 stop_button = gtk_button_new();
192 gtk_button_set_image( GTK_BUTTON( stop_button ),
193 gtk_image_new_from_stock( "vlc-stop", GTK_ICON_SIZE_BUTTON ) );
194 prev_button = gtk_button_new();
195 gtk_button_set_image( GTK_BUTTON( prev_button ),
196 gtk_image_new_from_stock( "vlc-previous", GTK_ICON_SIZE_BUTTON ) );
197 next_button = gtk_button_new();
198 gtk_button_set_image( GTK_BUTTON( next_button ),
199 gtk_image_new_from_stock( "vlc-next", GTK_ICON_SIZE_BUTTON ) );
200 seekbar = hildon_seekbar_new();
201 p_intf->p_sys->p_seekbar = HILDON_SEEKBAR( seekbar );
203 // We add them to the hbox
204 gtk_box_pack_start( GTK_BOX( bottom_hbox ), play_button, FALSE, FALSE, 5 );
205 gtk_box_pack_start( GTK_BOX( bottom_hbox ), stop_button, FALSE, FALSE, 0 );
206 gtk_box_pack_start( GTK_BOX( bottom_hbox ), prev_button, FALSE, FALSE, 0 );
207 gtk_box_pack_start( GTK_BOX( bottom_hbox ), next_button, FALSE, FALSE, 0 );
208 gtk_box_pack_start( GTK_BOX( bottom_hbox ), seekbar , TRUE , TRUE , 5 );
209 // We add the hbox to the main vbox
210 gtk_box_pack_start( GTK_BOX( main_vbox ), bottom_hbox, FALSE, FALSE, 0 );
212 g_signal_connect( window, "delete_event",
213 G_CALLBACK( delete_event_cb ), NULL );
214 g_signal_connect( play_button, "clicked", G_CALLBACK( play_cb ), NULL );
215 g_signal_connect( stop_button, "clicked", G_CALLBACK( stop_cb ), NULL );
216 g_signal_connect( prev_button, "clicked", G_CALLBACK( prev_cb ), NULL );
217 g_signal_connect( next_button, "clicked", G_CALLBACK( next_cb ), NULL );
218 g_signal_connect( seekbar, "change-value",
219 G_CALLBACK( seekbar_changed_cb ), NULL );
221 gtk_widget_show_all( GTK_WIDGET( window ) );
223 create_menu( p_intf );
225 // Set callback with the vlc core
226 g_timeout_add( INTF_IDLE_SLEEP / 1000, process_events, p_intf );
227 g_timeout_add( 150 /* miliseconds */, should_die, p_intf );
228 var_AddCallback( p_intf->p_sys->p_playlist, "item-change",
229 item_changed_cb, p_intf );
230 var_AddCallback( p_intf->p_sys->p_playlist, "playlist-current",
231 playlist_current_cb, p_intf );
232 var_AddCallback( p_intf->p_sys->p_playlist, "activity",
233 activity_cb, p_intf );
235 // Look if the playlist is already started
236 item_changed_pl( p_intf );
238 // The embedded video is only ready after gtk_main and windows are shown
239 g_idle_add( video_widget_ready, video );
243 delete_input( p_intf );
244 var_DelCallback( p_intf->p_sys->p_playlist, "item-change",
245 item_changed_cb, p_intf );
246 var_DelCallback( p_intf->p_sys->p_playlist, "playlist-current",
247 playlist_current_cb, p_intf );
248 var_DelCallback( p_intf->p_sys->p_playlist, "activity",
249 activity_cb, p_intf );
251 // Asking the vout to close
252 vout_thread_t *p_vout = p_intf->p_sys->p_vout;
256 if( vout_Control( p_vout, VOUT_CLOSE ) != VLC_SUCCESS )
257 vout_Control( p_vout, VOUT_REPARENT, 0 );
258 vlc_object_release( p_vout );
261 gtk_object_destroy( GTK_OBJECT( window ) );
264 static gboolean should_die( gpointer data )
266 intf_thread_t *p_intf = (intf_thread_t *)data;
267 if( !vlc_object_alive( p_intf ) )
273 * Video output window provider
275 static int OpenWindow (vlc_object_t *obj)
277 vout_window_t *wnd = (vout_window_t *)obj;
279 /* TODO: should probably be in the libvlc core instead: */
280 if (!config_GetInt (obj, "embedded-video"))
283 intf_thread_t *intf = (intf_thread_t *)
284 vlc_object_find_name (obj, "maemo", FIND_ANYWHERE);
287 msg_Err( obj, "Maemo interface not found" );
288 return VLC_EGENERIC; /* Maemo not in use */
291 wnd->handle = request_video( intf, wnd->vout );
292 msg_Dbg( intf, "Using handle %p", wnd->handle );
294 wnd->control = ControlWindow;
295 wnd->p_private = intf;
297 // Signaling that the window is not at the requested sizeof
298 int i_width, i_height, i_x_top, i_y_top, i_x, i_y;
299 gdk_drawable_get_size( GDK_DRAWABLE( intf->p_sys->p_video_window->window ),
300 &i_width, &i_height );
301 gdk_window_get_position( GTK_WIDGET(intf->p_sys->p_main_window)->window,
302 &i_x_top, &i_y_top );
303 gdk_window_get_position( intf->p_sys->p_video_window->window, &i_x, &i_y );
305 wnd->width = i_width;
306 wnd->height = i_height;
307 wnd->pos_x = i_x_top + i_x;
308 wnd->pos_y = i_y_top + i_y;
313 static int ControlWindow (vout_window_t *wnd, int query, va_list args)
315 (void)wnd; (void)query; (void)args;
319 static void CloseWindow (vlc_object_t *obj)
321 intf_thread_t *intf = (intf_thread_t *)obj->p_private;
323 release_video( intf );
324 vlc_object_release (intf);
327 static void *request_video( intf_thread_t *p_intf, vout_thread_t *p_nvout )
329 if( p_intf->p_sys->p_vout )
331 msg_Dbg( p_intf, "Embedded video already in use" );
335 vlc_mutex_lock( &p_intf->p_sys->p_video_mutex );
336 mutex_cleanup_push( &p_intf->p_sys->p_video_mutex );
338 // We wait until the p_video_window is set
339 while( p_intf->p_sys->p_video_window == NULL )
340 vlc_cond_wait( &p_intf->p_sys->p_video_cond,
341 &p_intf->p_sys->p_video_mutex );
345 p_intf->p_sys->p_vout = p_nvout;
346 return ( void * )GDK_WINDOW_XID( p_intf->p_sys->p_video_window->window );
349 static void release_video( intf_thread_t *p_intf )
351 msg_Dbg( p_intf, "Releasing embedded video" );
352 p_intf->p_sys->p_vout = NULL;
355 static gboolean video_widget_ready( gpointer data )
357 intf_thread_t *p_intf = NULL;
358 GtkWidget *top_window = NULL;
359 GtkWidget *video = (GtkWidget *)data;
361 top_window = gtk_widget_get_toplevel( GTK_WIDGET( video ) );
362 p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT( top_window ),
364 p_intf->p_sys->p_video_window = video;
365 gtk_widget_grab_focus( video );
367 vlc_cond_signal( &p_intf->p_sys->p_video_cond );
369 // We rewind the input
370 if( p_intf->p_sys->p_input )
372 input_Control( p_intf->p_sys->p_input, INPUT_SET_POSITION, 0.0 );
375 // We want it to be executed only one time