2 Copyright 2004-2005 Chris Tallon
4 This file is part of VOMP.
6 VOMP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 VOMP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with VOMP; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #define _WIN32_WINNT 0x501
30 #include "vompreswin.h"
34 #include "remotewin.h"
45 void sighandler(int signalReceived);
46 void shutdown(int code);
48 // Global variables --------------------------------------------------------------------------------------------------
61 bool wnd_fullscreen=false;
62 bool wnd_topmost=false;
63 RECT wnd_fs_rect={20,20,768+20,576+20};
64 RECT wnd_fs_rect_client={0,0,768,576};
65 //OSVERSIONINFO windows_ver; //attempt to distigsh windows versions
71 typedef UINT (WINAPI *GETRAWINPUTDATAFNC) (HRAWINPUT,UINT,LPVOID,PUINT,UINT);
72 typedef UINT (WINAPI *REGISTERRAWINPUTDEVICEFNC) (PCRAWINPUTDEVICE,UINT,UINT);
74 GETRAWINPUTDATAFNC dynGetRawInputData=NULL;
75 REGISTERRAWINPUTDEVICEFNC dynRegisterRawInputDevices=NULL;
79 void MILLISLEEP(ULONG a)
86 DWORD WINAPI commandthreadStart(void *arg)
92 void LoadRemoteFunctions() {
93 user32dll=LoadLibrary("user32.dll");
94 if (user32dll!=NULL) {
95 dynGetRawInputData=(GETRAWINPUTDATAFNC)GetProcAddress(user32dll,"GetRawInputData");
96 if (dynGetRawInputData!=NULL) {
97 dynRegisterRawInputDevices=(REGISTERRAWINPUTDEVICEFNC)GetProcAddress(user32dll,"RegisterRawInputDevices");
98 if (dynRegisterRawInputDevices!=NULL) {
105 bool InitApp(HINSTANCE hinst,int cmdshow);
107 HWND win_main;//global window handle
108 HWND win;//global child window handle
111 #define ERROR_MSG(str) MessageBox(win_main,str,"Error!",MB_OK|MB_ICONWARNING)
112 INT WINAPI WinMain( HINSTANCE hinst , HINSTANCE previnst, LPSTR cmdline, int cmdshow)
115 //On Windows we have to init a window, we use DXUT
116 LoadRemoteFunctions();
117 if (!InitApp(hinst,cmdshow)) return false;
118 //Starting Network support
120 int result = WSAStartup(MAKEWORD(2,2),&wsadat);
121 if (result!=NO_ERROR) {
122 ERROR_MSG("Initialising WinSocked: Error at WSAStartup()\n");
126 result= CoInitializeEx(NULL,COINIT_MULTITHREADED );//Initialize COM for DirectShow
128 ERROR_MSG("Initialising COM: Error at Coinitialize()\n");
135 // Init global vars ------------------------------------------------------------------------------------------------
138 remote = new RemoteWin();
141 timers = new Timers();
144 video = new VideoWin();
145 audio = new AudioWin();
146 viewman = new ViewMan();
147 command = new Command();
149 if (!logger || !remote || !mtd || !led || !osd || !video || !audio || !viewman || !command)
151 ERROR_MSG("Could not create objects. Memory problems?\n");
157 // Get logging module started --------------------------------------------------------------------------------------
159 if (!logger->init(Log::DEBUG, "vompwin.log", true))
161 ERROR_MSG("Could not initialise log object. Aborting.\n");
167 logger->log("Core", Log::INFO, "Starting up...");
171 // Init modules ----------------------------------------------------------------------------------------------------
174 success = remote->init("/dev/rawir");
177 logger->log("Core", Log::INFO, "Remote module initialised");
181 logger->log("Core", Log::EMERG, "Remote module failed to initialise");
187 success = led->init(0);
190 logger->log("Core", Log::INFO, "LED module initialised");
194 logger->log("Core", Log::EMERG, "LED module failed to initialise");
200 success = mtd->init("/dev/mtd1");
203 logger->log("Core", Log::INFO, "Mtd module initialised");
207 logger->log("Core", Log::EMERG, "Mtd module failed to initialise");
213 success = timers->init();
216 logger->log("Core", Log::INFO, "Timers module initialised");
220 logger->log("Core", Log::EMERG, "Timers module failed to initialise");
226 UCHAR videoFormat = (UCHAR)mtd->getPALorNTSC();
227 if (videoFormat == Video::PAL) logger->log("Core", Log::INFO, "Read from MTD: PAL 720x576");
228 else if (videoFormat == Video::NTSC) logger->log("Core", Log::INFO, "Read from MTD: NTSC 720x480");
229 else logger->log("Core", Log::INFO, "No help from MTD. Assuming NTSC 720x480");
231 success = video->init(videoFormat);
234 logger->log("Core", Log::INFO, "Video module initialised");
238 logger->log("Core", Log::EMERG, "Video module failed to initialise");
244 success = osd->init((void*)&win);
247 logger->log("Core", Log::INFO, "OSD module initialised");
251 logger->log("Core", Log::EMERG, "OSD module failed to initialise");
257 success = audio->init(Audio::MPEG2_PES);
260 logger->log("Core", Log::INFO, "Audio module initialised");
264 logger->log("Core", Log::EMERG, "Audio module failed to initialise");
270 success = vdr->init(3024);
273 logger->log("Core", Log::INFO, "VDR module initialised");
277 logger->log("Core", Log::EMERG, "VDR module failed to initialise");
283 success = viewman->init();
286 logger->log("Core", Log::INFO, "ViewMan module initialised");
290 logger->log("Core", Log::EMERG, "ViewMan module failed to initialise");
296 success = command->init();
299 logger->log("Core", Log::INFO, "Command module initialised");
303 logger->log("Core", Log::EMERG, "Command module failed to initialise");
309 // Other init ------------------------------------------------------------------------------------------------------
311 logger->log("Core", Log::NOTICE, "Startup successful");
313 // Run main loop ---------------------------------------------------------------------------------------------------
315 // Ok, all major device components and other bits are loaded and ready
316 lastmousemove=timeGetTime();
317 HANDLE commandthread;
318 commandthread= CreateThread(NULL, 0, commandthreadStart, NULL,0,
321 message.message=WM_NULL;
323 while(run && WaitForSingleObject(commandthread,0)==WAIT_TIMEOUT) {
324 if (PeekMessage(&message, NULL, 0,0,PM_REMOVE)!=0) {
325 if (TranslateAccelerator(win_main,acc,&message)==NULL) {
326 TranslateMessage(&message);
327 DispatchMessage(&message);
328 switch (message.message) {
330 run=false; //TODO post exit to command Messages
335 ((OsdWin*)osd)->Render();
338 // When that returns quit ------------------------------------------------------------------------------------------
339 WaitForSingleObject(commandthread,INFINITE);
342 if (user32dll) FreeModule(user32dll);
349 void CalculateWindowSize(RECT * size,ULONG size_mode) {
352 DWORD adjheight,adjwidth;
353 if (!wnd_fullscreen) {
354 DWORD flags =WS_VISIBLE | WS_POPUP | WS_CAPTION | WS_SYSMENU
355 |WS_MINIMIZEBOX | WS_SIZEBOX |WS_MAXIMIZEBOX;
356 RECT wnted={50,50,150,150};
357 AdjustWindowRect(&wnted,flags ,false);
358 adjwidth=-wnted.left+wnted.right-100;
359 adjheight=-wnted.top+wnted.bottom-100;
361 adjwidth=adjheight=0;
363 width=size->right-size->left-adjwidth;
364 height=size->bottom-size->top-adjheight;
365 UCHAR mode=video->getMode();
366 UCHAR aspect=((VideoWin*)video)->getAspectRatio();
367 UCHAR tvsize=((VideoWin*)video)->getPseudoTVsize();
368 double aspectrt=4./3.;
369 if (tvsize==Video::ASPECT16X9) {
370 if (aspect==Video::ASPECT16X9) {
371 aspectrt=4./3.; //looks strange, but it is a 16:9 tv
372 } else if (aspect==Video::ASPECT4X3) {
373 aspectrt=4./3./(16./9.)*(4./3.); //I hope this is correct
375 } else if (tvsize==Video::ASPECT4X3) {
376 if (aspect==Video::ASPECT16X9) {
377 if (mode!=Video::NORMAL) {
382 } else if (aspect==Video::ASPECT4X3) {
386 if (!wnd_fullscreen) {
389 case WMSZ_BOTTOMRIGHT:
392 width=(ULONG)(((double)height)*aspectrt);
393 size->right=size->left+width+adjwidth;
395 case WMSZ_BOTTOMLEFT:
397 width=(ULONG)(((double)height)*aspectrt);
398 size->left=size->right-width-adjwidth;
402 height=(ULONG)(((double)width)/aspectrt);
403 size->bottom=size->top+height+adjheight;
406 MoveWindow(win,0,0,width,height,TRUE);
408 RECT newrect={0,0,width,height};
410 if ((ULONG)(((double)height)*aspectrt)>width) {
411 newlength=(ULONG)(((double)width)/aspectrt);
412 newrect.top+=(height-newlength)/2;
413 newrect.bottom-=(height-newlength);
415 newlength=(ULONG)(((double)height)*aspectrt);
416 newrect.left+=(width-newlength)/2;
417 newrect.right-=(width-newlength);
419 MoveWindow(win,newrect.left,newrect.top,newrect.right,newrect.bottom,TRUE);
424 void AdjustWindow() {
425 if (!wnd_fullscreen) {
427 GetWindowRect(win_main,&winrect);
428 CalculateWindowSize(&winrect,WMSZ_BOTTOM);
429 MoveWindow(win_main,winrect.left,
430 winrect.top,winrect.right-winrect.left,winrect.bottom-winrect.top,true);
433 GetWindowRect(win_main,&winrect);
434 CalculateWindowSize(&winrect,WMSZ_BOTTOM);
439 void ToggleFullscreen() {
440 if (wnd_fullscreen) {
441 wnd_fullscreen=false;
442 SetWindowLong(win_main,GWL_STYLE,WS_VISIBLE | WS_POPUP | WS_CAPTION | WS_SYSMENU
443 |WS_MINIMIZEBOX | WS_SIZEBOX |WS_MAXIMIZEBOX);
444 SetWindowPos(win_main,NULL,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
446 SetWindowPos(win_main,wnd_topmost?HWND_TOPMOST:HWND_TOP,wnd_fs_rect.left,wnd_fs_rect.top,
447 wnd_fs_rect.right-wnd_fs_rect.left,
448 wnd_fs_rect.bottom-wnd_fs_rect.top,
449 SWP_DRAWFRAME | SWP_FRAMECHANGED);
450 MoveWindow(win,wnd_fs_rect_client.left,wnd_fs_rect_client.top,
451 wnd_fs_rect_client.right-wnd_fs_rect_client.left,
452 wnd_fs_rect_client.bottom-wnd_fs_rect_client.top,TRUE);
455 GetWindowRect(win_main,&wnd_fs_rect);
456 GetWindowRect(win,&wnd_fs_rect_client);
457 SetWindowLong(win_main,GWL_STYLE,WS_VISIBLE | WS_POPUP );
458 SetWindowPos(win_main,NULL,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
459 HMONITOR monitor=MonitorFromWindow(win_main,MONITOR_DEFAULTTONEAREST);
461 moninfo.cbSize=sizeof(moninfo);
463 if (!GetMonitorInfo(monitor,&moninfo)) return ;
464 SetWindowPos(win_main,wnd_topmost?HWND_TOPMOST:HWND_TOP,moninfo.rcMonitor.left,moninfo.rcMonitor.top,
465 moninfo.rcMonitor.right,moninfo.rcMonitor.bottom,SWP_FRAMECHANGED);
474 void ToggleTopmost() {
475 wnd_topmost=!wnd_topmost;
476 SetWindowPos(win_main,wnd_topmost?HWND_TOPMOST:HWND_NOTOPMOST,0,0,
477 0,0,SWP_NOMOVE | SWP_NOSIZE);
480 void CursorUpdate() {
482 GetCursorPos(&cursorpos);
484 asswind=WindowFromPoint(cursorpos);
485 if (asswind!=win_main && asswind!=win) {
486 return ; //not our responsibility
488 if ((timeGetTime()-lastmousemove)<4000 || cmenu) {
489 SetCursor(LoadCursor(NULL,IDC_ARROW));
495 bool ContextMenu(HWND wind,int x,int y) {
498 ScreenToClient(wind,&p);
499 GetClientRect(wind,&clientrect);
500 if (!PtInRect(&clientrect,p)) return false;
501 ClientToScreen(wind,&p);
504 menu=LoadMenu(hinstance,MAKEINTRESOURCE(VOMPMENU));
505 popup=GetSubMenu(menu,0);
506 if (wnd_fullscreen) {
507 CheckMenuItem(popup,VOMP_FULL_SCREEN,MF_BYCOMMAND|MF_CHECKED);
509 CheckMenuItem(popup,VOMP_FULL_SCREEN,MF_BYCOMMAND|MF_UNCHECKED);
512 CheckMenuItem(popup,VOMP_TOPMOST,MF_BYCOMMAND|MF_CHECKED);
514 CheckMenuItem(popup,VOMP_TOPMOST,MF_BYCOMMAND|MF_UNCHECKED);
517 TrackPopupMenu(popup,TPM_RIGHTBUTTON|TPM_LEFTALIGN,x,y,0,wind, NULL);
525 LONG FAR PASCAL WindowProc(HWND wind, UINT msg, WPARAM wparam, LPARAM lparam)
531 logger->log("Core", Log::NOTICE, "Window closed, shutting down...");
533 ((RemoteWin*)Remote::getInstance())->SendPower();
537 CalculateWindowSize((RECT*) lparam,wparam);
541 int width = LOWORD(lparam);
542 int height = HIWORD(lparam);
549 if (GetUpdateRect(wind, &r, FALSE)) {
550 BeginPaint(wind, &ps);
551 //Call Painting Mechanism
556 if (((RemoteWin*)remote)->ReceiveButtonVK(wparam)) {
557 return 0L; //We process that Key
559 return DefWindowProc(wind, msg, wparam, lparam);
564 if (((RemoteWin*)remote)->ReceiveButtonAP(GET_APPCOMMAND_LPARAM(lparam))){
565 return TRUE; //yes we process that message
567 return DefWindowProc(wind, msg, wparam, lparam);
576 dynGetRawInputData((HRAWINPUT)lparam,RID_INPUT,NULL,&risize,sizeof(RAWINPUTHEADER));
577 lpit=(LPRAWINPUT)malloc(risize);
578 dynGetRawInputData((HRAWINPUT)lparam,RID_INPUT,lpit,&risize,sizeof(RAWINPUTHEADER));
580 if (lpit->header.dwType==RIM_TYPEHID && lpit->data.hid.dwSizeHid>=2) {
581 DWORD button=lpit->data.hid.bRawData[1] | (lpit->data.hid.bRawData[0]<< 8);
582 if (((RemoteWin*)remote)->ReceiveButtonRI(button)){
584 return 0; //yes we process that message
589 return DefWindowProc(wind, msg, wparam, lparam);
594 if (LOWORD(wparam)==VOMP_FULL_SCREEN) {
598 if (LOWORD(wparam)==VOMP_TOPMOST) {
602 if (((RemoteWin*)remote)->ReceiveButtonAP(LOWORD(wparam))){
603 return 0; //yes we process that message
605 return DefWindowProc(wind, msg, wparam, lparam);
610 if (((HANDLE)wparam)==win) {
614 return DefWindowProc(wind, msg, wparam, lparam);
618 if (wparam==SC_MAXIMIZE) {
621 } else if (wparam==SC_SCREENSAVE || wparam==SC_MONITORPOWER) {
624 return DefWindowProc(wind,msg,wparam, lparam);
628 lastmousemove=timeGetTime();
629 SetCursor(LoadCursor(NULL,IDC_ARROW));
630 SetTimer(wind,VOMP_CURSORUPDATE,4500,NULL);
632 //return DefWindowProc(wind,msg,wparam, lparam);
635 if (wparam==VOMP_CURSORUPDATE) {
639 return DefWindowProc(wind, msg, wparam, lparam);
643 if (!ContextMenu(wind,GET_X_LPARAM(lparam),GET_Y_LPARAM(lparam))) {
644 return DefWindowProc(wind, msg, wparam, lparam);
650 return DefWindowProc(wind, msg, wparam, lparam);
656 bool InitApp(HINSTANCE hinst,int cmdshow) {
660 wcs.style = CS_HREDRAW | CS_VREDRAW;
661 wcs.lpfnWndProc = WindowProc;
663 wcs.cbWndExtra = sizeof(DWORD);
664 wcs.hInstance = hinst;
667 wcs.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
668 wcs.lpszMenuName = NULL;
669 wcs.lpszClassName = "vomp";
670 acc=LoadAccelerators(hinst,MAKEINTRESOURCE(VOMPACCELERATOR));
671 if (!RegisterClass(&wcs))
673 flags =WS_VISIBLE | WS_POPUP | WS_CAPTION | WS_SYSMENU
674 |WS_MINIMIZEBOX | WS_SIZEBOX |WS_MAXIMIZEBOX;
675 RECT wnted={50,50,768+50,576+50};
676 AdjustWindowRect(&wnted,flags ,false);
677 win_main=CreateWindow("vomp","VOMP on Windows",flags, CW_USEDEFAULT,CW_USEDEFAULT,
678 wnted.right-wnted.left,wnted.bottom-wnted.top,NULL,NULL,hinst,NULL);
681 ShowWindow(win_main,SW_SHOWNORMAL);
682 UpdateWindow(win_main);
683 /* in order to handle letterboxing we use a child window */
685 child_wcs.style = CS_HREDRAW | CS_VREDRAW;
686 child_wcs.lpfnWndProc = WindowProc;
687 child_wcs.cbClsExtra = 0;
688 child_wcs.cbWndExtra = sizeof(DWORD);
689 child_wcs.hInstance = hinst;
690 child_wcs.hIcon = NULL;
691 child_wcs.hCursor = NULL;
692 child_wcs.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
693 child_wcs.lpszMenuName = NULL;
694 child_wcs.lpszClassName = "vomp_playback";
695 if (!RegisterClass(&child_wcs))
698 win=CreateWindow("vomp_playback","Vomp Playback Window",WS_VISIBLE | WS_CHILD |WS_CLIPCHILDREN,
699 0,0,768,576,win_main,NULL,hinst,NULL);
702 ShowWindow(win,SW_SHOWNORMAL);
704 if (remotefnc) {//at least windows XP
705 /* We want to support MCE Remote controls*/
706 RAWINPUTDEVICE remote_control_data[4];
707 ZeroMemory(remote_control_data,sizeof(remote_control_data));
708 remote_control_data[0].usUsagePage=0xFFBC;
709 remote_control_data[0].usUsage=0x88;
710 remote_control_data[0].dwFlags=0;
711 remote_control_data[1].usUsagePage=0x0C;
712 remote_control_data[1].usUsage=0x80;
713 remote_control_data[1].dwFlags=0;
714 remote_control_data[2].usUsagePage=0x0C;
715 remote_control_data[2].usUsage=0x01;
716 remote_control_data[2].dwFlags=0;
717 remote_control_data[3].usUsagePage=0x01;
718 remote_control_data[3].usUsage=0x80;
719 remote_control_data[3].dwFlags=0;
720 if (dynRegisterRawInputDevices(remote_control_data,4,sizeof(remote_control_data[0]))!=TRUE) {
721 MessageBox(0,"Registering remote control failed!","Aborting!",0);
733 // -------------------------------------------------------------------------------------------------------------------
735 void shutdown(int code)
741 logger->log("Core", Log::NOTICE, "ViewMan module shut down");
744 if (command) // shut down command here in case views have posted messages
748 logger->log("Core", Log::NOTICE, "Command module shut down");
755 logger->log("Core", Log::NOTICE, "VDR module shut down");
762 logger->log("Core", Log::NOTICE, "OSD module shut down");
769 logger->log("Core", Log::NOTICE, "Audio module shut down");
776 logger->log("Core", Log::NOTICE, "Video module shut down");
783 logger->log("Core", Log::NOTICE, "Timers module shut down");
790 logger->log("Core", Log::NOTICE, "MTD module shut down");
797 logger->log("Core", Log::NOTICE, "LED module shut down");
804 logger->log("Core", Log::NOTICE, "Remote module shut down");
809 logger->log("Core", Log::NOTICE, "Log module shutting down... bye!\n\n");
817 // -------------------------------------------------------------------------------------------------------------------
819 ULLONG ntohll(ULLONG a)
824 ULLONG htonll(ULLONG a)
826 return (((ULLONG)htonl((ULONG)((a<<32)>> 32))<<32)
827 |(ULONG)htonl(((ULONG) (a >> 32))));