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