]> git.vomp.tv Git - vompclient.git/blob - winmain.cc
Control/main/winmain reorg
[vompclient.git] / winmain.cc
1 /*
2     Copyright 2004-2005 Chris Tallon
3     Copyright 2012 Marten Richter
4
5     This file is part of VOMP.
6
7     VOMP is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11
12     VOMP is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
19 */
20 #ifdef WIN32
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <signal.h>
25 #include <sstream>
26
27 #define _WIN32_WINNT 0x501
28 #include <winsock2.h>
29 #include <windows.h>
30
31 #include "vompreswin.h"
32
33 #include "defines.h"
34 #include "log.h"
35 #include "inputman.h"
36 #include "inputwin.h"
37 #include "ledwin.h"
38 #include "timers.h"
39 #include "videowin.h"
40 #include "audiowin.h"
41 #include "vdr.h"
42 #include "windowsosd.h"
43 #ifdef WINDOWS_LEGACY
44 #include "osdwinpixel.h"
45 #else
46 #include "osdwinvector.h"
47 #endif
48 #include "control.h"
49 #include "messagequeue.h"
50
51 void sighandler(int signalReceived);
52 void shutdown(int code);
53
54 // Global variables --------------------------------------------------------------------------------------------------
55 int debugEnabled = 0;
56 Log* logger;
57 InputMan* remote;
58 InputWin* inputWin;
59 Led* led;
60 Osd* osd;
61 Timers* timers;
62 Control* control;
63 VDR* vdr;
64 Video* video;
65 Audio* audio;
66 std::string commandLineServer;
67
68 bool wnd_fullscreen=false;
69 bool wnd_topmost=false;
70 RECT wnd_fs_rect={20,20,768+20,576+20};
71 RECT wnd_fs_rect_client={0,0,768,576};
72 //OSVERSIONINFO windows_ver; //attempt to distigsh windows versions
73 bool remotefnc=false;
74 HINSTANCE  hinstance;
75 bool cmenu=false;
76
77 HMODULE user32dll;
78 typedef UINT (WINAPI *GETRAWINPUTDATAFNC) (HRAWINPUT,UINT,LPVOID,PUINT,UINT);
79 typedef UINT (WINAPI *REGISTERRAWINPUTDEVICEFNC)  (PCRAWINPUTDEVICE,UINT,UINT);
80
81 GETRAWINPUTDATAFNC dynGetRawInputData=NULL;
82 REGISTERRAWINPUTDEVICEFNC dynRegisterRawInputDevices=NULL;
83
84 DWORD lastmousemove;
85
86 MessageQueue* messageQueue;
87
88
89 void MILLISLEEP(ULONG a)
90 {
91   Sleep(a);
92 }
93
94 int getClockRealTime(struct timespec *tp){
95         SYSTEMTIME systime;
96         __int64  filetime;
97         __int64  test;
98         GetSystemTime(&systime);
99         SystemTimeToFileTime(&systime, (FILETIME*)&filetime);
100         tp->tv_sec = (filetime - WINDOWS_TIME_BASE_OFFSET) / (10 * 1000 * 1000);
101         tp->tv_nsec = ((filetime - WINDOWS_TIME_BASE_OFFSET) % (10 * 1000 * 1000)) * 100;
102         return 0;
103 }
104
105 DWORD WINAPI controlthreadStart(void *arg)
106 {
107    control->run();
108    control->shutdown();
109    return 0;
110 }
111
112 void LoadRemoteFunctions() {
113   user32dll=LoadLibrary("user32.dll");
114   if (user32dll!=NULL) {
115     dynGetRawInputData=(GETRAWINPUTDATAFNC)GetProcAddress(user32dll,"GetRawInputData");
116     if (dynGetRawInputData!=NULL) {
117       dynRegisterRawInputDevices=(REGISTERRAWINPUTDEVICEFNC)GetProcAddress(user32dll,"RegisterRawInputDevices");
118       if (dynRegisterRawInputDevices!=NULL) {
119         remotefnc=true;
120       }
121     }
122   }
123 }
124
125 bool InitApp(HINSTANCE hinst,int cmdshow);
126
127 HWND win_main;//global window handle
128 HWND win;//global child window handle
129 HACCEL acc;
130
131 #define ERROR_MSG(str) MessageBox(win_main,str,"Error!",MB_OK|MB_ICONWARNING)
132 INT WINAPI WinMain( HINSTANCE hinst , HINSTANCE previnst, LPSTR cmdline, int cmdshow)
133 {
134   hinstance=hinst;
135   //On Windows we have to init a window, we use DXUT
136   LoadRemoteFunctions();
137   if (!InitApp(hinst,cmdshow)) return false;
138   //Starting Network support
139   WSADATA wsadat;
140   int result = WSAStartup(MAKEWORD(2,2),&wsadat);
141   if (result!=NO_ERROR) {
142         ERROR_MSG("Initialising WinSocked: Error at WSAStartup()\n");
143     return 0;
144   }
145
146   result= CoInitializeEx(NULL,COINIT_MULTITHREADED );//Initialize COM for DirectShow
147   if (result!=S_OK) {
148     ERROR_MSG("Initialising COM: Error at Coinitialize()\n");
149     return 0;
150   }
151
152
153
154
155   // Init global vars ------------------------------------------------------------------------------------------------
156
157   logger     = new Log();
158   remote     = new InputMan();
159   led        = new LedWin();
160   timers     = new Timers();
161   osd        = new Osd_TYPE();
162   vdr        = new VDR();
163   video      = new VideoWin();
164   audio      = new AudioWin();
165   control    = new Control();
166
167   if (!logger || !remote || !led || !osd || !video || !audio || !control)
168   {
169     ERROR_MSG("Could not create objects. Memory problems?\n");
170     shutdown(1);
171   WSACleanup();
172   return 0;
173   }
174
175   messageQueue = control;
176
177   // Get logging module started --------------------------------------------------------------------------------------
178
179   if (!logger->init(Log::DEBUG, "vompwin.log", true))
180   {
181     ERROR_MSG("Could not initialise log object. Aborting.\n");
182     shutdown(1);
183   WSACleanup();
184   return 0;
185   }
186
187   logger->log("Core", Log::INFO, "Starting up...");
188
189
190
191   // Init modules ----------------------------------------------------------------------------------------------------
192   int success;
193
194   success = remote->init();
195   if (success)
196   {
197     logger->log("Core", Log::INFO, "Remote module initialised");
198   }
199   else
200   {
201     logger->log("Core", Log::EMERG, "Remote module failed to initialise");
202     shutdown(1);
203   WSACleanup();
204   return 0;
205   }
206
207   inputWin = remote->getInputWin();
208
209   success = led->init(0);
210   if (success)
211   {
212     logger->log("Core", Log::INFO, "LED module initialised");
213   }
214   else
215   {
216     logger->log("Core", Log::EMERG, "LED module failed to initialise");
217     shutdown(1);
218   WSACleanup();
219   return 0;
220   }
221
222   success = timers->init();
223   if (success)
224   {
225     logger->log("Core", Log::INFO, "Timers module initialised");
226   }
227   else
228   {
229     logger->log("Core", Log::EMERG, "Timers module failed to initialise");
230     shutdown(1);
231   WSACleanup();
232   return 0;
233   }
234
235   UCHAR videoFormat = Video::PAL; // PALNTSC FIXME.
236
237   success = video->init(videoFormat);
238   if (success)
239   {
240     logger->log("Core", Log::INFO, "Video module initialised");
241   }
242   else
243   {
244     logger->log("Core", Log::EMERG, "Video module failed to initialise");
245     shutdown(1);
246   WSACleanup();
247   return 0;
248   }
249
250   dynamic_cast<WindowsOsd*>(osd)->setWindow(win);
251   success = osd->init();
252   if (success)
253   {
254     logger->log("Core", Log::INFO, "OSD module initialised");
255   }
256   else
257   {
258     logger->log("Core", Log::EMERG, "OSD module failed to initialise");
259     shutdown(1);
260   WSACleanup();
261   return 0;
262   }
263   video->setDefaultAspect();
264
265   success = audio->init(Audio::MPEG2_PES);
266   if (success)
267   {
268     logger->log("Core", Log::INFO, "Audio module initialised");
269   }
270   else
271   {
272     logger->log("Core", Log::EMERG, "Audio module failed to initialise");
273     shutdown(1);
274   WSACleanup();
275   return 0;
276   }
277
278   success = vdr->init();
279   if (success)
280   {
281     logger->log("Core", Log::INFO, "VDR module initialised");
282   }
283   else
284   {
285     logger->log("Core", Log::EMERG, "VDR module failed to initialise");
286     shutdown(1);
287   WSACleanup();
288   return 0;
289   }
290
291   success = control->init();
292   if (success)
293   {
294     logger->log("Core", Log::INFO, "Control module initialised");
295   }
296   else
297   {
298     logger->log("Core", Log::EMERG, "Control module failed to initialise");
299     shutdown(1);
300   WSACleanup();
301   return 0;
302   }
303
304   // Other init ------------------------------------------------------------------------------------------------------
305
306   logger->log("Core", Log::NOTICE, "Startup successful");
307
308   // Run main loop ---------------------------------------------------------------------------------------------------
309
310   // Ok, all major device components and other bits are loaded and ready
311   lastmousemove=timeGetTime();
312
313   HANDLE controlthread;
314  controlthread= CreateThread(NULL, 0, controlthreadStart, NULL,0,
315     NULL);
316   MSG message;
317   message.message=WM_NULL;
318   bool run=true;
319   while(run && WaitForSingleObject(controlthread,0)==WAIT_TIMEOUT) {
320     if (PeekMessage(&message, NULL, 0,0,PM_REMOVE)!=0) {
321       if (TranslateAccelerator(win_main,acc,&message)==NULL) {
322         TranslateMessage(&message);
323         DispatchMessage(&message);
324         switch (message.message) {
325         case WM_QUIT:
326           run=false; //TODO post exit to control Messages
327         };
328       }
329     } else {
330       //Render, moved to OSD !
331                 Sleep(20);
332       //((OsdWin*)osd)->Render();
333     }
334   }
335   // When that returns quit ------------------------------------------------------------------------------------------
336   WaitForSingleObject(controlthread,INFINITE);
337   shutdown(0);
338   WSACleanup();
339   if (user32dll) FreeModule(user32dll);
340   return 0;
341
342 }
343
344 bool TranslateMousePosition(POINT *pos) {
345
346   RECT clientrect;
347   ScreenToClient(win,pos);
348   GetClientRect(win,&clientrect);
349   if (!PtInRect(&clientrect,*pos)) return false;//Don't pass it further
350   pos->x=((double)pos->x)/((double) (clientrect.right-clientrect.left))
351     *((double)Video::getInstance()->getScreenWidth());
352   pos->y=((double)pos->y)/((double) (clientrect.bottom-clientrect.top))
353     *((double)Video::getInstance()->getScreenHeight());
354   return true;
355
356 }
357
358
359
360 void CalculateWindowSize(RECT * size,ULONG size_mode) {
361
362   DWORD width, height;
363   DWORD adjheight,adjwidth;
364   if (!wnd_fullscreen) {
365     DWORD flags =WS_VISIBLE | WS_POPUP | WS_CAPTION | WS_SYSMENU
366                |WS_MINIMIZEBOX | WS_SIZEBOX |WS_MAXIMIZEBOX;
367     RECT wnted={50,50,150,150};
368     AdjustWindowRect(&wnted,flags ,false);
369     adjwidth=-wnted.left+wnted.right-100;
370     adjheight=-wnted.top+wnted.bottom-100;
371   } else {
372     adjwidth=adjheight=0;
373   }
374   width=size->right-size->left-adjwidth;
375   height=size->bottom-size->top-adjheight;
376   UCHAR mode=Video::PAL;
377   UCHAR aspect=Video::ASPECT4X3;
378   UCHAR tvsize=Video::ASPECT4X3;
379   if (video) {
380       mode=video->getMode();
381       aspect=((VideoWin*)video)->getAspectRatio();
382       tvsize=((VideoWin*)video)->getPseudoTVsize();
383   }
384
385   double aspectrt=4./3.;
386   if (tvsize==Video::ASPECT16X9) {
387     if (aspect==Video::ASPECT16X9) {
388       aspectrt=4./3.; //looks strange, but it is a 16:9 tv
389     } else if (aspect==Video::ASPECT4X3) {
390       aspectrt=4./3./(16./9.)*(4./3.); //I hope this is correct
391     }
392   } else if (tvsize==Video::ASPECT4X3) {
393     if (aspect==Video::ASPECT16X9) {
394       if (mode!=Video::NORMAL) {
395         aspectrt=16./9.;
396       } else {
397         aspectrt=4./3.;
398       }
399     } else if (aspect==Video::ASPECT4X3) {
400       aspectrt=4./3.;
401     }
402   }
403   if (!wnd_fullscreen) {
404     switch (size_mode) {
405     case WMSZ_BOTTOM:
406     case WMSZ_BOTTOMRIGHT:
407     case WMSZ_TOP:
408     case WMSZ_TOPRIGHT:
409     width=(ULONG)(((double)height)*aspectrt);
410     size->right=size->left+width+adjwidth;
411     break;
412     case WMSZ_BOTTOMLEFT:
413     case WMSZ_TOPLEFT:
414     width=(ULONG)(((double)height)*aspectrt);
415     size->left=size->right-width-adjwidth;
416     break;
417     case WMSZ_LEFT:
418     case WMSZ_RIGHT:
419     height=(ULONG)(((double)width)/aspectrt);
420     size->bottom=size->top+height+adjheight;
421     break;
422     }
423     MoveWindow(win,0,0,width,height,TRUE);
424   } else {
425     RECT newrect={0,0,width,height};
426     DWORD newlength;
427     if ((ULONG)(((double)height)*aspectrt)>width) {
428       newlength=(ULONG)(((double)width)/aspectrt);
429       newrect.top+=(height-newlength)/2;
430       newrect.bottom-=(height-newlength);
431     } else {
432       newlength=(ULONG)(((double)height)*aspectrt);
433       newrect.left+=(width-newlength)/2;
434       newrect.right-=(width-newlength);
435     }
436     MoveWindow(win,newrect.left,newrect.top,newrect.right,newrect.bottom,TRUE);
437   }
438
439 }
440
441 void AdjustWindow() {
442   if (!wnd_fullscreen) {
443     RECT winrect;
444     GetWindowRect(win_main,&winrect);
445     CalculateWindowSize(&winrect,WMSZ_BOTTOM);
446     MoveWindow(win_main,winrect.left,
447       winrect.top,winrect.right-winrect.left,winrect.bottom-winrect.top,true);
448   } else {
449     RECT winrect;
450     GetWindowRect(win_main,&winrect);
451     CalculateWindowSize(&winrect,WMSZ_BOTTOM);
452
453   }
454 }
455
456 void ToggleFullscreen() {
457   if (wnd_fullscreen) {
458     wnd_fullscreen=false;
459     SetWindowLong(win_main,GWL_STYLE,WS_VISIBLE | WS_POPUP | WS_CAPTION | WS_SYSMENU
460                  |WS_MINIMIZEBOX | WS_SIZEBOX |WS_MAXIMIZEBOX);
461     SetWindowPos(win_main,NULL,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
462
463     SetWindowPos(win_main,wnd_topmost?HWND_TOPMOST:HWND_TOP,wnd_fs_rect.left,wnd_fs_rect.top,
464               wnd_fs_rect.right-wnd_fs_rect.left,
465               wnd_fs_rect.bottom-wnd_fs_rect.top,
466               SWP_DRAWFRAME | SWP_FRAMECHANGED);
467     MoveWindow(win,wnd_fs_rect_client.left,wnd_fs_rect_client.top,
468               wnd_fs_rect_client.right-wnd_fs_rect_client.left,
469               wnd_fs_rect_client.bottom-wnd_fs_rect_client.top,TRUE);
470     AdjustWindow();
471   } else {
472     GetWindowRect(win_main,&wnd_fs_rect);
473     GetWindowRect(win,&wnd_fs_rect_client);
474     SetWindowLong(win_main,GWL_STYLE,WS_VISIBLE | WS_POPUP );
475     SetWindowPos(win_main,NULL,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
476     HMONITOR monitor=MonitorFromWindow(win_main,MONITOR_DEFAULTTONEAREST);
477     MONITORINFO moninfo;
478     moninfo.cbSize=sizeof(moninfo);
479     wnd_fullscreen=true;
480     if (!GetMonitorInfo(monitor,&moninfo)) return ;
481     SetWindowPos(win_main,wnd_topmost?HWND_TOPMOST:HWND_TOP,moninfo.rcMonitor.left,moninfo.rcMonitor.top,
482       moninfo.rcMonitor.right,moninfo.rcMonitor.bottom,SWP_FRAMECHANGED);
483
484     AdjustWindow();
485
486   }
487
488
489 }
490
491 void ToggleTopmost() {
492   wnd_topmost=!wnd_topmost;
493   SetWindowPos(win_main,wnd_topmost?HWND_TOPMOST:HWND_NOTOPMOST,0,0,
494       0,0,SWP_NOMOVE | SWP_NOSIZE);
495 }
496
497 void CursorUpdate() {
498   POINT cursorpos;
499   GetCursorPos(&cursorpos);
500   HWND asswind;
501   asswind=WindowFromPoint(cursorpos);
502   if (asswind!=win_main && asswind!=win) {
503     return ; //not our responsibility
504   }
505   if ((timeGetTime()-lastmousemove)<4000 || cmenu) {
506     SetCursor(LoadCursor(NULL,IDC_ARROW));
507   } else {
508     SetCursor(NULL);
509   }
510 }
511
512 bool ContextMenu(HWND wind,int x,int y) {
513   POINT p={x,y};
514   RECT clientrect;
515   ScreenToClient(wind,&p);
516   GetClientRect(wind,&clientrect);
517   if (!PtInRect(&clientrect,p)) return false;
518   ClientToScreen(wind,&p);
519   HMENU menu;
520   HMENU popup;
521   menu=LoadMenu(hinstance,MAKEINTRESOURCE(VOMPMENU));
522   popup=GetSubMenu(menu,0);
523   if (wnd_fullscreen) {
524     CheckMenuItem(popup,VOMP_FULL_SCREEN,MF_BYCOMMAND|MF_CHECKED);
525   } else {
526     CheckMenuItem(popup,VOMP_FULL_SCREEN,MF_BYCOMMAND|MF_UNCHECKED);
527   }
528   if (wnd_topmost) {
529     CheckMenuItem(popup,VOMP_TOPMOST,MF_BYCOMMAND|MF_CHECKED);
530   } else {
531     CheckMenuItem(popup,VOMP_TOPMOST,MF_BYCOMMAND|MF_UNCHECKED);
532   }
533   cmenu=true;
534   TrackPopupMenu(popup,TPM_RIGHTBUTTON|TPM_LEFTALIGN,x,y,0,wind, NULL);
535   cmenu=false;
536
537
538   DestroyMenu(menu);
539   return true;
540 }
541
542 LONG FAR PASCAL WindowProc(HWND wind, UINT msg, WPARAM wparam, LPARAM lparam)
543 {
544
545    switch (msg) {
546    case WM_DESTROY: {
547      //TODO: call control
548      logger->log("Core", Log::NOTICE, "Window closed, shutting down...");
549      control->stop();
550      PostQuitMessage(0);
551   }break;
552    case WM_SIZING: {
553      CalculateWindowSize((RECT*) lparam,wparam);
554      return TRUE;
555            }break;
556   case WM_SIZE: {
557         int width = LOWORD(lparam);
558         int height = HIWORD(lparam);
559          //Call device
560         if (wparam == SIZE_MAXIMIZED) {
561             ToggleFullscreen();
562             return 0;
563         } /*else if (wparam == SIZE_MINIMIZED) {
564             ToggleFullscreen();
565             return 0;
566         }*/
567         //AdjustWindow();
568         }
569         break;
570    case WM_PAINT:
571         RECT r;
572         PAINTSTRUCT ps;
573         if (GetUpdateRect(wind, &r, FALSE)) {
574             BeginPaint(wind, &ps);
575             //Call Painting Mechanism
576             EndPaint(wind, &ps);
577         }
578         break;
579    case WM_KEYDOWN:
580      if (inputWin->ReceiveButtonVK(wparam)) {
581        return 0L; //We process that Key
582      } else {
583        return DefWindowProc(wind, msg, wparam, lparam);
584      }
585
586      break;
587      case WM_CHAR:
588      if (inputWin->ReceiveButtonCH(wparam)) {
589        return 0L; //We process that Key
590      } else {
591        return DefWindowProc(wind, msg, wparam, lparam);
592      }
593
594      break;
595   case WM_APPCOMMAND:
596     if (inputWin->ReceiveButtonAP(GET_APPCOMMAND_LPARAM(lparam))){
597       return TRUE; //yes we process that message
598     } else {
599       return DefWindowProc(wind, msg, wparam, lparam);
600     }
601
602     break;
603   case WM_INPUT:
604     if (remotefnc ) {
605       //only on XP!
606        LPRAWINPUT lpit;
607        UINT risize;
608        dynGetRawInputData((HRAWINPUT)lparam,RID_INPUT,NULL,&risize,sizeof(RAWINPUTHEADER));
609        lpit=(LPRAWINPUT)malloc(risize);
610        dynGetRawInputData((HRAWINPUT)lparam,RID_INPUT,lpit,&risize,sizeof(RAWINPUTHEADER));
611
612       if (lpit->header.dwType==RIM_TYPEHID && lpit->data.hid.dwSizeHid>=2) {
613         DWORD button=lpit->data.hid.bRawData[1] | (lpit->data.hid.bRawData[0]<< 8);
614         if (inputWin->ReceiveButtonRI(button)){
615           free(lpit);
616           return 0; //yes we process that message
617         }
618       }
619       free(lpit);
620     }
621     return DefWindowProc(wind, msg, wparam, lparam);
622
623
624     break;
625   case WM_COMMAND:
626     if (LOWORD(wparam)==VOMP_FULL_SCREEN) {
627       ToggleFullscreen();
628       return 0;
629     }
630     if (LOWORD(wparam)==VOMP_TOPMOST) {
631       ToggleTopmost();
632       return 0;
633     }
634     if (inputWin->ReceiveButtonAP(LOWORD(wparam))){
635       return 0; //yes we process that message
636     } else {
637       return DefWindowProc(wind, msg, wparam, lparam);
638     }
639
640     break;
641   case WM_SETCURSOR:
642     if (((HANDLE)wparam)==win) {
643       CursorUpdate();
644       return 1;
645     } else {
646       return DefWindowProc(wind, msg, wparam, lparam);
647     }
648     break;
649   case WM_SYSCOMMAND:
650     if (wparam==SC_MAXIMIZE) {
651       ToggleFullscreen();
652       return 0;
653     } else if (wparam==SC_SCREENSAVE || wparam==SC_MONITORPOWER) {
654       return 0;
655     } else {
656       return DefWindowProc(wind,msg,wparam, lparam);
657     }
658     break;
659   case WM_MOUSEMOVE: {
660
661     lastmousemove=timeGetTime();
662     SetCursor(LoadCursor(NULL,IDC_ARROW));
663     SetTimer(wind,VOMP_CURSORUPDATE,4500,NULL);
664     POINT mpos={GET_X_LPARAM(lparam),GET_Y_LPARAM(lparam)};
665     ClientToScreen(wind,&mpos);
666     if (TranslateMousePosition(&mpos)) {
667       Message *mousemes=new Message();
668       mousemes->message=Message::MOUSE_MOVE;
669       mousemes->from=NULL;
670       mousemes->p_to = Message::MOUSE_RECEIVER;
671       mousemes->parameter=(mpos.x & 0xFFFF)<< 16| (mpos.y & 0xFFFF);
672       mousemes->tag=0;
673       messageQueue->postMessage(mousemes);
674     }
675
676     return 0;
677     //return DefWindowProc(wind,msg,wparam, lparam);
678              }
679     break;
680   case WM_TIMER:
681     if (wparam==VOMP_CURSORUPDATE) {
682       CursorUpdate();
683       return 0;
684     }
685     return DefWindowProc(wind, msg, wparam, lparam);
686
687     break;
688   case WM_CONTEXTMENU:
689     if (!ContextMenu(wind,GET_X_LPARAM(lparam),GET_Y_LPARAM(lparam))) {
690       return DefWindowProc(wind, msg, wparam, lparam);
691     } else {
692       return 0;
693     }
694     break;
695   case WM_LBUTTONDOWN:{
696     POINT mpos={GET_X_LPARAM(lparam),GET_Y_LPARAM(lparam)};
697     ClientToScreen(wind,&mpos);
698     if (TranslateMousePosition(&mpos)) {
699       Message *mousemes=new Message();
700       mousemes->message=Message::MOUSE_LBDOWN;
701       mousemes->from=NULL;
702       mousemes->p_to = Message::MOUSE_RECEIVER;
703       mousemes->parameter=(mpos.x & 0xFFFF)<< 16| (mpos.y & 0xFFFF);
704       mousemes->tag=0;
705       messageQueue->postMessage(mousemes);
706     }
707             }break;
708   case WM_MOUSEWHEEL:{
709         POINT mpos = { GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) };
710         ClientToScreen(wind, &mpos);
711         if (TranslateMousePosition(&mpos)) {
712                 Message *mousemes = new Message();
713                 mousemes->message = Message::MOUSE_SCROLL;
714                 mousemes->from = NULL;
715         mousemes->p_to = Message::MOUSE_RECEIVER;
716                 mousemes->parameter = (0 & 0xFFFF) << 16 | (GET_WHEEL_DELTA_WPARAM(wparam)  &0xFFFF);
717                 mousemes->tag = (mpos.x & 0xFFFF) << 16 | (mpos.y & 0xFFFF);
718                 messageQueue->postMessage(mousemes);
719         }
720
721   } break;
722     default:
723         return DefWindowProc(wind, msg, wparam, lparam);
724     }
725     return 0L;
726 }
727
728
729 bool InitApp(HINSTANCE hinst,int cmdshow) {
730   /* main window */
731   WNDCLASS wcs;
732   DWORD flags;
733   wcs.style = CS_HREDRAW | CS_VREDRAW;
734     wcs.lpfnWndProc = WindowProc;
735     wcs.cbClsExtra = 0;
736     wcs.cbWndExtra = sizeof(DWORD);
737     wcs.hInstance = hinst;
738     wcs.hIcon = NULL;
739     wcs.hCursor = NULL;
740     wcs.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
741     wcs.lpszMenuName = NULL;
742     wcs.lpszClassName = "vomp";
743   acc=LoadAccelerators(hinst,MAKEINTRESOURCE(VOMPACCELERATOR));
744   if (!RegisterClass(&wcs))
745         return false;
746   flags =WS_VISIBLE | WS_POPUP | WS_CAPTION | WS_SYSMENU
747                  |WS_MINIMIZEBOX | WS_SIZEBOX |WS_MAXIMIZEBOX;
748   RECT wnted={50,50,768+50,576+50};
749   AdjustWindowRect(&wnted,flags ,false);
750   win_main=CreateWindow("vomp","VOMP on Windows",flags, CW_USEDEFAULT,CW_USEDEFAULT,
751     wnted.right-wnted.left,wnted.bottom-wnted.top,NULL,NULL,hinst,NULL);
752   if (!win_main)
753         return FALSE;
754   ShowWindow(win_main,SW_SHOWNORMAL);
755     UpdateWindow(win_main);
756   /* in order to handle letterboxing we use a child window */
757   WNDCLASS child_wcs;
758   child_wcs.style = CS_HREDRAW | CS_VREDRAW;
759     child_wcs.lpfnWndProc = WindowProc;
760     child_wcs.cbClsExtra = 0;
761     child_wcs.cbWndExtra = sizeof(DWORD);
762     child_wcs.hInstance = hinst;
763     child_wcs.hIcon = NULL;
764     child_wcs.hCursor = NULL;
765     child_wcs.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
766     child_wcs.lpszMenuName = NULL;
767     child_wcs.lpszClassName = "vomp_playback";
768   if (!RegisterClass(&child_wcs))
769         return false;
770
771   win=CreateWindow("vomp_playback","Vomp Playback Window",WS_VISIBLE | WS_CHILD |WS_CLIPCHILDREN,
772     0,0,768,576,win_main,NULL,hinst,NULL);
773   if (!win)
774     return FALSE;
775   ShowWindow(win,SW_SHOWNORMAL);
776   UpdateWindow(win);
777   if (remotefnc) {//at least windows XP
778     /* We want to support MCE Remote controls*/
779     RAWINPUTDEVICE remote_control_data[4];
780     ZeroMemory(remote_control_data,sizeof(remote_control_data));
781     remote_control_data[0].usUsagePage=0xFFBC;
782     remote_control_data[0].usUsage=0x88;
783     remote_control_data[0].dwFlags=0;
784     remote_control_data[1].usUsagePage=0x0C;
785     remote_control_data[1].usUsage=0x80;
786     remote_control_data[1].dwFlags=0;
787     remote_control_data[2].usUsagePage=0x0C;
788     remote_control_data[2].usUsage=0x01;
789     remote_control_data[2].dwFlags=0;
790     remote_control_data[3].usUsagePage=0x01;
791     remote_control_data[3].usUsage=0x80;
792     remote_control_data[3].dwFlags=0;
793     if (dynRegisterRawInputDevices(remote_control_data,4,sizeof(remote_control_data[0]))!=TRUE) {
794       MessageBox(0,"Registering remote control failed!","Aborting!",0);
795       return FALSE;
796     }
797
798   }
799   return TRUE;
800 }
801
802
803
804
805
806 // -------------------------------------------------------------------------------------------------------------------
807
808 void shutdown(int code)
809 {
810   if (control) // shut down control here in case views have posted messages
811   {
812     control->shutdown();
813     delete control;
814     logger->log("Core", Log::NOTICE, "Control module shut down");
815   }
816
817   if (vdr)
818   {
819     vdr->shutdown();
820     delete vdr;
821     logger->log("Core", Log::NOTICE, "VDR module shut down");
822   }
823
824   if (osd)
825   {
826     osd->shutdown();
827     delete osd;
828     logger->log("Core", Log::NOTICE, "OSD module shut down");
829   }
830
831   if (audio)
832   {
833     audio->shutdown();
834     delete audio;
835     logger->log("Core", Log::NOTICE, "Audio module shut down");
836   }
837
838   if (video)
839   {
840     video->shutdown();
841     delete video;
842     logger->log("Core", Log::NOTICE, "Video module shut down");
843   }
844
845   if (timers)
846   {
847     timers->shutdown();
848     delete timers;
849     logger->log("Core", Log::NOTICE, "Timers module shut down");
850   }
851
852   if (led)
853   {
854     led->shutdown();
855     delete led;
856     logger->log("Core", Log::NOTICE, "LED module shut down");
857   }
858
859   if (remote)
860   {
861     remote->shutdown();
862     delete remote;
863     logger->log("Core", Log::NOTICE, "Remote module shut down");
864   }
865
866   if (logger)
867   {
868     logger->log("Core", Log::NOTICE, "Log module shutting down... bye!\n\n");
869     logger->shutdown();
870     delete logger;
871   }
872
873   ExitProcess(0);
874 }
875
876 // -------------------------------------------------------------------------------------------------------------------
877
878 ULLONG htonll(ULLONG a)
879 {
880   return (((ULLONG)htonl((ULONG)((a<<32)>> 32))<<32)
881     |(ULONG)htonl(((ULONG) (a >> 32))));
882 }
883
884 ULLONG ntohll(ULLONG a)
885 {
886   return htonll(a);
887 }
888
889 std::string tp2str(const std::chrono::time_point<std::chrono::system_clock>& tp)
890 {
891   auto tms = std::chrono::time_point_cast<std::chrono::milliseconds>(tp);
892   std::chrono::milliseconds e = tms.time_since_epoch();
893   long long c = e.count();
894   time_t tt = c / 1000;
895   int ttm = c % 1000;
896   auto stm = std::localtime(&tt);
897   std::stringstream ss;
898   ss << std::put_time(stm, "%T") << "." << std::setfill('0') << std::setw(3) << ttm;
899   return ss.str();
900 }
901
902 const std::string& getCommandLineServer()
903 {
904   return commandLineServer;
905 }
906
907
908 #endif
909