Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

intf.c

00001 /*****************************************************************************
00002  * intf.c: interface for CMML annotations/hyperlinks
00003  *****************************************************************************
00004  * Copyright (C) 2003-2004 Commonwealth Scientific and Industrial Research
00005  *                         Organisation (CSIRO) Australia
00006  * Copyright (C) 2004 the VideoLAN team
00007  *
00008  * $Id: intf.c 12412 2005-08-27 16:40:23Z jpsaman $
00009  *
00010  * Authors: Andre Pang <[email protected]>
00011  *
00012  * This program is free software; you can redistribute it and/or modify
00013  * it under the terms of the GNU General Public License as published by
00014  * the Free Software Foundation; either version 2 of the License, or
00015  * (at your option) any later version.
00016  * 
00017  * This program is distributed in the hope that it will be useful,
00018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  * GNU General Public License for more details.
00021  *
00022  * You should have received a copy of the GNU General Public License
00023  * along with this program; if not, write to the Free Software
00024  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00025  *****************************************************************************/
00026 
00027 /*****************************************************************************
00028  * Preamble
00029  *****************************************************************************/
00030 #include <stdlib.h>                                      /* malloc(), free() */
00031 #include <string.h>
00032 
00033 #include <vlc/vlc.h>
00034 
00035 #ifdef HAVE_UNISTD_H
00036 #    include <unistd.h>
00037 #endif
00038 
00039 #include <vlc/decoder.h>
00040 #include <vlc/input.h>
00041 #include <vlc/intf.h>
00042 #include <vlc/vout.h>
00043 
00044 #include <vlc_osd.h>
00045 
00046 #include "vlc_keys.h"
00047 
00048 #include "browser_open.h"
00049 #include "history.h"
00050 #include "xstrcat.h"
00051 #include "xurl.h"
00052 
00053 #undef  CMML_INTF_USE_TIMED_URIS
00054 
00055 #undef  CMML_INTF_DEBUG
00056 #undef  CMML_INTF_HISTORY_DEBUG
00057 
00058 /*****************************************************************************
00059  * intf_sys_t: description and status of interface
00060  *****************************************************************************/
00061 struct intf_sys_t
00062 {
00063     decoder_t *         p_cmml_decoder;
00064     input_thread_t *    p_input;
00065 
00066     vlc_bool_t          b_key_pressed;
00067 };
00068 
00069 struct navigation_history_t
00070 {
00071     int i_history_size;
00072     int i_last_item;
00073 };
00074 
00075 /*****************************************************************************
00076  * Local prototypes.
00077  *****************************************************************************/
00078 static int   InitThread                 ( intf_thread_t * );
00079 static int   MouseEvent                 ( vlc_object_t *, char const *,
00080                                           vlc_value_t, vlc_value_t, void * );
00081 static int   KeyEvent                   ( vlc_object_t *, char const *,
00082                                           vlc_value_t, vlc_value_t, void * );
00083 
00084 static void  FollowAnchor               ( intf_thread_t * );
00085 static void  GoBack                     ( intf_thread_t * );
00086 static void  GoForward                  ( intf_thread_t * );
00087 
00088 static int   FollowAnchorCallback       ( vlc_object_t *, char const *,
00089                                           vlc_value_t, vlc_value_t, void * );
00090 static int   GoBackCallback             ( vlc_object_t *, char const *,
00091                                           vlc_value_t, vlc_value_t, void * );
00092 static int   GoForwardCallback          ( vlc_object_t *, char const *,
00093                                           vlc_value_t, vlc_value_t, void * );
00094 
00095 static char *GetTimedURLFromPlaylistItem( intf_thread_t *, playlist_item_t * );
00096 static char *GetTimedURIFragmentForTime ( int );
00097 static int   GetCurrentTimeInSeconds    ( input_thread_t * );
00098 static int   DisplayAnchor              ( intf_thread_t *, vout_thread_t *,
00099                                           char *, char * );
00100 static int   DisplayPendingAnchor       ( intf_thread_t *, vout_thread_t * );
00101 static history_t * GetHistory           ( playlist_t * );
00102 static void  ReplacePlaylistItem        ( playlist_t *, char * );
00103 
00104 /* Exported functions */
00105 static void RunIntf        ( intf_thread_t *p_intf );
00106 
00107 /*****************************************************************************
00108  * OpenIntf: initialize CMML interface
00109  *****************************************************************************/
00110 int E_(OpenIntf) ( vlc_object_t *p_this )
00111 {
00112     intf_thread_t *p_intf = (intf_thread_t *)p_this;
00113 
00114     p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
00115     if( p_intf->p_sys == NULL )
00116     {
00117         return( 1 );
00118     };
00119 
00120     p_intf->pf_run = RunIntf;
00121 
00122     var_AddCallback( p_intf->p_vlc, "key-pressed", KeyEvent, p_intf );
00123     /* we also need to add the callback for "mouse-clicked", but do that later
00124      * when we've found a p_vout */
00125 
00126     var_Create( p_intf->p_vlc, "browse-go-back", VLC_VAR_VOID );
00127     var_AddCallback( p_intf->p_vlc, "browse-go-back",
00128                      GoBackCallback, p_intf );
00129     var_Create( p_intf->p_vlc, "browse-go-forward", VLC_VAR_VOID );
00130     var_AddCallback( p_intf->p_vlc, "browse-go-forward",
00131                      GoForwardCallback, p_intf );
00132     var_Create( p_intf->p_vlc, "browse-follow-anchor", VLC_VAR_VOID );
00133     var_AddCallback( p_intf->p_vlc, "browse-follow-anchor",
00134                      FollowAnchorCallback, p_intf );
00135 
00136     return( 0 );
00137 }
00138 
00139 /*****************************************************************************
00140  * CloseIntf: destroy dummy interface
00141  *****************************************************************************/
00142 void E_(CloseIntf) ( vlc_object_t *p_this )
00143 {
00144     intf_thread_t * p_intf = (intf_thread_t *)p_this;
00145     vout_thread_t * p_vout;
00146 
00147 #ifdef CMML_INTF_DEBUG
00148     msg_Dbg( p_intf, "freeing CMML interface" );
00149 #endif
00150 
00151     /* erase the anchor text description from the video output if it exists */
00152     p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
00153     if( p_vout )
00154     {
00155         /* enable CMML as a subtitle track */
00156         spu_Control( p_vout->p_spu, SPU_CHANNEL_CLEAR, DEFAULT_CHAN );
00157         vlc_object_release( p_vout );
00158     }
00159 
00160     var_DelCallback( p_intf->p_vlc, "key-pressed", KeyEvent, p_intf );
00161 
00162     vlc_object_release( p_intf->p_sys->p_cmml_decoder );
00163 
00164     free( p_intf->p_sys );
00165 }
00166 
00167 
00168 /*****************************************************************************
00169  * RunIntf: main loop
00170  *****************************************************************************/
00171 static void RunIntf( intf_thread_t *p_intf )
00172 {
00173     vout_thread_t * p_vout = NULL;
00174 
00175     if( InitThread( p_intf ) < 0 )
00176     {
00177         msg_Err( p_intf, "can't initialize CMML interface" );
00178         return;
00179     }
00180 #ifdef CMML_INTF_DEBUG
00181     msg_Dbg( p_intf, "CMML intf initialized" );
00182 #endif
00183 
00184     /* if video output is dying, disassociate ourselves from it */
00185     if( p_vout && p_vout->b_die )
00186     {
00187         var_DelCallback( p_vout, "mouse-clicked", MouseEvent, p_intf );
00188         vlc_object_release( p_vout );
00189         p_vout = NULL;
00190     }
00191 
00192     /* Main loop */
00193     while( !p_intf->b_die )
00194     {
00195         
00196         /* find a video output if we currently don't have one */
00197         if( p_vout == NULL )
00198         {
00199             p_vout = vlc_object_find( p_intf->p_sys->p_input,
00200                                       VLC_OBJECT_VOUT, FIND_CHILD );
00201             if( p_vout )
00202             {
00203 #ifdef CMML_INTF_DEBUG
00204                 msg_Dbg( p_intf, "found vout thread" );
00205 #endif
00206                 var_AddCallback( p_vout, "mouse-clicked", MouseEvent, p_intf );
00207             }
00208         }
00209 
00210         vlc_mutex_lock( &p_intf->change_lock );
00211 
00212         /*
00213          * keyboard event
00214          */
00215         if( p_intf->p_sys->b_key_pressed )
00216         {
00217             vlc_value_t val;
00218             int i, i_action = -1;
00219             struct hotkey *p_hotkeys = p_intf->p_vlc->p_hotkeys;
00220 
00221             /* Find action triggered by hotkey (if any) */
00222             var_Get( p_intf->p_vlc, "key-pressed", &val );
00223 
00224             /* Acknowledge that we've handled the b_key_pressed event */
00225             p_intf->p_sys->b_key_pressed = VLC_FALSE;
00226 
00227 #ifdef CMML_INTF_DEBUG
00228             msg_Dbg( p_intf, "Got a keypress: %d", val.i_int );
00229 #endif
00230 
00231             for( i = 0; p_hotkeys[i].psz_action != NULL; i++ )
00232             {
00233                 if( p_hotkeys[i].i_key == val.i_int )
00234                     i_action = p_hotkeys[i].i_action;
00235             }
00236 
00237             /* What did the user do? */
00238             if( i_action != -1 )
00239             {
00240                 switch( i_action )
00241                 {
00242                     case ACTIONID_NAV_ACTIVATE:
00243                         FollowAnchor( p_intf );
00244                         break;
00245                     case ACTIONID_HISTORY_BACK:
00246                         GoBack( p_intf );
00247                         break;
00248                     case ACTIONID_HISTORY_FORWARD:
00249                         GoForward( p_intf );
00250                         break;
00251                     default:
00252                         break;
00253                 }
00254             }
00255         }
00256 
00257         vlc_mutex_unlock( &p_intf->change_lock );
00258 
00259         (void) DisplayPendingAnchor( p_intf, p_vout );
00260 
00261         /* Wait a bit */
00262         msleep( INTF_IDLE_SLEEP );
00263     }
00264 
00265     /* if we're here, the video output is dying: release the vout object */
00266 
00267     if( p_vout )
00268     {
00269         var_DelCallback( p_vout, "mouse-clicked", MouseEvent, p_intf );
00270         vlc_object_release( p_vout );
00271     }
00272 
00273     vlc_object_release( p_intf->p_sys->p_input );
00274 }
00275 
00276 /*****************************************************************************
00277  * DisplayPendingAnchor: get a pending anchor description/URL from the CMML
00278  * decoder and display it on screen
00279  *****************************************************************************/
00280 static int DisplayPendingAnchor( intf_thread_t *p_intf, vout_thread_t *p_vout )
00281 {
00282     decoder_t *p_cmml_decoder;
00283     char *psz_description = NULL;
00284     char *psz_url = NULL;
00285 
00286     intf_thread_t *p_primary_intf;
00287     vlc_value_t val;
00288 
00289     p_cmml_decoder = p_intf->p_sys->p_cmml_decoder;
00290     if( var_Get( p_cmml_decoder, "psz-current-anchor-description", &val )
00291             != VLC_SUCCESS )
00292     {
00293         return VLC_TRUE;
00294     }
00295 
00296     if( !val.p_address )
00297         return VLC_TRUE;
00298 
00299     psz_description = val.p_address;
00300 
00301     if( var_Get( p_cmml_decoder, "psz-current-anchor-url", &val )
00302             == VLC_SUCCESS )
00303     {
00304         psz_url = val.p_address;
00305     }
00306 
00307     if( p_vout != NULL )
00308     {
00309         /* don't display anchor if main interface can display it */
00310         p_primary_intf = vlc_object_find( p_intf->p_vlc, VLC_OBJECT_INTF,
00311                 FIND_CHILD );
00312 
00313         if( p_primary_intf )
00314         {
00315             if( var_Get( p_primary_intf, "intf-displays-cmml-description", &val )
00316                     == VLC_SUCCESS )
00317             {
00318                 if( val.b_bool == VLC_TRUE )
00319                 {
00320                     vlc_object_release( p_primary_intf );
00321                     return VLC_TRUE;
00322                 }
00323             }
00324 
00325             vlc_object_release( p_primary_intf );
00326         }
00327 
00328         /* display anchor as subtitle on-screen */
00329         if( DisplayAnchor( p_intf, p_vout, psz_description, psz_url )
00330                 != VLC_SUCCESS )
00331         {
00332             /* text render unsuccessful: do nothing */
00333             return VLC_FALSE;
00334         }
00335 
00336         /* text render successful: clear description */
00337         val.p_address = NULL;
00338         if( var_Set( p_cmml_decoder, "psz-current-anchor-description", val )
00339                 != VLC_SUCCESS )
00340         {
00341             msg_Dbg( p_intf,
00342                      "reset of psz-current-anchor-description failed" );
00343         }
00344         free( psz_description );
00345         psz_url = NULL;
00346     }
00347 
00348     return VLC_TRUE;
00349 }
00350 
00351 
00352 /*****************************************************************************
00353  * InitThread:
00354  *****************************************************************************/
00355 static int InitThread( intf_thread_t * p_intf )
00356 {
00357     /* We might need some locking here */
00358     if( !p_intf->b_die )
00359     {
00360         input_thread_t * p_input;
00361         decoder_t *p_cmml_decoder;
00362 
00363         p_cmml_decoder = vlc_object_find( p_intf, VLC_OBJECT_DECODER, FIND_PARENT );
00364         p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_PARENT );
00365 
00366 #ifdef CMML_INTF_DEBUG
00367         msg_Dbg( p_intf, "cmml decoder at %p, input thread at %p",
00368                  p_cmml_decoder, p_input );
00369 #endif
00370 
00371         /* Maybe the input just died */
00372         if( p_input == NULL )
00373         {
00374             return VLC_EGENERIC;
00375         }
00376 
00377         vlc_mutex_lock( &p_intf->change_lock );
00378 
00379         p_intf->p_sys->p_input = p_input;
00380         p_intf->p_sys->p_cmml_decoder = p_cmml_decoder;
00381 
00382         p_intf->p_sys->b_key_pressed = VLC_FALSE;
00383 
00384         vlc_mutex_unlock( &p_intf->change_lock );
00385 
00386         return VLC_SUCCESS;
00387     }
00388     else
00389     {
00390         return VLC_EGENERIC;
00391     }
00392 }
00393 
00394 /*****************************************************************************
00395  * MouseEvent: callback for mouse events
00396  *****************************************************************************/
00397 static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
00398                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
00399 {
00400     /* TODO: handle mouse clicks on the anchor text */
00401 
00402     return VLC_SUCCESS;
00403 }
00404 
00405 /*****************************************************************************
00406  * KeyEvent: callback for keyboard events
00407  *****************************************************************************/
00408 static int KeyEvent( vlc_object_t *p_this, char const *psz_var,
00409                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
00410 {
00411     intf_thread_t *p_intf = (intf_thread_t *)p_data;
00412     vlc_mutex_lock( &p_intf->change_lock );
00413 
00414     p_intf->p_sys->b_key_pressed = VLC_TRUE;
00415     
00416     vlc_mutex_unlock( &p_intf->change_lock );
00417 
00418     return VLC_SUCCESS;
00419 }
00420 
00421 /*****************************************************************************
00422  * FollowAnchor: follow the current anchor being displayed to the user
00423  *****************************************************************************/
00424 static void FollowAnchor ( intf_thread_t *p_intf )
00425 {
00426     intf_sys_t *p_sys;
00427     decoder_t *p_cmml_decoder;
00428     char *psz_url = NULL;
00429     vlc_value_t val;
00430 
00431     msg_Dbg( p_intf, "User followed anchor" );
00432 
00433     p_sys = p_intf->p_sys;
00434     p_cmml_decoder = p_sys->p_cmml_decoder;
00435 
00436     if( var_Get( p_cmml_decoder, "psz-current-anchor-url", &val ) ==
00437             VLC_SUCCESS )
00438     {
00439         if( val.p_address ) psz_url = val.p_address;
00440     }
00441 
00442 #ifdef CMML_INTF_DEBUG
00443     msg_Dbg( p_intf, "Current URL is \"%s\"", psz_url );
00444 #endif
00445 
00446     if( psz_url )
00447     {
00448         playlist_t *p_playlist;
00449         playlist_item_t *p_current_item;
00450         char *psz_uri_to_load;
00451         mtime_t i_seconds;
00452         vlc_value_t time;
00453 
00454         p_playlist = (playlist_t *) vlc_object_find( p_intf, 
00455                 VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
00456         if ( !p_playlist )
00457         {
00458             msg_Warn( p_intf, "can't find playlist" );
00459             return;
00460         }
00461 
00462         /* Get new URL */
00463         p_current_item = p_playlist->pp_items[p_playlist->i_index];
00464 #ifdef CMML_INTF_DEBUG
00465         msg_Dbg( p_intf, "Current playlist item URL is \"%s\"",
00466                 p_current_item->input.psz_uri );
00467 #endif
00468 
00469         psz_uri_to_load = XURL_Concat( p_current_item->input.psz_uri,
00470                                        psz_url );
00471 
00472 #ifdef CMML_INTF_DEBUG
00473         msg_Dbg( p_intf, "URL to load is \"%s\"", psz_uri_to_load );
00474 #endif
00475 
00476         if( var_Get( p_intf->p_sys->p_input, "time", &time ) )
00477         {
00478             msg_Dbg( p_intf, "couldn't get time from current clip" );
00479             time.i_time = 0;
00480         }
00481         i_seconds = time.i_time / 1000000;
00482 #ifdef CMML_INTF_DEBUG
00483         msg_Dbg( p_intf, "Current time is \"%lld\"", i_seconds );
00484 #endif
00485 
00486         /* TODO: we need a (much) more robust way of detecting whether
00487          * the file's a media file ... */
00488         if( strstr( psz_uri_to_load, ".anx" ) != NULL )
00489         {
00490             history_t *p_history = NULL;
00491             history_item_t *p_history_item = NULL;
00492             char *psz_timed_url;
00493 
00494             p_history = GetHistory( p_playlist );
00495 
00496             /* create history item */
00497             psz_timed_url = GetTimedURLFromPlaylistItem( p_intf, p_current_item );
00498             p_history_item = historyItem_New( psz_timed_url, psz_timed_url );
00499             free( psz_timed_url );
00500 
00501             if( !p_history_item )
00502             {
00503                 msg_Warn( p_intf, "could not initialise history item" );
00504             }
00505             else
00506             {
00507 #ifdef CMML_INTF_DEBUG
00508                 msg_Dbg( p_intf, "history pre-index %d", p_history->i_index );
00509 #endif
00510                 history_PruneAndInsert( p_history, p_history_item );
00511 #ifdef CMML_INTF_DEBUG
00512                 msg_Dbg( p_intf, "new history item at %p, uri is \"%s\"",
00513                          p_history_item, p_history_item->psz_uri );
00514                 msg_Dbg( p_intf, "history index now %d", p_history->i_index );
00515 #endif
00516             }
00517 
00518             /* free current-anchor-url */
00519             free( psz_url );
00520             val.p_address = NULL;
00521             if( var_Set( p_cmml_decoder, "psz-current-anchor-url", val ) !=
00522                     VLC_SUCCESS )
00523             {
00524                 msg_Dbg( p_intf, "couldn't reset psz-current-anchor-url" );
00525             }
00526 
00527             ReplacePlaylistItem( p_playlist, psz_uri_to_load );
00528         }
00529         else
00530         {
00531 #ifdef CMML_INTF_DEBUG
00532             msg_Dbg( p_intf, "calling browser_Open with \"%s\"", psz_url );
00533 #endif
00534             (void) browser_Open( psz_url );
00535             playlist_Control( p_playlist, PLAYLIST_PAUSE, 0 );
00536         }
00537 
00538         free( psz_uri_to_load );
00539 
00540         vlc_object_release( p_playlist );
00541     }
00542 }
00543 
00544 static
00545 char *GetTimedURLFromPlaylistItem( intf_thread_t *p_intf,
00546         playlist_item_t *p_current_item )
00547 {
00548 #ifdef CMML_INTF_USE_TIMED_URIS
00549     char *psz_url = NULL;
00550     char *psz_return_value = NULL;
00551     char *psz_seconds = NULL;
00552     int i_seconds;
00553     
00554     psz_url = XURL_GetWithoutFragment( p_current_item->input->psz_uri );
00555 
00556     /* Get current time as a string */
00557     if( XURL_IsFileURL( psz_url ) == VLC_TRUE )
00558         psz_url = xstrcat( psz_url, "#" );
00559     else
00560         psz_url = xstrcat( psz_url, "?" );
00561 
00562     /* jump back to 2 seconds before where we are now */
00563     i_seconds = GetCurrentTimeInSeconds( p_intf->p_sys->p_input ) - 2;
00564     psz_seconds = GetTimedURIFragmentForTime( i_seconds < 0 ? 0 : i_seconds );
00565     if( psz_seconds )
00566     {
00567         psz_url = xstrcat( psz_url, psz_seconds );
00568         free( psz_seconds );
00569         psz_return_value = psz_url;
00570     }
00571 
00572     return psz_return_value;
00573 #else
00574     void *p;
00575 
00576     /* Suppress warning messages about unused functions */
00577     p = GetTimedURIFragmentForTime; /* unused */
00578     p = GetCurrentTimeInSeconds;    /* unused */
00579 
00580     return strdup( p_current_item->input.psz_uri );
00581 #endif
00582 }
00583 
00584 
00585 /*
00586  * Get the current time, rounded down to the nearest second
00587  *
00588  * http://www.ietf.org/internet-drafts/draft-pfeiffer-temporal-fragments-02.txt
00589  */
00590 static
00591 int GetCurrentTimeInSeconds( input_thread_t *p_input )
00592 {
00593     vlc_value_t time;
00594     mtime_t i_seconds;
00595 
00596     var_Get( p_input, "time", &time );
00597     i_seconds = time.i_time / 1000000;
00598 
00599     return i_seconds;
00600 }
00601 
00602 static
00603 char *GetTimedURIFragmentForTime( int seconds )
00604 {
00605     char *psz_time;
00606 
00607     asprintf( &psz_time, "%d", seconds );
00608 
00609     return psz_time;
00610 }
00611 
00612 static
00613 int GoBackCallback( vlc_object_t *p_this, char const *psz_var,
00614                     vlc_value_t oldval, vlc_value_t newval, void *p_data )
00615 {
00616     intf_thread_t *p_intf = (intf_thread_t *) p_data;
00617     GoBack( p_intf );
00618     return VLC_SUCCESS;
00619 }
00620 
00621 static
00622 int GoForwardCallback( vlc_object_t *p_this, char const *psz_var,
00623                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
00624 {
00625     intf_thread_t *p_intf = (intf_thread_t *) p_data;
00626     GoForward( p_intf );
00627     return VLC_SUCCESS;
00628 }
00629 
00630 static
00631 int FollowAnchorCallback( vlc_object_t *p_this, char const *psz_var,
00632                           vlc_value_t oldval, vlc_value_t newval,
00633                           void *p_data )
00634 {
00635     intf_thread_t *p_intf = (intf_thread_t *) p_data;
00636     FollowAnchor( p_intf );
00637     return VLC_SUCCESS;
00638 }
00639 
00640 static
00641 void GoBack( intf_thread_t *p_intf )
00642 {
00643     vlc_value_t history;
00644     history_t *p_history = NULL;
00645     history_item_t *p_history_item = NULL;
00646     history_item_t *p_new_history_item = NULL;
00647     playlist_t *p_playlist = NULL;
00648     char *psz_timed_url = NULL;
00649     playlist_item_t *p_current_item;
00650 
00651 #ifdef CMML_INTF_DEBUG
00652     msg_Dbg( p_intf, "Going back in navigation history" );
00653 #endif
00654 
00655     /* Find the playlist */
00656     p_playlist = (playlist_t *) vlc_object_find( p_intf, 
00657             VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
00658     if ( !p_playlist )
00659     {
00660         msg_Warn( p_intf, "can't find playlist" );
00661         return;
00662     }
00663 
00664     /* Retrieve navigation history from playlist */
00665     if( var_Get( p_playlist, "navigation-history", &history ) != VLC_SUCCESS ||
00666         !history.p_address )
00667     {
00668         /* History doesn't exist yet: ignore user's request */
00669         msg_Warn( p_intf, "can't go back: no history exists yet" );
00670         vlc_object_release( p_playlist );
00671         return;
00672     }
00673 
00674     p_history = history.p_address;
00675 #ifdef CMML_INTF_DEBUG
00676     msg_Dbg( p_intf, "back: nav history retrieved from %p", p_history );
00677     msg_Dbg( p_intf, "nav history index:%d, p_xarray:%p", p_history->i_index,
00678              p_history->p_xarray );
00679 #endif
00680 
00681     /* Check whether we can go back in the history */
00682     if( history_CanGoBack( p_history ) == VLC_FALSE )
00683     {
00684         msg_Warn( p_intf, "can't go back: already at beginning of history" );
00685         vlc_object_release( p_playlist );
00686         return;
00687     }
00688 
00689     p_current_item = p_playlist->pp_items[p_playlist->i_index];
00690 
00691     /* Save the currently-playing media in a new history item */
00692     psz_timed_url = GetTimedURLFromPlaylistItem( p_intf, p_current_item );
00693     p_new_history_item = historyItem_New( psz_timed_url, psz_timed_url );
00694     free( psz_timed_url );
00695 
00696     if( !p_new_history_item )
00697     {
00698 #ifdef CMML_INTF_DEBUG
00699         msg_Dbg( p_intf, "back: could not initialise new history item" );
00700 #endif
00701         vlc_object_release( p_playlist );
00702         return;
00703     }
00704 
00705     /* Go back in the history, saving the currently-playing item */
00706     (void) history_GoBackSavingCurrentItem( p_history, p_new_history_item );
00707     p_history_item = history_Item( p_history );
00708 
00709 #ifdef CMML_INTF_DEBUG
00710     msg_Dbg( p_intf, "retrieving item from h index %d", p_history->i_index );
00711     msg_Dbg( p_intf, "got previous history item: %p", p_history_item );
00712     msg_Dbg( p_intf, "prev history item URL: \"%s\"", p_history_item->psz_uri );
00713 #endif
00714 
00715     ReplacePlaylistItem( p_playlist, p_history_item->psz_uri );
00716     vlc_object_release( p_playlist );
00717 }
00718 
00719 static
00720 void GoForward( intf_thread_t *p_intf )
00721 {
00722     vlc_value_t history;
00723     history_t *p_history = NULL;
00724     history_item_t *p_history_item = NULL;
00725     history_item_t *p_new_history_item = NULL;
00726     playlist_t *p_playlist = NULL;
00727     playlist_item_t *p_current_item;
00728 
00729 #ifdef CMML_INTF_DEBUG
00730     msg_Dbg( p_intf, "Going forward in navigation history" );
00731 #endif
00732 
00733     /* Find the playlist */
00734     p_playlist = (playlist_t *) vlc_object_find( p_intf, 
00735             VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
00736     if ( !p_playlist )
00737     {
00738         msg_Warn( p_intf, "can't find playlist" );
00739         return;
00740     }
00741 
00742     /* Retrieve navigation history from playlist */
00743     if( var_Get( p_playlist, "navigation-history", &history ) != VLC_SUCCESS ||
00744         !history.p_address )
00745     {
00746         /* History doesn't exist yet: ignore user's request */
00747         msg_Warn( p_intf, "can't go back: no history exists yet" );
00748         vlc_object_release( p_playlist );
00749         return;
00750     }
00751 
00752     p_history = history.p_address;
00753 #ifdef CMML_INTF_DEBUG
00754     msg_Dbg( p_intf, "forward: nav history retrieved from %p", p_history );
00755     msg_Dbg( p_intf, "nav history index:%d, p_xarray:%p", p_history->i_index,
00756              p_history->p_xarray );
00757 #endif
00758 
00759     /* Check whether we can go forward in the history */
00760     if( history_CanGoForward( p_history ) == VLC_FALSE )
00761     {
00762         msg_Warn( p_intf, "can't go forward: already at end of history" );
00763         vlc_object_release( p_playlist );
00764         return;
00765     }
00766 
00767     /* Save the currently-playing media in a new history item */
00768     p_new_history_item = malloc( sizeof(history_item_t) );
00769     if( !p_new_history_item )
00770     {
00771 #ifdef CMML_INTF_DEBUG
00772         msg_Dbg( p_intf, "forward: could not initialise new history item" );
00773 #endif
00774         vlc_object_release( p_playlist );
00775         return;
00776     }
00777     p_current_item = p_playlist->pp_items[p_playlist->i_index];
00778     p_new_history_item->psz_uri = GetTimedURLFromPlaylistItem( p_intf, 
00779             p_current_item );
00780     p_new_history_item->psz_name = p_new_history_item->psz_uri;
00781 
00782     /* Go forward in the history, saving the currently-playing item */
00783     (void) history_GoForwardSavingCurrentItem( p_history, p_new_history_item );
00784     p_history_item = history_Item( p_history );
00785 
00786 #ifdef CMML_INTF_DEBUG
00787     msg_Dbg( p_intf, "retrieving item from h index %d", p_history->i_index );
00788     msg_Dbg( p_intf, "got next history item: %p", p_history_item );
00789     msg_Dbg( p_intf, "next history item URL: \"%s\"", p_history_item->psz_uri );
00790 #endif
00791 
00792     ReplacePlaylistItem( p_playlist, p_history_item->psz_uri );
00793     vlc_object_release( p_playlist );
00794 }
00795 
00796 static void ReplacePlaylistItem( playlist_t *p_playlist, char *psz_uri )
00797 {
00798     playlist_Stop( p_playlist );
00799     (void) playlist_Add( p_playlist, psz_uri, psz_uri,
00800                          PLAYLIST_REPLACE, p_playlist->i_index );
00801     playlist_Goto( p_playlist, p_playlist->i_index );
00802 }
00803 
00804 /****************************************************************************
00805  * DisplayAnchor: displays an anchor on the given video output
00806  ****************************************************************************/
00807 static int DisplayAnchor( intf_thread_t *p_intf,
00808         vout_thread_t *p_vout,
00809         char *psz_anchor_description,
00810         char *psz_anchor_url )
00811 {
00812     int i_margin_h, i_margin_v;
00813     mtime_t i_now;
00814 
00815     i_margin_h = 0;
00816     i_margin_v = 10;
00817 
00818     i_now = mdate();
00819 
00820     if( p_vout )
00821     {
00822         text_style_t *p_style = NULL;
00823 
00824         text_style_t blue_with_underline = default_text_style;
00825         blue_with_underline.b_underline = VLC_TRUE;
00826         blue_with_underline.i_color = 0x22ff22;
00827 
00828         if( psz_anchor_url )
00829         {
00830             /* Should display subtitle underlined and in blue, but it looks
00831              * like VLC doesn't implement any text styles yet.  D'oh! */
00832             p_style = &blue_with_underline;
00833 
00834         }
00835 
00836         /* TODO: p_subpicture doesn't have the proper i_x and i_y
00837          * coordinates.  Need to look at the subpicture display system to
00838          * work out why. */
00839         if ( vout_ShowTextAbsolute( p_vout, DEFAULT_CHAN,
00840                 psz_anchor_description, p_style, OSD_ALIGN_BOTTOM,
00841                 i_margin_h, i_margin_v, i_now, 0 ) == VLC_SUCCESS )
00842         {
00843             /* Displayed successfully */
00844         }
00845         else
00846         {
00847             return VLC_EGENERIC;
00848         }
00849 
00850     }
00851     else
00852     {
00853         msg_Dbg( p_intf, "DisplayAnchor couldn't find a video output" );
00854         return VLC_EGENERIC;
00855     }
00856 
00857     return VLC_SUCCESS;
00858 }
00859 
00860 static history_t * GetHistory( playlist_t *p_playlist )
00861 {
00862     vlc_value_t val;
00863     history_t *p_history = NULL;
00864 
00865     if( var_Get( p_playlist, "navigation-history", &val ) != VLC_SUCCESS )
00866     {
00867         /* history doesn't exist yet: need to create it */
00868         history_t *new_history = history_New();
00869         val.p_address = new_history;
00870         var_Create( p_playlist, "navigation-history",
00871                 VLC_VAR_ADDRESS|VLC_VAR_DOINHERIT );
00872         if( var_Set( p_playlist, "navigation-history", val ) != VLC_SUCCESS )
00873         {
00874             msg_Warn( p_playlist, "could not initialise history" );
00875         }
00876         else
00877         {
00878             p_history = new_history;
00879 #ifdef CMML_INTF_HISTORY_DEBUG
00880             msg_Dbg( p_playlist, "nav history created at %p", new_history );
00881             msg_Dbg( p_playlist, "nav history index:%d, p_xarray:%p",
00882                      p_history->i_index, p_history->p_xarray );
00883 #endif
00884         }
00885     }
00886     else
00887     {
00888         p_history = val.p_address;
00889 #ifdef CMML_INTF_HISTORY_DEBUG
00890         msg_Dbg( p_playlist, "nav history retrieved from %p", p_history );
00891 #endif
00892     }
00893 
00894     return p_history;
00895 }
00896 

Generated on Tue Dec 20 10:14:27 2005 for vlc-0.8.4a by  doxygen 1.4.2