xref: /haiku/src/apps/mediaplayer/MainWin.cpp (revision e1d8d7d6b48c655bab349c1fde5200fed917289e)
1 /*
2  * MainWin.cpp - Media Player for the Haiku Operating System
3  *
4  * Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * version 2 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  *
19  */
20 #include "MainWin.h"
21 #include "MainApp.h"
22 
23 #include <View.h>
24 #include <Screen.h>
25 #include <Menu.h>
26 #include <MenuBar.h>
27 #include <MenuItem.h>
28 #include <Application.h>
29 #include <Alert.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <Messenger.h>
33 #include <PopUpMenu.h>
34 #include <String.h>
35 
36 #define NAME "MediaPlayer"
37 
38 enum
39 {
40 	M_DUMMY = 0x100,
41 	M_FILE_OPEN = 0x1000,
42 	M_FILE_NEWPLAYER,
43 	M_FILE_INFO,
44 	M_FILE_ABOUT,
45 	M_FILE_CLOSE,
46 	M_FILE_QUIT,
47 	M_VIEW_50,
48 	M_VIEW_100,
49 	M_VIEW_200,
50 	M_VIEW_300,
51 	M_VIEW_400,
52 	M_SCALE_TO_NATIVE_SIZE,
53 	M_TOGGLE_FULLSCREEN,
54 	M_TOGGLE_NO_BORDER,
55 	M_TOGGLE_NO_MENU,
56 	M_TOGGLE_NO_BORDER_NO_MENU,
57 	M_TOGGLE_ALWAYS_ON_TOP,
58 	M_TOGGLE_KEEP_ASPECT_RATIO,
59 	M_PREFERENCES,
60 	M_VOLUME_UP,
61 	M_VOLUME_DOWN,
62 	M_CHANNEL_NEXT,
63 	M_CHANNEL_PREV,
64 	M_ASPECT_100000_1,
65 	M_ASPECT_106666_1,
66 	M_ASPECT_109091_1,
67 	M_ASPECT_141176_1,
68 	M_ASPECT_720_576,
69 	M_ASPECT_704_576,
70 	M_ASPECT_544_576,
71 	M_SELECT_AUDIO_TRACK		= 0x00000800,
72 	M_SELECT_AUDIO_TRACK_END	= 0x00000fff,
73 	M_SELECT_VIDEO_TRACK		= 0x00010000,
74 	M_SELECT_VIDEO_TRACK_END	= 0x000fffff,
75 };
76 
77 //#define printf(a...)
78 
79 
80 MainWin::MainWin()
81  :	BWindow(BRect(200,200,0,0), NAME, B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS /* | B_WILL_ACCEPT_FIRST_CLICK */)
82  ,  fFilePanel(NULL)
83  ,	fHasFile(false)
84  ,	fHasVideo(false)
85  ,	fController(new Controller)
86  ,	fIsFullscreen(false)
87  ,	fKeepAspectRatio(true)
88  ,	fAlwaysOnTop(false)
89  ,	fNoMenu(false)
90  ,	fNoBorder(false)
91  ,	fSourceWidth(720)
92  ,	fSourceHeight(576)
93  ,	fWidthScale(1.0)
94  ,	fHeightScale(1.0)
95  ,	fMouseDownTracking(false)
96  ,	fFrameResizedTriggeredAutomatically(false)
97  ,	fIgnoreFrameResized(false)
98  ,	fFrameResizedCalled(true)
99 {
100 	BRect rect = Bounds();
101 
102 	// background
103 	fBackground = new BView(rect, "background", B_FOLLOW_ALL, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE);
104 	fBackground->SetViewColor(0,0,0);
105 	AddChild(fBackground);
106 
107 	// menu
108 	fMenuBar = new BMenuBar(fBackground->Bounds(), "menu");
109 	CreateMenu();
110 	fBackground->AddChild(fMenuBar);
111 	fMenuBar->ResizeToPreferred();
112 	fMenuBarHeight = (int)fMenuBar->Frame().Height() + 1;
113 	fMenuBar->SetResizingMode(B_FOLLOW_TOP | B_FOLLOW_LEFT_RIGHT);
114 
115 	// video view
116 	BRect video_rect = BRect(0, fMenuBarHeight, rect.right, rect.bottom);
117 	fVideoView = new VideoView(video_rect, "video display", B_FOLLOW_ALL, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE);
118 	fBackground->AddChild(fVideoView);
119 
120 	fVideoView->MakeFocus();
121 
122 //	SetSizeLimits(fControlViewMinWidth - 1, 32767,
123 //		fMenuBarHeight + fControlViewHeight - 1, fMenuBarHeight + fControlViewHeight - 1);
124 
125 //	SetSizeLimits(320 - 1, 32767, 240 + fMenuBarHeight - 1, 32767);
126 
127 	SetSizeLimits(0, 32767, fMenuBarHeight - 1, 32767);
128 
129 	fController->SetVideoView(fVideoView);
130 
131 	fVideoView->IsOverlaySupported();
132 
133 	VideoFormatChange(fSourceWidth, fSourceHeight, fWidthScale, fHeightScale);
134 
135 	Show();
136 }
137 
138 
139 MainWin::~MainWin()
140 {
141 	printf("MainWin::~MainWin\n");
142 	delete fController;
143 	delete fFilePanel;
144 }
145 
146 
147 void
148 MainWin::OpenFile(const entry_ref &ref)
149 {
150 	printf("MainWin::OpenFile\n");
151 
152 	status_t err = fController->SetTo(ref);
153 	if (err != B_OK) {
154 		char s[300];
155 		sprintf(s, "Can't open file\n\n%s\n\nError 0x%08lx\n(%s)\n",
156 			ref.name, err, strerror(err));
157 		(new BAlert("error", s, "OK"))->Go();
158 		fHasFile = false;
159 		fHasVideo = false;
160 		SetTitle(NAME);
161 	} else {
162 		fHasFile = true;
163 		fHasVideo = fController->VideoTrackCount() != 0;
164 		SetTitle(ref.name);
165 	}
166 	SetupWindow();
167 }
168 
169 void
170 MainWin::SetupWindow()
171 {
172 	printf("MainWin::SetupWindow\n");
173 
174 	// Pupulate the track menus
175 	SetupTrackMenus();
176 	// Enable both if a file was loaded
177 	fAudioMenu->SetEnabled(fHasFile);
178 	fVideoMenu->SetEnabled(fHasFile);
179 	// Select first track (might be "none") in both
180 	fAudioMenu->ItemAt(0)->SetMarked(true);
181 	fVideoMenu->ItemAt(0)->SetMarked(true);
182 
183 }
184 
185 
186 void
187 MainWin::CreateMenu()
188 {
189 	fFileMenu = new BMenu(NAME);
190 	fViewMenu = new BMenu("View");
191 	fSettingsMenu = new BMenu("Settings");
192 	fAudioMenu = new BMenu("Audio Track");
193 	fVideoMenu = new BMenu("Video Track");
194 	fDebugMenu = new BMenu("Debug");
195 
196 	fMenuBar->AddItem(fFileMenu);
197 	fMenuBar->AddItem(fViewMenu);
198 	fMenuBar->AddItem(fSettingsMenu);
199 	fMenuBar->AddItem(fDebugMenu);
200 
201 	fFileMenu->AddItem(new BMenuItem("New Player", new BMessage(M_FILE_NEWPLAYER), 'N', B_COMMAND_KEY));
202 	fFileMenu->AddSeparatorItem();
203 	fFileMenu->AddItem(new BMenuItem("Open File"B_UTF8_ELLIPSIS, new BMessage(M_FILE_OPEN), 'O', B_COMMAND_KEY));
204 	fFileMenu->AddItem(new BMenuItem("File Info"B_UTF8_ELLIPSIS, new BMessage(M_FILE_INFO), 'I', B_COMMAND_KEY));
205 	fFileMenu->AddSeparatorItem();
206 	fFileMenu->AddItem(new BMenuItem("About", new BMessage(M_FILE_ABOUT), 'A', B_COMMAND_KEY));
207 	fFileMenu->AddSeparatorItem();
208 	fFileMenu->AddItem(new BMenuItem("Close", new BMessage(M_FILE_CLOSE), 'W', B_COMMAND_KEY));
209 	fFileMenu->AddItem(new BMenuItem("Quit", new BMessage(M_FILE_QUIT), 'Q', B_COMMAND_KEY));
210 
211 	fViewMenu->AddItem(new BMenuItem("50% scale", new BMessage(M_VIEW_50), '0', B_COMMAND_KEY));
212 	fViewMenu->AddItem(new BMenuItem("100% scale", new BMessage(M_VIEW_100), '1', B_COMMAND_KEY));
213 	fViewMenu->AddItem(new BMenuItem("200% scale", new BMessage(M_VIEW_200), '2', B_COMMAND_KEY));
214 	fViewMenu->AddItem(new BMenuItem("300% scale", new BMessage(M_VIEW_300), '3', B_COMMAND_KEY));
215 	fViewMenu->AddItem(new BMenuItem("400% scale", new BMessage(M_VIEW_400), '4', B_COMMAND_KEY));
216 	fViewMenu->AddItem(new BMenuItem("Full Screen", new BMessage(M_TOGGLE_FULLSCREEN), 'F', B_COMMAND_KEY));
217 	fViewMenu->SetRadioMode(true);
218 	fViewMenu->AddSeparatorItem();
219 	fViewMenu->AddItem(new BMenuItem("Always on Top", new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T', B_COMMAND_KEY));
220 
221 	fSettingsMenu->AddItem(fAudioMenu);
222 	fSettingsMenu->AddItem(fVideoMenu);
223 	fSettingsMenu->AddItem(new BMenuItem("Scale to native size", new BMessage(M_SCALE_TO_NATIVE_SIZE), 'N', B_COMMAND_KEY));
224 	fSettingsMenu->AddItem(new BMenuItem("Full Screen", new BMessage(M_TOGGLE_FULLSCREEN), 'F', B_COMMAND_KEY));
225 	fSettingsMenu->AddSeparatorItem();
226 	fSettingsMenu->AddItem(new BMenuItem("No Menu", new BMessage(M_TOGGLE_NO_MENU), 'M', B_COMMAND_KEY));
227 	fSettingsMenu->AddItem(new BMenuItem("No Border", new BMessage(M_TOGGLE_NO_BORDER), 'B', B_COMMAND_KEY));
228 	fSettingsMenu->AddItem(new BMenuItem("Always on Top", new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T', B_COMMAND_KEY));
229 	fSettingsMenu->AddItem(new BMenuItem("Keep Aspect Ratio", new BMessage(M_TOGGLE_KEEP_ASPECT_RATIO), 'K', B_COMMAND_KEY));
230 	fSettingsMenu->AddSeparatorItem();
231 	fSettingsMenu->AddItem(new BMenuItem("Preferences"B_UTF8_ELLIPSIS, new BMessage(M_PREFERENCES), 'P', B_COMMAND_KEY));
232 
233 	fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.00000:1", new BMessage(M_ASPECT_100000_1)));
234 	fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.06666:1", new BMessage(M_ASPECT_106666_1)));
235 	fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.09091:1", new BMessage(M_ASPECT_109091_1)));
236 	fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.41176:1", new BMessage(M_ASPECT_141176_1)));
237 	fDebugMenu->AddItem(new BMenuItem("force 720 x 576, display aspect 4:3", new BMessage(M_ASPECT_720_576)));
238 	fDebugMenu->AddItem(new BMenuItem("force 704 x 576, display aspect 4:3", new BMessage(M_ASPECT_704_576)));
239 	fDebugMenu->AddItem(new BMenuItem("force 544 x 576, display aspect 4:3", new BMessage(M_ASPECT_544_576)));
240 
241 	fAudioMenu->SetRadioMode(true);
242 	fVideoMenu->SetRadioMode(true);
243 
244 	fSettingsMenu->ItemAt(3)->SetMarked(fIsFullscreen);
245 	fSettingsMenu->ItemAt(5)->SetMarked(fNoMenu);
246 	fSettingsMenu->ItemAt(6)->SetMarked(fNoBorder);
247 	fSettingsMenu->ItemAt(7)->SetMarked(fAlwaysOnTop);
248 	fSettingsMenu->ItemAt(8)->SetMarked(fKeepAspectRatio);
249 	fSettingsMenu->ItemAt(10)->SetEnabled(false); // XXX disable unused preference menu
250 }
251 
252 
253 void
254 MainWin::SetupTrackMenus()
255 {
256 	fAudioMenu->RemoveItems(0, fAudioMenu->CountItems(), true);
257 	fVideoMenu->RemoveItems(0, fVideoMenu->CountItems(), true);
258 
259 	int c, i;
260 	char s[100];
261 
262 	c = fController->AudioTrackCount();
263 	for (i = 0; i < c; i++) {
264 		sprintf(s, "Track %d", i + 1);
265 		fAudioMenu->AddItem(new BMenuItem(s, new BMessage(M_SELECT_AUDIO_TRACK + i)));
266 	}
267 	if (!c)
268 		fAudioMenu->AddItem(new BMenuItem("none", new BMessage(M_DUMMY)));
269 
270 	c = fController->VideoTrackCount();
271 	for (i = 0; i < c; i++) {
272 		sprintf(s, "Track %d", i + 1);
273 		fVideoMenu->AddItem(new BMenuItem(s, new BMessage(M_SELECT_VIDEO_TRACK + i)));
274 	}
275 	if (!c)
276 		fVideoMenu->AddItem(new BMenuItem("none", new BMessage(M_DUMMY)));
277 }
278 
279 
280 bool
281 MainWin::QuitRequested()
282 {
283 	be_app->PostMessage(B_QUIT_REQUESTED);
284 	return true;
285 }
286 
287 
288 void
289 MainWin::MouseDown(BMessage *msg)
290 {
291 	BPoint screen_where;
292 	uint32 buttons = msg->FindInt32("buttons");
293 
294 	// On Zeta, only "screen_where" is relyable, "where" and "be:view_where" seem to be broken
295 	if (B_OK != msg->FindPoint("screen_where", &screen_where)) {
296 		// Workaround for BeOS R5, it has no "screen_where"
297 		fVideoView->GetMouse(&screen_where, &buttons, false);
298 		fVideoView->ConvertToScreen(&screen_where);
299 	}
300 
301 //	msg->PrintToStream();
302 
303 //	if (1 == msg->FindInt32("buttons") && msg->FindInt32("clicks") == 1) {
304 
305 	if (1 == buttons && msg->FindInt32("clicks") % 2 == 0) {
306 		BRect r(screen_where.x - 1, screen_where.y - 1, screen_where.x + 1, screen_where.y + 1);
307 		if (r.Contains(fMouseDownMousePos)) {
308 			PostMessage(M_TOGGLE_FULLSCREEN);
309 			return;
310 		}
311 	}
312 
313 	if (2 == buttons && msg->FindInt32("clicks") % 2 == 0) {
314 		BRect r(screen_where.x - 1, screen_where.y - 1, screen_where.x + 1, screen_where.y + 1);
315 		if (r.Contains(fMouseDownMousePos)) {
316 			PostMessage(M_TOGGLE_NO_BORDER_NO_MENU);
317 			return;
318 		}
319 	}
320 
321 /*
322 		// very broken in Zeta:
323 		fMouseDownMousePos = fVideoView->ConvertToScreen(msg->FindPoint("where"));
324 */
325 	fMouseDownMousePos = screen_where;
326 	fMouseDownWindowPos = Frame().LeftTop();
327 
328 	if (buttons == 1 && !fIsFullscreen) {
329 		// start mouse tracking
330 		fVideoView->SetMouseEventMask(B_POINTER_EVENTS | B_NO_POINTER_HISTORY /* | B_LOCK_WINDOW_FOCUS */);
331 		fMouseDownTracking = true;
332 	}
333 
334 	// pop up a context menu if right mouse button is down for 200 ms
335 
336 	if ((buttons & 2) == 0)
337 		return;
338 	bigtime_t start = system_time();
339 	bigtime_t delay = 200000;
340 	BPoint location;
341 	do {
342 		fVideoView->GetMouse(&location, &buttons);
343 		if ((buttons & 2) == 0)
344 			break;
345 		snooze(1000);
346 	} while (system_time() - start < delay);
347 
348 	if (buttons & 2)
349 		ShowContextMenu(screen_where);
350 }
351 
352 
353 void
354 MainWin::MouseMoved(BMessage *msg)
355 {
356 //	msg->PrintToStream();
357 
358 	BPoint mousePos;
359 	uint32 buttons = msg->FindInt32("buttons");
360 
361 	if (1 == buttons && fMouseDownTracking && !fIsFullscreen) {
362 /*
363 		// very broken in Zeta:
364 		BPoint mousePos = msg->FindPoint("where");
365 		printf("view where: %.0f, %.0f => ", mousePos.x, mousePos.y);
366 		fVideoView->ConvertToScreen(&mousePos);
367 */
368 		// On Zeta, only "screen_where" is relyable, "where" and "be:view_where" seem to be broken
369 		if (B_OK != msg->FindPoint("screen_where", &mousePos)) {
370 			// Workaround for BeOS R5, it has no "screen_where"
371 			fVideoView->GetMouse(&mousePos, &buttons, false);
372 			fVideoView->ConvertToScreen(&mousePos);
373 		}
374 //		printf("screen where: %.0f, %.0f => ", mousePos.x, mousePos.y);
375 		float delta_x = mousePos.x - fMouseDownMousePos.x;
376 		float delta_y = mousePos.y - fMouseDownMousePos.y;
377 		float x = fMouseDownWindowPos.x + delta_x;
378 		float y = fMouseDownWindowPos.y + delta_y;
379 //		printf("move window to %.0f, %.0f\n", x, y);
380 		MoveTo(x, y);
381 	}
382 }
383 
384 
385 void
386 MainWin::MouseUp(BMessage *msg)
387 {
388 //	msg->PrintToStream();
389 	fMouseDownTracking = false;
390 }
391 
392 
393 void
394 MainWin::ShowContextMenu(const BPoint &screen_point)
395 {
396 	printf("Show context menu\n");
397 	BPopUpMenu *menu = new BPopUpMenu("context menu", false, false);
398 	BMenuItem *item;
399 	menu->AddItem(new BMenuItem("Scale to native size", new BMessage(M_SCALE_TO_NATIVE_SIZE), 'N', B_COMMAND_KEY));
400 	menu->AddItem(item = new BMenuItem("Full Screen", new BMessage(M_TOGGLE_FULLSCREEN), 'F', B_COMMAND_KEY));
401 	item->SetMarked(fIsFullscreen);
402 	menu->AddSeparatorItem();
403 	menu->AddItem(item = new BMenuItem("No Menu", new BMessage(M_TOGGLE_NO_MENU), 'M', B_COMMAND_KEY));
404 	item->SetMarked(fNoMenu);
405 	menu->AddItem(item = new BMenuItem("No Border", new BMessage(M_TOGGLE_NO_BORDER), 'B', B_COMMAND_KEY));
406 	item->SetMarked(fNoBorder);
407 	menu->AddItem(item = new BMenuItem("Always on Top", new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T', B_COMMAND_KEY));
408 	item->SetMarked(fAlwaysOnTop);
409 	menu->AddItem(item = new BMenuItem("Keep Aspect Ratio", new BMessage(M_TOGGLE_KEEP_ASPECT_RATIO), 'K', B_COMMAND_KEY));
410 	item->SetMarked(fKeepAspectRatio);
411 	menu->AddSeparatorItem();
412 	menu->AddItem(new BMenuItem("About", new BMessage(M_FILE_ABOUT), 'A', B_COMMAND_KEY));
413 	menu->AddSeparatorItem();
414 	menu->AddItem(new BMenuItem("Quit", new BMessage(M_FILE_QUIT), 'Q', B_COMMAND_KEY));
415 
416 	menu->AddSeparatorItem();
417 	menu->AddItem(new BMenuItem("pixel aspect ratio 1.00000:1", new BMessage(M_ASPECT_100000_1)));
418 	menu->AddItem(new BMenuItem("pixel aspect ratio 1.06666:1", new BMessage(M_ASPECT_106666_1)));
419 	menu->AddItem(new BMenuItem("pixel aspect ratio 1.09091:1", new BMessage(M_ASPECT_109091_1)));
420 	menu->AddItem(new BMenuItem("pixel aspect ratio 1.41176:1", new BMessage(M_ASPECT_141176_1)));
421 	menu->AddItem(new BMenuItem("force 720 x 576, display aspect 4:3", new BMessage(M_ASPECT_720_576)));
422 	menu->AddItem(new BMenuItem("force 704 x 576, display aspect 4:3", new BMessage(M_ASPECT_704_576)));
423 	menu->AddItem(new BMenuItem("force 544 x 576, display aspect 4:3", new BMessage(M_ASPECT_544_576)));
424 
425 	menu->SetTargetForItems(this);
426 	BRect r(screen_point.x - 5, screen_point.y - 5, screen_point.x + 5, screen_point.y + 5);
427 	menu->Go(screen_point, true, true, r, true);
428 }
429 
430 
431 void
432 MainWin::VideoFormatChange(int width, int height, float width_scale, float height_scale)
433 {
434 	// called when video format or aspect ratio changes
435 
436 	printf("VideoFormatChange enter: width %d, height %d, width_scale %.6f, height_scale %.6f\n", width, height, width_scale, height_scale);
437 
438 	if (width_scale < 1.0 && height_scale >= 1.0) {
439 		width_scale  = 1.0 / width_scale;
440 		height_scale = 1.0 / height_scale;
441 		printf("inverting! new values: width_scale %.6f, height_scale %.6f\n", width_scale, height_scale);
442 	}
443 
444  	fSourceWidth  = width;
445  	fSourceHeight = height;
446  	fWidthScale   = width_scale;
447  	fHeightScale  = height_scale;
448 
449 //	ResizeWindow(Bounds().Width() + 1, Bounds().Height() + 1, true);
450 
451 	if (fIsFullscreen) {
452 		AdjustFullscreenRenderer();
453 	} else {
454 		AdjustWindowedRenderer(false);
455 	}
456 
457 	printf("VideoFormatChange leave\n");
458 
459 }
460 
461 
462 void
463 MainWin::Zoom(BPoint rec_position, float rec_width, float rec_height)
464 {
465 	PostMessage(M_TOGGLE_FULLSCREEN);
466 }
467 
468 
469 void
470 MainWin::FrameResized(float new_width, float new_height)
471 {
472 	// called when the window got resized
473 	fFrameResizedCalled = true;
474 
475 	if (new_width != Bounds().Width() || new_height != Bounds().Height()) {
476 		debugger("size wrong\n");
477 	}
478 
479 
480 	printf("FrameResized enter: new_width %.0f, new_height %.0f, bounds width %.0f, bounds height %.0f\n", new_width, new_height, Bounds().Width(), Bounds().Height());
481 
482 	if (fIsFullscreen) {
483 
484 		printf("FrameResized in fullscreen mode\n");
485 
486 		fIgnoreFrameResized = false;
487 		AdjustFullscreenRenderer();
488 
489 	} else {
490 
491 		if (fFrameResizedTriggeredAutomatically) {
492 			fFrameResizedTriggeredAutomatically = false;
493 			printf("FrameResized triggered automatically\n");
494 
495 			fIgnoreFrameResized = false;
496 
497 			AdjustWindowedRenderer(false);
498 		} else {
499 			printf("FrameResized by user in window mode\n");
500 
501 			if (fIgnoreFrameResized) {
502 				fIgnoreFrameResized = false;
503 				printf("FrameResized ignored\n");
504 				return;
505 			}
506 
507 			AdjustWindowedRenderer(true);
508 		}
509 
510 	}
511 
512 	printf("FrameResized leave\n");
513 }
514 
515 
516 
517 void
518 MainWin::UpdateWindowTitle()
519 {
520 	char buf[100];
521 	sprintf(buf, "%s - %d x %d, %.3f:%.3f => %.0f x %.0f", NAME, fSourceWidth, fSourceHeight, fWidthScale, fHeightScale, fVideoView->Bounds().Width() + 1, fVideoView->Bounds().Height() + 1);
522 	SetTitle(buf);
523 }
524 
525 
526 void
527 MainWin::AdjustFullscreenRenderer()
528 {
529 	// n.b. we don't have a menu in fullscreen mode!
530 
531 	if (fKeepAspectRatio) {
532 
533 		// Keep aspect ratio, place render inside
534 		// the background area (may create black bars).
535 		float max_width  = fBackground->Bounds().Width() + 1.0f;
536 		float max_height = fBackground->Bounds().Height() + 1.0f;
537 		float scaled_width  = fSourceWidth * fWidthScale;
538 		float scaled_height = fSourceHeight * fHeightScale;
539 		float factor = min_c(max_width / scaled_width, max_height / scaled_height);
540 		int render_width = int(scaled_width * factor);
541 		int render_height = int(scaled_height * factor);
542 		int x_ofs = (int(max_width) - render_width) / 2;
543 		int y_ofs = (int(max_height) - render_height) / 2;
544 
545 		printf("AdjustFullscreenRenderer: background %.1f x %.1f, src video %d x %d, "
546 			  "scaled video %.3f x %.3f, factor %.3f, render %d x %d, x-ofs %d, y-ofs %d\n",
547 			  max_width, max_height, fSourceWidth, fSourceHeight, scaled_width, scaled_height,
548 			  factor, render_width, render_height, x_ofs, y_ofs);
549 
550 		fVideoView->MoveTo(x_ofs, y_ofs);
551 		fVideoView->ResizeTo(render_width - 1, render_height - 1);
552 
553 	} else {
554 
555 		printf("AdjustFullscreenRenderer: using whole background area\n");
556 
557 		// no need to keep aspect ratio, make
558 		// render cover the whole background
559 		fVideoView->MoveTo(0, 0);
560 		fVideoView->ResizeTo(fBackground->Bounds().Width(), fBackground->Bounds().Height());
561 
562 	}
563 }
564 
565 
566 void
567 MainWin::AdjustWindowedRenderer(bool user_resized)
568 {
569 	printf("AdjustWindowedRenderer enter - user_resized %d\n", user_resized);
570 
571 	// In windowed mode, the renderer always covers the
572 	// whole background, accounting for the menu
573 	fVideoView->MoveTo(0, fNoMenu ? 0 : fMenuBarHeight);
574 	fVideoView->ResizeTo(fBackground->Bounds().Width(), fBackground->Bounds().Height() - (fNoMenu ? 0 : fMenuBarHeight));
575 
576 	if (fKeepAspectRatio) {
577 		// To keep the aspect ratio correct, we
578 		// do resize the window as required
579 
580 		float max_width  = Bounds().Width() + 1.0f;
581 		float max_height = Bounds().Height() + 1.0f - (fNoMenu ? 0 : fMenuBarHeight);
582 		float scaled_width  = fSourceWidth * fWidthScale;
583 		float scaled_height = fSourceHeight * fHeightScale;
584 
585 		if (!user_resized && (scaled_width > max_width || scaled_height > max_height)) {
586 			// A format switch occured, and the window was
587 			// smaller then the video source. As it was not
588 			// initiated by the user resizing the window, we
589 			// enlarge the window to fit the video.
590 			fIgnoreFrameResized = true;
591 			ResizeTo(scaled_width - 1, scaled_height - 1 + (fNoMenu ? 0 : fMenuBarHeight));
592 //			Sync();
593 			return;
594 		}
595 
596 		float display_aspect_ratio = scaled_width / scaled_height;
597 		int new_width  = int(max_width);
598 		int new_height = int(max_width / display_aspect_ratio + 0.5);
599 
600 		printf("AdjustWindowedRenderer: old display %d x %d, src video %d x %d, "
601 			  "scaled video %.3f x %.3f, aspect ratio %.3f, new display %d x %d\n",
602 			  int(max_width), int(max_height), fSourceWidth, fSourceHeight, scaled_width, scaled_height,
603 			  display_aspect_ratio, new_width, new_height);
604 
605 		fIgnoreFrameResized = true;
606 		ResizeTo(new_width - 1, new_height - 1 + (fNoMenu ? 0 : fMenuBarHeight));
607 //		Sync();
608 	}
609 
610 	printf("AdjustWindowedRenderer leave\n");
611 }
612 
613 
614 void
615 MainWin::ToggleNoBorderNoMenu()
616 {
617 	if (!fNoMenu && fNoBorder) {
618 		// if no border, switch of menu, too
619 		PostMessage(M_TOGGLE_NO_MENU);
620 	} else
621 	if (fNoMenu && !fNoBorder) {
622 		// if no menu, switch of border, too
623 		PostMessage(M_TOGGLE_NO_BORDER);
624 	} else {
625 		// both are either on or off, toggle both
626 		PostMessage(M_TOGGLE_NO_MENU);
627 		PostMessage(M_TOGGLE_NO_BORDER);
628 	}
629 }
630 
631 
632 void
633 MainWin::ToggleFullscreen()
634 {
635 	printf("ToggleFullscreen enter\n");
636 
637 	if (!fFrameResizedCalled) {
638 		printf("ToggleFullscreen - ignoring, as FrameResized wasn't called since last switch\n");
639 		return;
640 	}
641 	fFrameResizedCalled = false;
642 
643 
644 	fIsFullscreen = !fIsFullscreen;
645 
646 	if (fIsFullscreen) {
647 		// switch to fullscreen
648 
649 		fSavedFrame = Frame();
650 		printf("saving current frame: %d %d %d %d\n", int(fSavedFrame.left), int(fSavedFrame.top), int(fSavedFrame.right), int(fSavedFrame.bottom));
651 		BScreen screen(this);
652 		BRect rect(screen.Frame());
653 
654 		Hide();
655 		if (!fNoMenu) {
656 			// if we have a menu, remove it now
657 			fMenuBar->Hide();
658 		}
659 		fFrameResizedTriggeredAutomatically = true;
660 		MoveTo(rect.left, rect.top);
661 		ResizeTo(rect.Width(), rect.Height());
662 		Show();
663 
664 	} else {
665 		// switch back from full screen mode
666 
667 		Hide();
668 		// if we need a menu, show it now
669 		if (!fNoMenu) {
670 			fMenuBar->Show();
671 		}
672 		fFrameResizedTriggeredAutomatically = true;
673 		MoveTo(fSavedFrame.left, fSavedFrame.top);
674 		ResizeTo(fSavedFrame.Width(), fSavedFrame.Height());
675 		Show();
676 
677 	}
678 
679 	// FrameResized() will do the required adjustments
680 
681 	printf("ToggleFullscreen leave\n");
682 }
683 
684 
685 void
686 MainWin::ToggleNoMenu()
687 {
688 	printf("ToggleNoMenu enter\n");
689 
690 	fNoMenu = !fNoMenu;
691 
692 	if (fIsFullscreen) {
693 		// fullscreen is always without menu
694 		printf("ToggleNoMenu leave, doing nothing, we are fullscreen\n");
695 		return;
696 	}
697 
698 //	fFrameResizedTriggeredAutomatically = true;
699 	fIgnoreFrameResized = true;
700 
701 	if (fNoMenu) {
702 		fMenuBar->Hide();
703 		fVideoView->MoveTo(0, 0);
704 		fVideoView->ResizeBy(0, fMenuBarHeight);
705 		MoveBy(0, fMenuBarHeight);
706 		ResizeBy(0, - fMenuBarHeight);
707 //		Sync();
708 	} else {
709 		fMenuBar->Show();
710 		fVideoView->MoveTo(0, fMenuBarHeight);
711 		fVideoView->ResizeBy(0, -fMenuBarHeight);
712 		MoveBy(0, - fMenuBarHeight);
713 		ResizeBy(0, fMenuBarHeight);
714 //		Sync();
715 	}
716 
717 	printf("ToggleNoMenu leave\n");
718 }
719 
720 
721 void
722 MainWin::ToggleNoBorder()
723 {
724 	printf("ToggleNoBorder enter\n");
725 	fNoBorder = !fNoBorder;
726 //	SetLook(fNoBorder ? B_NO_BORDER_WINDOW_LOOK : B_TITLED_WINDOW_LOOK);
727 	SetLook(fNoBorder ? B_BORDERED_WINDOW_LOOK : B_TITLED_WINDOW_LOOK);
728 	printf("ToggleNoBorder leave\n");
729 }
730 
731 
732 void
733 MainWin::ToggleAlwaysOnTop()
734 {
735 	printf("ToggleAlwaysOnTop enter\n");
736 	fAlwaysOnTop = !fAlwaysOnTop;
737 	SetFeel(fAlwaysOnTop ? B_FLOATING_ALL_WINDOW_FEEL : B_NORMAL_WINDOW_FEEL);
738 	printf("ToggleAlwaysOnTop leave\n");
739 }
740 
741 
742 void
743 MainWin::ToggleKeepAspectRatio()
744 {
745 	printf("ToggleKeepAspectRatio enter\n");
746 	fKeepAspectRatio = !fKeepAspectRatio;
747 
748 	fFrameResizedTriggeredAutomatically = true;
749 	FrameResized(Bounds().Width(), Bounds().Height());
750 //	if (fIsFullscreen) {
751 //		AdjustFullscreenRenderer();
752 //	} else {
753 //		AdjustWindowedRenderer(false);
754 //	}
755 	printf("ToggleKeepAspectRatio leave\n");
756 }
757 
758 
759 void
760 MainWin::RefsReceived(BMessage *msg)
761 {
762 	printf("MainWin::RefsReceived\n");
763 	// the first file is played in this window,
764 	// if additional files (refs) are included,
765 	// more windows are launched
766 
767 	entry_ref ref;
768 	int n = 0;
769 	for (int i = 0; B_OK == msg->FindRef("refs", i, &ref); i++) {
770 		BEntry entry(&ref, true);
771 		if (!entry.Exists() || !entry.IsFile())
772 			continue;
773 		if (n == 0) {
774 			OpenFile(ref);
775 		} else {
776 			BMessage m(B_REFS_RECEIVED);
777 			m.AddRef("refs", &ref);
778 			gMainApp->NewWindow()->PostMessage(&m);
779 		}
780 		n++;
781 	}
782 }
783 
784 
785 /* Trap keys that are about to be send to background or renderer view.
786  * Return B_OK if it shouldn't be passed to the view
787  */
788 status_t
789 MainWin::KeyDown(BMessage *msg)
790 {
791 //	msg->PrintToStream();
792 
793 	uint32 key		 = msg->FindInt32("key");
794 	uint32 raw_char  = msg->FindInt32("raw_char");
795 	uint32 modifiers = msg->FindInt32("modifiers");
796 
797 	printf("key 0x%lx, raw_char 0x%lx, modifiers 0x%lx\n", key, raw_char, modifiers);
798 
799 	switch (raw_char) {
800 		case B_SPACE:
801 			PostMessage(M_TOGGLE_NO_BORDER_NO_MENU);
802 			return B_OK;
803 
804 		case B_ESCAPE:
805 			if (fIsFullscreen) {
806 				PostMessage(M_TOGGLE_FULLSCREEN);
807 				return B_OK;
808 			} else
809 				break;
810 
811 		case B_ENTER:		// Enter / Return
812 			if (modifiers & B_COMMAND_KEY) {
813 				PostMessage(M_TOGGLE_FULLSCREEN);
814 				return B_OK;
815 			} else
816 				break;
817 
818 		case B_TAB:
819 			if ((modifiers & (B_COMMAND_KEY | B_CONTROL_KEY | B_OPTION_KEY | B_MENU_KEY)) == 0) {
820 				PostMessage(M_TOGGLE_FULLSCREEN);
821 				return B_OK;
822 			} else
823 				break;
824 
825 		case B_UP_ARROW:
826 			if (modifiers & B_COMMAND_KEY) {
827 				PostMessage(M_CHANNEL_NEXT);
828 			} else {
829 				PostMessage(M_VOLUME_UP);
830 			}
831 			return B_OK;
832 
833 		case B_DOWN_ARROW:
834 			if (modifiers & B_COMMAND_KEY) {
835 				PostMessage(M_CHANNEL_PREV);
836 			} else {
837 				PostMessage(M_VOLUME_DOWN);
838 			}
839 			return B_OK;
840 
841 		case B_RIGHT_ARROW:
842 			if (modifiers & B_COMMAND_KEY) {
843 				PostMessage(M_VOLUME_UP);
844 			} else {
845 				PostMessage(M_CHANNEL_NEXT);
846 			}
847 			return B_OK;
848 
849 		case B_LEFT_ARROW:
850 			if (modifiers & B_COMMAND_KEY) {
851 				PostMessage(M_VOLUME_DOWN);
852 			} else {
853 				PostMessage(M_CHANNEL_PREV);
854 			}
855 			return B_OK;
856 
857 		case B_PAGE_UP:
858 			PostMessage(M_CHANNEL_NEXT);
859 			return B_OK;
860 
861 		case B_PAGE_DOWN:
862 			PostMessage(M_CHANNEL_PREV);
863 			return B_OK;
864 	}
865 
866 	switch (key) {
867 		case 0x3a:  		// numeric keypad +
868 			if ((modifiers & B_COMMAND_KEY) == 0) {
869 				printf("if\n");
870 				PostMessage(M_VOLUME_UP);
871 				return B_OK;
872 			} else {
873 				printf("else\n");
874 				break;
875 			}
876 
877 		case 0x25:  		// numeric keypad -
878 			if ((modifiers & B_COMMAND_KEY) == 0) {
879 				PostMessage(M_VOLUME_DOWN);
880 				return B_OK;
881 			} else {
882 				break;
883 			}
884 
885 		case 0x38:			// numeric keypad up arrow
886 			PostMessage(M_VOLUME_UP);
887 			return B_OK;
888 
889 		case 0x59:			// numeric keypad down arrow
890 			PostMessage(M_VOLUME_DOWN);
891 			return B_OK;
892 
893 		case 0x39:			// numeric keypad page up
894 		case 0x4a:			// numeric keypad right arrow
895 			PostMessage(M_CHANNEL_NEXT);
896 			return B_OK;
897 
898 		case 0x5a:			// numeric keypad page down
899 		case 0x48:			// numeric keypad left arrow
900 			PostMessage(M_CHANNEL_PREV);
901 			return B_OK;
902 	}
903 
904 	return B_ERROR;
905 }
906 
907 
908 void
909 MainWin::DispatchMessage(BMessage *msg, BHandler *handler)
910 {
911 	if ((msg->what == B_MOUSE_DOWN) && (handler == fBackground || handler == fVideoView))
912 		MouseDown(msg);
913 	if ((msg->what == B_MOUSE_MOVED) && (handler == fBackground || handler == fVideoView))
914 		MouseMoved(msg);
915 	if ((msg->what == B_MOUSE_UP) && (handler == fBackground || handler == fVideoView))
916 		MouseUp(msg);
917 
918 	if ((msg->what == B_KEY_DOWN) && (handler == fBackground || handler == fVideoView)) {
919 
920 		// special case for PrintScreen key
921 		if (msg->FindInt32("key") == B_PRINT_KEY) {
922 			fVideoView->OverlayScreenshotPrepare();
923 			BWindow::DispatchMessage(msg, handler);
924 			fVideoView->OverlayScreenshotCleanup();
925 			return;
926 		}
927 
928 		// every other key gets dispatched to our KeyDown first
929 		if (KeyDown(msg) == B_OK) {
930 			// it got handled, don't pass it on
931 			return;
932 		}
933 	}
934 
935 	BWindow::DispatchMessage(msg, handler);
936 }
937 
938 
939 void
940 MainWin::MessageReceived(BMessage *msg)
941 {
942 	switch (msg->what) {
943 		case B_REFS_RECEIVED:
944 			printf("MainWin::MessageReceived: B_REFS_RECEIVED\n");
945 			RefsReceived(msg);
946 			break;
947 		case B_SIMPLE_DATA:
948 			printf("MainWin::MessageReceived: B_SIMPLE_DATA\n");
949 			if (msg->HasRef("refs"))
950 				RefsReceived(msg);
951 			break;
952 		case M_FILE_OPEN:
953 		{
954 			if (!fFilePanel) {
955 				fFilePanel = new BFilePanel();
956 				fFilePanel->SetTarget(BMessenger(0, this));
957 				fFilePanel->SetPanelDirectory("/boot/home/");
958 			}
959 			fFilePanel->Show();
960 			break;
961 		}
962 /*
963 
964 		case B_ACQUIRE_OVERLAY_LOCK:
965 			printf("B_ACQUIRE_OVERLAY_LOCK\n");
966 			fVideoView->OverlayLockAcquire();
967 			break;
968 
969 		case B_RELEASE_OVERLAY_LOCK:
970 			printf("B_RELEASE_OVERLAY_LOCK\n");
971 			fVideoView->OverlayLockRelease();
972 			break;
973 
974 		case B_MOUSE_WHEEL_CHANGED:
975 		{
976 			printf("B_MOUSE_WHEEL_CHANGED\n");
977 			float dx = msg->FindFloat("be:wheel_delta_x");
978 			float dy = msg->FindFloat("be:wheel_delta_y");
979 			bool inv = modifiers() & B_COMMAND_KEY;
980 			if (dx > 0.1)	PostMessage(inv ? M_VOLUME_DOWN : M_CHANNEL_PREV);
981 			if (dx < -0.1)	PostMessage(inv ? M_VOLUME_UP : M_CHANNEL_NEXT);
982 			if (dy > 0.1)	PostMessage(inv ? M_CHANNEL_PREV : M_VOLUME_DOWN);
983 			if (dy < -0.1)	PostMessage(inv ? M_CHANNEL_NEXT : M_VOLUME_UP);
984 			break;
985 		}
986 
987 		case M_CHANNEL_NEXT:
988 		{
989 			printf("M_CHANNEL_NEXT\n");
990 			int chan = fController->CurrentChannel();
991 			if (chan != -1) {
992 				chan++;
993 				if (chan < fController->ChannelCount())
994 					SelectChannel(chan);
995 			}
996 			break;
997 		}
998 
999 		case M_CHANNEL_PREV:
1000 		{
1001 			printf("M_CHANNEL_PREV\n");
1002 			int chan = fController->CurrentChannel();
1003 			if (chan != -1) {
1004 				chan--;
1005 				if (chan >= 0)
1006 					SelectChannel(chan);
1007 			}
1008 			break;
1009 		}
1010 
1011 		case M_VOLUME_UP:
1012 			printf("M_VOLUME_UP\n");
1013 			fController->VolumeUp();
1014 			break;
1015 
1016 		case M_VOLUME_DOWN:
1017 			printf("M_VOLUME_DOWN\n");
1018 			fController->VolumeDown();
1019 			break;
1020 
1021 		case M_ASPECT_100000_1:
1022 			VideoFormatChange(fSourceWidth, fSourceHeight, 1.0, 1.0);
1023 			break;
1024 
1025 		case M_ASPECT_106666_1:
1026 			VideoFormatChange(fSourceWidth, fSourceHeight, 1.06666, 1.0);
1027 			break;
1028 
1029 		case M_ASPECT_109091_1:
1030 			VideoFormatChange(fSourceWidth, fSourceHeight, 1.09091, 1.0);
1031 			break;
1032 
1033 		case M_ASPECT_141176_1:
1034 			VideoFormatChange(fSourceWidth, fSourceHeight, 1.41176, 1.0);
1035 			break;
1036 
1037 		case M_ASPECT_720_576:
1038 			VideoFormatChange(720, 576, 1.06666, 1.0);
1039 			break;
1040 
1041 		case M_ASPECT_704_576:
1042 			VideoFormatChange(704, 576, 1.09091, 1.0);
1043 			break;
1044 
1045 		case M_ASPECT_544_576:
1046 			VideoFormatChange(544, 576, 1.41176, 1.0);
1047 			break;
1048 
1049 		case B_REFS_RECEIVED:
1050 			printf("MainWin::MessageReceived: B_REFS_RECEIVED\n");
1051 //			RefsReceived(msg);
1052 			break;
1053 
1054 		case B_SIMPLE_DATA:
1055 			printf("MainWin::MessageReceived: B_SIMPLE_DATA\n");
1056 //			if (msg->HasRef("refs"))
1057 //				RefsReceived(msg);
1058 			break;
1059 
1060 		case M_FILE_ABOUT:
1061 			BAlert *alert;
1062 			alert = new BAlert("about", NAME"\n\n"
1063 			INFO1
1064 			"\n\nCopyright "COPYRIGHT"\n\nVersion "VERSION"\n\nRevision "REVISION"\n\nBuild "BUILD, "Thanks");
1065 			if (fAlwaysOnTop) {
1066 				ToggleAlwaysOnTop();
1067 				alert->Go();
1068 				ToggleAlwaysOnTop();
1069 			} else {
1070 				alert->Go();
1071 			}
1072 			break;
1073 
1074 		case M_FILE_QUIT:
1075 //			be_app->PostMessage(B_QUIT_REQUESTED);
1076 			PostMessage(B_QUIT_REQUESTED);
1077 			break;
1078 
1079 		case M_SCALE_TO_NATIVE_SIZE:
1080 			printf("M_SCALE_TO_NATIVE_SIZE\n");
1081 			if (fIsFullscreen) {
1082 				ToggleFullscreen();
1083 			}
1084 			ResizeTo(int(fSourceWidth * fWidthScale),
1085 					 int(fSourceHeight * fHeightScale) + (fNoMenu ? 0 : fMenuBarHeight));
1086 //			Sync();
1087 			break;
1088 
1089 		case M_TOGGLE_FULLSCREEN:
1090 			ToggleFullscreen();
1091 			fSettingsMenu->ItemAt(1)->SetMarked(fIsFullscreen);
1092 			break;
1093 
1094 		case M_TOGGLE_NO_MENU:
1095 			ToggleNoMenu();
1096 			fSettingsMenu->ItemAt(3)->SetMarked(fNoMenu);
1097 			break;
1098 
1099 		case M_TOGGLE_NO_BORDER:
1100 			ToggleNoBorder();
1101 			fSettingsMenu->ItemAt(4)->SetMarked(fNoBorder);
1102 			break;
1103 
1104 		case M_TOGGLE_ALWAYS_ON_TOP:
1105 			ToggleAlwaysOnTop();
1106 			fSettingsMenu->ItemAt(5)->SetMarked(fAlwaysOnTop);
1107 			break;
1108 
1109 		case M_TOGGLE_KEEP_ASPECT_RATIO:
1110 			ToggleKeepAspectRatio();
1111 			fSettingsMenu->ItemAt(6)->SetMarked(fKeepAspectRatio);
1112 			break;
1113 
1114 		case M_TOGGLE_NO_BORDER_NO_MENU:
1115 			ToggleNoBorderNoMenu();
1116 			break;
1117 
1118 		case M_PREFERENCES:
1119 			break;
1120 
1121 		default:
1122 			if (msg->what >= M_SELECT_CHANNEL && msg->what <= M_SELECT_CHANNEL_END) {
1123 				SelectChannel(msg->what - M_SELECT_CHANNEL);
1124 				break;
1125 			}
1126 			if (msg->what >= M_SELECT_INTERFACE && msg->what <= M_SELECT_INTERFACE_END) {
1127 				SelectInterface(msg->what - M_SELECT_INTERFACE - 1);
1128 				break;
1129 			}
1130 */
1131 	}
1132 }
1133