1 /*
2  * This file is part of MPlayer.
3  *
4  * MPlayer is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * MPlayer is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 /**
20  * @file
21  * @brief User interface actions
22  */
23 
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "actions.h"
30 #include "ui.h"
31 #include "gui/interface.h"
32 #include "gui/app/app.h"
33 #include "gui/app/cfg.h"
34 #include "gui/app/gui.h"
35 #include "gui/dialog/dialog.h"
36 #include "gui/skin/skin.h"
37 #include "gui/util/mem.h"
38 #include "gui/util/string.h"
39 #include "gui/wm/ws.h"
40 #include "gui/wm/wsxdnd.h"
41 
42 #include "access_mpcontext.h"
43 #include "config.h"
44 #include "help_mp.h"
45 #include "m_property.h"
46 #include "mixer.h"
47 #include "mp_core.h"
48 #include "mp_fifo.h"
49 #include "mp_msg.h"
50 #include "mpcommon.h"
51 #include "mplayer.h"
52 #include "input/input.h"
53 #include "libmpdemux/demuxer.h"
54 #include "libvo/video_out.h"
55 #include "osdep/keycodes.h"
56 #include "osdep/timer.h"
57 #include "stream/stream.h"
58 #include "sub/sub.h"
59 
60 #define GUI_REDRAW_WAIT 375   // in milliseconds
61 
62 int uiLoadPlay;
63 
64 static unsigned int last_redraw_time;
65 
66 /**
67  * @brief Clear information not used for this @a type of stream.
68  *
69  * @param type stream type
70  */
MediumPrepare(int type)71 static void MediumPrepare(int type)
72 {
73     switch (type) {
74     case STREAMTYPE_DVD:
75         listMgr(PLAYLIST_DELETE, 0);
76         break;
77 
78     case STREAMTYPE_CDDA:
79     case STREAMTYPE_VCD:
80     case STREAMTYPE_TV:
81     case STREAMTYPE_DVB:
82         listMgr(PLAYLIST_DELETE, 0);
83     case STREAMTYPE_FILE:
84     case STREAMTYPE_STREAM:
85     case STREAMTYPE_PLAYLIST:
86         guiInfo.Angles = 0;
87     case STREAMTYPE_BINCUE:
88         guiInfo.AudioStreams = 0;
89         guiInfo.Subtitles    = 0;
90         guiInfo.Chapters     = 0;
91         break;
92     }
93 }
94 
uiEvent(int ev,float param)95 void uiEvent(int ev, float param)
96 {
97     int iparam     = (int)param;
98     mixer_t *mixer = mpctx_get_mixer(guiInfo.mpcontext);
99     float aspect;
100     char cmd[40];
101 
102     switch (ev) {
103 /* user events */
104     case evExit:
105         mplayer(MPLAYER_EXIT_GUI, EXIT_QUIT, 0);
106         break;
107 
108     case evLoadURL:
109         gtkShow(evLoadURL, NULL);
110         break;
111 
112     case ivSetAudio:
113 
114         if (!mpctx_get_demuxer(guiInfo.mpcontext) || audio_id == iparam)
115             break;
116 
117         mp_property_do("switch_audio", M_PROPERTY_SET, &iparam, guiInfo.mpcontext);
118         break;
119 
120     case ivSetVideo:
121 
122         if (!mpctx_get_demuxer(guiInfo.mpcontext) || video_id == iparam)
123             break;
124 
125         mp_property_do("switch_video", M_PROPERTY_SET, &iparam, guiInfo.mpcontext);
126         break;
127 
128     case ivSetSubtitle:
129         mp_property_do("sub", M_PROPERTY_SET, &iparam, guiInfo.mpcontext);
130         break;
131 
132 #ifdef CONFIG_CDDA
133     case ivSetCDTrack:
134         guiInfo.Track = iparam;
135 
136     case evPlayCD:
137         if (guiInfo.StreamType != STREAMTYPE_CDDA)
138             guiInfo.Track = 0;
139         guiInfo.StreamType = STREAMTYPE_CDDA;
140         goto play;
141 #endif
142 #ifdef CONFIG_VCD
143     case ivSetVCDTrack:
144         guiInfo.Track = iparam;
145 
146     case evPlayVCD:
147         if (guiInfo.StreamType != STREAMTYPE_VCD)
148             guiInfo.Track = 0;
149         guiInfo.StreamType = STREAMTYPE_VCD;
150         goto play;
151 #endif
152 #ifdef CONFIG_DVDREAD
153     case ivSetDVDSubtitle:
154         dvdsub_id = iparam;
155         uiEvent(ivPlayDVD, 0);
156         break;
157 
158     case ivSetDVDAudio:
159         audio_id = iparam;
160         uiEvent(ivPlayDVD, 0);
161         break;
162 
163     case ivSetDVDChapter:
164         guiInfo.Chapter = iparam;
165         uiEvent(ivPlayDVD, 0);
166         break;
167 
168     case ivSetDVDTitle:
169         guiInfo.Track   = iparam;
170         guiInfo.Chapter = 1;
171         guiInfo.Angle   = 1;
172         reset_stream_ids();
173         uiEvent(ivPlayDVD, 0);
174         break;
175 
176     case evPlayDVD:
177         guiInfo.Chapter = 1;
178         guiInfo.Angle   = 1;
179         reset_stream_ids();
180         if (guiInfo.StreamType != STREAMTYPE_DVD)
181             guiInfo.Track = 0;
182 
183     case ivPlayDVD:
184         guiInfo.StreamType = STREAMTYPE_DVD;
185         goto play;
186 #endif
187 #ifdef CONFIG_TV
188     case evPlayTV:
189         guiInfo.StreamType = guiTV[gui_tv_digital].StreamType;
190         goto play;
191 #endif
192     case evPlay:
193     case evPlaySwitchToPause:
194 play:
195 
196         if (guiInfo.Playing != GUI_PAUSE) {
197             MediumPrepare(guiInfo.StreamType);
198 
199             switch (guiInfo.StreamType) {
200             case STREAMTYPE_FILE:
201             case STREAMTYPE_STREAM:
202             case STREAMTYPE_PLAYLIST:
203 
204                 if (!guiInfo.Track)
205                     guiInfo.Track = 1;
206 
207                 guiInfo.MediumChanged = GUI_MEDIUM_NEW;
208                 guiInfo.PlaylistNext  = !guiInfo.Playing;
209 
210                 break;
211 
212             case STREAMTYPE_CDDA:
213             case STREAMTYPE_VCD:
214             case STREAMTYPE_DVD:
215             case STREAMTYPE_TV:
216             case STREAMTYPE_DVB:
217 
218                 if (!guiInfo.Track)
219                     guiInfo.Track = (guiInfo.StreamType == STREAMTYPE_VCD ? 2 : 1);
220 
221             case STREAMTYPE_BINCUE:   // track 0 is OK and will auto-select first media data track
222                 guiInfo.MediumChanged = GUI_MEDIUM_SAME;
223 
224                 break;
225             }
226         }
227 
228         uiPlay();
229         break;
230 
231     case evPause:
232     case evPauseSwitchToPlay:
233         uiPause();
234         break;
235 
236     case evStop:
237         guiInfo.Playing = GUI_STOP;
238         uiState();
239         break;
240 
241     case evLoadPlay:
242         uiLoadPlay = True;
243 
244 //      guiInfo.StreamType=STREAMTYPE_FILE;
245     case evLoad:
246         gtkShow(evLoad, NULL);
247         break;
248 
249     case evLoadSubtitle:
250         gtkShow(evLoadSubtitle, NULL);
251         break;
252 
253     case evDropSubtitle:
254         mplayerLoadSubtitle(NULL);
255         break;
256 
257     case evLoadAudioFile:
258         gtkShow(evLoadAudioFile, NULL);
259         break;
260 
261     case evPlayImage:
262         gtkShow(evPlayImage, NULL);
263         break;
264 
265     case evPrev:
266         uiPrev();
267         break;
268 
269     case evNext:
270         uiNext();
271         break;
272 
273     case evPlaylist:
274         gtkShow(evPlaylist, NULL);
275         break;
276 
277     case evSkinBrowser:
278         gtkShow(evSkinBrowser, skinName);
279         break;
280 
281     case evAbout:
282         gtkShow(evAbout, NULL);
283         break;
284 
285     case evPreferences:
286         gtkShow(evPreferences, NULL);
287         break;
288 
289     case evEqualizer:
290         gtkShow(evEqualizer, NULL);
291         break;
292 
293     case evForward10min:
294         uiRelSeek(600);
295         break;
296 
297     case evBackward10min:
298         uiRelSeek(-600);
299         break;
300 
301     case evForward1min:
302         uiRelSeek(60);
303         break;
304 
305     case evBackward1min:
306         uiRelSeek(-60);
307         break;
308 
309     case evForward10sec:
310         uiRelSeek(10);
311         break;
312 
313     case evBackward10sec:
314         uiRelSeek(-10);
315         break;
316 
317     case evSetMoviePosition:
318         guiInfo.Position = param;
319         uiPctSeek(guiInfo.Position);
320         break;
321 
322     case evIncVolume:
323         mplayer_put_key(KEY_VOLUME_UP);
324         break;
325 
326     case evDecVolume:
327         mplayer_put_key(KEY_VOLUME_DOWN);
328         break;
329 
330     case evMute:
331         mixer_mute(mixer);
332         break;
333 
334     case evSetVolume:
335     case ivSetVolume:
336         guiInfo.Volume = param;
337         {
338             float l = guiInfo.Volume * (100.0 - guiInfo.Balance) / 50.0;
339             float r = guiInfo.Volume * guiInfo.Balance / 50.0;
340             mixer_setvolume(mixer, FFMIN(l, guiInfo.Volume), FFMIN(r, guiInfo.Volume));
341         }
342 
343         if (ev == ivSetVolume)
344             break;
345 
346         if (osd_level) {
347             osd_visible = (GetTimerMS() + 1000) | 1;
348             vo_osd_progbar_type  = OSD_VOLUME;
349             vo_osd_progbar_value = guiInfo.Volume * 256.0 / 100.0;
350             vo_osd_changed(OSDTYPE_PROGBAR);
351         }
352 
353         break;
354 
355     case evSetBalance:
356     case ivSetBalance:
357         guiInfo.Balance = param;
358         mixer_setbalance(mixer, (guiInfo.Balance - 50.0) / 50.0);     // transform 0..100 to -1..1
359         uiEvent(ivSetVolume, guiInfo.Volume);
360 
361         if (ev == ivSetBalance)
362             break;
363 
364         if (osd_level) {
365             osd_visible = (GetTimerMS() + 1000) | 1;
366             vo_osd_progbar_type  = OSD_BALANCE;
367             vo_osd_progbar_value = guiInfo.Balance * 256.0 / 100.0;
368             vo_osd_changed(OSDTYPE_PROGBAR);
369         }
370 
371         break;
372 
373     case evMenu:
374         /*if (guiApp.menuIsPresent)   NOTE TO MYSELF: Uncomment only after mouse
375          * {                                            pointer and cursor keys work
376          * gtkShow( ivHidePopUpMenu,NULL );            with this menu from skin as
377          * uiMenuShow( 0,0 );                          they do with normal menus.
378          * }
379          * else*/gtkShow(ivShowPopUpMenu, (void *)wMain);
380         break;
381 
382     case evIconify:
383 
384         switch (iparam) {
385         case wMain:
386             wsWindowIconify(&guiApp.mainWindow);
387             break;
388 
389         case wVideo:
390             wsWindowIconify(&guiApp.videoWindow);
391             break;
392         }
393 
394         break;
395 
396     case evHalfSize:
397 
398         if (guiInfo.VideoWindow && guiInfo.Playing) {
399             if (guiApp.videoWindow.isFullScreen) {
400                 uiFullScreen();
401             }
402 
403             wsWindowResize(&guiApp.videoWindow, guiInfo.VideoWidth / 2, guiInfo.VideoHeight / 2);
404             btnSet(evFullScreen, btnReleased);
405         }
406 
407         break;
408 
409     case evDoubleSize:
410 
411         if (guiInfo.VideoWindow && guiInfo.Playing) {
412             if (guiApp.videoWindow.isFullScreen) {
413                 uiFullScreen();
414             }
415 
416             wsWindowResize(&guiApp.videoWindow, guiInfo.VideoWidth * 2, guiInfo.VideoHeight * 2);
417             wsWindowMoveWithin(&guiApp.videoWindow, False, guiApp.video.x, guiApp.video.y);
418             btnSet(evFullScreen, btnReleased);
419         }
420 
421         break;
422 
423     case evNormalSize:
424 
425         if (guiInfo.VideoWindow && guiInfo.Playing) {
426             if (guiApp.videoWindow.isFullScreen) {
427                 uiFullScreen();
428             }
429 
430             wsWindowResize(&guiApp.videoWindow, guiInfo.VideoWidth, guiInfo.VideoHeight);
431             btnSet(evFullScreen, btnReleased);
432             break;
433         } else if (!guiApp.videoWindow.isFullScreen)
434             break;
435 
436     case evFullScreen:
437 
438         if (guiInfo.VideoWindow && (guiInfo.Playing || !iparam)) {
439             uiFullScreen();
440 
441             if (!guiApp.videoWindow.isFullScreen)
442                 wsWindowResize(&guiApp.videoWindow, iparam >= 0 ? guiInfo.VideoWidth : guiApp.video.width, iparam >= 0 ? guiInfo.VideoHeight : guiApp.video.height);
443         }
444 
445         if (guiApp.videoWindow.isFullScreen)
446             btnSet(evFullScreen, btnPressed);
447         else
448             btnSet(evFullScreen, btnReleased);
449 
450         break;
451 
452     case evSetAspect:
453 
454         switch (iparam) {
455         case 2:
456             aspect = 16.0f / 9.0f;
457             break;
458 
459         case 3:
460             aspect = 4.0f / 3.0f;
461             break;
462 
463         case 4:
464             aspect = 2.35f;
465             break;
466 
467         case 1:
468         default:
469             aspect = -1;
470             break;
471         }
472 
473         snprintf(cmd, sizeof(cmd), "pausing_keep switch_ratio %f", aspect);
474         mp_input_queue_cmd(mp_input_parse_cmd(cmd));
475 
476         break;
477 
478     case evSetRotation:
479 
480         switch (iparam) {
481         case 90:
482             guiInfo.Rotation = 1;
483             break;
484 
485         case -90:
486             guiInfo.Rotation = 2;
487             break;
488 
489         case 180:
490             guiInfo.Rotation = 8;
491             break;
492 
493         case 0:
494         default:
495             guiInfo.Rotation = -1;
496             break;
497         }
498 
499         guiInfo.MediumChanged = GUI_MEDIUM_SAME;
500 
501         break;
502 
503 /* timer events */
504     case ivRedraw:
505     {
506         unsigned int now = GetTimerMS();
507 
508         if ((now > last_redraw_time) &&
509             (now < last_redraw_time + GUI_REDRAW_WAIT) &&
510             !uiPlaybarFade && (iparam == 0))
511             break;
512 
513         last_redraw_time = now;
514     }
515         uiMainRender = True;
516         wsWindowRedraw(&guiApp.mainWindow);
517         wsWindowRedraw(&guiApp.playbarWindow);
518         break;
519 
520 /* system events */
521     case evNone:
522         mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[actions] uiEvent: evNone\n");
523         break;
524 
525     default:
526         mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[actions] uiEvent: unknown event %d, param %.2f\n", ev, param);
527         break;
528     }
529 }
530 
531 /**
532  * @brief Switch video window fullscreen mode.
533  *
534  *        Switch normal video to fullscreen and fullscreen video to normal.
535  */
uiFullScreen(void)536 void uiFullScreen(void)
537 {
538     if (!guiInfo.VideoWindow)
539         return;
540 
541     wsWindowFullscreen(&guiApp.videoWindow);
542 
543     vo_fs = guiApp.videoWindow.isFullScreen;
544 
545     wsWindowLayer(wsDisplay, guiApp.mainWindow.WindowID, guiApp.videoWindow.isFullScreen);
546 
547     if (guiApp.menuIsPresent)
548         wsWindowLayer(wsDisplay, guiApp.menuWindow.WindowID, guiApp.videoWindow.isFullScreen);
549 }
550 
551 /**
552  * @brief Switch to play mode.
553  */
uiPlay(void)554 void uiPlay(void)
555 {
556     if (guiInfo.Playing == GUI_PLAY)
557         return;
558 
559     if (guiInfo.StreamType != STREAMTYPE_CDDA &&
560         guiInfo.StreamType != STREAMTYPE_VCD &&
561         guiInfo.StreamType != STREAMTYPE_DVD &&
562         guiInfo.StreamType != STREAMTYPE_TV &&
563         guiInfo.StreamType != STREAMTYPE_DVB &&
564         (!guiInfo.Filename || (guiInfo.Filename[0] == 0)))
565         return;
566 
567     if (guiInfo.Playing == GUI_PAUSE) {
568         uiPause();
569         return;
570     }
571 
572     gui(GUI_SET_STATE, (void *)GUI_PLAY);
573 }
574 
575 /**
576  * @brief Switch to pause mode.
577  */
uiPause(void)578 void uiPause(void)
579 {
580     if (!guiInfo.Playing)
581         return;
582 
583     if (guiInfo.Playing == GUI_PLAY) {
584         mp_cmd_t *cmd = calloc(1, sizeof(*cmd));
585 
586         if (cmd) {
587             cmd->id = MP_CMD_PAUSE;
588             ARRAY_STRCPY(cmd->name, "pause");
589             mp_input_queue_cmd(cmd);
590         }
591     } else
592         guiInfo.Playing = GUI_PLAY;
593 }
594 
595 /**
596  * @brief Adjust GUI items to reflect current state (i.e. current playing mode).
597  */
uiState(void)598 void uiState(void)
599 {
600     if (guiInfo.Playing == GUI_STOP || guiInfo.Playing == GUI_PAUSE) {
601         btnSet(evPlaySwitchToPause, btnReleased);
602         btnSet(evPauseSwitchToPlay, btnDisabled);
603     } else {
604         btnSet(evPauseSwitchToPlay, btnReleased);
605         btnSet(evPlaySwitchToPause, btnDisabled);
606     }
607 }
608 
609 /**
610  * @brief Seek new playback position.
611  *
612  *        The new position is an absolute one.
613  *
614  * @param sec playback time in seconds to position to
615  */
uiAbsSeek(float sec)616 void uiAbsSeek(float sec)
617 {
618     rel_seek_secs = sec;
619     abs_seek_pos  = SEEK_ABSOLUTE;
620 }
621 
622 /**
623  * @brief Seek new playback position.
624  *
625  *        The new position is a relative one.
626  *
627  * @param sec seconds to seek (either forward (> 0) or backward (< 0))
628  */
uiRelSeek(float sec)629 void uiRelSeek(float sec)
630 {
631     rel_seek_secs = sec;
632     abs_seek_pos  = 0;
633 }
634 
635 /**
636  * @brief Seek new playback position.
637  *
638  *        The new position is an absolute one.
639  *
640  * @param percent percentage of playback time to position to
641  */
uiPctSeek(float percent)642 void uiPctSeek(float percent)
643 {
644     rel_seek_secs = percent / 100.0;
645     abs_seek_pos  = SEEK_ABSOLUTE | SEEK_FACTOR;
646 }
647 
648 /**
649  * @brief Change to a different skin.
650  *
651  * @param name name of the skin to change to
652  */
uiChangeSkin(char * name)653 void uiChangeSkin(char *name)
654 {
655     int was_menu, was_playbar;
656 
657     was_menu    = guiApp.menuIsPresent;
658     was_playbar = guiApp.playbarIsPresent;
659 
660     mainVisible = False;
661 
662     if (skinRead(name) != 0) {
663         if (skinRead(skinName) != 0) {
664             gmp_msg(MSGT_GPLAYER, MSGL_FATAL, _(MSGTR_GUI_MSG_SkinCfgError), skinName);
665             mplayer(MPLAYER_EXIT_GUI, EXIT_ERROR, 0);
666         }
667     }
668 
669     /* reload main window (must be first!) */
670 
671     uiMainDone();
672     uiMainInit();
673 
674     wsWindowVisibility(&guiApp.mainWindow, wsShowWindow);
675     mainVisible = True;
676 
677     /* adjust video window */
678 
679     if (guiApp.video.Bitmap.Image) {
680         wsImageResize(&guiApp.videoWindow, guiApp.video.Bitmap.Width, guiApp.video.Bitmap.Height);
681         wsImageRender(&guiApp.videoWindow, guiApp.video.Bitmap.Image);
682     }
683 
684     if (!guiInfo.Playing) {
685         if (!guiApp.videoWindow.isFullScreen) {
686             wsWindowResize(&guiApp.videoWindow, guiApp.video.width, guiApp.video.height);
687             wsWindowMove(&guiApp.videoWindow, False, guiApp.video.x, guiApp.video.y);
688         }
689 
690         wsWindowRedraw(&guiApp.videoWindow);
691     }
692 
693     /* reload playbar */
694 
695     if (was_playbar)
696         uiPlaybarDone();
697 
698     uiPlaybarInit();
699 
700     /* reload menu window */
701 
702     if (was_menu)
703         uiMenuDone();
704 
705     uiMenuInit();
706 
707     /* */
708 
709     if (guiInfo.AudioPassthrough)
710         btnSet(evSetVolume, btnDisabled);
711     if (guiInfo.AudioChannels < 2 || guiInfo.AudioPassthrough)
712         btnSet(evSetBalance, btnDisabled);
713 
714     btnSet(evFullScreen, guiApp.videoWindow.isFullScreen ? btnPressed : btnReleased);
715 
716     wsWindowLayer(wsDisplay, guiApp.mainWindow.WindowID, guiApp.videoWindow.isFullScreen);
717     wsWindowLayer(wsDisplay, guiApp.menuWindow.WindowID, guiApp.videoWindow.isFullScreen);
718 }
719 
720 /**
721  * @brief Set the file to be played from a playlist item.
722  *
723  * @note This allows a file to be played partially (seeking before playback
724  *       and stopping before its end).
725  *
726  * @param item pointer to the playlist item
727  *
728  * @note All #guiInfo members associated with the file will be cleared.
729  */
uiSetFileFromPlaylist(plItem * item)730 void uiSetFileFromPlaylist(plItem *item)
731 {
732     uiSetFile(item->path, item->name, STREAMTYPE_FILE);
733     guiInfo.Start = item->start;
734     guiInfo.Stop  = item->stop;
735     guiInfo.Title = gstrdup(item->title);
736     guiInfo.Track = (uintptr_t)listMgr(PLAYLIST_ITEM_GET_POS, item);
737 }
738 
739 /**
740  * @brief Set the file to be played.
741  *
742  * @param dir directory (optional, else NULL)
743  * @param name filename
744  * @param type stream type of the file
745  *
746  * @note All #guiInfo members associated with the file will be cleared.
747  */
uiSetFile(const char * dir,const char * name,int type)748 void uiSetFile(const char *dir, const char *name, int type)
749 {
750     if (!dir)
751         setdup(&guiInfo.Filename, name);
752     else
753         setddup(&guiInfo.Filename, dir, name);
754 
755     filename = guiInfo.Filename;
756 
757     if (type != SAME_STREAMTYPE) {
758         guiInfo.StreamType = type;
759         uiUnsetMedia(False);
760     }
761 }
762 
763 /**
764  * @brief Unset the file being played.
765  */
uiUnsetFile(void)766 void uiUnsetFile(void)
767 {
768     uiSetFile(NULL, NULL, STREAMTYPE_DUMMY);
769 }
770 
771 /**
772  * @brief Unset media information.
773  *
774  * @param totals whether to additionally unset number of chapters, angles and
775  *               audio and subtitle filenames (#True)
776  *               or just track, chapter and angle (#False)
777  */
uiUnsetMedia(int totals)778 void uiUnsetMedia(int totals)
779 {
780     guiInfo.VideoWidth       = 0;
781     guiInfo.VideoHeight      = 0;
782     guiInfo.AudioChannels    = 0;
783     guiInfo.AudioPassthrough = False;
784     guiInfo.RunningTime      = 0;
785     guiInfo.Start = 0;
786     guiInfo.Stop  = 0;
787 
788     if (totals) {
789         guiInfo.Chapters = 0;
790 
791         if (guiInfo.StreamType != STREAMTYPE_BINCUE)
792             guiInfo.Angles = 0;
793 
794         nfree(guiInfo.AudioFilename);
795         nfree(guiInfo.SubtitleFilename);
796     } else {
797         guiInfo.Track   = 0;
798         guiInfo.Chapter = 0;
799         guiInfo.Angle   = 0;
800     }
801 
802     nfree(guiInfo.CodecName);
803     nfree(guiInfo.Title);
804     nfree(guiInfo.ImageFilename);
805 }
806 
807 /**
808  * @brief Set file to be played to current playlist entry.
809  */
uiCurr(void)810 void uiCurr(void)
811 {
812     plItem *curr;
813 
814     if (guiInfo.Playing == GUI_PAUSE)
815         return;
816 
817     switch (guiInfo.StreamType) {
818     case STREAMTYPE_CDDA:
819     case STREAMTYPE_VCD:
820     case STREAMTYPE_DVD:
821     case STREAMTYPE_TV:
822     case STREAMTYPE_DVB:
823 
824         break;
825 
826     default:
827 
828         curr = listMgr(PLAYLIST_ITEM_GET_CURR, 0);
829 
830         if (curr) {
831             uiSetFileFromPlaylist(curr);
832             guiInfo.PlaylistNext = False;
833             break;
834         }
835 
836         return;
837     }
838 
839     if (guiInfo.Playing == GUI_PLAY)
840         uiEvent(evPlay, 0);
841 }
842 
843 /**
844  * @brief Switch to previous playback track.
845  */
uiPrev(void)846 void uiPrev(void)
847 {
848     int stop = False, unset = True;
849     plItem *prev = NULL;
850 
851     if (guiInfo.Playing == GUI_PAUSE)
852         return;
853 
854     switch (guiInfo.StreamType) {
855     case STREAMTYPE_CDDA:
856 
857         if (--guiInfo.Track == 0) {
858             guiInfo.Track = 1;
859             stop = True;
860         }
861 
862         break;
863 
864     case STREAMTYPE_VCD:
865 
866         if (--guiInfo.Track == 1) {
867             guiInfo.Track = 2;
868             stop = True;
869         }
870 
871         break;
872 
873     case STREAMTYPE_DVD:
874 
875         if (--guiInfo.Chapter == 0) {
876             guiInfo.Chapter = 1;
877             reset_stream_ids();
878 
879             if (--guiInfo.Track == 0) {
880                 guiInfo.Track = 1;
881                 stop = True;
882             }
883         } else
884             unset = False;
885 
886         break;
887 
888     case STREAMTYPE_TV:
889     case STREAMTYPE_DVB:
890 
891         if (guiInfo.Playing == GUI_PLAY)
892             mp_input_queue_cmd(mp_input_parse_cmd("tv_step_channel -1"));
893 
894         return;
895 
896     case STREAMTYPE_BINCUE:
897 
898         if (--guiInfo.Track == 0) {
899             guiInfo.Track = 1 + guiInfo.Angles;
900             stop = True;
901         }
902 
903         break;
904 
905     default:
906 
907         prev = listMgr(PLAYLIST_ITEM_GET_PREV, 0);
908 
909         if (prev) {
910             uiSetFileFromPlaylist(prev);
911             guiInfo.PlaylistNext = !guiInfo.Playing;
912             break;
913         }
914 
915         return;
916     }
917 
918     if (stop)
919         uiEvent(evStop, 0);
920 
921     if (guiInfo.Playing == GUI_PLAY)
922         uiEvent(evPlay, 0);
923     else if (!stop && !prev && unset)
924         uiUnsetMedia(True);
925 }
926 
927 /**
928  * @brief Switch to next playback track.
929  */
uiNext(void)930 void uiNext(void)
931 {
932     int stop = False, unset = True;
933     plItem *next = NULL;
934 
935     if (guiInfo.Playing == GUI_PAUSE)
936         return;
937 
938     switch (guiInfo.StreamType) {
939     case STREAMTYPE_CDDA:
940     case STREAMTYPE_VCD:
941     case STREAMTYPE_BINCUE:
942 
943         if (++guiInfo.Track > guiInfo.Tracks) {
944             guiInfo.Track = guiInfo.Tracks;
945             stop = True;
946         }
947 
948         break;
949 
950     case STREAMTYPE_DVD:
951 
952         if (guiInfo.Chapter++ >= guiInfo.Chapters) {
953             guiInfo.Chapter = 1;
954             reset_stream_ids();
955 
956             if (++guiInfo.Track > guiInfo.Tracks) {
957                 guiInfo.Track   = guiInfo.Tracks;
958                 guiInfo.Chapter = guiInfo.Chapters;
959                 stop = True;
960             }
961         } else
962             unset = False;
963 
964         break;
965 
966     case STREAMTYPE_TV:
967     case STREAMTYPE_DVB:
968 
969         if (guiInfo.Playing == GUI_PLAY)
970             mp_input_queue_cmd(mp_input_parse_cmd("tv_step_channel 1"));
971 
972         return;
973 
974     default:
975 
976         next = listMgr(PLAYLIST_ITEM_GET_NEXT, 0);
977 
978         if (next) {
979             uiSetFileFromPlaylist(next);
980             guiInfo.PlaylistNext = !guiInfo.Playing;
981             break;
982         }
983 
984         return;
985     }
986 
987     if (stop)
988         uiEvent(evStop, 0);
989 
990     if (guiInfo.Playing == GUI_PLAY)
991         uiEvent(evPlay, 0);
992     else if (!stop && !next && unset)
993         uiUnsetMedia(True);
994 }
995 
996 /**
997  * @brief Check whether the end of a cue sheet playlist track has been
998  *        reached and set #guiInfo information for the next track.
999  *
1000  * @param set whether to set next track's information or skip setting
1001  *            information once
1002  *
1003  * @note Parameter @a set will be set for next call of the function.
1004  *
1005  * @return #True (information for next track has been set),
1006  *         #False (end not yet reached) or -1 (@a set was #False)
1007  */
uiCueCheckNext(int * set)1008 int uiCueCheckNext(int *set)
1009 {
1010     plItem *next;
1011 
1012     if (guiInfo.Stop && (guiInfo.ElapsedTime == guiInfo.Stop)) {
1013         if (!*set) {
1014             *set = True;
1015             return -1;
1016         }
1017 
1018         next = listMgr(PLAYLIST_ITEM_GET_NEXT, 0);
1019 
1020         if (next) {
1021             free(guiInfo.Title);
1022             guiInfo.Title = gstrdup(next->title);
1023             guiInfo.Track = (uintptr_t)listMgr(PLAYLIST_ITEM_GET_POS, next);
1024             guiInfo.Start = next->start;
1025             guiInfo.Stop  = next->stop;
1026 
1027             if (guiInfo.ElapsedTime != guiInfo.Start) {
1028                 guiInfo.PlaylistNext  = False;
1029                 guiInfo.MediumChanged = GUI_MEDIUM_NEW;
1030             }
1031 
1032             *set = False;
1033         }
1034 
1035         return True;
1036     } else
1037         return False;
1038 }
1039 
1040 /**
1041  * @brief Set or unset #guiInfo member @ref guiInterface_t.Title "Title"
1042  *        depending on whether playback position is within the current
1043  *        cue sheet playlist track or not.
1044  */
uiCueSetTitle(void)1045 void uiCueSetTitle(void)
1046 {
1047     if (guiInfo.MediumChanged)
1048         return;
1049 
1050     if (guiInfo.Stop) {
1051         if (guiInfo.ElapsedTime >= guiInfo.Start && guiInfo.ElapsedTime <= guiInfo.Stop) {
1052             plItem *curr = listMgr(PLAYLIST_ITEM_GET_CURR, 0);
1053 
1054             if (curr && !guiInfo.Title)
1055                 guiInfo.Title = gstrdup(curr->title);
1056         } else
1057             nfree(guiInfo.Title);
1058     }
1059 }
1060