core: playlist: refactor current media update
[vlc.git] / src / playlist / content.c
blob312db312027753f857019429651cb32888184f23
1 /*****************************************************************************
2 * playlist/content.c
3 *****************************************************************************
4 * Copyright (C) 2018 VLC authors and VideoLAN
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
25 #include "content.h"
27 #include "control.h"
28 #include "item.h"
29 #include "notify.h"
30 #include "playlist.h"
32 void
33 vlc_playlist_ClearItems(vlc_playlist_t *playlist)
35 vlc_playlist_item_t *item;
36 vlc_vector_foreach(item, &playlist->items)
37 vlc_playlist_item_Release(item);
38 vlc_vector_clear(&playlist->items);
41 static void
42 vlc_playlist_ItemsReset(vlc_playlist_t *playlist)
44 if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM)
45 randomizer_Clear(&playlist->randomizer);
47 struct vlc_playlist_state state;
48 vlc_playlist_state_Save(playlist, &state);
50 playlist->current = -1;
51 playlist->has_prev = vlc_playlist_ComputeHasPrev(playlist);
52 playlist->has_next = vlc_playlist_ComputeHasNext(playlist);
54 vlc_playlist_Notify(playlist, on_items_reset, playlist->items.data,
55 playlist->items.size);
56 vlc_playlist_state_NotifyChanges(playlist, &state);
59 static void
60 vlc_playlist_ItemsInserted(vlc_playlist_t *playlist, size_t index, size_t count)
62 if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM)
63 randomizer_Add(&playlist->randomizer,
64 &playlist->items.data[index], count);
66 struct vlc_playlist_state state;
67 vlc_playlist_state_Save(playlist, &state);
69 if (playlist->current >= (ssize_t) index)
70 playlist->current += count;
71 playlist->has_prev = vlc_playlist_ComputeHasPrev(playlist);
72 playlist->has_next = vlc_playlist_ComputeHasNext(playlist);
74 vlc_playlist_item_t **items = &playlist->items.data[index];
75 vlc_playlist_Notify(playlist, on_items_added, index, items, count);
76 vlc_playlist_state_NotifyChanges(playlist, &state);
79 static void
80 vlc_playlist_ItemsMoved(vlc_playlist_t *playlist, size_t index, size_t count,
81 size_t target)
83 struct vlc_playlist_state state;
84 vlc_playlist_state_Save(playlist, &state);
86 if (playlist->current != -1) {
87 size_t current = (size_t) playlist->current;
88 if (index < target)
90 if (current >= index && current < index + count)
91 /* current item belongs to the moved block */
92 playlist->current += target - index;
93 else if (current >= index + count && current < target + count)
94 /* current item was shifted backwards to the moved block */
95 playlist->current -= count;
96 /* else the current item does not move */
98 else
100 if (current >= index && current < index + count)
101 /* current item belongs to the moved block */
102 playlist->current -= index - target;
103 else if (current >= target && current < index)
104 /* current item was shifted forward to the moved block */
105 playlist->current += count;
106 /* else the current item does not move */
110 playlist->has_prev = vlc_playlist_ComputeHasPrev(playlist);
111 playlist->has_next = vlc_playlist_ComputeHasNext(playlist);
113 vlc_playlist_Notify(playlist, on_items_moved, index, count, target);
114 vlc_playlist_state_NotifyChanges(playlist, &state);
117 static void
118 vlc_playlist_ItemsRemoving(vlc_playlist_t *playlist, size_t index, size_t count)
120 if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM)
121 randomizer_Remove(&playlist->randomizer,
122 &playlist->items.data[index], count);
125 /* return whether the current media has changed */
126 static bool
127 vlc_playlist_ItemsRemoved(vlc_playlist_t *playlist, size_t index, size_t count)
129 struct vlc_playlist_state state;
130 vlc_playlist_state_Save(playlist, &state);
132 bool current_media_changed = false;
133 if (playlist->current != -1) {
134 size_t current = (size_t) playlist->current;
135 if (current >= index && current < index + count) {
136 /* current item has been removed */
137 if (index + count < playlist->items.size) {
138 /* select the first item after the removed block */
139 playlist->current = index;
140 } else {
141 /* no more items */
142 playlist->current = -1;
144 current_media_changed = true;
145 } else if (current >= index + count) {
146 playlist->current -= count;
149 playlist->has_prev = vlc_playlist_ComputeHasPrev(playlist);
150 playlist->has_next = vlc_playlist_ComputeHasNext(playlist);
152 vlc_playlist_Notify(playlist, on_items_removed, index, count);
153 vlc_playlist_state_NotifyChanges(playlist, &state);
155 return current_media_changed;
158 size_t
159 vlc_playlist_Count(vlc_playlist_t *playlist)
161 vlc_playlist_AssertLocked(playlist);
162 return playlist->items.size;
165 vlc_playlist_item_t *
166 vlc_playlist_Get(vlc_playlist_t *playlist, size_t index)
168 vlc_playlist_AssertLocked(playlist);
169 return playlist->items.data[index];
172 ssize_t
173 vlc_playlist_IndexOf(vlc_playlist_t *playlist, const vlc_playlist_item_t *item)
175 vlc_playlist_AssertLocked(playlist);
177 ssize_t index;
178 vlc_vector_index_of(&playlist->items, item, &index);
179 return index;
182 ssize_t
183 vlc_playlist_IndexOfMedia(vlc_playlist_t *playlist, const input_item_t *media)
185 vlc_playlist_AssertLocked(playlist);
187 playlist_item_vector_t *items = &playlist->items;
188 for (size_t i = 0; i < items->size; ++i)
189 if (items->data[i]->media == media)
190 return i;
191 return -1;
194 void
195 vlc_playlist_Clear(vlc_playlist_t *playlist)
197 vlc_playlist_AssertLocked(playlist);
199 int ret = vlc_player_SetCurrentMedia(playlist->player, NULL);
200 VLC_UNUSED(ret); /* what could we do? */
202 vlc_playlist_ClearItems(playlist);
203 vlc_playlist_ItemsReset(playlist);
206 static int
207 vlc_playlist_MediaToItems(input_item_t *const media[], size_t count,
208 vlc_playlist_item_t *items[])
210 size_t i;
211 for (i = 0; i < count; ++i)
213 items[i] = vlc_playlist_item_New(media[i]);
214 if (unlikely(!items[i]))
215 break;
217 if (i < count)
219 /* allocation failure, release partial items */
220 while (i)
221 vlc_playlist_item_Release(items[--i]);
222 return VLC_ENOMEM;
224 return VLC_SUCCESS;
228 vlc_playlist_Insert(vlc_playlist_t *playlist, size_t index,
229 input_item_t *const media[], size_t count)
231 vlc_playlist_AssertLocked(playlist);
232 assert(index <= playlist->items.size);
234 /* make space in the vector */
235 if (!vlc_vector_insert_hole(&playlist->items, index, count))
236 return VLC_ENOMEM;
238 /* create playlist items in place */
239 int ret = vlc_playlist_MediaToItems(media, count,
240 &playlist->items.data[index]);
241 if (ret != VLC_SUCCESS)
243 /* we were optimistic, it failed, restore the vector state */
244 vlc_vector_remove_slice(&playlist->items, index, count);
245 return ret;
248 vlc_playlist_ItemsInserted(playlist, index, count);
249 vlc_player_InvalidateNextMedia(playlist->player);
251 return VLC_SUCCESS;
254 void
255 vlc_playlist_Move(vlc_playlist_t *playlist, size_t index, size_t count,
256 size_t target)
258 vlc_playlist_AssertLocked(playlist);
259 assert(index + count <= playlist->items.size);
260 assert(target + count <= playlist->items.size);
262 vlc_vector_move_slice(&playlist->items, index, count, target);
264 vlc_playlist_ItemsMoved(playlist, index, count, target);
265 vlc_player_InvalidateNextMedia(playlist->player);
268 void
269 vlc_playlist_Remove(vlc_playlist_t *playlist, size_t index, size_t count)
271 vlc_playlist_AssertLocked(playlist);
272 assert(index < playlist->items.size);
274 vlc_playlist_ItemsRemoving(playlist, index, count);
276 for (size_t i = 0; i < count; ++i)
277 vlc_playlist_item_Release(playlist->items.data[index + i]);
279 vlc_vector_remove_slice(&playlist->items, index, count);
281 bool current_media_changed = vlc_playlist_ItemsRemoved(playlist, index,
282 count);
283 if (current_media_changed)
284 vlc_playlist_SetCurrentMedia(playlist, playlist->current);
285 else
286 vlc_player_InvalidateNextMedia(playlist->player);
290 vlc_playlist_Expand(vlc_playlist_t *playlist, size_t index,
291 input_item_t *const media[], size_t count)
293 vlc_playlist_AssertLocked(playlist);
294 assert(index < playlist->items.size);
296 vlc_playlist_RemoveOne(playlist, index);
297 return vlc_playlist_Insert(playlist, index, media, count);