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_vout_window.h>
35 #include <hildon/hildon-program.h>
36 #include <hildon/hildon-banner.h>
43 #include "maemo_callbacks.h"
44 #include "maemo_input.h"
45 #include "maemo_interface.h"
47 /*****************************************************************************
49 *****************************************************************************/
50 static int Open ( vlc_object_t
* );
51 static void Close ( vlc_object_t
* );
52 static void Run ( intf_thread_t
* );
53 static gboolean
should_die ( gpointer
);
54 static int OpenWindow ( vlc_object_t
* );
55 static void CloseWindow ( vlc_object_t
* );
56 static int ControlWindow ( vout_window_t
*, int, va_list );
57 static uint32_t request_video ( intf_thread_t
*, vout_thread_t
* );
58 static void release_video ( intf_thread_t
* );
59 static gboolean
video_widget_ready ( gpointer data
);
61 /*****************************************************************************
63 *****************************************************************************/
65 set_shortname( "Maemo" );
66 set_description( N_("Maemo hildon interface") );
67 set_category( CAT_INTERFACE
);
68 set_subcategory( SUBCAT_INTERFACE_MAIN
);
69 set_capability( "interface", 70 );
70 set_callbacks( Open
, Close
);
71 add_shortcut( "maemo" );
74 set_capability( "vout window xid", 50 );
75 set_callbacks( OpenWindow
, CloseWindow
);
84 } wnd_req
= { VLC_STATIC_MUTEX
, PTHREAD_COND_INITIALIZER
, NULL
, false };
86 /*****************************************************************************
88 *****************************************************************************/
89 static int Open( vlc_object_t
*p_this
)
91 intf_thread_t
*p_intf
= (intf_thread_t
*)p_this
;
93 /* Allocate instance and initialize some members */
94 p_intf
->p_sys
= malloc( sizeof( intf_sys_t
) );
95 if( p_intf
->p_sys
== NULL
)
100 p_intf
->p_sys
->p_playlist
= pl_Hold( p_intf
);
101 p_intf
->p_sys
->p_input
= NULL
;
102 p_intf
->p_sys
->p_vout
= NULL
;
104 p_intf
->p_sys
->p_main_window
= NULL
;
105 p_intf
->p_sys
->p_video_window
= NULL
;
107 wnd_req
.enabled
= true;
108 /* ^no need to lock, interfacesare started before video outputs */
109 vlc_spin_init( &p_intf
->p_sys
->event_lock
);
114 static void Close( vlc_object_t
*p_this
)
116 intf_thread_t
*p_intf
= (intf_thread_t
*)p_this
;
118 vlc_object_release( p_intf
->p_sys
->p_playlist
);
120 vlc_spin_destroy( &p_intf
->p_sys
->event_lock
);
122 /* Destroy structure */
123 free( p_intf
->p_sys
);
126 /*****************************************************************************
127 * Initialize and launch the interface
128 *****************************************************************************/
129 static void Run( intf_thread_t
*p_intf
)
131 char *p_args
[] = { (char *)"vlc", NULL
};
132 char **pp_args
= p_args
;
135 HildonProgram
*program
;
136 HildonWindow
*window
;
137 GtkWidget
*main_vbox
;
141 GtkWidget
*bottom_hbox
;
142 GtkWidget
*play_button
;
143 GtkWidget
*prev_button
;
144 GtkWidget
*next_button
;
145 GtkWidget
*stop_button
;
148 gtk_init( &i_args
, &pp_args
);
150 program
= HILDON_PROGRAM( hildon_program_get_instance() );
151 g_set_application_name( "VLC Media Player" );
153 window
= HILDON_WINDOW( hildon_window_new() );
154 hildon_program_add_window( program
, window
);
155 gtk_object_set_data( GTK_OBJECT( window
),
157 p_intf
->p_sys
->p_main_window
= window
;
160 char *psz_rc_file
= NULL
;
161 if( asprintf( &psz_rc_file
, "%s/maemo/vlc_intf.rc",
162 config_GetDataDir() ) != -1 )
164 gtk_rc_parse( psz_rc_file
);
168 // We create the main vertical box
169 main_vbox
= gtk_vbox_new( FALSE
, 0 );
170 gtk_container_add( GTK_CONTAINER( window
), main_vbox
);
172 tabs
= gtk_notebook_new();
173 p_intf
->p_sys
->p_tabs
= tabs
;
174 gtk_notebook_set_tab_pos( GTK_NOTEBOOK( tabs
), GTK_POS_LEFT
);
175 gtk_notebook_set_show_border( GTK_NOTEBOOK( tabs
), FALSE
);
176 gtk_box_pack_start( GTK_BOX( main_vbox
), tabs
, TRUE
, TRUE
, 0 );
178 // We put first the embedded video
179 video
= gtk_event_box_new();
180 gtk_notebook_append_page( GTK_NOTEBOOK( tabs
),
182 gtk_image_new_from_stock( "vlc",
183 GTK_ICON_SIZE_DIALOG
) );
184 gtk_notebook_set_tab_label_packing( GTK_NOTEBOOK( tabs
),
187 create_playlist( p_intf
);
189 // We put the horizontal box which contains all the buttons
190 bottom_hbox
= gtk_hbox_new( FALSE
, 0 );
192 // We create the buttons
193 play_button
= gtk_button_new();
194 gtk_button_set_image( GTK_BUTTON( play_button
),
195 gtk_image_new_from_stock( "vlc-play", GTK_ICON_SIZE_BUTTON
) );
196 gtk_widget_set_size_request( play_button
, 60, 60);
197 p_intf
->p_sys
->p_play_button
= play_button
;
198 stop_button
= gtk_button_new();
199 gtk_button_set_image( GTK_BUTTON( stop_button
),
200 gtk_image_new_from_stock( "vlc-stop", GTK_ICON_SIZE_BUTTON
) );
201 prev_button
= gtk_button_new();
202 gtk_button_set_image( GTK_BUTTON( prev_button
),
203 gtk_image_new_from_stock( "vlc-previous", GTK_ICON_SIZE_BUTTON
) );
204 next_button
= gtk_button_new();
205 gtk_button_set_image( GTK_BUTTON( next_button
),
206 gtk_image_new_from_stock( "vlc-next", GTK_ICON_SIZE_BUTTON
) );
207 seekbar
= hildon_seekbar_new();
208 p_intf
->p_sys
->p_seekbar
= HILDON_SEEKBAR( seekbar
);
210 // We add them to the hbox
211 gtk_box_pack_start( GTK_BOX( bottom_hbox
), play_button
, FALSE
, FALSE
, 5 );
212 gtk_box_pack_start( GTK_BOX( bottom_hbox
), stop_button
, FALSE
, FALSE
, 0 );
213 gtk_box_pack_start( GTK_BOX( bottom_hbox
), prev_button
, FALSE
, FALSE
, 0 );
214 gtk_box_pack_start( GTK_BOX( bottom_hbox
), next_button
, FALSE
, FALSE
, 0 );
215 gtk_box_pack_start( GTK_BOX( bottom_hbox
), seekbar
, TRUE
, TRUE
, 5 );
216 // We add the hbox to the main vbox
217 gtk_box_pack_start( GTK_BOX( main_vbox
), bottom_hbox
, FALSE
, FALSE
, 0 );
219 g_signal_connect( window
, "delete_event",
220 G_CALLBACK( delete_event_cb
), NULL
);
221 g_signal_connect( play_button
, "clicked", G_CALLBACK( play_cb
), NULL
);
222 g_signal_connect( stop_button
, "clicked", G_CALLBACK( stop_cb
), NULL
);
223 g_signal_connect( prev_button
, "clicked", G_CALLBACK( prev_cb
), NULL
);
224 g_signal_connect( next_button
, "clicked", G_CALLBACK( next_cb
), NULL
);
225 g_signal_connect( seekbar
, "change-value",
226 G_CALLBACK( seekbar_changed_cb
), NULL
);
228 gtk_widget_show_all( GTK_WIDGET( window
) );
230 create_menu( p_intf
);
232 // Set callback with the vlc core
233 g_timeout_add( INTF_IDLE_SLEEP
/ 1000, process_events
, p_intf
);
234 g_timeout_add( 150 /* miliseconds */, should_die
, p_intf
);
235 var_AddCallback( p_intf
->p_sys
->p_playlist
, "item-change",
236 item_changed_cb
, p_intf
);
237 var_AddCallback( p_intf
->p_sys
->p_playlist
, "item-current",
238 playlist_current_cb
, p_intf
);
239 var_AddCallback( p_intf
->p_sys
->p_playlist
, "activity",
240 activity_cb
, p_intf
);
242 // Look if the playlist is already started
243 item_changed_pl( p_intf
);
245 // The embedded video is only ready after gtk_main and windows are shown
246 g_idle_add( video_widget_ready
, video
);
250 delete_input( p_intf
);
251 var_DelCallback( p_intf
->p_sys
->p_playlist
, "item-change",
252 item_changed_cb
, p_intf
);
253 var_DelCallback( p_intf
->p_sys
->p_playlist
, "item-current",
254 playlist_current_cb
, p_intf
);
255 var_DelCallback( p_intf
->p_sys
->p_playlist
, "activity",
256 activity_cb
, p_intf
);
258 /* FIXME: we need to wait for vout to clean up... */
259 assert( !p_intf
->p_sys
->p_vout
); /* too late */
260 gtk_object_destroy( GTK_OBJECT( window
) );
263 static gboolean
should_die( gpointer data
)
265 intf_thread_t
*p_intf
= (intf_thread_t
*)data
;
266 if( !vlc_object_alive( p_intf
) )
272 * Video output window provider
274 static int OpenWindow (vlc_object_t
*obj
)
276 vout_window_t
*wnd
= (vout_window_t
*)obj
;
279 if (wnd
->cfg
->is_standalone
|| !wnd_req
.enabled
)
282 /* FIXME it should NOT be needed */
283 vout_thread_t
*vout
= vlc_object_find (obj
, VLC_OBJECT_VOUT
, FIND_PARENT
);
287 vlc_mutex_lock (&wnd_req
.lock
);
288 while ((intf
= wnd_req
.intf
) == NULL
)
289 vlc_cond_wait (&wnd_req
.wait
, &wnd_req
.lock
);
291 wnd
->handle
.xid
= request_video( intf
, vout
);
292 vlc_mutex_unlock (&wnd_req
.lock
);
294 vlc_object_release( vout
);
296 if (!wnd
->handle
.xid
)
299 msg_Dbg( intf
, "Using handle %"PRIu32
, wnd
->handle
.xid
);
301 wnd
->control
= ControlWindow
;
302 wnd
->sys
= (vout_window_sys_t
*)intf
;
307 static int ControlWindow (vout_window_t
*wnd
, int query
, va_list args
)
309 intf_thread_t
*intf
= (intf_thread_t
*)wnd
->sys
;
313 case VOUT_WINDOW_SET_SIZE
:
315 int i_width
= (int)va_arg( args
, int );
316 int i_height
= (int)va_arg( args
, int );
318 int i_current_w
, i_current_h
;
319 gdk_drawable_get_size( GDK_DRAWABLE( intf
->p_sys
->p_video_window
->window
),
320 &i_current_w
, &i_current_h
);
321 if( i_width
!= i_current_w
|| i_height
!= i_current_h
)
330 static void CloseWindow (vlc_object_t
*obj
)
332 vout_window_t
*wnd
= (vout_window_t
*)obj
;
333 intf_thread_t
*intf
= (intf_thread_t
*)wnd
->sys
;
335 vlc_mutex_lock( &wnd_req
.lock
);
336 release_video( intf
);
337 vlc_mutex_unlock( &wnd_req
.lock
);
340 static uint32_t request_video( intf_thread_t
*p_intf
, vout_thread_t
*p_nvout
)
342 if( p_intf
->p_sys
->p_vout
)
344 msg_Dbg( p_intf
, "Embedded video already in use" );
348 p_intf
->p_sys
->p_vout
= vlc_object_hold( p_nvout
);
349 return GDK_WINDOW_XID( p_intf
->p_sys
->p_video_window
->window
);
352 static void release_video( intf_thread_t
*p_intf
)
354 msg_Dbg( p_intf
, "Releasing embedded video" );
356 vlc_object_release( p_intf
->p_sys
->p_vout
);
357 p_intf
->p_sys
->p_vout
= NULL
;
360 static gboolean
video_widget_ready( gpointer data
)
362 intf_thread_t
*p_intf
= NULL
;
363 GtkWidget
*top_window
= NULL
;
364 GtkWidget
*video
= (GtkWidget
*)data
;
366 top_window
= gtk_widget_get_toplevel( GTK_WIDGET( video
) );
367 p_intf
= (intf_thread_t
*)gtk_object_get_data( GTK_OBJECT( top_window
),
369 p_intf
->p_sys
->p_video_window
= video
;
370 gtk_widget_grab_focus( video
);
372 vlc_mutex_lock( &wnd_req
.lock
);
373 wnd_req
.intf
= p_intf
;
374 vlc_cond_signal( &wnd_req
.wait
);
375 vlc_mutex_unlock( &wnd_req
.lock
);
377 // We rewind the input
378 if( p_intf
->p_sys
->p_input
)
380 input_Control( p_intf
->p_sys
->p_input
, INPUT_SET_POSITION
, 0.0 );
383 // We want it to be executed only one time