From b36e6edbb29f2791fe4c4539b4b6639e43f5d863 Mon Sep 17 00:00:00 2001 From: Gildas Bazin Date: Sun, 7 Feb 2010 23:02:49 +0000 Subject: [PATCH 1/1] Make the maemo interface a bit more useable --- NEWS | 1 + modules/gui/hildon/maemo.c | 286 ++++++++++++++------------- modules/gui/hildon/maemo.h | 17 +- modules/gui/hildon/maemo_callbacks.c | 191 +++++++++++++++--- modules/gui/hildon/maemo_callbacks.h | 4 + modules/gui/hildon/maemo_input.c | 43 ++-- modules/gui/hildon/maemo_input.h | 42 ++-- modules/gui/hildon/maemo_interface.c | 50 +++-- modules/gui/hildon/maemo_interface.h | 42 ++-- share/Makefile.am | 10 +- share/maemo/next.png | Bin 0 -> 162 bytes share/maemo/pause.png | Bin 0 -> 149 bytes share/maemo/play.png | Bin 0 -> 178 bytes share/maemo/playlist.png | Bin 1602 -> 147 bytes share/maemo/previous.png | Bin 0 -> 163 bytes share/maemo/stop.png | Bin 0 -> 146 bytes 16 files changed, 414 insertions(+), 272 deletions(-) create mode 100644 share/maemo/next.png create mode 100644 share/maemo/pause.png create mode 100644 share/maemo/play.png create mode 100644 share/maemo/previous.png create mode 100644 share/maemo/stop.png diff --git a/NEWS b/NEWS index 1686477c70..b88bfc6fb9 100644 --- a/NEWS +++ b/NEWS @@ -103,6 +103,7 @@ Windows port: Maemo port: * Multiple improvements for N900 compliance and efficiency * Support for HW accelerated video decoding on N900 + * Improvements to the maemo interface Misc: * new sqlite module diff --git a/modules/gui/hildon/maemo.c b/modules/gui/hildon/maemo.c index bcb0f404af..6ae8dbf7cd 100644 --- a/modules/gui/hildon/maemo.c +++ b/modules/gui/hildon/maemo.c @@ -1,32 +1,31 @@ -/***************************************************************************** -* maemo.c : Maemo plugin for VLC -***************************************************************************** -* Copyright (C) 2008 the VideoLAN team -* $Id$ -* -* Authors: Antoine Lejeune -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. -*****************************************************************************/ +/**************************************************************************** + * maemo.c : Maemo plugin for VLC + ***************************************************************************** + * Copyright (C) 2008 the VideoLAN team + * $Id$ + * + * Authors: Antoine Lejeune + * Gildas Bazin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ #ifdef HAVE_CONFIG_H # include "config.h" #endif -#include - #include #include #include @@ -49,14 +48,12 @@ *****************************************************************************/ static int Open ( vlc_object_t * ); static void Close ( vlc_object_t * ); -static void Run ( intf_thread_t * ); +static void *Thread ( void * ); static gboolean should_die ( gpointer ); static int OpenWindow ( vlc_object_t * ); static void CloseWindow ( vlc_object_t * ); static int ControlWindow ( vout_window_t *, int, va_list ); -static uint32_t request_video ( intf_thread_t *, vout_thread_t * ); -static void release_video ( intf_thread_t * ); -static gboolean video_widget_ready ( gpointer data ); +static gboolean interface_ready ( gpointer ); /***************************************************************************** * Module descriptor @@ -75,38 +72,46 @@ vlc_module_begin(); set_callbacks( OpenWindow, CloseWindow ); vlc_module_end(); -static struct -{ - vlc_mutex_t lock; - vlc_cond_t wait; - intf_thread_t *intf; - bool enabled; -} wnd_req = { VLC_STATIC_MUTEX, PTHREAD_COND_INITIALIZER, NULL, false }; - /***************************************************************************** * Module callbacks *****************************************************************************/ static int Open( vlc_object_t *p_this ) { intf_thread_t *p_intf = (intf_thread_t *)p_this; + intf_sys_t *p_sys;; + vlc_value_t val; /* Allocate instance and initialize some members */ - p_intf->p_sys = malloc( sizeof( intf_sys_t ) ); + p_intf->p_sys = p_sys = malloc( sizeof( intf_sys_t ) ); if( p_intf->p_sys == NULL ) return VLC_ENOMEM; - p_intf->pf_run = Run; + p_sys->p_playlist = pl_Hold( p_intf ); + p_sys->p_input = NULL; - p_intf->p_sys->p_playlist = pl_Hold( p_intf ); - p_intf->p_sys->p_input = NULL; - p_intf->p_sys->p_vout = NULL; + p_sys->p_main_window = NULL; + p_sys->p_video_window = NULL; + p_sys->p_control_window = NULL; + p_sys->b_fullscreen = false; - p_intf->p_sys->p_main_window = NULL; - p_intf->p_sys->p_video_window = NULL; + vlc_spin_init( &p_sys->event_lock ); - wnd_req.enabled = true; - /* ^no need to lock, interfacesare started before video outputs */ - vlc_spin_init( &p_intf->p_sys->event_lock ); + /* Create separate thread for main interface */ + vlc_sem_init (&p_sys->ready, 0); + if( vlc_clone( &p_sys->thread, Thread, p_intf, VLC_THREAD_PRIORITY_LOW ) ) + { + pl_Release (p_sys->p_playlist); + free (p_sys); + return VLC_ENOMEM; + } + + /* Wait for interface thread to be fully initialised */ + vlc_sem_wait (&p_sys->ready); + vlc_sem_destroy (&p_sys->ready); + + var_Create (p_this->p_libvlc, "hildon-iface", VLC_VAR_ADDRESS); + val.p_address = p_this; + var_Set (p_this->p_libvlc, "hildon-iface", val); return VLC_SUCCESS; } @@ -115,34 +120,42 @@ static void Close( vlc_object_t *p_this ) { intf_thread_t *p_intf = (intf_thread_t *)p_this; - vlc_object_release( p_intf->p_sys->p_playlist ); - + var_Destroy (p_this->p_libvlc, "hildon-iface"); + vlc_join (p_intf->p_sys->thread, NULL); + pl_Release ( p_intf->p_sys->p_playlist ); vlc_spin_destroy( &p_intf->p_sys->event_lock ); - - /* Destroy structure */ free( p_intf->p_sys ); } +static gint quit_event( GtkWidget *widget, GdkEvent *event, gpointer data ) +{ + intf_thread_t *p_intf = (intf_thread_t *)data; + (void)widget; (void)event; + libvlc_Quit( p_intf->p_libvlc ); + return TRUE; +} + /***************************************************************************** * Initialize and launch the interface *****************************************************************************/ -static void Run( intf_thread_t *p_intf ) +static void *Thread( void *obj ) { - char *p_args[] = { (char *)"vlc", NULL }; - char **pp_args = p_args; - int i_args = 1; + intf_thread_t *p_intf = (intf_thread_t *)obj; + const char *p_args[] = { "vlc", "--sync" }; + int i_args = sizeof(p_args)/sizeof(char *); + char **pp_args = (char **)p_args; HildonProgram *program; HildonWindow *window; GtkWidget *main_vbox; - GtkWidget *tabs; GtkWidget *video; GtkWidget *bottom_hbox; GtkWidget *play_button; GtkWidget *prev_button; GtkWidget *next_button; GtkWidget *stop_button; + GtkWidget *playlist_button; GtkWidget *seekbar; gtk_init( &i_args, &pp_args ); @@ -152,10 +165,14 @@ static void Run( intf_thread_t *p_intf ) window = HILDON_WINDOW( hildon_window_new() ); hildon_program_add_window( program, window ); - gtk_object_set_data( GTK_OBJECT( window ), - "p_intf", p_intf ); + gtk_object_set_data( GTK_OBJECT( window ), "p_intf", p_intf ); p_intf->p_sys->p_main_window = window; + g_signal_connect( GTK_WIDGET(window), "key-press-event", + G_CALLBACK( key_cb ), p_intf ); + g_signal_connect (GTK_WIDGET(window), "delete_event", + GTK_SIGNAL_FUNC( quit_event), p_intf ); + // A little theming char *psz_rc_file = NULL; char *psz_data = config_GetDataDir( p_intf ); @@ -170,25 +187,18 @@ static void Run( intf_thread_t *p_intf ) main_vbox = gtk_vbox_new( FALSE, 0 ); gtk_container_add( GTK_CONTAINER( window ), main_vbox ); - tabs = gtk_notebook_new(); - p_intf->p_sys->p_tabs = tabs; - gtk_notebook_set_tab_pos( GTK_NOTEBOOK( tabs ), GTK_POS_LEFT ); - gtk_notebook_set_show_border( GTK_NOTEBOOK( tabs ), FALSE ); - gtk_box_pack_start( GTK_BOX( main_vbox ), tabs, TRUE, TRUE, 0 ); - // We put first the embedded video video = gtk_event_box_new(); - gtk_notebook_append_page( GTK_NOTEBOOK( tabs ), - video, - gtk_image_new_from_stock( "vlc", - GTK_ICON_SIZE_DIALOG ) ); - gtk_notebook_set_tab_label_packing( GTK_NOTEBOOK( tabs ), - video, - FALSE, FALSE, 0 ); + GdkColor black = {0,0,0,0}; + gtk_widget_modify_bg(video, GTK_STATE_NORMAL, &black); + p_intf->p_sys->p_video_window = video; + gtk_box_pack_start( GTK_BOX( main_vbox ), video, TRUE, TRUE, 0 ); + create_playlist( p_intf ); + gtk_box_pack_start( GTK_BOX( main_vbox ), p_intf->p_sys->p_playlist_window, TRUE, TRUE, 0 ); // We put the horizontal box which contains all the buttons - bottom_hbox = gtk_hbox_new( FALSE, 0 ); + p_intf->p_sys->p_control_window = bottom_hbox = gtk_hbox_new( FALSE, 0 ); // We create the buttons play_button = gtk_button_new(); @@ -205,6 +215,9 @@ static void Run( intf_thread_t *p_intf ) next_button = gtk_button_new(); gtk_button_set_image( GTK_BUTTON( next_button ), gtk_image_new_from_stock( "vlc-next", GTK_ICON_SIZE_BUTTON ) ); + playlist_button = gtk_button_new(); + gtk_button_set_image( GTK_BUTTON( playlist_button ), + gtk_image_new_from_stock( "vlc-playlist", GTK_ICON_SIZE_BUTTON ) ); seekbar = hildon_seekbar_new(); p_intf->p_sys->p_seekbar = HILDON_SEEKBAR( seekbar ); @@ -213,6 +226,7 @@ static void Run( intf_thread_t *p_intf ) gtk_box_pack_start( GTK_BOX( bottom_hbox ), stop_button, FALSE, FALSE, 0 ); gtk_box_pack_start( GTK_BOX( bottom_hbox ), prev_button, FALSE, FALSE, 0 ); gtk_box_pack_start( GTK_BOX( bottom_hbox ), next_button, FALSE, FALSE, 0 ); + gtk_box_pack_start( GTK_BOX( bottom_hbox ), playlist_button, FALSE, FALSE, 0 ); gtk_box_pack_start( GTK_BOX( bottom_hbox ), seekbar , TRUE , TRUE , 5 ); // We add the hbox to the main vbox gtk_box_pack_start( GTK_BOX( main_vbox ), bottom_hbox, FALSE, FALSE, 0 ); @@ -223,13 +237,28 @@ static void Run( intf_thread_t *p_intf ) g_signal_connect( stop_button, "clicked", G_CALLBACK( stop_cb ), NULL ); g_signal_connect( prev_button, "clicked", G_CALLBACK( prev_cb ), NULL ); g_signal_connect( next_button, "clicked", G_CALLBACK( next_cb ), NULL ); + g_signal_connect( playlist_button, "clicked", G_CALLBACK( playlist_cb ), NULL ); g_signal_connect( seekbar, "change-value", G_CALLBACK( seekbar_changed_cb ), NULL ); gtk_widget_show_all( GTK_WIDGET( window ) ); + gtk_widget_hide_all( p_intf->p_sys->p_playlist_window ); create_menu( p_intf ); +#if 1 + /* HACK: Only one X11 client can subscribe to mouse button press events. + * VLC currently handles those in the video display. + * Force GTK to unsubscribe from mouse press and release events. */ + Display *dpy = GDK_WINDOW_XDISPLAY( gtk_widget_get_window(p_intf->p_sys->p_video_window) ); + Window w = GDK_WINDOW_XID( gtk_widget_get_window(p_intf->p_sys->p_video_window) ); + XWindowAttributes attr; + + XGetWindowAttributes( dpy, w, &attr ); + attr.your_event_mask &= ~(ButtonPressMask|ButtonReleaseMask); + XSelectInput( dpy, w, attr.your_event_mask ); +#endif + // Set callback with the vlc core g_timeout_add( INTF_IDLE_SLEEP / 1000, process_events, p_intf ); g_timeout_add( 150 /* miliseconds */, should_die, p_intf ); @@ -240,11 +269,8 @@ static void Run( intf_thread_t *p_intf ) var_AddCallback( p_intf->p_sys->p_playlist, "activity", activity_cb, p_intf ); - // Look if the playlist is already started - item_changed_pl( p_intf ); - // The embedded video is only ready after gtk_main and windows are shown - g_idle_add( video_widget_ready, video ); + g_idle_add( interface_ready, p_intf ); gtk_main(); @@ -256,9 +282,9 @@ static void Run( intf_thread_t *p_intf ) var_DelCallback( p_intf->p_sys->p_playlist, "activity", activity_cb, p_intf ); - /* FIXME: we need to wait for vout to clean up... */ - assert( !p_intf->p_sys->p_vout ); /* too late */ gtk_object_destroy( GTK_OBJECT( window ) ); + + return NULL; } static gboolean should_die( gpointer data ) @@ -272,42 +298,39 @@ static gboolean should_die( gpointer data ) /** * Video output window provider */ -static int OpenWindow (vlc_object_t *obj) +static int OpenWindow (vlc_object_t *p_obj) { - vout_window_t *wnd = (vout_window_t *)obj; - intf_thread_t *intf; + vout_window_t *p_wnd = (vout_window_t *)p_obj; + intf_thread_t *p_intf; + vlc_value_t val; - if (wnd->cfg->is_standalone || !wnd_req.enabled) + if (p_wnd->cfg->is_standalone) return VLC_EGENERIC; - /* FIXME it should NOT be needed */ - vout_thread_t *vout = vlc_object_find (obj, VLC_OBJECT_VOUT, FIND_PARENT); - if (!vout) - return VLC_EGENERIC; + if( var_Get( p_obj->p_libvlc, "hildon-iface", &val ) ) + val.p_address = NULL; - vlc_mutex_lock (&wnd_req.lock); - while ((intf = wnd_req.intf) == NULL) - vlc_cond_wait (&wnd_req.wait, &wnd_req.lock); - - wnd->handle.xid = request_video( intf, vout ); - vlc_mutex_unlock (&wnd_req.lock); + p_intf = (intf_thread_t *)val.p_address; + if( !p_intf ) + { /* If another interface is used, this plugin cannot work */ + msg_Dbg( p_obj, "Hildon interface not found" ); + return VLC_EGENERIC; + } - vlc_object_release( vout ); + p_wnd->handle.xid = p_intf->p_sys->xid; - if (!wnd->handle.xid) + if (!p_wnd->handle.xid) return VLC_EGENERIC; - msg_Dbg( intf, "Using handle %"PRIu32, wnd->handle.xid ); - - wnd->control = ControlWindow; - wnd->sys = (vout_window_sys_t*)intf; + p_wnd->control = ControlWindow; + p_wnd->sys = (vout_window_sys_t*)p_intf; return VLC_SUCCESS; } -static int ControlWindow (vout_window_t *wnd, int query, va_list args) +static int ControlWindow (vout_window_t *p_wnd, int query, va_list args) { - intf_thread_t *intf = (intf_thread_t *)wnd->sys; + intf_thread_t *p_intf = (intf_thread_t *)p_wnd->sys; switch( query ) { @@ -317,69 +340,48 @@ static int ControlWindow (vout_window_t *wnd, int query, va_list args) int i_height = (int)va_arg( args, int ); int i_current_w, i_current_h; - gdk_drawable_get_size( GDK_DRAWABLE( intf->p_sys->p_video_window->window ), + gdk_drawable_get_size( GDK_DRAWABLE( p_intf->p_sys->p_video_window ), &i_current_w, &i_current_h ); if( i_width != i_current_w || i_height != i_current_h ) return VLC_EGENERIC; return VLC_SUCCESS; } + case VOUT_WINDOW_SET_FULLSCREEN: + { + bool b_fs = va_arg( args, int ); + p_intf->p_sys->b_fullscreen = b_fs; + g_idle_add( fullscreen_cb, p_intf ); + return VLC_SUCCESS; + } default: return VLC_EGENERIC; } } -static void CloseWindow (vlc_object_t *obj) +static void CloseWindow (vlc_object_t *p_obj) { - vout_window_t *wnd = (vout_window_t *)obj; - intf_thread_t *intf = (intf_thread_t *)wnd->sys; - - vlc_mutex_lock( &wnd_req.lock ); - release_video( intf ); - vlc_mutex_unlock( &wnd_req.lock ); -} + vout_window_t *p_wnd = (vout_window_t *)p_obj; + intf_thread_t *p_intf = (intf_thread_t *)p_wnd->sys; -static uint32_t request_video( intf_thread_t *p_intf, vout_thread_t *p_nvout ) -{ - if( p_intf->p_sys->p_vout ) + if( p_intf->p_sys->b_fullscreen ) { - msg_Dbg( p_intf, "Embedded video already in use" ); - return 0; + p_intf->p_sys->b_fullscreen = false; + g_idle_add( fullscreen_cb, p_intf ); } - - p_intf->p_sys->p_vout = vlc_object_hold( p_nvout ); - return GDK_WINDOW_XID( p_intf->p_sys->p_video_window->window ); -} - -static void release_video( intf_thread_t *p_intf ) -{ - msg_Dbg( p_intf, "Releasing embedded video" ); - - vlc_object_release( p_intf->p_sys->p_vout ); - p_intf->p_sys->p_vout = NULL; } -static gboolean video_widget_ready( gpointer data ) +static gboolean interface_ready( gpointer data ) { - intf_thread_t *p_intf = NULL; - GtkWidget *top_window = NULL; - GtkWidget *video = (GtkWidget *)data; + intf_thread_t *p_intf = (intf_thread_t *)data; - top_window = gtk_widget_get_toplevel( GTK_WIDGET( video ) ); - p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT( top_window ), - "p_intf" ); - p_intf->p_sys->p_video_window = video; - gtk_widget_grab_focus( video ); + p_intf->p_sys->xid = + GDK_WINDOW_XID( gtk_widget_get_window(p_intf->p_sys->p_video_window) ); - vlc_mutex_lock( &wnd_req.lock ); - wnd_req.intf = p_intf; - vlc_cond_signal( &wnd_req.wait ); - vlc_mutex_unlock( &wnd_req.lock ); + // Look if the playlist is already started + item_changed_pl( p_intf ); - // We rewind the input - if( p_intf->p_sys->p_input ) - { - input_Control( p_intf->p_sys->p_input, INPUT_SET_POSITION, 0.0 ); - } + // Everything is initialised + vlc_sem_post (&p_intf->p_sys->ready); // We want it to be executed only one time return FALSE; diff --git a/modules/gui/hildon/maemo.h b/modules/gui/hildon/maemo.h index 7814dfcdc3..6bf93c9b82 100644 --- a/modules/gui/hildon/maemo.h +++ b/modules/gui/hildon/maemo.h @@ -21,9 +21,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include #include -#include #include #include @@ -32,19 +35,25 @@ struct intf_sys_t { + vlc_thread_t thread; + playlist_t *p_playlist; input_thread_t *p_input; + vlc_sem_t ready; HildonWindow *p_main_window; HildonSeekbar *p_seekbar; - GtkWidget *p_tabs; GtkWidget *p_play_button; - GtkWidget *p_playlist_store; + GtkListStore *p_playlist_store; + GtkWidget *p_playlist_window; int i_event; vlc_spinlock_t event_lock; GtkWidget *p_video_window; - vout_thread_t *p_vout; + uint32_t xid; /* X11 windows ID */ + bool b_fullscreen; + + GtkWidget *p_control_window; }; diff --git a/modules/gui/hildon/maemo_callbacks.c b/modules/gui/hildon/maemo_callbacks.c index cf6395171a..3e8568939d 100644 --- a/modules/gui/hildon/maemo_callbacks.c +++ b/modules/gui/hildon/maemo_callbacks.c @@ -1,31 +1,39 @@ /***************************************************************************** -* maemo_callbacks.c : Callbacks for the maemo plugin. -***************************************************************************** -* Copyright (C) 2008 the VideoLAN team -* $Id$ -* -* Authors: Antoine Lejeune -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. -*****************************************************************************/ + * maemo_callbacks.c : Callbacks for the maemo plugin. + ***************************************************************************** + * Copyright (C) 2008 the VideoLAN team + * $Id$ + * + * Authors: Antoine Lejeune + * Gildas Bazin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ #include #include "maemo.h" #include "maemo_callbacks.h" +#include +#include + +#ifdef HAVE_MAEMO +# include +#endif + /* * Function used to retrieve an intf_thread_t object from a GtkWidget */ @@ -99,6 +107,22 @@ void next_cb( GtkButton *button, gpointer user_data ) playlist_Next( p_intf->p_sys->p_playlist ); } +void playlist_cb( GtkButton *button, gpointer user_data ) +{ + (void)user_data; + intf_thread_t *p_intf = get_intf_from_widget( GTK_WIDGET( button ) ); + if( GTK_WIDGET_VISIBLE(p_intf->p_sys->p_playlist_window) ) + { + gtk_widget_show_all( p_intf->p_sys->p_video_window ); + gtk_widget_hide_all( p_intf->p_sys->p_playlist_window ); + } + else + { + gtk_widget_hide_all( p_intf->p_sys->p_video_window ); + gtk_widget_show_all( p_intf->p_sys->p_playlist_window ); + } +} + void seekbar_changed_cb( GtkRange *range, GtkScrollType scroll, gdouble value, gpointer data ) { @@ -124,8 +148,6 @@ void pl_row_activated_cb( GtkTreeView *tree_view , GtkTreePath *path, gtk_tree_model_get_iter( model, &iter, path ); gtk_tree_model_get( model, &iter, 0, &filename, -1 ); - gtk_notebook_set_current_page( GTK_NOTEBOOK( p_intf->p_sys->p_tabs ), 0 ); - p_input = input_item_New( p_intf, filename, NULL ); playlist_AddInput( p_intf->p_sys->p_playlist, p_input, PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END, true, false ); @@ -140,8 +162,15 @@ void open_cb( GtkMenuItem *menuitem, gpointer user_data ) GtkWidget *dialog; char *psz_filename = NULL; +#ifdef HAVE_MAEMO dialog = hildon_file_chooser_dialog_new( GTK_WINDOW( p_intf->p_sys->p_main_window ), GTK_FILE_CHOOSER_ACTION_OPEN ); +#else + dialog = gtk_file_chooser_dialog_new( "Open File", GTK_WINDOW( p_intf->p_sys->p_main_window ), + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_OK, NULL ); +#endif gtk_widget_show_all( GTK_WIDGET( dialog ) ); if( gtk_dialog_run( GTK_DIALOG( dialog ) ) == GTK_RESPONSE_OK ) @@ -217,22 +246,22 @@ void open_webcam_cb( GtkMenuItem *menuitem, gpointer user_data ) void snapshot_cb( GtkMenuItem *menuitem, gpointer user_data ) { - (void)menuitem; intf_thread_t *p_intf = (intf_thread_t *)user_data; + input_thread_t *p_input = p_intf->p_sys->p_input; + vout_thread_t *p_vout = p_input ? input_GetVout( p_input ) : NULL; + (void)menuitem; - if( !p_intf->p_sys->p_vout ) + if( !p_vout ) { hildon_banner_show_information( GTK_WIDGET( p_intf->p_sys->p_main_window ), - "gtk-dialog-error", - "There is no video" ); + "gtk-dialog-error", "There is no video" ); return; } - var_TriggerCallback( p_intf->p_sys->p_vout, "video-snapshot" ); + var_TriggerCallback( p_vout, "video-snapshot" ); hildon_banner_show_information( GTK_WIDGET( p_intf->p_sys->p_main_window ), - NULL, - "Snapshot taken" ); + NULL, "Snapshot taken" ); } void dropframe_cb( GtkMenuItem *menuitem, gpointer user_data ) @@ -244,3 +273,105 @@ void dropframe_cb( GtkMenuItem *menuitem, gpointer user_data ) else config_PutInt( p_intf, "ffmpeg-skip-frame", 0 ); } + +static int keyModifiersToVLC( GdkEventKey *event ) +{ + int i_keyModifiers = 0; + if( event->state & GDK_SHIFT_MASK ) i_keyModifiers |= KEY_MODIFIER_SHIFT; + if( event->state & GDK_MOD1_MASK ) i_keyModifiers |= KEY_MODIFIER_ALT; + if( event->state & GDK_CONTROL_MASK ) i_keyModifiers |= KEY_MODIFIER_CTRL; + if( event->state & GDK_META_MASK ) i_keyModifiers |= KEY_MODIFIER_META; + return i_keyModifiers; +} + +static int eventToVLCKey( GdkEventKey *event ) +{ + int i_vlck = 0; + + switch( event->keyval ) + { + case GDK_Left: i_vlck |= KEY_LEFT; break; + case GDK_Right: i_vlck |= KEY_RIGHT; break; + case GDK_Up: i_vlck |= KEY_UP; break; + case GDK_Down: i_vlck |= KEY_DOWN; break; + case GDK_Escape: i_vlck |= KEY_ESC; break; + case GDK_Return: i_vlck |= KEY_ENTER; break; + + case GDK_F1: i_vlck |= KEY_F1; break; + case GDK_F2: i_vlck |= KEY_F2; break; + case GDK_F3: i_vlck |= KEY_F3; break; + case GDK_F4: i_vlck |= KEY_F4; break; + case GDK_F5: i_vlck |= KEY_F5; break; + case GDK_F6: i_vlck |= KEY_F6; break; + case GDK_F7: i_vlck |= KEY_F7; break; + case GDK_F8: i_vlck |= KEY_F8; break; + case GDK_F9: i_vlck |= KEY_F9; break; + case GDK_F10: i_vlck |= KEY_F10; break; + case GDK_F11: i_vlck |= KEY_F11; break; + case GDK_F12: i_vlck |= KEY_F12; break; + + case GDK_Page_Up: i_vlck |= KEY_PAGEUP; break; + case GDK_Page_Down: i_vlck |= KEY_PAGEDOWN; break; + case GDK_Home: i_vlck |= KEY_HOME; break; + case GDK_End: i_vlck |= KEY_END; break; + case GDK_Insert: i_vlck |= KEY_INSERT; break; + case GDK_Delete: i_vlck |= KEY_DELETE; break; + +#ifndef HAVE_MAEMO + case GDK_AudioLowerVolume: i_vlck |= KEY_VOLUME_DOWN; break; + case GDK_AudioRaiseVolume: i_vlck |= KEY_VOLUME_UP; break; + case GDK_AudioMute: i_vlck |= KEY_VOLUME_MUTE; break; + case GDK_AudioPlay: i_vlck |= KEY_MEDIA_PLAY_PAUSE; break; + case GDK_AudioStop: i_vlck |= KEY_MEDIA_STOP; break; + case GDK_AudioNext: i_vlck |= KEY_MEDIA_NEXT_TRACK; break; + case GDK_AudioPrev: i_vlck |= KEY_MEDIA_PREV_TRACK; break; +#endif + } + + if( !i_vlck ) + { + /* Force lowercase */ + if( event->keyval >= GDK_A && event->keyval <= GDK_Z ) + i_vlck = event->keyval + 32; + /* Rest of the ascii range */ + else if( event->keyval >= GDK_space && event->keyval <= GDK_asciitilde ) + i_vlck = event->keyval; + } + + /* Handle modifiers */ + i_vlck |= keyModifiersToVLC( event ); + + return i_vlck; +} + +gboolean key_cb(GtkWidget *widget, GdkEventKey *event, gpointer user_data) +{ + intf_thread_t *p_intf = (intf_thread_t *)user_data; + widget = widget; /* unused */ + + int i_vlck = eventToVLCKey( event ); + if( i_vlck > 0 ) + { + var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck ); + return TRUE; + } + + return FALSE; +} + +gboolean fullscreen_cb( gpointer user_data ) +{ + intf_thread_t *p_intf = (intf_thread_t *)user_data; + + if(p_intf->p_sys->b_fullscreen) + { + gtk_widget_hide_all( GTK_WIDGET( p_intf->p_sys->p_control_window ) ); + gtk_window_fullscreen( GTK_WINDOW(p_intf->p_sys->p_main_window) ); + } + else + { + gtk_window_unfullscreen( GTK_WINDOW(p_intf->p_sys->p_main_window) ); + gtk_widget_show_all( GTK_WIDGET( p_intf->p_sys->p_control_window ) ); + } + return FALSE; +} diff --git a/modules/gui/hildon/maemo_callbacks.h b/modules/gui/hildon/maemo_callbacks.h index 84e7550c99..46c42a7571 100644 --- a/modules/gui/hildon/maemo_callbacks.h +++ b/modules/gui/hildon/maemo_callbacks.h @@ -34,6 +34,7 @@ void play_cb( GtkButton *button, gpointer user_data ); void stop_cb( GtkButton *button, gpointer user_data ); void prev_cb( GtkButton *button, gpointer user_data ); void next_cb( GtkButton *button, gpointer user_data ); +void playlist_cb( GtkButton *button, gpointer user_data ); void seekbar_changed_cb( GtkRange *range, GtkScrollType scroll, gdouble value, gpointer data ); @@ -46,3 +47,6 @@ void open_webcam_cb( GtkMenuItem *menuitem, gpointer user_data ); void snapshot_cb( GtkMenuItem *menuitem, gpointer user_data ); void dropframe_cb( GtkMenuItem *menuitem, gpointer user_data ); + +gboolean key_cb(GtkWidget *widget, GdkEventKey *event, gpointer user_data); +gboolean fullscreen_cb(gpointer user_data); diff --git a/modules/gui/hildon/maemo_input.c b/modules/gui/hildon/maemo_input.c index de7ba9800d..a4fa3161dd 100644 --- a/modules/gui/hildon/maemo_input.c +++ b/modules/gui/hildon/maemo_input.c @@ -1,25 +1,25 @@ /***************************************************************************** -* maemo_input.c : Input handling for the maemo plugin -***************************************************************************** -* Copyright (C) 2008 the VideoLAN team -* $Id$ -* -* Authors: Antoine Lejeune -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. -*****************************************************************************/ + * maemo_input.c : Input handling for the maemo plugin + ***************************************************************************** + * Copyright (C) 2008 the VideoLAN team + * $Id$ + * + * Authors: Antoine Lejeune + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ #ifdef HAVE_CONFIG_H # include "config.h" @@ -194,4 +194,3 @@ static int input_event_cb( vlc_object_t *p_this, const char *psz_var, else return interface_changed_cb( p_this, psz_var, oldval, newval, param ); } - diff --git a/modules/gui/hildon/maemo_input.h b/modules/gui/hildon/maemo_input.h index 03eae50e5c..75ac69a3e9 100644 --- a/modules/gui/hildon/maemo_input.h +++ b/modules/gui/hildon/maemo_input.h @@ -1,25 +1,25 @@ /***************************************************************************** -* maemo_input.h : Input handling header file for the maemo plugin. -***************************************************************************** -* Copyright (C) 2008 the VideoLAN team -* $Id$ -* -* Authors: Antoine Lejeune -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. -*****************************************************************************/ + * maemo_input.h : Input handling header file for the maemo plugin. + ***************************************************************************** + * Copyright (C) 2008 the VideoLAN team + * $Id$ + * + * Authors: Antoine Lejeune + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ #include diff --git a/modules/gui/hildon/maemo_interface.c b/modules/gui/hildon/maemo_interface.c index 16cf8f0927..2824a82832 100644 --- a/modules/gui/hildon/maemo_interface.c +++ b/modules/gui/hildon/maemo_interface.c @@ -1,25 +1,25 @@ /***************************************************************************** -* maemo_interface.c : Interface creation of the maemo plugin -***************************************************************************** -* Copyright (C) 2008 the VideoLAN team -* $Id$ -* -* Authors: Antoine Lejeune -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. -*****************************************************************************/ + * maemo_interface.c : Interface creation of the maemo plugin + ***************************************************************************** + * Copyright (C) 2008 the VideoLAN team + * $Id$ + * + * Authors: Antoine Lejeune + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ #include @@ -101,7 +101,7 @@ void create_playlist( intf_thread_t *p_intf ) playlist = gtk_tree_view_new(); playlist_store = gtk_list_store_new( 1, G_TYPE_STRING ); - p_intf->p_sys->p_playlist_store = GTK_WIDGET( playlist_store ); + p_intf->p_sys->p_playlist_store = playlist_store; gtk_tree_view_set_model( GTK_TREE_VIEW( playlist ), GTK_TREE_MODEL( playlist_store ) ); @@ -117,11 +117,7 @@ void create_playlist( intf_thread_t *p_intf ) scroll = gtk_scrolled_window_new( NULL, NULL ); gtk_container_add( GTK_CONTAINER( scroll ), playlist ); - gtk_notebook_append_page( GTK_NOTEBOOK( p_intf->p_sys->p_tabs ), scroll, - gtk_image_new_from_stock( "vlc-playlist", - GTK_ICON_SIZE_DIALOG ) ); - gtk_notebook_set_tab_label_packing( GTK_NOTEBOOK( p_intf->p_sys->p_tabs ), scroll, - FALSE, FALSE, GTK_PACK_START ); + p_intf->p_sys->p_playlist_window = scroll; g_signal_connect( playlist, "row-activated", G_CALLBACK( pl_row_activated_cb ), NULL ); diff --git a/modules/gui/hildon/maemo_interface.h b/modules/gui/hildon/maemo_interface.h index 87b535e415..2f48462e3a 100644 --- a/modules/gui/hildon/maemo_interface.h +++ b/modules/gui/hildon/maemo_interface.h @@ -1,25 +1,25 @@ /***************************************************************************** -* maemo_interface.h : Interface creation header file for the maemo plugin. -***************************************************************************** -* Copyright (C) 2008 the VideoLAN team -* $Id$ -* -* Authors: Antoine Lejeune -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. -*****************************************************************************/ + * maemo_interface.h : Interface creation header file for the maemo plugin. + ***************************************************************************** + * Copyright (C) 2008 the VideoLAN team + * $Id$ + * + * Authors: Antoine Lejeune + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ #include diff --git a/share/Makefile.am b/share/Makefile.am index 3135827045..748008d955 100644 --- a/share/Makefile.am +++ b/share/Makefile.am @@ -308,11 +308,11 @@ DIST_maemo = \ maemo/vlc_left_tab_active.png \ maemo/vlc_left_tab_passive.png \ maemo/playlist.png + maemo/play.png \ + maemo/pause.png \ + maemo/stop.png \ + maemo/previous.png \ + maemo/next.png maemo_FILES = \ - ../modules/gui/qt4/pixmaps/play.png \ - ../modules/gui/qt4/pixmaps/pause.png \ - ../modules/gui/qt4/pixmaps/stop.png \ - ../modules/gui/qt4/pixmaps/previous.png \ - ../modules/gui/qt4/pixmaps/next.png \ vlc32x32.png diff --git a/share/maemo/next.png b/share/maemo/next.png new file mode 100644 index 0000000000000000000000000000000000000000..67136ffd75d2dc1b8d10c13d57fb88ac49700df8 GIT binary patch literal 162 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP$50j7)XV!(8wLl?#PZ!4!i_^&o609d4*jpy~q)0Vg zW|+jAxafkl1#f~%5YK8xm+WI{44$*x8K*KZ#Qx;uS|d;z2h_^o>FVdQ&MBb@0RKcP A9{>OV literal 0 HcmV?d00001 diff --git a/share/maemo/pause.png b/share/maemo/pause.png new file mode 100644 index 0000000000000000000000000000000000000000..4c33caff5218e1aab46c5f2abb2d235612820201 GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP$50j7)gD{WcO`wpHr;B5V#p&b(iBAoJ-8brWKK(Cz nnYic*>tZ$@Ze}+|W@d&Cbta+2dt3T|su?_8{an^LB{Ts5+Sw*0 literal 0 HcmV?d00001 diff --git a/share/maemo/play.png b/share/maemo/play.png new file mode 100644 index 0000000000000000000000000000000000000000..7b47c69338b10c3fb1dad745882dd89bd49d52bf GIT binary patch literal 178 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP$50j9g3X9UT(?B76PZ!4!i_^&o5;+g-MTB`JHcB-3 z&r4zEkaAhWXu+#=m4T<$M})=9mF+<60jG6tLA(bfxpkgosiZI{A3njzu*8vF`j=FC QGtejoPgg&ebxsLQ042yR1ONa4 literal 0 HcmV?d00001 diff --git a/share/maemo/playlist.png b/share/maemo/playlist.png index c6c703bab68a973de1e31d48ee8575f3afeb814e..b96e2b0c2d8778ef888d3fe41742dfeeaa37e8a2 100644 GIT binary patch delta 108 zcmX@aGnrAbGr-TCmrII^fq{Y7)59eQNDF{42OE%-|NK93qMm`%RURfWP6gqcZeM|d z3Z5>GAr_~T6C^%02zLIJ_kCk;ST)n_aDoX>o4Z5+4?}1g8`t7fTc!imGI+ZBxvX2HE+O0m2L}iBL{Q4GJ0x0000DNk~Le0000W0000W2nGNE0CReJ^Z)<=0drDE zLIAGL9O;oEFn`z!0|6B`*%pH_0000PbVXQnLvL+uWo~o;Lvm$dbY)~9cWHEJAV*0} zP*;Ht7XSbSok>JNR9M69m)mb#R~5#;wf8=^N#Z)h*SKLkF~n}|wgFWYH@^+i{p~|2cm3n~#W&7jM4(4lw{QgSw|z?taG4-pqWm#Iwh} z1`&aX@RMslJ$abE{>^U-cJ8t<=1RMrOj~QuD^HcfAb3>UtKTm?ez>!E^S6`r#=+~Y zR_n4cdVh=o0l@bBW`-i7w(onzAPB!uN#u}Nlli4T=v*}9{6N7^Ts65@7 zEtM;-)ow2XSZT)bv=H*U=`W`zMn}gWh+ti>1%Dt&DWSENg<|1rrBYEPNpcs!Cjg+F zb7ZU?Bch4Xks)LzFCmUwD3&Ty*4S47Kx;h`hH7GDWE5B5x(Xo#wAMYR9s~i7j*f6} z&_JwkKfb1f5Kc*1X6AgkvYkF^#@O4hg9z(N$$bFuJg>sc`ATIgefJ+0Lob2=SLN2uc7rl}fEQoAFXE zpPS#vZ%l(heKjE<0knzeo)F^WRFuj+QvtF>@^h_CHEy;3YONdal-iD>FfWxX5D_ol zTDZ^5hs|blSsQ(!E5P+5fC$?6gQrmx6@Qgd`TrRhbvaV&cb<$S_h)y|BtJRzk zV$Jis>WKg;r6ZqL9rNv{+tn<9R{?rJM9aRfN&qpcYzN4 zU^|MUvQldE)G500#@p|ZPBffjNGY&(@AKyj|Chi11vL&DNRkBTa};1O1QEh8!q0#9 z5kJp?Z+uHQXD6NGuNq^oIOg+GP+3a(?^f)`1biLk~iQ_nZ*1to5MF<67E;PiFZ4JE`o525vx(ik8kjk4jU9Y;7dRnAfq^Fnhs~)Z z(TH1Z09X}7H30B^zr>E8l**;4cDn_D;9Nf>6fnl3R@=2gh*i(?c1}Sgg_A5+nfZ3( z;K%{E1fu&yv@C@v18?9|6s;dMDW_51IK7t#<1ZW6aQt%mW~3-}5VB7;Z`_b1(mjUdD0! Y2cFRvCk<5_!vFvP07*qoM6N<$g3tou_W%F@ diff --git a/share/maemo/previous.png b/share/maemo/previous.png new file mode 100644 index 0000000000000000000000000000000000000000..988c08aaa77c5321b5ea3fbf699860c725933b82 GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP$50j9g^d^_x-+)2}o-U3d7N?UFBv?;8u(wR|nId(< zWnuOPDTgg-F>D4xnr+v)U8I}z1w4yRYAgV1aQ(^2mDZlz4`ecUy85}Sb4q9e09|n_ AT>t<8 literal 0 HcmV?d00001 diff --git a/share/maemo/stop.png b/share/maemo/stop.png new file mode 100644 index 0000000000000000000000000000000000000000..d905a4935c77ccbb7394d4b4fc7d73b4b1880eec GIT binary patch literal 146 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP$50j9-$hTcHcYqA=ba4!^IGvmz@u@+u`$m1x7lXi8 jO@Yj9t&EEs8W|aqJ~0Ya+`JYCRLbD#>gTe~DWM4f>@z5s literal 0 HcmV?d00001 -- 2.39.2