Mercurial > mplayer.hg
annotate gui/win32/interface.c @ 24992:5701e23ebcb4
Better handling of win32 GUI thread:
1. Use _beginthreadex to create the GUI thread to avoid possible memory leak
when linked to MS CRT.
2. Terminate the GUI thread in an cleaner way using PostThreadMessage()
rather than the unrecommended TerminateThread().
author | zuxy |
---|---|
date | Sun, 11 Nov 2007 08:14:57 +0000 |
parents | 71efd1fc20c8 |
children | 304fc0bbefe1 |
rev | line source |
---|---|
23077 | 1 /* |
23079 | 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 | |
20 * along with MPlayer; if not, write to the Free Software | |
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 */ | |
23077 | 23 |
24 #include <windows.h> | |
23091
52488bb09d90
Consistently use quotes instead of angled brackets in #include
diego
parents:
23079
diff
changeset
|
25 |
52488bb09d90
Consistently use quotes instead of angled brackets in #include
diego
parents:
23079
diff
changeset
|
26 #include "interface.h" |
52488bb09d90
Consistently use quotes instead of angled brackets in #include
diego
parents:
23079
diff
changeset
|
27 #include "m_option.h" |
52488bb09d90
Consistently use quotes instead of angled brackets in #include
diego
parents:
23079
diff
changeset
|
28 #include "mixer.h" |
52488bb09d90
Consistently use quotes instead of angled brackets in #include
diego
parents:
23079
diff
changeset
|
29 #include "mp_msg.h" |
52488bb09d90
Consistently use quotes instead of angled brackets in #include
diego
parents:
23079
diff
changeset
|
30 #include "help_mp.h" |
52488bb09d90
Consistently use quotes instead of angled brackets in #include
diego
parents:
23079
diff
changeset
|
31 #include "codec-cfg.h" |
52488bb09d90
Consistently use quotes instead of angled brackets in #include
diego
parents:
23079
diff
changeset
|
32 #include "stream/stream.h" |
52488bb09d90
Consistently use quotes instead of angled brackets in #include
diego
parents:
23079
diff
changeset
|
33 #include "libmpdemux/demuxer.h" |
52488bb09d90
Consistently use quotes instead of angled brackets in #include
diego
parents:
23079
diff
changeset
|
34 #include "libmpdemux/stheader.h" |
23077 | 35 #ifdef USE_DVDREAD |
23091
52488bb09d90
Consistently use quotes instead of angled brackets in #include
diego
parents:
23079
diff
changeset
|
36 #include "stream/stream_dvd.h" |
23077 | 37 #endif |
23091
52488bb09d90
Consistently use quotes instead of angled brackets in #include
diego
parents:
23079
diff
changeset
|
38 #include "input/input.h" |
52488bb09d90
Consistently use quotes instead of angled brackets in #include
diego
parents:
23079
diff
changeset
|
39 #include "libvo/video_out.h" |
52488bb09d90
Consistently use quotes instead of angled brackets in #include
diego
parents:
23079
diff
changeset
|
40 #include "libao2/audio_out.h" |
52488bb09d90
Consistently use quotes instead of angled brackets in #include
diego
parents:
23079
diff
changeset
|
41 #include "access_mpcontext.h" |
23077 | 42 #include "gui.h" |
43 #include "dialogs.h" | |
44 #include "wincfg.h" | |
45 #ifdef HAVE_LIBCDIO | |
46 #include <cdio/cdio.h> | |
47 #endif | |
48 | |
49 extern int abs_seek_pos; | |
50 extern float rel_seek_secs; | |
51 extern int vcd_track; | |
52 extern af_cfg_t af_cfg; | |
53 int guiWinID = 0; | |
54 | |
55 char *skinName = NULL; | |
56 char *codecname = NULL; | |
57 int mplGotoTheNext = 1; | |
58 static gui_t *mygui = NULL; | |
59 static int update_subwindow(void); | |
60 static RECT old_rect; | |
61 static DWORD style; | |
24992 | 62 static HANDLE hThread; |
63 static unsigned threadId; | |
23077 | 64 ao_functions_t *audio_out = NULL; |
65 vo_functions_t *video_out = NULL; | |
66 mixer_t *mixer = NULL; | |
67 | |
68 /* test for playlist files, no need to specify -playlist on the commandline. | |
69 * add any conceivable playlist extensions here. | |
70 * - Erik | |
71 */ | |
72 int parse_filename(char *file, play_tree_t *playtree, m_config_t *mconfig, int clear) | |
73 { | |
74 if(clear) | |
75 mygui->playlist->clear_playlist(mygui->playlist); | |
76 | |
77 if(strstr(file, ".m3u") || strstr(file, ".pls")) | |
78 { | |
79 playtree = parse_playlist_file(file); | |
80 import_playtree_playlist_into_gui(playtree, mconfig); | |
81 return 1; | |
82 } | |
83 return 0; | |
84 } | |
85 | |
86 /** | |
87 * \brief this actually creates a new list containing only one element... | |
88 */ | |
89 void gaddlist( char ***list, const char *entry) | |
90 { | |
91 int i; | |
92 | |
93 if (*list) | |
94 { | |
95 for (i=0; (*list)[i]; i++) free((*list)[i]); | |
96 free(*list); | |
97 } | |
98 | |
99 *list = malloc(2 * sizeof(char **)); | |
100 (*list)[0] = gstrdup(entry); | |
101 (*list)[1] = NULL; | |
102 } | |
103 | |
104 char *gstrdup(const char *str) | |
105 { | |
106 if (!str) return NULL; | |
107 return strdup(str); | |
108 } | |
109 | |
110 /** | |
111 * \brief this replaces a string starting with search by replace. | |
112 * If not found, replace is appended. | |
113 */ | |
114 void greplace(char ***list, char *search, char *replace) | |
115 { | |
116 int i = 0; | |
117 int len = (search) ? strlen(search) : 0; | |
118 | |
119 if (*list) | |
120 { | |
121 for (i = 0; (*list)[i]; i++) | |
122 { | |
123 if (search && (!strncmp((*list)[i], search, len))) | |
124 { | |
125 free((*list)[i]); | |
126 (*list)[i] = gstrdup(replace); | |
127 return; | |
128 } | |
129 } | |
130 *list = realloc(*list, (i + 2) * sizeof(char *)); | |
131 } | |
132 else | |
133 *list = malloc(2 * sizeof(char *)); | |
134 | |
135 (*list)[i] = gstrdup(replace); | |
136 (*list)[i + 1] = NULL; | |
137 } | |
138 | |
139 /* this function gets called by the gui to update mplayer */ | |
140 static void guiSetEvent(int event) | |
141 { | |
142 if(guiIntfStruct.mpcontext) | |
143 mixer = mpctx_get_mixer(guiIntfStruct.mpcontext); | |
144 | |
145 switch(event) | |
146 { | |
147 case evPlay: | |
148 case evPlaySwitchToPause: | |
23148
71efd1fc20c8
add missing case value, fixes functionality when using some skins.
vayne
parents:
23147
diff
changeset
|
149 case evPauseSwitchToPlay: |
23077 | 150 mplPlay(); |
151 break; | |
152 case evPause: | |
153 mplPause(); | |
154 break; | |
155 #ifdef USE_DVDREAD | |
156 case evPlayDVD: | |
157 { | |
158 static char dvdname[MAX_PATH]; | |
159 guiIntfStruct.DVD.current_title = dvd_title; | |
160 guiIntfStruct.DVD.current_chapter = dvd_chapter; | |
161 guiIntfStruct.DVD.current_angle = dvd_angle; | |
162 guiIntfStruct.DiskChanged = 1; | |
163 | |
164 mplSetFileName(NULL, dvd_device, STREAMTYPE_DVD); | |
165 dvdname[0] = 0; | |
166 strcat(dvdname, "DVD Movie"); | |
167 GetVolumeInformation(dvd_device, dvdname, MAX_PATH, NULL, NULL, NULL, NULL, 0); | |
168 capitalize(dvdname); | |
169 mp_msg(MSGT_GPLAYER, MSGL_V, "Opening DVD %s -> %s\n", dvd_device, dvdname); | |
170 guiGetEvent(guiSetParameters, (char *) STREAMTYPE_DVD); | |
171 mygui->playlist->clear_playlist(mygui->playlist); | |
172 mygui->playlist->add_track(mygui->playlist, filename, NULL, dvdname, 0); | |
173 mygui->startplay(mygui); | |
174 break; | |
175 } | |
176 #endif | |
177 #ifdef HAVE_LIBCDIO | |
178 case evPlayCD: | |
179 { | |
180 int i; | |
181 char track[10]; | |
182 char trackname[10]; | |
183 CdIo_t *p_cdio = cdio_open(NULL, DRIVER_UNKNOWN); | |
184 track_t i_tracks; | |
185 | |
186 if(p_cdio == NULL) printf("Couldn't find a driver.\n"); | |
187 i_tracks = cdio_get_num_tracks(p_cdio); | |
188 | |
189 mygui->playlist->clear_playlist(mygui->playlist); | |
190 for(i=0;i<i_tracks;i++) | |
191 { | |
192 sprintf(track, "cdda://%d", i+1); | |
193 sprintf(trackname, "Track %d", i+1); | |
194 mygui->playlist->add_track(mygui->playlist, track, NULL, trackname, 0); | |
195 } | |
196 cdio_destroy(p_cdio); | |
197 mygui->startplay(mygui); | |
198 break; | |
199 } | |
200 #endif | |
201 case evFullScreen: | |
202 mp_input_queue_cmd(mp_input_parse_cmd("vo_fullscreen")); | |
203 break; | |
204 case evExit: | |
205 { | |
206 /* We are asking mplayer to exit, later it will ask us after uninit is made | |
207 this should be the only safe way to quit */ | |
208 mygui->activewidget = NULL; | |
209 mp_input_queue_cmd(mp_input_parse_cmd("quit")); | |
210 break; | |
211 } | |
212 case evStop: | |
213 if(guiIntfStruct.Playing) | |
214 guiGetEvent(guiCEvent, (void *) guiSetStop); | |
215 break; | |
216 case evSetMoviePosition: | |
217 { | |
218 rel_seek_secs = guiIntfStruct.Position / 100.0f; | |
219 abs_seek_pos = 3; | |
220 break; | |
221 } | |
222 case evForward10sec: | |
223 { | |
224 rel_seek_secs = 10.0f; | |
225 abs_seek_pos = 0; | |
226 break; | |
227 } | |
228 case evBackward10sec: | |
229 { | |
230 rel_seek_secs = -10.0f; | |
231 abs_seek_pos = 0; | |
232 break; | |
233 } | |
234 case evSetBalance: | |
235 case evSetVolume: | |
236 { | |
237 float l,r; | |
238 | |
239 if (guiIntfStruct.Playing == 0) | |
240 break; | |
241 | |
242 if (guiIntfStruct.Balance == 50.0f) | |
243 mixer_setvolume(mixer, guiIntfStruct.Volume, guiIntfStruct.Volume); | |
244 | |
245 l = guiIntfStruct.Volume * ((100.0f - guiIntfStruct.Balance) / 50.0f); | |
246 r = guiIntfStruct.Volume * ((guiIntfStruct.Balance) / 50.0f); | |
247 | |
248 if (l > guiIntfStruct.Volume) l=guiIntfStruct.Volume; | |
249 if (r > guiIntfStruct.Volume) r=guiIntfStruct.Volume; | |
250 mixer_setvolume(mixer, l, r); | |
251 /* Check for balance support on mixer - there is a better way ?? */ | |
252 if (r != l) | |
253 { | |
254 mixer_getvolume(mixer, &l, &r); | |
255 if (r == l) | |
256 { | |
257 mp_msg(MSGT_GPLAYER, MSGL_V, "[GUI] Mixer doesn't support balanced audio\n"); | |
258 mixer_setvolume(mixer, guiIntfStruct.Volume, guiIntfStruct.Volume); | |
259 guiIntfStruct.Balance = 50.0f; | |
260 } | |
261 } | |
262 break; | |
263 } | |
264 case evMute: | |
265 { | |
266 mp_cmd_t * cmd = calloc(1, sizeof(*cmd)); | |
267 cmd->id=MP_CMD_MUTE; | |
268 cmd->name=strdup("mute"); | |
269 mp_input_queue_cmd(cmd); | |
270 break; | |
271 } | |
272 case evDropFile: | |
273 case evLoadPlay: | |
274 { | |
275 switch(guiIntfStruct.StreamType) | |
276 { | |
23147
21c35763b178
compilation fix for disabling dvd functionality, patch by <bangbangbear at gmail dot com>, slightly modified by me.
vayne
parents:
23123
diff
changeset
|
277 #ifdef USE_DVDREAD |
23077 | 278 case STREAMTYPE_DVD: |
279 { | |
280 guiIntfStruct.Title = guiIntfStruct.DVD.current_title; | |
281 guiIntfStruct.Chapter = guiIntfStruct.DVD.current_chapter; | |
282 guiIntfStruct.Angle = guiIntfStruct.DVD.current_angle; | |
283 guiIntfStruct.DiskChanged = 1; | |
284 guiGetEvent(guiCEvent, (void *) guiSetPlay); | |
285 break; | |
286 } | |
23147
21c35763b178
compilation fix for disabling dvd functionality, patch by <bangbangbear at gmail dot com>, slightly modified by me.
vayne
parents:
23123
diff
changeset
|
287 #endif |
23077 | 288 default: |
289 { | |
290 guiIntfStruct.FilenameChanged = guiIntfStruct.NewPlay = 1; | |
291 update_playlistwindow(); | |
292 mplGotoTheNext = guiIntfStruct.Playing? 0 : 1; | |
293 guiGetEvent(guiCEvent, (void *) guiSetStop); | |
294 guiGetEvent(guiCEvent, (void *) guiSetPlay); | |
295 break; | |
296 } | |
297 } | |
298 break; | |
299 } | |
300 case evNext: | |
301 mplNext(); | |
302 break; | |
303 case evPrev: | |
304 mplPrev(); | |
305 break; | |
306 } | |
307 } | |
308 | |
309 void mplPlay( void ) | |
310 { | |
311 if((!guiIntfStruct.Filename ) || (guiIntfStruct.Filename[0] == 0)) | |
312 return; | |
313 | |
314 if(guiIntfStruct.Playing > 0) | |
315 { | |
316 mplPause(); | |
317 return; | |
318 } | |
319 guiIntfStruct.NewPlay = 1; | |
320 guiGetEvent(guiCEvent, (void *) guiSetPlay); | |
321 } | |
322 | |
323 void mplPause( void ) | |
324 { | |
325 if(!guiIntfStruct.Playing) return; | |
326 | |
327 if(guiIntfStruct.Playing == 1) | |
328 { | |
329 mp_cmd_t * cmd = calloc(1, sizeof(*cmd)); | |
330 cmd->id=MP_CMD_PAUSE; | |
331 cmd->name=strdup("pause"); | |
332 mp_input_queue_cmd(cmd); | |
333 } else guiIntfStruct.Playing = 1; | |
334 } | |
335 | |
336 void mplNext(void) | |
337 { | |
338 if(guiIntfStruct.Playing == 2) return; | |
339 switch(guiIntfStruct.StreamType) | |
340 { | |
341 #ifdef USE_DVDREAD | |
342 case STREAMTYPE_DVD: | |
343 if(guiIntfStruct.DVD.current_chapter == (guiIntfStruct.DVD.chapters - 1)) | |
344 return; | |
345 guiIntfStruct.DVD.current_chapter++; | |
346 break; | |
347 #endif | |
348 default: | |
349 if(mygui->playlist->current == (mygui->playlist->trackcount - 1)) | |
350 return; | |
351 mplSetFileName(NULL, mygui->playlist->tracks[(mygui->playlist->current)++]->filename, | |
352 STREAMTYPE_STREAM); | |
353 break; | |
354 } | |
355 mygui->startplay(mygui); | |
356 } | |
357 | |
358 void mplPrev(void) | |
359 { | |
360 if(guiIntfStruct.Playing == 2) return; | |
361 switch(guiIntfStruct.StreamType) | |
362 { | |
363 #ifdef USE_DVDREAD | |
364 case STREAMTYPE_DVD: | |
365 if(guiIntfStruct.DVD.current_chapter == 1) | |
366 return; | |
367 guiIntfStruct.DVD.current_chapter--; | |
368 break; | |
369 #endif | |
370 default: | |
371 if(mygui->playlist->current == 0) | |
372 return; | |
373 mplSetFileName(NULL, mygui->playlist->tracks[(mygui->playlist->current)--]->filename, | |
374 STREAMTYPE_STREAM); | |
375 break; | |
376 } | |
377 mygui->startplay(mygui); | |
378 } | |
379 | |
380 void mplEnd( void ) | |
381 { | |
382 if(!mplGotoTheNext && guiIntfStruct.Playing) | |
383 { | |
384 mplGotoTheNext = 1; | |
385 return; | |
386 } | |
387 | |
388 if(mplGotoTheNext && guiIntfStruct.Playing && | |
389 (mygui->playlist->current < (mygui->playlist->trackcount - 1)) && | |
390 guiIntfStruct.StreamType != STREAMTYPE_DVD && | |
391 guiIntfStruct.StreamType != STREAMTYPE_DVDNAV) | |
392 { | |
393 /* we've finished this file, reset the aspect */ | |
394 if(movie_aspect >= 0) | |
395 movie_aspect = -1; | |
396 | |
397 mplGotoTheNext = guiIntfStruct.FilenameChanged = guiIntfStruct.NewPlay = 1; | |
398 mplSetFileName(NULL, mygui->playlist->tracks[(mygui->playlist->current)++]->filename, STREAMTYPE_STREAM); | |
399 //sprintf(guiIntfStruct.Filename, mygui->playlist->tracks[(mygui->playlist->current)++]->filename); | |
400 } | |
401 | |
402 if(guiIntfStruct.FilenameChanged && guiIntfStruct.NewPlay) | |
403 return; | |
404 | |
405 guiIntfStruct.TimeSec = 0; | |
406 guiIntfStruct.Position = 0; | |
407 guiIntfStruct.AudioType = 0; | |
408 | |
409 #ifdef USE_DVDREAD | |
410 guiIntfStruct.DVD.current_title = 1; | |
411 guiIntfStruct.DVD.current_chapter = 1; | |
412 guiIntfStruct.DVD.current_angle = 1; | |
413 #endif | |
414 | |
415 if (mygui->playlist->current == (mygui->playlist->trackcount - 1)) | |
416 mygui->playlist->current = 0; | |
417 | |
418 fullscreen = 0; | |
419 if(style == WS_VISIBLE | WS_POPUP) | |
420 { | |
421 style = WS_OVERLAPPEDWINDOW | WS_SIZEBOX; | |
422 SetWindowLong(mygui->subwindow, GWL_STYLE, style); | |
423 } | |
424 guiGetEvent(guiCEvent, (void *) guiSetStop); | |
425 } | |
426 | |
427 void mplSetFileName(char *dir, char *name, int type) | |
428 { | |
429 if(!name) return; | |
430 if(!dir) | |
431 guiSetFilename(guiIntfStruct.Filename, name) | |
432 else | |
433 guiSetDF(guiIntfStruct.Filename, dir, name); | |
434 | |
435 guiIntfStruct.StreamType = type; | |
436 free((void **) &guiIntfStruct.AudioFile); | |
437 free((void **) &guiIntfStruct.Subtitlename); | |
438 } | |
439 | |
440 void mplFullScreen( void ) | |
441 { | |
442 if(!guiIntfStruct.sh_video) return; | |
443 | |
444 if(sub_window) | |
445 { | |
446 if(!fullscreen && IsWindowVisible(mygui->subwindow) && !IsIconic(mygui->subwindow)) | |
447 GetWindowRect(mygui->subwindow, &old_rect); | |
448 | |
449 if(fullscreen) | |
450 { | |
451 fullscreen = 0; | |
452 style = WS_OVERLAPPEDWINDOW | WS_SIZEBOX; | |
453 } else { | |
454 fullscreen = 1; | |
455 style = WS_VISIBLE | WS_POPUP; | |
456 } | |
457 SetWindowLong(mygui->subwindow, GWL_STYLE, style); | |
458 update_subwindow(); | |
459 } | |
460 video_out->control(VOCTRL_FULLSCREEN, 0); | |
461 if(sub_window) ShowWindow(mygui->subwindow, SW_SHOW); | |
462 } | |
463 | |
24992 | 464 static unsigned __stdcall GuiThread(void* param) |
23077 | 465 { |
466 MSG msg; | |
467 | |
468 if(!skinName) skinName = strdup("Blue"); | |
469 if(!mygui) mygui = create_gui(get_path("skins"), skinName, guiSetEvent); | |
23078 | 470 if(!mygui) exit_player("Unable to load GUI."); |
23077 | 471 |
472 if(autosync && autosync != gtkAutoSync) | |
473 { | |
474 gtkAutoSyncOn = 1; | |
475 gtkAutoSync = autosync; | |
476 } | |
477 | |
24992 | 478 while(GetMessage(&msg, NULL, 0, 0)) |
23077 | 479 { |
480 TranslateMessage(&msg); | |
481 DispatchMessage(&msg); | |
482 } | |
23078 | 483 fprintf(stderr, "[GUI] GUI thread terminated.\n"); |
23077 | 484 fflush(stderr); |
485 return 0; | |
486 } | |
487 | |
488 void guiInit(void) | |
489 { | |
490 memset(&guiIntfStruct, 0, sizeof(guiIntfStruct)); | |
491 /* Create The gui thread */ | |
492 if (!mygui) | |
493 { | |
24992 | 494 hThread = _beginthreadex(NULL, 0, GuiThread, NULL, 0, &threadId); |
23077 | 495 mp_msg(MSGT_GPLAYER, MSGL_V, "[GUI] Creating GUI Thread 0x%04x\n", threadId); |
496 } | |
497 | |
498 /* Wait until the gui is created */ | |
499 while(!mygui) Sleep(100); | |
23078 | 500 mp_msg(MSGT_GPLAYER, MSGL_V, "[GUI] GUI thread started.\n"); |
23077 | 501 } |
502 | |
503 void guiDone(void) | |
504 { | |
505 if(mygui) | |
506 { | |
507 fprintf(stderr, "[GUI] Closed by main mplayer window\n"); | |
508 fflush(stderr); | |
24992 | 509 PostThreadMessage(threadId, WM_QUIT, 0, 0); |
510 WaitForSingleObject(hThread, INFINITE); | |
511 CloseHandle(hThread); | |
23077 | 512 mygui->uninit(mygui); |
513 free(mygui); | |
514 mygui = NULL; | |
515 } | |
516 /* Remove tray icon */ | |
517 Shell_NotifyIcon(NIM_DELETE, &nid); | |
518 cfg_write(); | |
519 } | |
520 | |
521 /* this function gets called by mplayer to update the gui */ | |
522 int guiGetEvent(int type, char *arg) | |
523 { | |
524 stream_t *stream = (stream_t *) arg; | |
525 #ifdef USE_DVDREAD | |
526 dvd_priv_t *dvdp = (dvd_priv_t *) arg; | |
527 #endif | |
528 if(!mygui || !mygui->skin) return 0; | |
529 | |
530 if(guiIntfStruct.mpcontext) | |
531 { | |
532 audio_out = mpctx_get_audio_out(guiIntfStruct.mpcontext); | |
533 video_out = mpctx_get_video_out(guiIntfStruct.mpcontext); | |
534 mixer = mpctx_get_mixer(guiIntfStruct.mpcontext); | |
535 playtree = mpctx_get_playtree_iter(guiIntfStruct.mpcontext); | |
536 } | |
537 | |
538 switch (type) | |
539 { | |
540 case guiSetFileFormat: | |
541 guiIntfStruct.FileFormat = (int) arg; | |
542 break; | |
543 case guiSetParameters: | |
544 { | |
545 guiGetEvent(guiSetDefaults, NULL); | |
546 guiIntfStruct.DiskChanged = 0; | |
547 guiIntfStruct.FilenameChanged = 0; | |
548 guiIntfStruct.NewPlay = 0; | |
549 switch(guiIntfStruct.StreamType) | |
550 { | |
551 case STREAMTYPE_PLAYLIST: | |
552 break; | |
553 #ifdef USE_DVDREAD | |
554 case STREAMTYPE_DVD: | |
555 { | |
556 char tmp[512]; | |
557 dvd_title = guiIntfStruct.DVD.current_title; | |
558 dvd_chapter = guiIntfStruct.DVD.current_chapter; | |
559 dvd_angle = guiIntfStruct.DVD.current_angle; | |
560 sprintf(tmp,"dvd://%d", guiIntfStruct.Title); | |
561 guiSetFilename(guiIntfStruct.Filename, tmp); | |
562 break; | |
563 } | |
564 #endif | |
565 } | |
566 if(guiIntfStruct.Filename) | |
567 filename = strdup(guiIntfStruct.Filename); | |
568 else if(filename) | |
569 strcpy(guiIntfStruct.Filename, filename); | |
570 break; | |
571 } | |
572 case guiSetAudioOnly: | |
573 { | |
574 guiIntfStruct.AudioOnly = (int) arg; | |
575 if(IsWindowVisible(mygui->subwindow)) | |
576 ShowWindow(mygui->subwindow, SW_HIDE); | |
577 break; | |
578 } | |
579 case guiSetContext: | |
580 guiIntfStruct.mpcontext = (void *) arg; | |
581 break; | |
582 case guiSetDemuxer: | |
583 guiIntfStruct.demuxer = (void *) arg; | |
584 break; | |
585 case guiSetValues: | |
586 { | |
587 guiIntfStruct.sh_video = arg; | |
588 if (arg) | |
589 { | |
590 sh_video_t *sh = (sh_video_t *)arg; | |
591 codecname = sh->codec->name; | |
592 guiIntfStruct.FPS = sh->fps; | |
593 | |
594 /* we have video, show the subwindow */ | |
595 if(!IsWindowVisible(mygui->subwindow) || IsIconic(mygui->subwindow)) | |
596 ShowWindow(mygui->subwindow, SW_SHOWNORMAL); | |
597 if(WinID == -1) | |
598 update_subwindow(); | |
599 | |
600 } | |
601 break; | |
602 } | |
603 case guiSetShVideo: | |
604 { | |
605 guiIntfStruct.MovieWidth = vo_dwidth; | |
606 guiIntfStruct.MovieHeight = vo_dheight; | |
607 | |
608 sub_aspect = (float)guiIntfStruct.MovieWidth/guiIntfStruct.MovieHeight; | |
609 if(WinID != -1) | |
610 update_subwindow(); | |
611 break; | |
612 } | |
613 case guiSetStream: | |
614 { | |
615 guiIntfStruct.StreamType = stream->type; | |
616 switch(stream->type) | |
617 { | |
618 #ifdef USE_DVDREAD | |
619 case STREAMTYPE_DVD: | |
620 guiGetEvent(guiSetDVD, (char *) stream->priv); | |
621 break; | |
622 #endif | |
623 } | |
624 break; | |
625 } | |
626 #ifdef USE_DVDREAD | |
627 case guiSetDVD: | |
628 { | |
629 guiIntfStruct.DVD.titles = dvdp->vmg_file->tt_srpt->nr_of_srpts; | |
630 guiIntfStruct.DVD.chapters = dvdp->vmg_file->tt_srpt->title[dvd_title].nr_of_ptts; | |
631 guiIntfStruct.DVD.angles = dvdp->vmg_file->tt_srpt->title[dvd_title].nr_of_angles; | |
632 guiIntfStruct.DVD.nr_of_audio_channels = dvdp->nr_of_channels; | |
633 memcpy(guiIntfStruct.DVD.audio_streams, dvdp->audio_streams, sizeof(dvdp->audio_streams)); | |
634 guiIntfStruct.DVD.nr_of_subtitles = dvdp->nr_of_subtitles; | |
635 memcpy(guiIntfStruct.DVD.subtitles, dvdp->subtitles, sizeof(dvdp->subtitles)); | |
636 guiIntfStruct.DVD.current_title = dvd_title + 1; | |
637 guiIntfStruct.DVD.current_chapter = dvd_chapter + 1; | |
638 guiIntfStruct.DVD.current_angle = dvd_angle + 1; | |
639 guiIntfStruct.Track = dvd_title + 1; | |
640 break; | |
641 } | |
642 #endif | |
643 case guiReDraw: | |
644 mygui->updatedisplay(mygui, mygui->mainwindow); | |
645 break; | |
646 case guiSetAfilter: | |
647 guiIntfStruct.afilter = (void *) arg; | |
648 break; | |
649 case guiCEvent: | |
650 { | |
651 guiIntfStruct.Playing = (int) arg; | |
652 switch (guiIntfStruct.Playing) | |
653 { | |
654 case guiSetPlay: | |
655 { | |
656 guiIntfStruct.Playing = 1; | |
657 break; | |
658 } | |
659 case guiSetStop: | |
660 { | |
661 guiIntfStruct.Playing = 0; | |
662 if(movie_aspect >= 0) | |
663 movie_aspect = -1; | |
664 update_subwindow(); | |
665 break; | |
666 } | |
667 case guiSetPause: | |
668 guiIntfStruct.Playing = 2; | |
669 break; | |
670 } | |
671 break; | |
672 } | |
673 case guiIEvent: | |
674 { | |
675 mp_msg(MSGT_GPLAYER,MSGL_V, "cmd: %d\n", (int) arg); | |
676 /* MPlayer asks us to quit */ | |
677 switch((int) arg) | |
678 { | |
679 case MP_CMD_GUI_FULLSCREEN: | |
680 mplFullScreen(); | |
681 break; | |
682 case MP_CMD_QUIT: | |
683 { | |
684 mygui->uninit(mygui); | |
685 free(mygui); | |
686 mygui = NULL; | |
687 exit_player("Done"); | |
688 return 0; | |
689 } | |
690 case MP_CMD_GUI_STOP: | |
691 guiGetEvent(guiCEvent, (void *) guiSetStop); | |
692 break; | |
693 case MP_CMD_GUI_PLAY: | |
694 guiGetEvent(guiCEvent, (void *) guiSetPlay); | |
695 break; | |
696 case MP_CMD_GUI_SKINBROWSER: | |
697 if(fullscreen) guiSetEvent(evFullScreen); | |
698 PostMessage(mygui->mainwindow, WM_COMMAND, (WPARAM) ID_SKINBROWSER, 0); | |
699 break; | |
700 case MP_CMD_GUI_PLAYLIST: | |
701 if(fullscreen) guiSetEvent(evFullScreen); | |
702 PostMessage(mygui->mainwindow, WM_COMMAND, (WPARAM) ID_PLAYLIST, 0); | |
703 break; | |
704 case MP_CMD_GUI_PREFERENCES: | |
705 if(fullscreen) guiSetEvent(evFullScreen); | |
706 PostMessage(mygui->mainwindow, WM_COMMAND, (WPARAM) ID_PREFS, 0); | |
707 break; | |
708 case MP_CMD_GUI_LOADFILE: | |
709 if(fullscreen) guiSetEvent(evFullScreen); | |
710 PostMessage(mygui->mainwindow, WM_COMMAND, (WPARAM) IDFILE_OPEN, 0); | |
711 break; | |
712 case MP_CMD_GUI_LOADSUBTITLE: | |
713 if(fullscreen) guiSetEvent(evFullScreen); | |
714 PostMessage(mygui->mainwindow, WM_COMMAND, (WPARAM) IDSUBTITLE_OPEN, 0); | |
715 break; | |
716 default: | |
717 break; | |
718 } | |
719 break; | |
720 } | |
721 case guiSetFileName: | |
722 if (arg) guiIntfStruct.Filename = (char *) arg; | |
723 break; | |
724 case guiSetDefaults: | |
725 { | |
726 audio_id = -1; | |
727 video_id = -1; | |
728 dvdsub_id = -1; | |
729 vobsub_id = -1; | |
730 stream_cache_size = -1; | |
731 autosync = 0; | |
732 vcd_track = 0; | |
733 dvd_title = 0; | |
734 force_fps = 0; | |
735 if(!mygui->playlist->tracks) return 0; | |
736 filename = guiIntfStruct.Filename = mygui->playlist->tracks[mygui->playlist->current]->filename; | |
737 guiIntfStruct.Track = mygui->playlist->current + 1; | |
738 if(gtkAONorm) greplace(&af_cfg.list, "volnorm", "volnorm"); | |
739 if(gtkAOExtraStereo) | |
740 { | |
741 char *name = malloc(12 + 20 + 1); | |
742 snprintf(name, 12 + 20, "extrastereo=%f", gtkAOExtraStereoMul); | |
743 name[12 + 20] = 0; | |
744 greplace(&af_cfg.list, "extrastereo", name); | |
745 free(name); | |
746 } | |
747 if(gtkCacheOn) stream_cache_size = gtkCacheSize; | |
748 if(gtkAutoSyncOn) autosync = gtkAutoSync; | |
749 break; | |
750 } | |
751 case guiSetVolume: | |
752 { | |
753 if(audio_out) | |
754 { | |
755 /* Some audio_out drivers do not support balance e.g. dsound */ | |
756 /* FIXME this algo is not correct */ | |
757 float l, r; | |
758 mixer_getvolume(mixer, &l, &r); | |
759 guiIntfStruct.Volume = (r > l ? r : l); /* max(r,l) */ | |
760 if (r != l) | |
761 guiIntfStruct.Balance = ((r-l) + 100.0f) * 0.5f; | |
762 else | |
763 guiIntfStruct.Balance = 50.0f; | |
764 } | |
765 break; | |
766 } | |
767 default: | |
768 mp_msg(MSGT_GPLAYER, MSGL_ERR, "[GUI] GOT UNHANDLED EVENT %i\n", type); | |
769 } | |
770 return 0; | |
771 } | |
772 | |
773 /* This function adds/inserts one file into the gui playlist */ | |
774 int import_file_into_gui(char *pathname, int insert) | |
775 { | |
776 char filename[MAX_PATH]; | |
777 char *filepart = filename; | |
778 | |
779 if (strstr(pathname, "://")) | |
780 { | |
781 mp_msg(MSGT_GPLAYER, MSGL_V, "[GUI] Adding special %s\n", pathname); | |
782 mygui->playlist->add_track(mygui->playlist, pathname, NULL, NULL, 0); | |
783 return 1; | |
784 } | |
785 if (GetFullPathName(pathname, MAX_PATH, filename, &filepart)) | |
786 { | |
787 if (!(GetFileAttributes(filename) & FILE_ATTRIBUTE_DIRECTORY)) | |
788 { | |
789 mp_msg(MSGT_GPLAYER, MSGL_V, "[GUI] Adding filename: %s - fullpath: %s\n", filepart, filename); | |
790 mygui->playlist->add_track(mygui->playlist, filename, NULL, filepart, 0); | |
791 return 1; | |
792 } | |
793 else | |
794 mp_msg(MSGT_GPLAYER, MSGL_V, "[GUI] Cannot add %s\n", filename); | |
795 } | |
796 | |
797 return 0; | |
798 } | |
799 | |
800 /* This function imports the initial playtree (based on cmd-line files) into the gui playlist | |
801 by either: | |
802 - overwriting gui pl (enqueue=0) */ | |
803 | |
804 int import_initial_playtree_into_gui(play_tree_t *my_playtree, m_config_t *config, int enqueue) | |
805 { | |
806 play_tree_iter_t *my_pt_iter = NULL; | |
807 int result = 0; | |
808 | |
809 if(!mygui) guiInit(); | |
810 | |
811 if((my_pt_iter = pt_iter_create(&my_playtree, config))) | |
812 { | |
813 while ((filename = pt_iter_get_next_file(my_pt_iter)) != NULL) | |
814 { | |
815 if (parse_filename(filename, my_playtree, config, 0)) | |
816 result = 1; | |
817 else if (import_file_into_gui(filename, 0)) /* Add it to end of list */ | |
818 result = 1; | |
819 } | |
820 } | |
821 mplGotoTheNext = 1; | |
822 | |
823 if (result) | |
824 { | |
825 mygui->playlist->current = 0; | |
826 filename = mygui->playlist->tracks[0]->filename; | |
827 } | |
828 return result; | |
829 } | |
830 | |
831 /* This function imports and inserts an playtree, that is created "on the fly", for example by | |
832 parsing some MOV-Reference-File; or by loading an playlist with "File Open" | |
833 The file which contained the playlist is thereby replaced with it's contents. */ | |
834 | |
835 int import_playtree_playlist_into_gui(play_tree_t *my_playtree, m_config_t *config) | |
836 { | |
837 play_tree_iter_t *my_pt_iter = NULL; | |
838 int result = 0; | |
839 | |
840 if((my_pt_iter = pt_iter_create(&my_playtree, config))) | |
841 { | |
842 while ((filename = pt_iter_get_next_file(my_pt_iter)) != NULL) | |
843 if (import_file_into_gui(filename, 1)) /* insert it into the list and set plCurrent = new item */ | |
844 result = 1; | |
845 pt_iter_destroy(&my_pt_iter); | |
846 } | |
847 filename = NULL; | |
848 return result; | |
849 } | |
850 | |
851 inline void gtkMessageBox(int type, const char *str) | |
852 { | |
853 if (type & GTK_MB_FATAL) | |
854 MessageBox(NULL, str, "MPlayer GUI for Windows Error", MB_OK | MB_ICONERROR); | |
855 | |
856 fprintf(stderr, "[GUI] MessageBox: %s\n", str); | |
857 fflush(stderr); | |
858 } | |
859 | |
860 void guiMessageBox(int level, char *str) | |
861 { | |
862 switch(level) | |
863 { | |
864 case MSGL_FATAL: | |
865 gtkMessageBox(GTK_MB_FATAL | GTK_MB_SIMPLE, str); | |
866 break; | |
867 case MSGL_ERR: | |
868 gtkMessageBox(GTK_MB_ERROR | GTK_MB_SIMPLE, str); | |
869 break; | |
870 } | |
871 } | |
872 | |
873 static int update_subwindow(void) | |
874 { | |
875 int x,y; | |
876 RECT rd; | |
877 WINDOWPOS wp; | |
878 | |
879 if(!sub_window) | |
880 { | |
881 WinID = -1; // so far only directx supports WinID in windows | |
882 | |
883 if(IsWindowVisible(mygui->subwindow) && guiIntfStruct.sh_video && guiIntfStruct.Playing) | |
884 { | |
885 ShowWindow(mygui->subwindow, SW_HIDE); | |
886 return 0; | |
887 } | |
888 else if(guiIntfStruct.AudioOnly) | |
889 return 0; | |
890 else ShowWindow(mygui->subwindow, SW_SHOW); | |
891 } | |
892 | |
893 /* we've come out of fullscreen at the end of file */ | |
894 if((!IsWindowVisible(mygui->subwindow) || IsIconic(mygui->subwindow)) && !guiIntfStruct.AudioOnly) | |
895 ShowWindow(mygui->subwindow, SW_SHOWNORMAL); | |
896 | |
897 /* get our current window coordinates */ | |
898 GetWindowRect(mygui->subwindow, &rd); | |
899 | |
900 x = rd.left; | |
901 y = rd.top; | |
902 | |
903 /* restore sub window position when coming out of fullscreen */ | |
904 if(x <= 0) x = old_rect.left; | |
905 if(y <= 0) y = old_rect.top; | |
906 | |
907 if(!guiIntfStruct.Playing) | |
908 { | |
909 window *desc = NULL; | |
910 int i; | |
911 | |
912 for (i=0; i<mygui->skin->windowcount; i++) | |
913 if(mygui->skin->windows[i]->type == wiSub) | |
914 desc = mygui->skin->windows[i]; | |
915 | |
916 rd.right = rd.left+desc->base->bitmap[0]->width; | |
917 rd.bottom = rd.top+desc->base->bitmap[0]->height; | |
918 sub_aspect = (float)(rd.right-rd.left)/(rd.bottom-rd.top); | |
919 } | |
920 else | |
921 { | |
922 rd.right = rd.left+guiIntfStruct.MovieWidth; | |
923 rd.bottom = rd.top+guiIntfStruct.MovieHeight; | |
924 | |
925 if (movie_aspect > 0.0) // forced aspect from the cmdline | |
926 sub_aspect = movie_aspect; | |
927 } | |
928 | |
929 | |
930 AdjustWindowRect(&rd, WS_OVERLAPPEDWINDOW | WS_SIZEBOX, 0); | |
931 SetWindowPos(mygui->subwindow, 0, x, y, rd.right-rd.left, rd.bottom-rd.top, SWP_NOOWNERZORDER); | |
932 | |
933 wp.hwnd = mygui->subwindow; | |
934 wp.x = rd.left; | |
935 wp.y = rd.top; | |
936 wp.cx = rd.right-rd.left; | |
937 wp.cy = rd.bottom-rd.top; | |
938 wp.flags = SWP_NOOWNERZORDER | SWP_SHOWWINDOW; | |
939 | |
940 /* erase the bitmap image if there's video */ | |
941 if(guiIntfStruct.Playing != 0 && guiIntfStruct.sh_video) | |
942 SendMessage(mygui->subwindow, WM_ERASEBKGND, (WPARAM)GetDC(mygui->subwindow), 0); | |
943 | |
944 /* reset the window aspect */ | |
945 SendMessage(mygui->subwindow, WM_WINDOWPOSCHANGED, 0, (LPARAM)&wp); | |
946 return 0; | |
947 } | |
948 | |
949 void guiEventHandling(void) {} |