1 /*
2  * MPlayer GUI for Win32
3  * Copyright (C) 2003 Sascha Sommer <saschasommer@freenet.de>
4  * Copyright (C) 2006 Erik Augustson <erik_27can@yahoo.com>
5  * Copyright (C) 2006 Gianluigi Tiesi <sherpya@netfarm.it>
6  *
7  * This file is part of MPlayer.
8  *
9  * MPlayer is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * MPlayer is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with MPlayer; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  */
23 
24 #include "config.h"
25 
26 #if defined(CONFIG_LIBCDIO)
27 #if HAVE_CDIO_PARANOIA_H
28 #include <cdio/cdda.h>
29 #elif HAVE_CDIO_PARANOIA_PARANOIA_H
30 #include <cdio/paranoia/cdda.h>
31 #endif
32 #elif defined(CONFIG_CDDA)
33 #include <cdda_interface.h>
34 #endif
35 
36 #include <windows.h>
37 #include <stdint.h>
38 
39 #if defined(__CYGWIN__) || defined(__WINE__)
40 #define _beginthreadex CreateThread
41 #ifdef __WINE__
42 #include <winioctl.h>
43 #define WINE_MOUNTMGR_EXTENSIONS
44 #include <ddk/mountmgr.h>
45 #endif
46 #else
47 #include <process.h>
48 #endif
49 
50 #include "path.h"
51 #include "gui/interface.h"
52 #include "m_option.h"
53 #include "mixer.h"
54 #include "mp_msg.h"
55 #include "help_mp.h"
56 #include "codec-cfg.h"
57 #include "stream/stream.h"
58 #include "libmpdemux/demuxer.h"
59 #include "libmpdemux/stheader.h"
60 #ifdef CONFIG_DVDREAD
61 #include "stream/stream_dvd.h"
62 #endif
63 #include "input/input.h"
64 #include "libvo/video_out.h"
65 #include "libao2/audio_out.h"
66 #include "access_mpcontext.h"
67 #include "libmpcodecs/ad.h"
68 #include "libmpcodecs/vd.h"
69 #include "libmpcodecs/dec_audio.h"
70 #include "gui/ui/actions.h"
71 #include "gui/ui/ui.h"
72 #include "gui/util/mem.h"
73 #include "gui/util/list.h"
74 #include "gui/util/string.h"
75 #include "mp_core.h"
76 #include "mpcommon.h"
77 #include "gui.h"
78 #include "dialogs.h"
79 
80 #define SAME_STREAMTYPE (STREAMTYPE_DUMMY - 1)
81 
82 int guiWinID = 0;
83 
84 char *skinName = NULL;
85 const char *codecname = NULL;
86 static gui_t *mygui = NULL;
87 static int update_videowindow(void);
88 static RECT old_rect;
89 static DWORD style;
90 static HANDLE hThread;
91 static unsigned threadId;
92 const ao_functions_t *audio_out = NULL;
93 const vo_functions_t *video_out = NULL;
94 mixer_t *mixer = NULL;
95 
96 #ifdef __WINE__
97 /**
98  * @brief Convert a Windows style path to a file name into an Unix style one.
99  *
100  * @param filename file path string to be converted
101  *
102  * @return converted file path string
103  */
unix_name(const char * win_filename)104 char *unix_name (const char *win_filename)
105 {
106     static char *unix_filename;
107     LPSTR (*CDECL wine_get_unix_file_name_ptr)(LPCWSTR);
108     int wchar_conv;
109 
110     setdup(&unix_filename, win_filename);
111 
112     if (*win_filename && (win_filename[1] == ':'))
113     {
114         wine_get_unix_file_name_ptr = (void *) GetProcAddress(GetModuleHandleA("KERNEL32"), "wine_get_unix_file_name");
115         wchar_conv = MultiByteToWideChar(CP_UNIXCP, 0, win_filename, -1, NULL, 0);
116 
117         if (wine_get_unix_file_name_ptr && wchar_conv)
118         {
119             WCHAR *ntpath;
120             char *unix_name;
121 
122             ntpath = HeapAlloc(GetProcessHeap(), 0, sizeof(*ntpath) * (wchar_conv + 1));
123             MultiByteToWideChar(CP_UNIXCP, 0, win_filename, -1, ntpath, wchar_conv);
124             unix_name = wine_get_unix_file_name_ptr(ntpath);
125             setdup(&unix_filename, unix_name);
126             HeapFree(GetProcessHeap(), 0, unix_name);
127             HeapFree(GetProcessHeap(), 0, ntpath);
128         }
129     }
130 
131     return unix_filename;
132 }
133 
134 #if defined(CONFIG_CDDA) || defined(CONFIG_DVDREAD)
135 /**
136  * @brief Convert a Windows style device name into an Unix style one.
137  *
138  * @param device device name to be converted
139  *
140  * @return converted device name
141  */
unix_device(char * device)142 static char *unix_device (char *device)
143 {
144     static char *unix_devname;
145     HANDLE mgr;
146     DWORD size = 1024;
147 
148     mgr = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
149 
150     if (mgr != INVALID_HANDLE_VALUE)
151     {
152         struct mountmgr_unix_drive input;
153         struct mountmgr_unix_drive *data;
154 
155         data = HeapAlloc(GetProcessHeap(), 0, size);
156 
157         if (data)
158         {
159             memset(&input, 0, sizeof(input));
160             input.letter = *device;
161 
162             if (DeviceIoControl(mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, &input, sizeof(input), data, size, NULL, NULL))
163             {
164                 if (data->device_offset)
165                 {
166                     setdup(&unix_devname, (char *) data + data->device_offset);
167                     device = unix_devname;
168                 }
169             }
170 
171             HeapFree(GetProcessHeap(), 0, data);
172         }
173 
174         CloseHandle(mgr);
175     }
176 
177     return device;
178 }
179 #endif
180 #endif
181 
182 /* test for playlist files, no need to specify -playlist on the commandline.
183  * add any conceivable playlist extensions here.
184  * - Erik
185  */
parse_filename(char * file,play_tree_t * playtree,m_config_t * mconfig,int clear)186 int parse_filename(char *file, play_tree_t *playtree, m_config_t *mconfig, int clear)
187 {
188     if(clear)
189         mygui->playlist->clear_playlist(mygui->playlist);
190 
191     if(strstr(file, ".m3u") || strstr(file, ".m4u") || strstr(file, ".mxu") || strstr(file, ".pls"))
192     {
193         playtree = parse_playlist_file(file);
194         guiPlaylist(GUI_PLAYLIST_ADD, playtree, mconfig, 0);
195         return 1;
196     }
197     return 0;
198 }
199 
200 /* this function gets called by the gui to update mplayer */
guiSetEvent(int event)201 static void guiSetEvent(int event)
202 {
203     if(guiInfo.mpcontext)
204         mixer = mpctx_get_mixer(guiInfo.mpcontext);
205 
206     switch(event)
207     {
208         case evPlay:
209         case evPlaySwitchToPause:
210         case evPauseSwitchToPlay:
211             uiPlay();
212             break;
213         case evPause:
214             uiPause();
215             break;
216 #ifdef CONFIG_DVDREAD
217         case evPlayDVD:
218         {
219             static char dvdname[MAX_PATH];
220             guiInfo.Track = 1;
221             guiInfo.Chapter = 1;
222             guiInfo.Angle = 1;
223             guiInfo.MediumChanged = GUI_MEDIUM_SAME;
224 
225 #ifdef __WINE__
226             // dvd_device is in the Windows style (D:\), which needs to be
227             // converted for MPlayer, so that it will find the device in the
228             // Linux filesystem.
229             dvd_device = unix_device(dvd_device);
230 #endif
231             uiSetFile(NULL, dvd_device, STREAMTYPE_DVD);
232             dvdname[0] = 0;
233             strcat(dvdname, "DVD Movie");
234             GetVolumeInformation(dvd_device, dvdname, MAX_PATH, NULL, NULL, NULL, NULL, 0);
235             capitalize(dvdname);
236             mp_msg(MSGT_GPLAYER, MSGL_V, "Opening DVD %s -> %s\n", dvd_device, dvdname);
237             mygui->playlist->clear_playlist(mygui->playlist);
238             mygui->playlist->add_track(mygui->playlist, filename, NULL, dvdname, 0);
239             uiPlay();
240             break;
241         }
242 #endif
243 #ifdef CONFIG_CDDA
244         case evPlayCD:
245         {
246             int i;
247             char track[10];
248             char trackname[10];
249 #ifdef CONFIG_LIBCDIO
250             cdrom_drive_t *cd;
251 #else
252             cdrom_drive *cd;
253 #endif
254             int i_tracks;
255 
256 #ifdef __WINE__
257             // cdrom_device is in the Windows style (D:\), which needs to be
258             // converted for MPlayer, so that it will find the device in the
259             // Linux filesystem.
260             cdrom_device = unix_device(cdrom_device);
261 #endif
262             cd = cdda_identify(cdrom_device, 0, NULL);
263             if (cd)
264             {
265                 if (cdda_open(cd) != 0)
266                 {
267                     cdda_close(cd);
268                     cd = NULL;
269                 }
270             }
271             if(!cd)
272             {
273                 printf("Couldn't find a driver.\n");
274                 break;
275             }
276             i_tracks = cdda_tracks(cd);
277 
278             mygui->playlist->clear_playlist(mygui->playlist);
279             for(i=0;i<i_tracks;i++)
280             {
281                 sprintf(track, "cdda://%d", i+1);
282                 sprintf(trackname, "Track %d", i+1);
283                 mygui->playlist->add_track(mygui->playlist, track, NULL, trackname, 0);
284             }
285             cdda_close(cd);
286             mygui->startplay(mygui);
287             break;
288         }
289 #endif
290         case evFullScreen:
291             mp_input_queue_cmd(mp_input_parse_cmd("vo_fullscreen"));
292             break;
293         case evExit:
294         {
295             /* We are asking mplayer to exit, later it will ask us after uninit is made
296                this should be the only safe way to quit */
297             mygui->activewidget = NULL;
298             mp_input_queue_cmd(mp_input_parse_cmd("quit"));
299             break;
300         }
301         case evStop:
302             if(guiInfo.Playing)
303                 gui(GUI_SET_STATE, (void *) GUI_STOP);
304             break;
305         case evSetMoviePosition:
306         {
307             rel_seek_secs = guiInfo.Position / 100.0;
308             abs_seek_pos = SEEK_ABSOLUTE | SEEK_FACTOR;
309             break;
310         }
311         case evForward10sec:
312         {
313             rel_seek_secs = 10.0f;
314             abs_seek_pos = 0;
315             break;
316         }
317         case evBackward10sec:
318         {
319             rel_seek_secs = -10.0f;
320             abs_seek_pos = 0;
321             break;
322         }
323         case evSetBalance:
324         case evSetVolume:
325         {
326             float l,r;
327 
328             if (guiInfo.Playing == GUI_STOP)
329                 break;
330 
331             l = guiInfo.Volume * (100.0 - guiInfo.Balance) / 50.0;
332             r = guiInfo.Volume * guiInfo.Balance / 50.0;
333 
334             if (l > guiInfo.Volume) l=guiInfo.Volume;
335             if (r > guiInfo.Volume) r=guiInfo.Volume;
336             mixer_setvolume(mixer, l, r);
337             /* Check for balance support on mixer - there is a better way ?? */
338             if (r != l)
339             {
340                 mixer_getvolume(mixer, &l, &r);
341                 if (r == l)
342                 {
343                     mp_msg(MSGT_GPLAYER, MSGL_V, "[GUI] Mixer doesn't support unbalanced audio\n");
344                     mixer_setvolume(mixer, guiInfo.Volume, guiInfo.Volume);
345                     guiInfo.Balance = 50.0f;
346                 }
347             }
348             break;
349         }
350         case evMute:
351         {
352             mp_cmd_t * cmd = calloc(1, sizeof(*cmd));
353             cmd->id=MP_CMD_MUTE;
354             ARRAY_STRCPY(cmd->name, "mute");
355             mp_input_queue_cmd(cmd);
356             break;
357         }
358         case evLoadPlay:
359         {
360             switch(guiInfo.StreamType)
361             {
362                 case STREAMTYPE_DVD:
363                 {
364                     guiInfo.MediumChanged = GUI_MEDIUM_SAME;
365                     gui(GUI_SET_STATE, (void *) GUI_PLAY);
366                     break;
367                 }
368                 default:
369                 {
370                     guiInfo.MediumChanged = GUI_MEDIUM_NEW;
371                     update_playlistwindow();
372                     guiInfo.PlaylistNext = guiInfo.Playing? 0 : 1;
373                     gui(GUI_SET_STATE, (void *) GUI_STOP);
374                     gui(GUI_SET_STATE, (void *) GUI_PLAY);
375                     break;
376                }
377            }
378            break;
379         }
380         case evNext:
381             uiNext();
382             break;
383         case evPrev:
384             uiPrev();
385             break;
386     }
387 }
388 
uiPlay(void)389 void uiPlay( void )
390 {
391    if((!guiInfo.Filename ) || (guiInfo.Filename[0] == 0))
392      return;
393 
394    if(guiInfo.Playing > GUI_STOP)
395    {
396        uiPause();
397        return;
398    }
399    guiInfo.MediumChanged = GUI_MEDIUM_NEW;
400    gui(GUI_SET_STATE, (void *) GUI_PLAY);
401 }
402 
uiPause(void)403 void uiPause( void )
404 {
405    if(!guiInfo.Playing) return;
406 
407    if(guiInfo.Playing == GUI_PLAY)
408    {
409        mp_cmd_t * cmd = calloc(1, sizeof(*cmd));
410        cmd->id=MP_CMD_PAUSE;
411        ARRAY_STRCPY(cmd->name, "pause");
412        mp_input_queue_cmd(cmd);
413    } else guiInfo.Playing = GUI_PLAY;
414 }
415 
uiNext(void)416 void uiNext(void)
417 {
418     if(guiInfo.Playing == GUI_PAUSE) return;
419     switch(guiInfo.StreamType)
420     {
421         case STREAMTYPE_DVD:
422             if(guiInfo.Chapter == (guiInfo.Chapters - 1))
423                 return;
424             guiInfo.Chapter++;
425             break;
426         default:
427             if(mygui->playlist->current == (mygui->playlist->trackcount - 1))
428                 return;
429             uiSetFile(NULL, mygui->playlist->tracks[(mygui->playlist->current)++]->filename,
430                            STREAMTYPE_FILE);
431             break;
432     }
433     mygui->startplay(mygui);
434 }
435 
uiPrev(void)436 void uiPrev(void)
437 {
438     if(guiInfo.Playing == GUI_PAUSE) return;
439     switch(guiInfo.StreamType)
440     {
441         case STREAMTYPE_DVD:
442             if(guiInfo.Chapter == 1)
443                 return;
444             guiInfo.Chapter--;
445             break;
446         default:
447             if(mygui->playlist->current == 0)
448                 return;
449             uiSetFile(NULL, mygui->playlist->tracks[(mygui->playlist->current)--]->filename,
450                            STREAMTYPE_FILE);
451             break;
452     }
453     mygui->startplay(mygui);
454 }
455 
uiSetFile(const char * dir,const char * name,int type)456 void uiSetFile(const char *dir, const char *name, int type)
457 {
458     if(!name) return;
459     if(!dir)
460         setdup(&guiInfo.Filename, name);
461     else
462         setddup(&guiInfo.Filename, dir, name);
463 
464     filename = guiInfo.Filename;
465 #ifdef __WINE__
466     // When the GUI receives the files to be played in guiPlaylist(),
467     // it calls import_file_into_gui() where the call of
468     // Wine's GetFullPathName() converts each file name into the Windows style
469     // (C:\path\to\file), which needs to be reconverted for MPlayer, so that
470     // it will find the filename in the Linux filesystem.
471     filename = unix_name(filename);
472 #endif
473 
474     if (type != SAME_STREAMTYPE)
475         guiInfo.StreamType = type;
476 
477     nfree(guiInfo.AudioFilename);
478     nfree(guiInfo.SubtitleFilename);
479 }
480 
uiFullScreen(void)481 void uiFullScreen( void )
482 {
483     if(!guiInfo.sh_video) return;
484 
485     if(video_window)
486     {
487         if(!fullscreen && IsWindowVisible(mygui->videowindow) && !IsIconic(mygui->videowindow))
488            GetWindowRect(mygui->videowindow, &old_rect);
489 
490         if(fullscreen)
491         {
492             fullscreen = FALSE;
493             style = WS_OVERLAPPEDWINDOW | WS_SIZEBOX;
494         } else {
495             fullscreen = TRUE;
496             style = WS_VISIBLE | WS_POPUP;
497         }
498         SetWindowLong(mygui->videowindow, GWL_STYLE, style);
499         update_videowindow();
500     }
501     video_out->control(VOCTRL_FULLSCREEN, 0);
502     if(video_window) ShowWindow(mygui->videowindow, SW_SHOW);
503 }
504 
GuiThread(void * param)505 static unsigned __stdcall GuiThread(void* param)
506 {
507     MSG msg;
508 
509     (void) param;
510 
511     if(!skinName) skinName = strdup("Blue");
512     if(!mygui) mygui = create_gui(get_path("skins"), guiSetEvent);
513     if(!mygui) exit_player(EXIT_ERROR);
514 
515     if(autosync && autosync != gtkAutoSync)
516     {
517        gtkAutoSyncOn = TRUE;
518        gtkAutoSync = autosync;
519     }
520 
521     while(GetMessage(&msg, NULL, 0, 0))
522     {
523         TranslateMessage(&msg);
524         DispatchMessage(&msg);
525     }
526     fprintf(stderr, "[GUI] GUI thread terminated.\n");
527     fflush(stderr);
528     return 0;
529 }
530 
guiInit(void)531 void guiInit(void)
532 {
533     memset(&guiInfo, 0, sizeof(guiInfo));
534     /* Create The gui thread */
535     if (!mygui)
536     {
537         hThread = _beginthreadex(NULL, 0, GuiThread, NULL, 0, &threadId);
538         mp_msg(MSGT_GPLAYER, MSGL_V, "[GUI] Creating GUI Thread 0x%04x\n", threadId);
539     }
540 
541     /* Wait until the gui is created */
542     while(!mygui) Sleep(100);
543     mp_msg(MSGT_GPLAYER, MSGL_V, "[GUI] GUI thread started.\n");
544 
545     guiInfo.Volume = mygui->default_volume;
546     guiInfo.Balance = mygui->default_balance;
547 }
548 
guiDone(void)549 void guiDone(void)
550 {
551     if(mygui)
552     {
553         fprintf(stderr, "[GUI] Closed by main mplayer window\n");
554         fflush(stderr);
555         PostThreadMessage(threadId, WM_QUIT, 0, 0);
556         WaitForSingleObject(hThread, INFINITE);
557         CloseHandle(hThread);
558         mygui->uninit(mygui);
559         nfree(mygui);
560     }
561     /* Remove tray icon */
562     Shell_NotifyIcon(NIM_DELETE, &nid);
563     cfg_write();
564 }
565 
566 /* this function gets called by mplayer to update the gui */
gui(int what,void * data)567 int gui(int what, void *data)
568 {
569     int idata = (intptr_t) data;
570     stream_t *stream;
571     sh_audio_t *sh_audio;
572 #ifdef CONFIG_DVDREAD
573     dvd_priv_t *dvdp;
574 #endif
575     if(!mygui || !mygui->skin) return FALSE;
576 
577     if(guiInfo.mpcontext)
578     {
579         audio_out = mpctx_get_audio_out(guiInfo.mpcontext);
580         video_out = mpctx_get_video_out(guiInfo.mpcontext);
581         mixer = mpctx_get_mixer(guiInfo.mpcontext);
582         playtree = mpctx_get_playtree_iter(guiInfo.mpcontext);
583     }
584 
585     switch (what)
586     {
587         case GUI_PREPARE:
588         {
589             audio_id = -1;
590             video_id = -1;
591             dvdsub_id = -1;
592             vobsub_id = -1;
593             stream_cache_size = -1;
594             autosync = 0;
595             force_fps = 0;
596             if(!mygui->playlist->tracks) return FALSE;
597             switch(guiInfo.StreamType)
598             {
599                 case STREAMTYPE_FILE:
600                 case STREAMTYPE_STREAM:
601                     uiSetFile(NULL, mygui->playlist->tracks[mygui->playlist->current]->filename, SAME_STREAMTYPE);
602                     guiInfo.Track = mygui->playlist->current + 1;
603                     break;
604                 case STREAMTYPE_DVD:
605                 {
606                     char tmp[512];
607 #ifdef CONFIG_DVDREAD
608                     dvd_chapter = guiInfo.Chapter;
609                     dvd_angle = guiInfo.Angle;
610 #endif
611                     sprintf(tmp,"dvd://%d", guiInfo.Track);
612                     uiSetFile(NULL, tmp, SAME_STREAMTYPE);
613                     break;
614                 }
615             }
616             guiInfo.VideoWindow = TRUE;
617             if(gtkAONorm) listRepl(&af_cfg.list, "volnorm", "volnorm");
618             if(gtkAOExtraStereo)
619             {
620                 char *name = malloc(12 + 20 + 1);
621                 snprintf(name, 12 + 20, "extrastereo=%f", gtkAOExtraStereoMul);
622                 name[12 + 20] = 0;
623                 listRepl(&af_cfg.list, "extrastereo", name);
624                 free(name);
625             }
626             if(gtkCacheOn) stream_cache_size = gtkCacheSize;
627             if(gtkAutoSyncOn) autosync = gtkAutoSync;
628             guiInfo.MediumChanged = 0;
629             break;
630         }
631         case GUI_SET_AUDIO:
632         {
633             sh_audio = data;
634             if (sh_audio)
635             {
636                 guiInfo.AudioChannels = sh_audio->channels;
637                 guiInfo.AudioPassthrough = (gstrcmp(sh_audio->ad_driver->info->short_name, "hwac3") == 0);
638 
639                 if (!guiInfo.sh_video) guiInfo.VideoWindow = FALSE;
640             }
641             else
642             {
643                 guiInfo.AudioChannels = 0;
644                 guiInfo.AudioPassthrough = FALSE;
645             }
646             if (guiInfo.Volume >= 0.0f) /* otherwise skin demands usage of current volume */
647             {
648                 guiSetEvent(evSetVolume);
649                 guiSetEvent(evSetBalance);
650             }
651             if(IsWindowVisible(mygui->videowindow) && !guiInfo.VideoWindow)
652                 ShowWindow(mygui->videowindow, SW_HIDE);
653             break;
654         }
655         case GUI_SET_CONTEXT:
656             guiInfo.mpcontext = data;
657             break;
658         case GUI_SET_VIDEO:
659         {
660             guiInfo.sh_video = data;
661             if (guiInfo.sh_video)
662             {
663                 codecname = codec_idx2str(guiInfo.sh_video->codec->name_idx);
664 
665                 /* we have video, show the video window */
666                 if(!IsWindowVisible(mygui->videowindow) || IsIconic(mygui->videowindow))
667                     ShowWindow(mygui->videowindow, SW_SHOWNORMAL);
668                 if(WinID == -1)
669                     update_videowindow();
670 
671             }
672             break;
673         }
674         case GUI_SETUP_VIDEO_WINDOW:
675         {
676             guiInfo.VideoWidth = vo_dwidth;
677             guiInfo.VideoHeight = vo_dheight;
678 
679             video_aspect = (float)guiInfo.VideoWidth/guiInfo.VideoHeight;
680             if(WinID != -1)
681                update_videowindow();
682             break;
683         }
684         case GUI_SET_STREAM:
685         {
686             stream = data;
687             guiInfo.StreamType = stream->type;
688             switch(guiInfo.StreamType)
689             {
690                 case STREAMTYPE_DVD:
691                     guiInfo.Tracks = 0;
692                     stream_control(stream, STREAM_CTRL_GET_NUM_TITLES, &guiInfo.Tracks);
693                     guiInfo.Chapters = 0;
694                     stream_control(stream, STREAM_CTRL_GET_NUM_CHAPTERS, &guiInfo.Chapters);
695                     guiInfo.Angles = 0;
696                     stream_control(stream, STREAM_CTRL_GET_NUM_ANGLES, &guiInfo.Angles);
697                     if (stream_control(stream, STREAM_CTRL_GET_CURRENT_TITLE, &guiInfo.Track) == STREAM_OK)
698                         guiInfo.Track++;
699                     // guiInfo.Chapter will be set by mplayer
700                     guiInfo.Angle = 1;
701                     stream_control(stream, STREAM_CTRL_GET_ANGLE, &guiInfo.Angle);
702 #ifdef CONFIG_DVDREAD
703                     dvdp = stream->priv;
704                     guiInfo.AudioStreams = dvdp->nr_of_channels;
705                     memcpy(guiInfo.AudioStream, dvdp->audio_streams, sizeof(dvdp->audio_streams));
706                     guiInfo.Subtitles = dvdp->nr_of_subtitles;
707                     memcpy(guiInfo.Subtitle, dvdp->subtitles, sizeof(dvdp->subtitles));
708 #endif
709                     break;
710             }
711             break;
712         }
713         case GUI_REDRAW:
714             mygui->updatedisplay(mygui, mygui->mainwindow);
715             break;
716         case GUI_SET_STATE:
717         {
718             guiInfo.Playing = idata;
719             switch (guiInfo.Playing)
720             {
721                 case GUI_PLAY:
722                 {
723                     guiInfo.Playing = GUI_PLAY;
724                     break;
725                 }
726                 case GUI_STOP:
727                 {
728                     guiInfo.Playing = GUI_STOP;
729                     if(movie_aspect >= 0)
730                         movie_aspect = -1;
731                     update_videowindow();
732                     break;
733                 }
734                 case GUI_PAUSE:
735                     guiInfo.Playing = GUI_PAUSE;
736                     break;
737             }
738             break;
739         }
740         case GUI_RUN_COMMAND:
741         {
742             mp_msg(MSGT_GPLAYER,MSGL_V, "cmd: %d\n", idata);
743             /* MPlayer asks us to quit */
744             switch(idata)
745             {
746                 case MP_CMD_VO_FULLSCREEN:
747                     uiFullScreen();
748                     break;
749                 case MP_CMD_QUIT:
750                 {
751                     mygui->uninit(mygui);
752                     nfree(mygui);
753                     exit_player(EXIT_QUIT);
754                     return TRUE;
755                 }
756                 case MP_CMD_PLAY_TREE_STEP:
757                   guiSetEvent(evNext);
758                   break;
759                 case -MP_CMD_PLAY_TREE_STEP:
760                   guiSetEvent(evPrev);
761                   break;
762                 case MP_CMD_STOP:
763                   guiSetEvent(evStop);
764                   break;
765                 default:
766                     break;
767             }
768             break;
769         }
770         case GUI_RUN_MESSAGE:
771           break;
772         case GUI_SET_VOLUME_BALANCE:
773         {
774             if(audio_out)
775             {
776                 /* Some audio_out drivers do not support balance e.g. dsound */
777                 /* FIXME this algo is not correct */
778                 float l, r;
779                 mixer_getvolume(mixer, &l, &r);
780                 guiInfo.Volume = (r > l ? r : l); /* max(r,l) */
781                 if (r != l)
782                     guiInfo.Balance = ((r-l) + 100.0) * 0.5;
783                 else
784                     guiInfo.Balance = 50.0f;
785             }
786             break;
787         }
788         case GUI_END_PLAY:
789         {
790           guiInfo.sh_video = NULL;
791 
792           if(!guiInfo.PlaylistNext && guiInfo.Playing)
793           {
794               guiInfo.PlaylistNext = TRUE;
795               break;
796           }
797 
798           if(guiInfo.PlaylistNext && guiInfo.Playing &&
799             (mygui->playlist->current < (mygui->playlist->trackcount - 1)) &&
800             guiInfo.StreamType != STREAMTYPE_DVD &&
801             guiInfo.StreamType != STREAMTYPE_DVDNAV)
802           {
803               /* we've finished this file, reset the aspect */
804               if(movie_aspect >= 0)
805                   movie_aspect = -1;
806 
807               guiInfo.PlaylistNext = TRUE;
808               guiInfo.MediumChanged = GUI_MEDIUM_NEW;
809               uiSetFile(NULL, mygui->playlist->tracks[(mygui->playlist->current)++]->filename, STREAMTYPE_FILE);
810               //sprintf(guiInfo.Filename, mygui->playlist->tracks[(mygui->playlist->current)++]->filename);
811           }
812 
813           if(guiInfo.MediumChanged == GUI_MEDIUM_NEW)
814               break;
815 
816           guiInfo.ElapsedTime = 0;
817           guiInfo.Position = 0;
818           guiInfo.AudioChannels = 0;
819           guiInfo.AudioPassthrough = FALSE;
820 
821           guiInfo.Track = 1;
822           guiInfo.Chapter = 1;
823           guiInfo.Angle = 1;
824 
825           if (mygui->playlist->current == (mygui->playlist->trackcount - 1))
826               mygui->playlist->current = 0;
827 
828           fullscreen = FALSE;
829           if(style == (WS_VISIBLE | WS_POPUP))
830           {
831               style = WS_OVERLAPPEDWINDOW | WS_SIZEBOX;
832               SetWindowLong(mygui->videowindow, GWL_STYLE, style);
833           }
834           gui(GUI_SET_STATE, (void *) GUI_STOP);
835           break;
836         }
837 #ifdef __WINE__
838         // it's possible to have an X11 video output driver (sending events)
839         case GUI_HANDLE_X_EVENT:
840         {
841           break;
842         }
843 #endif
844         default:
845             mp_msg(MSGT_GPLAYER, MSGL_ERR, "[GUI] GOT UNHANDLED EVENT %i\n", what);
846     }
847     return TRUE;
848 }
849 
850 /* This function adds/inserts one file into the gui playlist */
import_file_into_gui(char * pathname,int insert)851 static int import_file_into_gui(char *pathname, int insert)
852 {
853     char file[MAX_PATH];
854     char *filepart = file;
855 
856     (void) insert;   // NOTE TO MYSELF: this isn't yet implemented
857 
858     if (strstr(pathname, "://"))
859     {
860         mp_msg(MSGT_GPLAYER, MSGL_V, "[GUI] Adding special %s\n", pathname);
861         mygui->playlist->add_track(mygui->playlist, pathname, NULL, NULL, 0);
862         return 1;
863     }
864     if (GetFullPathName(pathname, MAX_PATH, file, &filepart))
865     {
866         if (!(GetFileAttributes(file) & FILE_ATTRIBUTE_DIRECTORY))
867         {
868             mp_msg(MSGT_GPLAYER, MSGL_V, "[GUI] Adding filename: %s - fullpath: %s\n", filepart, file);
869             mygui->playlist->add_track(mygui->playlist, file, NULL, filepart, 0);
870             return 1;
871         }
872         else
873             mp_msg(MSGT_GPLAYER, MSGL_V, "[GUI] Cannot add %s\n", file);
874     }
875 
876     return 0;
877 }
878 
guiPlaylist(int what,play_tree_t * playtree,m_config_t * config,int enqueue)879 int guiPlaylist (int what, play_tree_t *playtree, m_config_t *config, int enqueue)
880 {
881     play_tree_iter_t *pt_iter = NULL;
882     char *file;
883     int added = FALSE;
884 
885     switch (what)
886     {
887         /*  This function imports the initial playtree (based on cmd-line files) into the gui playlist
888             by either:
889             - overwriting gui pl (enqueue=0) */
890         case GUI_PLAYLIST_INIT:
891 
892             if(!mygui) guiInit();
893 
894             if((pt_iter = pt_iter_create(&playtree, config)))
895             {
896                 while ((file = pt_iter_get_next_file(pt_iter)) != NULL)
897                 {
898                     if (parse_filename(file, playtree, config, 0))
899                         added = TRUE;
900                     else if (import_file_into_gui(file, 0)) /* Add it to end of list */
901                         added = TRUE;
902                 }
903             }
904             guiInfo.PlaylistNext = TRUE;
905 
906             if (added)
907             {
908                 mygui->playlist->current = 0;
909                 uiSetFile(NULL, mygui->playlist->tracks[0]->filename, STREAMTYPE_FILE);
910             }
911 
912             if (enqueue) filename = NULL;
913 
914             break;
915 
916         /* This function imports and inserts an playtree, that is created "on the fly", for example by
917            parsing some MOV-Reference-File; or by loading an playlist with "File Open"
918            The file which contained the playlist is thereby replaced with it's contents. */
919         case GUI_PLAYLIST_ADD:
920 
921             if((pt_iter = pt_iter_create(&playtree, config)))
922             {
923                 while ((file = pt_iter_get_next_file(pt_iter)) != NULL)
924                     if (import_file_into_gui(file, 1)) /* insert it into the list and set plCurrent = new item */
925                         added = TRUE;
926                 pt_iter_destroy(&pt_iter);
927             }
928 
929             break;
930     }
931 
932     return added;
933 }
934 
update_videowindow(void)935 static int update_videowindow(void)
936 {
937     int x,y;
938     RECT rd;
939     WINDOWPOS wp;
940 
941     if(!video_window)
942     {
943         WinID = -1;
944 
945         if(IsWindowVisible(mygui->videowindow) && guiInfo.sh_video && guiInfo.Playing)
946         {
947             ShowWindow(mygui->videowindow, SW_HIDE);
948             return 0;
949         }
950         else if(!guiInfo.VideoWindow)
951             return 0;
952         else ShowWindow(mygui->videowindow, SW_SHOW);
953     }
954 
955     /* we've come out of fullscreen at the end of file */
956     if((!IsWindowVisible(mygui->videowindow) || IsIconic(mygui->videowindow)) && guiInfo.VideoWindow)
957         ShowWindow(mygui->videowindow, SW_SHOWNORMAL);
958 
959     /* get our current window coordinates */
960     GetWindowRect(mygui->videowindow, &rd);
961 
962     x = rd.left;
963     y = rd.top;
964 
965     /* restore video window position when coming out of fullscreen */
966     if(x <= 0) x = old_rect.left;
967     if(y <= 0) y = old_rect.top;
968 
969     if(!guiInfo.Playing)
970     {
971         window *desc = NULL;
972         unsigned int i;
973 
974         for (i=0; i<mygui->skin->windowcount; i++)
975             if(mygui->skin->windows[i]->type == wVideo)
976                 desc = mygui->skin->windows[i];
977 
978         rd.right = rd.left+desc->base->bitmap[0]->width;
979         rd.bottom = rd.top+desc->base->bitmap[0]->height;
980         video_aspect = (float)(rd.right-rd.left)/(rd.bottom-rd.top);
981     }
982     else
983     {
984         rd.right = rd.left+guiInfo.VideoWidth;
985         rd.bottom = rd.top+guiInfo.VideoHeight;
986 
987         if (movie_aspect > 0.0f)       // forced aspect from the cmdline
988             video_aspect = movie_aspect;
989     }
990 
991 
992     AdjustWindowRect(&rd, WS_OVERLAPPEDWINDOW | WS_SIZEBOX, 0);
993     SetWindowPos(mygui->videowindow, 0, x, y, rd.right-rd.left, rd.bottom-rd.top, SWP_NOOWNERZORDER);
994 
995     wp.hwnd = mygui->videowindow;
996     wp.x = rd.left;
997     wp.y = rd.top;
998     wp.cx = rd.right-rd.left;
999     wp.cy = rd.bottom-rd.top;
1000     wp.flags = SWP_NOOWNERZORDER | SWP_SHOWWINDOW;
1001 
1002     /* erase the bitmap image if there's video */
1003     if(guiInfo.Playing != GUI_STOP && guiInfo.sh_video)
1004         SendMessage(mygui->videowindow, WM_ERASEBKGND, (WPARAM)GetDC(mygui->videowindow), 0);
1005 
1006     /* reset the window aspect */
1007     SendMessage(mygui->videowindow, WM_WINDOWPOSCHANGED, 0, (LPARAM)&wp);
1008     return 0;
1009 }
1010