]> git.sesse.net Git - vlc/blob - src/playlist/item.c
Fix deletion of items when changing them to nodes
[vlc] / src / playlist / item.c
1 /*****************************************************************************
2  * item.c : Playlist item creation/deletion/add/removal functions
3  *****************************************************************************
4  * Copyright (C) 1999-2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *          ClĂ©ment Stenac <zorglub@videolan.org>
9  *
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.
14  *
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.
19  *
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  *****************************************************************************/
24 #include <vlc/vlc.h>
25 #include <vlc/input.h>
26 #include <assert.h>
27 #include "vlc_playlist.h"
28
29 void AddItem( playlist_t *p_playlist, playlist_item_t *p_item,
30               playlist_item_t *p_node, int i_pos );
31 void GoAndPreparse( playlist_t *p_playlist, int i_mode,
32                     playlist_item_t *, playlist_item_t * );
33 void ChangeToNode( playlist_t *p_playlist, playlist_item_t *p_item );
34 int DeleteInner( playlist_t * p_playlist, playlist_item_t *p_item,
35                           vlc_bool_t b_stop );
36
37 /*****************************************************************************
38  * Playlist item creation
39  *****************************************************************************/
40 /**
41  * Create a new item, without adding it to the playlist
42  *
43  * \param p_obj a vlc object (anyone will do)
44  * \param psz_uri the mrl of the item
45  * \param psz_name a text giving a name or description of the item
46  * \return the new item or NULL on failure
47  */
48 playlist_item_t * __playlist_ItemNew( vlc_object_t *p_obj,
49                                       const char *psz_uri,
50                                       const char *psz_name )
51 {
52     return playlist_ItemNewWithType( p_obj, psz_uri,
53                                      psz_name, 0, NULL, -1,
54                                      ITEM_TYPE_UNKNOWN );
55 }
56
57 playlist_item_t * playlist_ItemNewWithType( vlc_object_t *p_obj,
58                                             const char *psz_uri,
59                                             const char *psz_name,
60                                             int i_options,
61                                             const char **ppsz_options,
62                                             int i_duration,
63                                             int i_type )
64 {
65     input_item_t *p_input;
66
67     if( psz_uri == NULL ) return NULL;
68     p_input = input_ItemNewWithType( p_obj, psz_uri,
69                                         psz_name, i_options, ppsz_options,
70                                         i_duration, i_type );
71     return playlist_ItemNewFromInput( p_obj, p_input );
72 }
73
74 playlist_item_t *__playlist_ItemNewFromInput( vlc_object_t *p_obj,
75                                             input_item_t *p_input )
76 {
77     /** FIXME !!!!! don't find playlist each time */
78     playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_obj, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
79     DECMALLOC_NULL( p_item, playlist_item_t );
80
81     p_item->p_input = p_input;
82     vlc_gc_incref( p_item->p_input );
83
84     p_item->i_id = ++p_playlist->i_last_playlist_id;
85
86     p_item->p_parent = NULL;
87     p_item->i_children = -1;
88     p_item->pp_children = NULL;
89     p_item->i_flags = 0;
90
91     vlc_object_release( p_playlist );
92
93     return p_item;
94 }
95
96 /***************************************************************************
97  * Playlist item destruction
98  ***************************************************************************/
99
100 /** Delete a playlist item and detach its input item */
101 int playlist_ItemDelete( playlist_item_t *p_item )
102 {
103     vlc_gc_decref( p_item->p_input );
104     free( p_item );
105     return VLC_SUCCESS;
106 }
107
108 /** Remove an input item from ONELEVEL and CATEGORY */
109 int playlist_DeleteAllFromInput( playlist_t *p_playlist, int i_input_id )
110 {
111     playlist_DeleteFromInput( p_playlist, i_input_id,
112                               p_playlist->p_root_category, VLC_TRUE );
113     playlist_DeleteFromInput( p_playlist, i_input_id,
114                               p_playlist->p_root_onelevel, VLC_TRUE );
115     return VLC_SUCCESS;
116 }
117
118 /** Remove an input item from ONELEVEL and CATEGORY.
119  * This function must be entered without the playlist lock */
120 int playlist_LockDeleteAllFromInput( playlist_t * p_playlist, int i_id )
121 {
122     int i_ret;
123     vlc_mutex_lock( &p_playlist->object_lock );
124     i_ret = playlist_DeleteAllFromInput( p_playlist, i_id );
125     vlc_mutex_unlock( &p_playlist->object_lock );
126     return i_ret;
127 }
128
129 /** Remove an input item when it appears from a root playlist item */
130 int playlist_DeleteFromInput( playlist_t *p_playlist, int i_input_id,
131                               playlist_item_t *p_root, vlc_bool_t b_do_stop )
132 {
133     int i;
134     for( i = 0 ; i< p_root->i_children ; i++ )
135     {
136         if( p_root->pp_children[i]->i_children == -1 &&
137             p_root->pp_children[i]->p_input->i_id == i_input_id )
138         {
139             DeleteInner( p_playlist, p_root->pp_children[i], b_do_stop );
140             return VLC_SUCCESS;
141         }
142         else if( p_root->pp_children[i]->i_children >= 0 )
143         {
144             int i_ret = playlist_DeleteFromInput( p_playlist, i_input_id,
145                                         p_root->pp_children[i], b_do_stop );
146             if( i_ret == VLC_SUCCESS ) return VLC_SUCCESS;
147         }
148     }
149     return VLC_EGENERIC;
150 }
151
152 /** Remove a playlist item from the playlist, given its id */
153 int playlist_DeleteFromItemId( playlist_t *p_playlist, int i_id )
154 {
155     playlist_item_t *p_item = playlist_ItemGetById( p_playlist, i_id );
156     if( !p_item ) return VLC_EGENERIC;
157     return DeleteInner( p_playlist, p_item, VLC_TRUE );
158 }
159
160 /** Remove a playlist item from the playlist, given its id
161  * This function should be entered without the playlist lock */
162 int playlist_LockDelete( playlist_t * p_playlist, int i_id )
163 {
164     int i_ret;
165     vlc_mutex_lock( &p_playlist->object_lock );
166     i_ret = playlist_DeleteFromItemId( p_playlist, i_id );
167     vlc_mutex_unlock( &p_playlist->object_lock );
168     return i_ret;
169 }
170
171 /** Clear the playlist */
172 void playlist_Clear( playlist_t * p_playlist )
173 {
174     playlist_NodeEmpty( p_playlist, p_playlist->p_root_category, VLC_TRUE );
175     playlist_NodeEmpty( p_playlist, p_playlist->p_root_onelevel, VLC_TRUE );
176 }
177 /** Clear the playlist. This function must be entered without the lock */
178 void playlist_LockClear( playlist_t *p_playlist )
179 {
180     vlc_mutex_lock( &p_playlist->object_lock );
181     playlist_Clear( p_playlist );
182     vlc_mutex_unlock( &p_playlist->object_lock );
183 }
184
185 /***************************************************************************
186  * Playlist item addition
187  ***************************************************************************/
188
189 /**
190  * Add a MRL into the playlist.
191  *
192  * \param p_playlist the playlist to add into
193  * \param psz_uri the mrl to add to the playlist
194  * \param psz_name a text giving a name or description of this item
195  * \param i_mode the mode used when adding
196  * \param i_pos the position in the playlist where to add. If this is
197  *        PLAYLIST_END the item will be added at the end of the playlist
198  *        regardless of it's size
199  * \return The id of the playlist item
200  */
201 int playlist_PlaylistAdd( playlist_t *p_playlist, const char *psz_uri,
202                           const char *psz_name, int i_mode, int i_pos )
203 {
204     return playlist_PlaylistAddExt( p_playlist, psz_uri, psz_name,
205                                     i_mode, i_pos, -1, NULL, 0 );
206 }
207
208 /**
209  * Add a MRL into the playlist, duration and options given
210  *
211  * \param p_playlist the playlist to add into
212  * \param psz_uri the mrl to add to the playlist
213  * \param psz_name a text giving a name or description of this item
214  * \param i_mode the mode used when adding
215  * \param i_pos the position in the playlist where to add. If this is
216  *        PLAYLIST_END the item will be added at the end of the playlist
217  *        regardless of it's size
218  * \param i_duration length of the item in milliseconds.
219  * \param ppsz_options an array of options
220  * \param i_options the number of options
221  * \return The id of the playlist item
222 */
223 int playlist_PlaylistAddExt( playlist_t *p_playlist, const char * psz_uri,
224                              const char *psz_name, int i_mode, int i_pos,
225                              mtime_t i_duration, const char **ppsz_options,
226                              int i_options )
227 {
228     input_item_t *p_input = input_ItemNewExt( p_playlist, psz_uri, psz_name,
229                                               i_options, ppsz_options,
230                                               i_duration );
231
232     return playlist_PlaylistAddInput( p_playlist, p_input, i_mode, i_pos );
233 }
234
235 /** Add an input item to the playlist node */
236 int playlist_PlaylistAddInput( playlist_t* p_playlist, input_item_t *p_input,
237                                int i_mode, int i_pos )
238 {
239     playlist_item_t *p_item_cat, *p_item_one;
240
241     msg_Dbg( p_playlist, "adding playlist item `%s' ( %s )",
242              p_input->psz_name, p_input->psz_uri );
243
244     vlc_mutex_lock( &p_playlist->object_lock );
245
246     /* Add to ONELEVEL */
247     p_item_one = playlist_ItemNewFromInput( p_playlist, p_input );
248     if( p_item_one == NULL ) return VLC_EGENERIC;
249     AddItem( p_playlist, p_item_one ,p_playlist->p_local_onelevel, i_pos );
250
251     /* Add to CATEGORY */
252     p_item_cat = playlist_ItemNewFromInput( p_playlist, p_input );
253     if( p_item_cat == NULL ) return VLC_EGENERIC;
254     AddItem( p_playlist, p_item_cat, p_playlist->p_local_category, i_pos );
255
256     GoAndPreparse( p_playlist, i_mode, p_item_cat, p_item_one );
257
258     vlc_mutex_unlock( &p_playlist->object_lock );
259     return VLC_SUCCESS;
260 }
261
262 /** Add an input item to p_direct_parent in the category tree, and to the
263  *  matching top category in onelevel **/
264 int playlist_BothAddInput( playlist_t *p_playlist,
265                            input_item_t *p_input,
266                            playlist_item_t *p_direct_parent,
267                            int i_mode, int i_pos )
268 {
269     playlist_item_t *p_item_cat, *p_item_one, *p_up;
270     int i_top;
271     assert( p_input );
272     vlc_mutex_lock( & p_playlist->object_lock );
273
274     /* Add to category */
275     p_item_cat = playlist_ItemNewFromInput( p_playlist, p_input );
276     if( p_item_cat == NULL ) return VLC_EGENERIC;
277     AddItem( p_playlist, p_item_cat, p_direct_parent, i_pos );
278
279     /* Add to onelevel */
280     /** \todo make a faster case for ml import */
281     p_item_one = playlist_ItemNewFromInput( p_playlist, p_input );
282     if( p_item_one == NULL ) return VLC_EGENERIC;
283
284     p_up = p_direct_parent;
285     while( p_up->p_parent != p_playlist->p_root_category )
286     {
287         p_up = p_up->p_parent;
288     }
289     for( i_top = 0 ; i_top < p_playlist->p_root_onelevel->i_children; i_top++ )
290     {
291         if( p_playlist->p_root_onelevel->pp_children[i_top]->p_input->i_id == p_up->p_input->i_id )
292         {
293             AddItem( p_playlist, p_item_one,
294                      p_playlist->p_root_onelevel->pp_children[i_top], i_pos );
295             break;
296         }
297     }
298     GoAndPreparse( p_playlist, i_mode, p_item_cat, p_item_one );
299
300     vlc_mutex_unlock( &p_playlist->object_lock );
301     return VLC_SUCCESS;
302 }
303
304 /**
305  * Add an item where it should be added, when adding from a node
306  * (ex: directory access, playlist demuxers, services discovery, ... )
307  * \param p_playlist the playlist
308  * \param p_input the input to add
309  * \param p_parent the direct node
310  * \param p_item_in_category the item within category root (as returned by playlist_ItemToNode)
311  * \param b_forced_parent Are we forced to add only to p_parent ?
312  */
313 void playlist_AddWhereverNeeded( playlist_t *p_playlist, input_item_t *p_input,
314                                  playlist_item_t *p_parent,
315                                  playlist_item_t *p_item_in_category,
316                                  vlc_bool_t b_forced_parent, int i_mode )
317 {
318     /* If we have forced a parent :
319      *   - Just add the input to the forced parent (which should be p_parent)
320      * Else
321      *    - If we have item in category, add to it, and to onelevel (bothadd)
322      *    - If we don't, just add to p_parent
323      */
324     if( b_forced_parent == VLC_TRUE || !p_item_in_category  )
325     {
326         playlist_NodeAddInput( p_playlist, p_input, p_parent, i_mode,
327                                PLAYLIST_END );
328     }
329     else
330     {
331         playlist_BothAddInput( p_playlist, p_input, p_item_in_category,
332                                i_mode, PLAYLIST_END );
333     }
334 }
335
336
337 /** Add an input item to a given node */
338 playlist_item_t * playlist_NodeAddInput( playlist_t *p_playlist,
339                                          input_item_t *p_input,
340                                          playlist_item_t *p_parent,
341                                          int i_mode, int i_pos )
342 {
343     playlist_item_t *p_item;
344     assert( p_input );
345     assert( p_parent && p_parent->i_children != -1 );
346
347     vlc_mutex_lock( &p_playlist->object_lock );
348
349     p_item = playlist_ItemNewFromInput( p_playlist, p_input );
350     if( p_item == NULL ) return NULL;
351     AddItem( p_playlist, p_item, p_parent, i_pos );
352
353     vlc_mutex_unlock( &p_playlist->object_lock );
354
355     return p_item;
356 }
357
358 /** Add a playlist item to a given node */
359 void playlist_NodeAddItem( playlist_t *p_playlist, playlist_item_t *p_item,
360                            playlist_item_t *p_parent, int i_mode, int i_pos )
361 {
362     vlc_mutex_lock( &p_playlist->object_lock );
363     AddItem( p_playlist, p_item, p_parent, i_pos );
364     vlc_mutex_unlock( &p_playlist->object_lock );
365 }
366
367 /*****************************************************************************
368  * Playlist item misc operations
369  *****************************************************************************/
370
371 /**
372  * Transform an item to a node. Return the node in the category tree, or NULL
373  * if not found there
374  * This function must be entered without the playlist lock
375  */
376 playlist_item_t *playlist_ItemToNode( playlist_t *p_playlist,
377                                       playlist_item_t *p_item )
378 {
379     /* What we do
380      * Find the input in CATEGORY.
381      *  - If we find it
382      *    - change it to node
383      *    - we'll return it at the end
384      *    - If we are a direct child of onelevel root, change to node, else
385      *      delete the input from ONELEVEL
386      *  - If we don't find it, just change to node (we are probably in VLM)
387      *    and return NULL
388      *
389      * If we were in ONELEVEL, we thus retrieve the node in CATEGORY (will be
390      * useful for later BothAddInput )
391      */
392
393     /* Fast track the media library, no time to loose */
394     if( p_item == p_playlist->p_ml_category )
395         return p_item;
396
397     /** \todo First look if we don't already have it */
398     playlist_item_t *p_item_in_category = playlist_ItemFindFromInputAndRoot(
399                                             p_playlist, p_item->p_input->i_id,
400                                             p_playlist->p_root_category );
401
402     if( p_item_in_category )
403     {
404         playlist_item_t *p_item_in_one = playlist_ItemFindFromInputAndRoot(
405                                             p_playlist, p_item->p_input->i_id,
406                                             p_playlist->p_root_onelevel );
407         ChangeToNode( p_playlist, p_item_in_category );
408         if( p_item_in_one->p_parent == p_playlist->p_root_onelevel )
409         {
410             ChangeToNode( p_playlist, p_item_in_one );
411         }
412         else
413         {
414             playlist_DeleteFromInput( p_playlist, p_item_in_one->p_input->i_id,
415                                       p_playlist->p_root_onelevel, VLC_FALSE );
416         }
417         var_SetInteger( p_playlist, "item-change", p_item->p_input->i_id );
418         return p_item_in_category;
419     }
420     else
421     {
422         ChangeToNode( p_playlist, p_item );
423         return NULL;
424     }
425 }
426
427 /** Transform an item to a node
428  *  This function must be entered without the playlist lock
429  *  \see playlist_ItemToNode
430  */
431 playlist_item_t * playlist_LockItemToNode( playlist_t *p_playlist,
432                                            playlist_item_t *p_item )
433 {
434     playlist_item_t *p_ret;
435     vlc_mutex_lock( &p_playlist->object_lock );
436     p_ret = playlist_ItemToNode( p_playlist, p_item );
437     vlc_mutex_unlock( &p_playlist->object_lock );
438     return p_ret;
439 }
440
441 /** Find an item within a root, given its input id.
442  * \return the first found item, or NULL if not found
443  */
444 playlist_item_t *playlist_ItemFindFromInputAndRoot( playlist_t *p_playlist,
445                                                     int i_input_id,
446                                                     playlist_item_t *p_root )
447 {
448     int i;
449     for( i = 0 ; i< p_root->i_children ; i++ )
450     {
451         if( p_root->pp_children[i]->i_children == -1 &&
452             p_root->pp_children[i]->p_input->i_id == i_input_id )
453         {
454             return p_root->pp_children[i];
455         }
456         else if( p_root->pp_children[i]->i_children >= 0 )
457         {
458             playlist_item_t *p_search =
459                  playlist_ItemFindFromInputAndRoot( p_playlist, i_input_id,
460                                                     p_root->pp_children[i] );
461             if( p_search ) return p_search;
462         }
463     }
464     return NULL;
465 }
466
467
468 /**
469  * Moves an item
470  *
471  * This function must be entered with the playlist lock
472  *
473  * \param p_playlist the playlist
474  * \param p_item the item to move
475  * \param p_node the new parent of the item
476  * \param i_newpos the new position under this new parent
477  * \return VLC_SUCCESS or an error
478  */
479 int playlist_TreeMove( playlist_t * p_playlist, playlist_item_t *p_item,
480                        playlist_item_t *p_node, int i_newpos )
481 {
482     int j;
483     playlist_item_t *p_detach = NULL;
484
485     if( p_node->i_children == -1 ) return VLC_EGENERIC;
486
487     p_detach = p_item->p_parent;
488     for( j = 0; j < p_detach->i_children; j++ )
489     {
490          if( p_detach->pp_children[j] == p_item ) break;
491     }
492     REMOVE_ELEM( p_detach->pp_children, p_detach->i_children, j );
493
494     /* Attach to new parent */
495     INSERT_ELEM( p_node->pp_children, p_node->i_children, i_newpos, p_item );
496
497     return VLC_SUCCESS;
498 }
499
500 /** Send a notification that an item has been added to a node */
501 void playlist_SendAddNotify( playlist_t *p_playlist, int i_item_id,
502                              int i_node_id )
503 {
504     vlc_value_t val;
505     playlist_add_t *p_add = (playlist_add_t *)malloc(sizeof( playlist_add_t));
506     p_add->i_item = i_item_id;
507     p_add->i_node = i_node_id;
508     val.p_address = p_add;
509     var_Set( p_playlist, "item-append", val );
510     free( p_add );
511 }
512
513 /*****************************************************************************
514  * Playlist item accessors
515  *****************************************************************************/
516
517 /** Set the name of a playlist item */
518 int playlist_ItemSetName( playlist_item_t *p_item, char *psz_name )
519 {
520     if( psz_name && p_item )
521     {
522         if( p_item->p_input->psz_name ) free( p_item->p_input->psz_name );
523         p_item->p_input->psz_name = strdup( psz_name );
524         return VLC_SUCCESS;
525     }
526     return VLC_EGENERIC;
527 }
528
529 /** Set the duration of a playlist item
530  * \param i_duration the new duration in microseconds
531  */
532 int playlist_ItemSetDuration( playlist_item_t *p_item, mtime_t i_duration )
533 {
534     char psz_buffer[MSTRTIME_MAX_SIZE];
535     if( p_item )
536     {
537         p_item->p_input->i_duration = i_duration;
538         if( i_duration != -1 )
539         {
540             secstotimestr( psz_buffer, (int)(i_duration/1000000) );
541         }
542         else
543         {
544             memcpy( psz_buffer, "--:--:--", sizeof("--:--:--") );
545         }
546         vlc_input_item_AddInfo( p_item->p_input, _("General") , _("Duration"),
547                                 "%s", psz_buffer );
548
549         return VLC_SUCCESS;
550     }
551     return VLC_EGENERIC;
552 }
553
554 /** Add an option to a playlist item */
555 void playlist_ItemAddOption( playlist_item_t *p_item,
556                              const char *psz_option)
557 {
558     vlc_input_item_AddOption( p_item->p_input, psz_option );
559 }
560
561 /***************************************************************************
562  * The following functions are local
563  ***************************************************************************/
564
565 /* Enqueue an item for preparsing, and play it, if needed */
566 void GoAndPreparse( playlist_t *p_playlist, int i_mode,
567                     playlist_item_t *p_item_cat, playlist_item_t *p_item_one )
568 {
569     if( (i_mode & PLAYLIST_GO ) )
570     {
571         playlist_item_t *p_parent = p_item_one;
572         playlist_item_t *p_toplay = NULL;
573         while( p_parent )
574         {
575             if( p_parent == p_playlist->p_root_category )
576             {
577                 p_toplay = p_item_cat; break;
578             }
579             else if( p_parent == p_playlist->p_root_onelevel )
580             {
581                 p_toplay = p_item_one; break;
582             }
583             p_parent = p_parent->p_parent;
584         }
585         assert( p_toplay );
586         p_playlist->request.b_request = VLC_TRUE;
587         p_playlist->request.p_item = p_toplay;
588         if( p_playlist->p_input )
589         {
590             input_StopThread( p_playlist->p_input );
591         }
592         p_playlist->request.i_status = PLAYLIST_RUNNING;
593     }
594     if( i_mode & PLAYLIST_PREPARSE &&
595         var_CreateGetBool( p_playlist, "auto-preparse" ) )
596     {
597         playlist_PreparseEnqueue( p_playlist, p_item_cat->p_input );
598     }
599 }
600
601 /* Add the playlist item to the requested node and fire a notification */
602 void AddItem( playlist_t *p_playlist, playlist_item_t *p_item,
603               playlist_item_t *p_node, int i_pos )
604 {
605     INSERT_ELEM( p_playlist->pp_items, p_playlist->i_size,
606                  p_playlist->i_size, p_item );
607 #if 0
608     fprintf( stderr, "Adding input %s (id %i) - playlist item id %i "
609                      "to node %s (id %i)\n",
610                      p_item->p_input->psz_name, p_item->p_input->i_id,
611                      p_item->i_id, p_node->p_input->psz_name,
612                      p_node->i_id );
613 #endif
614     INSERT_ELEM( p_playlist->pp_all_items, p_playlist->i_all_size,
615                  p_playlist->i_all_size, p_item );
616     p_playlist->i_enabled ++;
617
618     if( i_pos == PLAYLIST_END )
619     {
620         playlist_NodeAppend( p_playlist, p_item, p_node );
621     }
622     else
623     {
624         playlist_NodeInsert( p_playlist, p_item, p_node, i_pos );
625     }
626
627     playlist_SendAddNotify( p_playlist, p_item->i_id, p_node->i_id );
628 }
629
630 /* Actually convert an item to a node */
631 void ChangeToNode( playlist_t *p_playlist, playlist_item_t *p_item )
632 {
633     int i;
634     if( p_item->i_children == -1 )
635         p_item->i_children = 0;
636
637     /* Remove it from the array of available items */
638     for( i = 0 ; i < p_playlist->i_size ; i++ )
639     {
640         if( p_item == p_playlist->pp_items[i] )
641         {
642             REMOVE_ELEM( p_playlist->pp_items, p_playlist->i_size, i );
643         }
644     }
645 }
646
647 /* Do the actual removal */
648 int DeleteInner( playlist_t * p_playlist, playlist_item_t *p_item,
649                 vlc_bool_t b_stop )
650 {
651     int i, i_top, i_bottom;
652     int i_id = p_item->i_id;
653     vlc_bool_t b_flag = VLC_FALSE;
654
655     if( p_item->i_children > -1 )
656     {
657         return playlist_NodeDelete( p_playlist, p_item, VLC_TRUE, VLC_FALSE );
658     }
659     var_SetInteger( p_playlist, "item-deleted", i_id );
660
661     /* Remove the item from the bank */
662     i_bottom = 0; i_top = p_playlist->i_all_size - 1;
663     i = i_top / 2;
664     while( p_playlist->pp_all_items[i]->i_id != i_id &&
665            i_top > i_bottom )
666     {
667         if( p_playlist->pp_all_items[i]->i_id < i_id )
668         {
669             i_bottom = i + 1;
670         }
671         else
672         {
673             i_top = i - 1;
674         }
675         i = i_bottom + ( i_top - i_bottom ) / 2;
676     }
677     if( p_playlist->pp_all_items[i]->i_id == i_id )
678     {
679         REMOVE_ELEM( p_playlist->pp_all_items, p_playlist->i_all_size, i );
680     }
681
682     /* Check if it is the current item */
683     if( p_playlist->status.p_item == p_item )
684     {
685         /* Hack we don't call playlist_Control for lock reasons */
686         if( b_stop )
687         {
688             p_playlist->status.i_status = PLAYLIST_STOPPED;
689             p_playlist->request.b_request = VLC_TRUE;
690             p_playlist->request.p_item = NULL;
691             msg_Info( p_playlist, "stopping playback" );
692         }
693         b_flag = VLC_TRUE;
694     }
695
696     msg_Dbg( p_playlist, "deleting playlist item `%s'",
697                           p_item->p_input->psz_name );
698
699     /* Remove the item from its parent */
700     playlist_NodeRemoveItem( p_playlist, p_item, p_item->p_parent );
701
702     if( b_flag == VLC_FALSE )
703         playlist_ItemDelete( p_item );
704     else
705         p_item->i_flags |= PLAYLIST_REMOVE_FLAG;
706
707     return VLC_SUCCESS;
708 }