1
/****************************************************************************
2
* maemo.c : Maemo plugin for VLC
3
*****************************************************************************
4
* Copyright (C) 2008 the VideoLAN team
5
* $Id: 401860f8453a743410b7da4b16031e53c9ef9797 $
7
* Authors: Antoine Lejeune <phytos@videolan.org>
8
* Gildas Bazin <gbazin@videolan.org>
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
15
* This program is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23
*****************************************************************************/
29
#include <vlc_common.h>
30
#include <vlc_plugin.h>
31
#include <vlc_interface.h>
32
#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 *Thread ( void * );
53
static int OpenWindow ( vlc_object_t * );
54
static void CloseWindow ( vlc_object_t * );
55
static int ControlWindow ( vout_window_t *, int, va_list );
56
static gboolean interface_ready ( gpointer );
58
/*****************************************************************************
60
*****************************************************************************/
62
set_shortname( "Maemo" );
63
set_description( N_("Maemo hildon interface") );
64
set_category( CAT_INTERFACE );
65
set_subcategory( SUBCAT_INTERFACE_MAIN );
66
set_capability( "interface", 70 );
67
set_callbacks( Open, Close );
68
add_shortcut( "maemo" );
71
set_capability( "vout window xid", 50 );
72
set_callbacks( OpenWindow, CloseWindow );
75
/*****************************************************************************
77
*****************************************************************************/
78
static int Open( vlc_object_t *p_this )
80
intf_thread_t *p_intf = (intf_thread_t *)p_this;
84
if( !vlc_xlib_init( p_this ) )
87
/* Allocate instance and initialize some members */
88
p_intf->p_sys = p_sys = malloc( sizeof( intf_sys_t ) );
89
if( p_intf->p_sys == NULL )
92
p_sys->p_playlist = pl_Get( p_intf );
93
p_sys->p_input = NULL;
95
p_sys->p_main_window = NULL;
96
p_sys->p_video_window = NULL;
97
p_sys->p_control_window = NULL;
98
p_sys->b_fullscreen = false;
101
vlc_spin_init( &p_sys->event_lock );
103
/* Create separate thread for main interface */
104
vlc_sem_init (&p_sys->ready, 0);
105
if( vlc_clone( &p_sys->thread, Thread, p_intf, VLC_THREAD_PRIORITY_LOW ) )
111
/* Wait for interface thread to be fully initialised */
112
vlc_sem_wait (&p_sys->ready);
113
vlc_sem_destroy (&p_sys->ready);
115
var_Create (p_this->p_libvlc, "hildon-iface", VLC_VAR_ADDRESS);
116
val.p_address = p_this;
117
var_Set (p_this->p_libvlc, "hildon-iface", val);
122
static void Close( vlc_object_t *p_this )
124
intf_thread_t *p_intf = (intf_thread_t *)p_this;
126
var_Destroy (p_this->p_libvlc, "hildon-iface");
129
vlc_join (p_intf->p_sys->thread, NULL);
130
vlc_spin_destroy( &p_intf->p_sys->event_lock );
131
free( p_intf->p_sys );
134
static gint quit_event( GtkWidget *widget, GdkEvent *event, gpointer data )
136
intf_thread_t *p_intf = (intf_thread_t *)data;
137
(void)widget; (void)event;
138
libvlc_Quit( p_intf->p_libvlc );
142
/*****************************************************************************
143
* Initialize and launch the interface
144
*****************************************************************************/
145
static void *Thread( void *obj )
147
intf_thread_t *p_intf = (intf_thread_t *)obj;
148
const char *p_args[] = { "vlc" };
149
int i_args = sizeof(p_args)/sizeof(char *);
150
char **pp_args = (char **)p_args;
152
HildonProgram *program;
153
HildonWindow *window;
154
GtkWidget *main_vbox, *bottom_hbox;
155
GtkWidget *video, *seekbar;
156
GtkWidget *play_button, *prev_button, *next_button;
157
GtkWidget *stop_button, *playlist_button;
159
gtk_init( &i_args, &pp_args );
161
program = HILDON_PROGRAM( hildon_program_get_instance() );
162
g_set_application_name( "VLC Media Player" );
164
window = HILDON_WINDOW( hildon_window_new() );
165
hildon_program_add_window( program, window );
166
gtk_object_set_data( GTK_OBJECT( window ), "p_intf", p_intf );
167
p_intf->p_sys->p_main_window = window;
169
g_signal_connect( GTK_WIDGET(window), "key-press-event",
170
G_CALLBACK( key_cb ), p_intf );
171
g_signal_connect (GTK_WIDGET(window), "delete_event",
172
GTK_SIGNAL_FUNC( quit_event), p_intf );
175
char *psz_rc_file = NULL;
176
char *psz_data = config_GetDataDir( p_intf );
177
if( asprintf( &psz_rc_file, "%s/maemo/vlc_intf.rc", psz_data ) != -1 )
179
gtk_rc_parse( psz_rc_file );
184
// We create the main vertical box
185
main_vbox = gtk_vbox_new( FALSE, 0 );
186
gtk_container_add( GTK_CONTAINER( window ), main_vbox );
189
GtkWidget *main_menu = create_menu( p_intf );
191
hildon_window_set_menu( HILDON_WINDOW( p_intf->p_sys->p_main_window ),
192
GTK_MENU( main_menu ) );
194
GtkWidget *menu_bar = gtk_menu_bar_new ();
195
GtkWidget *item = gtk_menu_item_new_with_label ("Menu");
196
gtk_menu_bar_append(menu_bar, item);
197
gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), main_menu);
198
gtk_widget_show_all (menu_bar);
199
gtk_box_pack_start(GTK_BOX(main_vbox), menu_bar, FALSE, FALSE, 0);
202
// We put first the embedded video
203
video = gtk_event_box_new();
204
GdkColor black = {0,0,0,0};
205
gtk_widget_modify_bg(video, GTK_STATE_NORMAL, &black);
206
p_intf->p_sys->p_video_window = video;
207
gtk_box_pack_start( GTK_BOX( main_vbox ), video, TRUE, TRUE, 0 );
209
create_playlist( p_intf );
210
gtk_box_pack_start( GTK_BOX( main_vbox ), p_intf->p_sys->p_playlist_window, TRUE, TRUE, 0 );
212
// We put the horizontal box which contains all the buttons
213
p_intf->p_sys->p_control_window = bottom_hbox = gtk_hbox_new( FALSE, 0 );
215
// We create the buttons
216
play_button = gtk_button_new();
217
gtk_button_set_image( GTK_BUTTON( play_button ),
218
gtk_image_new_from_stock( "vlc-play", GTK_ICON_SIZE_BUTTON ) );
219
p_intf->p_sys->p_play_button = play_button;
220
stop_button = gtk_button_new();
221
gtk_button_set_image( GTK_BUTTON( stop_button ),
222
gtk_image_new_from_stock( "vlc-stop", GTK_ICON_SIZE_BUTTON ) );
223
prev_button = gtk_button_new();
224
gtk_button_set_image( GTK_BUTTON( prev_button ),
225
gtk_image_new_from_stock( "vlc-previous", GTK_ICON_SIZE_BUTTON ) );
226
next_button = gtk_button_new();
227
gtk_button_set_image( GTK_BUTTON( next_button ),
228
gtk_image_new_from_stock( "vlc-next", GTK_ICON_SIZE_BUTTON ) );
229
playlist_button = gtk_button_new();
230
gtk_button_set_image( GTK_BUTTON( playlist_button ),
231
gtk_image_new_from_stock( "vlc-playlist", GTK_ICON_SIZE_BUTTON ) );
232
seekbar = hildon_seekbar_new();
233
p_intf->p_sys->p_seekbar = HILDON_SEEKBAR( seekbar );
235
// We add them to the hbox
236
gtk_box_pack_start( GTK_BOX( bottom_hbox ), play_button, FALSE, FALSE, 0 );
237
gtk_box_pack_start( GTK_BOX( bottom_hbox ), stop_button, FALSE, FALSE, 0 );
238
gtk_box_pack_start( GTK_BOX( bottom_hbox ), prev_button, FALSE, FALSE, 0 );
239
gtk_box_pack_start( GTK_BOX( bottom_hbox ), next_button, FALSE, FALSE, 0 );
240
gtk_box_pack_start( GTK_BOX( bottom_hbox ), playlist_button, FALSE, FALSE, 0 );
241
gtk_box_pack_start( GTK_BOX( bottom_hbox ), seekbar , TRUE , TRUE , 5 );
242
// We add the hbox to the main vbox
243
gtk_box_pack_start( GTK_BOX( main_vbox ), bottom_hbox, FALSE, FALSE, 0 );
245
g_signal_connect( play_button, "clicked", G_CALLBACK( play_cb ), NULL );
246
g_signal_connect( stop_button, "clicked", G_CALLBACK( stop_cb ), NULL );
247
g_signal_connect( prev_button, "clicked", G_CALLBACK( prev_cb ), NULL );
248
g_signal_connect( next_button, "clicked", G_CALLBACK( next_cb ), NULL );
249
g_signal_connect( playlist_button, "clicked", G_CALLBACK( playlist_cb ), NULL );
250
g_signal_connect( seekbar, "change-value",
251
G_CALLBACK( seekbar_changed_cb ), NULL );
253
gtk_widget_show_all( GTK_WIDGET( window ) );
254
gtk_widget_hide_all( p_intf->p_sys->p_playlist_window );
257
/* HACK: Only one X11 client can subscribe to mouse button press events.
258
* VLC currently handles those in the video display.
259
* Force GTK to unsubscribe from mouse press and release events. */
260
Display *dpy = GDK_WINDOW_XDISPLAY( gtk_widget_get_window(p_intf->p_sys->p_video_window) );
261
Window w = GDK_WINDOW_XID( gtk_widget_get_window(p_intf->p_sys->p_video_window) );
262
XWindowAttributes attr;
264
XGetWindowAttributes( dpy, w, &attr );
265
attr.your_event_mask &= ~(ButtonPressMask|ButtonReleaseMask);
266
XSelectInput( dpy, w, attr.your_event_mask );
269
// The embedded video is only ready after gtk_main and windows are shown
270
g_idle_add( interface_ready, p_intf );
274
delete_input( p_intf );
275
delete_playlist( p_intf );
277
gtk_object_destroy( GTK_OBJECT( main_menu ) );
278
gtk_object_destroy( GTK_OBJECT( window ) );
284
* Video output window provider
286
static int OpenWindow (vlc_object_t *p_obj)
288
vout_window_t *p_wnd = (vout_window_t *)p_obj;
289
intf_thread_t *p_intf;
292
if (p_wnd->cfg->is_standalone)
295
if( var_Get( p_obj->p_libvlc, "hildon-iface", &val ) )
296
val.p_address = NULL;
298
p_intf = (intf_thread_t *)val.p_address;
300
{ /* If another interface is used, this plugin cannot work */
301
msg_Dbg( p_obj, "Hildon interface not found" );
305
p_wnd->handle.xid = p_intf->p_sys->xid;
307
if (!p_wnd->handle.xid)
310
p_wnd->control = ControlWindow;
311
p_wnd->sys = (vout_window_sys_t*)p_intf;
316
static int ControlWindow (vout_window_t *p_wnd, int query, va_list args)
318
intf_thread_t *p_intf = (intf_thread_t *)p_wnd->sys;
322
case VOUT_WINDOW_SET_SIZE:
324
int i_width = (int)va_arg( args, int );
325
int i_height = (int)va_arg( args, int );
327
int i_current_w, i_current_h;
328
gdk_drawable_get_size( GDK_DRAWABLE( p_intf->p_sys->p_video_window ),
329
&i_current_w, &i_current_h );
330
if( i_width != i_current_w || i_height != i_current_h )
334
case VOUT_WINDOW_SET_FULLSCREEN:
336
bool b_fs = va_arg( args, int );
337
p_intf->p_sys->b_fullscreen = b_fs;
338
g_idle_add( fullscreen_cb, p_intf );
346
static void CloseWindow (vlc_object_t *p_obj)
348
vout_window_t *p_wnd = (vout_window_t *)p_obj;
349
intf_thread_t *p_intf = (intf_thread_t *)p_wnd->sys;
351
if( p_intf->p_sys->b_fullscreen )
353
p_intf->p_sys->b_fullscreen = false;
354
g_idle_add( fullscreen_cb, p_intf );
358
static gboolean interface_ready( gpointer data )
360
intf_thread_t *p_intf = (intf_thread_t *)data;
363
GDK_WINDOW_XID( gtk_widget_get_window(p_intf->p_sys->p_video_window) );
366
post_event( p_intf, EVENT_PLAYLIST_CURRENT );
368
// Everything is initialised
369
vlc_sem_post (&p_intf->p_sys->ready);
371
// We want it to be executed only one time