Systray.cpp

00001 /* 
00002  *      Copyright (C) 2003-2005 Gabest
00003  *      http://www.gabest.org
00004  *
00005  *  This Program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2, or (at your option)
00008  *  any later version.
00009  *   
00010  *  This Program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013  *  GNU General Public License for more details.
00014  *   
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with GNU Make; see the file COPYING.  If not, write to
00017  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
00018  *  http://www.gnu.org/copyleft/gpl.html
00019  *
00020  */
00021 
00022 #include "stdafx.h"
00023 #include "resource.h"
00024 #include "DirectVobSubFilter.h"
00025 #include "..\..\..\DSUtil\DSUtil.h"
00026 
00027 // hWnd == INVALID_HANDLE_VALUE - get name, hWnd != INVALID_HANDLE_VALUE - show ppage
00028 static TCHAR* CallPPage(IFilterGraph* pGraph, int idx, HWND hWnd);
00029 
00030 static HHOOK g_hHook = (HHOOK)INVALID_HANDLE_VALUE;
00031 
00032 static UINT WM_DVSPREVSUB = RegisterWindowMessage(TEXT("WM_DVSPREVSUB"));
00033 static UINT WM_DVSNEXTSUB = RegisterWindowMessage(TEXT("WM_DVSNEXTSUB"));
00034 static UINT WM_DVSHIDESUB = RegisterWindowMessage(TEXT("WM_DVSHIDESUB"));
00035 static UINT WM_DVSSHOWSUB = RegisterWindowMessage(TEXT("WM_DVSSHOWSUB"));
00036 static UINT WM_DVSSHOWHIDESUB = RegisterWindowMessage(TEXT("WM_DVSSHOWHIDESUB"));
00037 static UINT s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
00038 static UINT WM_NOTIFYICON = RegisterWindowMessage(TEXT("MYWM_NOTIFYICON"));
00039 
00040 LRESULT CALLBACK HookProc(UINT code, WPARAM wParam, LPARAM lParam)
00041 {
00042         MSG* msg = (MSG*)lParam;
00043 
00044         if(msg->message == WM_KEYDOWN)
00045         {
00046                 switch(msg->wParam)
00047                 {
00048                 case VK_F13: PostMessage(HWND_BROADCAST, WM_DVSPREVSUB, 0, 0); break;
00049                 case VK_F14: PostMessage(HWND_BROADCAST, WM_DVSNEXTSUB, 0, 0); break;
00050                 case VK_F15: PostMessage(HWND_BROADCAST, WM_DVSHIDESUB, 0, 0); break;
00051                 case VK_F16: PostMessage(HWND_BROADCAST, WM_DVSSHOWSUB, 0, 0); break;
00052                 case VK_F17: PostMessage(HWND_BROADCAST, WM_DVSSHOWHIDESUB, 0, 0); break;
00053                 default: break;
00054                 }
00055         }
00056 
00057         // Always call next hook in chain 
00058         return CallNextHookEx(g_hHook, code,  wParam, lParam);
00059 } 
00060 
00061 class CSystrayWindow : public CWnd
00062 {
00063         SystrayIconData* m_tbid;
00064 
00065         void StepSub(int dir)
00066         {
00067                 int iSelected, nLangs;
00068                 if(FAILED(m_tbid->dvs->get_LanguageCount(&nLangs))) return;
00069                 if(FAILED(m_tbid->dvs->get_SelectedLanguage(&iSelected))) return;
00070         if(nLangs > 0) m_tbid->dvs->put_SelectedLanguage((iSelected+dir+nLangs)%nLangs);
00071         }
00072 
00073         void ShowSub(bool fShow)
00074         {
00075                 m_tbid->dvs->put_HideSubtitles(!fShow);
00076         }
00077 
00078         void ToggleSub()
00079         {
00080                 bool fShow;
00081                 if(FAILED(m_tbid->dvs->get_HideSubtitles(&fShow))) return;
00082                 m_tbid->dvs->put_HideSubtitles(!fShow);
00083         }
00084 
00085 public:
00086         CSystrayWindow(SystrayIconData* tbid) : m_tbid(tbid) {}
00087 
00088 protected:
00089         DECLARE_MESSAGE_MAP()
00090 
00091 public:
00092         afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
00093         afx_msg void OnClose();
00094         afx_msg void OnDestroy();
00095         afx_msg void OnTimer(UINT nIDEvent);
00096         afx_msg LRESULT OnDVSPrevSub(WPARAM, LPARAM);
00097         afx_msg LRESULT OnDVSNextSub(WPARAM, LPARAM);
00098         afx_msg LRESULT OnDVSHideSub(WPARAM, LPARAM);
00099         afx_msg LRESULT OnDVSShowSub(WPARAM, LPARAM);
00100         afx_msg LRESULT OnDVSShowHideSub(WPARAM, LPARAM);
00101         afx_msg LRESULT OnTaskBarRestart(WPARAM, LPARAM);
00102         afx_msg LRESULT OnNotifyIcon(WPARAM, LPARAM);
00103 };
00104 
00105 BEGIN_MESSAGE_MAP(CSystrayWindow, CWnd)
00106         ON_WM_CREATE()
00107         ON_WM_CLOSE()
00108         ON_WM_DESTROY()
00109         ON_WM_TIMER()
00110         ON_REGISTERED_MESSAGE(WM_DVSPREVSUB, OnDVSPrevSub)
00111         ON_REGISTERED_MESSAGE(WM_DVSNEXTSUB, OnDVSNextSub)
00112         ON_REGISTERED_MESSAGE(WM_DVSHIDESUB, OnDVSHideSub)
00113         ON_REGISTERED_MESSAGE(WM_DVSSHOWSUB, OnDVSShowSub)
00114         ON_REGISTERED_MESSAGE(WM_DVSSHOWHIDESUB, OnDVSShowHideSub)
00115         ON_REGISTERED_MESSAGE(s_uTaskbarRestart, OnTaskBarRestart)
00116         ON_REGISTERED_MESSAGE(WM_NOTIFYICON, OnNotifyIcon)
00117 END_MESSAGE_MAP()
00118 
00119 int CSystrayWindow::OnCreate(LPCREATESTRUCT lpCreateStruct)
00120 {
00121         if(CWnd::OnCreate(lpCreateStruct) == -1)
00122                 return -1;
00123 
00124         if(g_hHook == INVALID_HANDLE_VALUE)
00125         {
00126                 AFX_MANAGE_STATE(AfxGetStaticModuleState());
00127 //              g_hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)HookProc, AfxGetInstanceHandle(), 0);
00128         }
00129 
00130         SetTimer(1, 5000, NULL);
00131 
00132         PostMessage(s_uTaskbarRestart);
00133 
00134         return 0;
00135 }
00136 
00137 void CSystrayWindow::OnClose()
00138 {
00139         DestroyWindow();
00140 }
00141 
00142 void CSystrayWindow::OnDestroy()
00143 {
00144         NOTIFYICONDATA tnid; 
00145         tnid.cbSize = sizeof(NOTIFYICONDATA); 
00146         tnid.hWnd = m_hWnd;
00147         tnid.uID = IDI_ICON1; 
00148         Shell_NotifyIcon(NIM_DELETE, &tnid); 
00149 
00150         if(g_hHook != INVALID_HANDLE_VALUE)
00151         {
00152                 UnhookWindowsHookEx(g_hHook);
00153                 g_hHook = (HHOOK)INVALID_HANDLE_VALUE;
00154         }
00155 
00156         PostQuitMessage(0); 
00157 }
00158 
00159 void CSystrayWindow::OnTimer(UINT nIDEvent)
00160 {
00161         if(nIDEvent == 1)
00162         {
00163                 UINT fScreenSaver = 0;
00164                 if(SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, (PVOID)&fScreenSaver, 0))
00165                 {
00166                         SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 0, 0, SPIF_SENDWININICHANGE); // this might not be needed at all...
00167                         SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, fScreenSaver, 0, SPIF_SENDWININICHANGE);
00168                 }
00169         }
00170 
00171         CWnd::OnTimer(nIDEvent);
00172 }
00173 
00174 LRESULT CSystrayWindow::OnDVSPrevSub(WPARAM, LPARAM)
00175         {StepSub(-1); return 0;}
00176 LRESULT CSystrayWindow::OnDVSNextSub(WPARAM, LPARAM)
00177         {StepSub(+1); return 0;}
00178 LRESULT CSystrayWindow::OnDVSHideSub(WPARAM, LPARAM)
00179         {ShowSub(false); return 0;}
00180 LRESULT CSystrayWindow::OnDVSShowSub(WPARAM, LPARAM)
00181         {ShowSub(true); return 0;}
00182 LRESULT CSystrayWindow::OnDVSShowHideSub(WPARAM, LPARAM)
00183         {ToggleSub(); return 0;}
00184 
00185 LRESULT CSystrayWindow::OnTaskBarRestart(WPARAM, LPARAM)
00186 {
00187         AFX_MANAGE_STATE(AfxGetStaticModuleState());
00188 
00189         if(m_tbid->fShowIcon)
00190         {
00191                 NOTIFYICONDATA tnid; 
00192                 tnid.cbSize = sizeof(NOTIFYICONDATA); 
00193                 tnid.hWnd = m_hWnd; 
00194                 tnid.uID = IDI_ICON1; 
00195                 tnid.hIcon = (HICON)LoadIcon(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_ICON1));
00196 //              tnid.hIcon = (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, 0, 0, LR_LOADTRANSPARENT);
00197                 tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; 
00198                 tnid.uCallbackMessage = WM_NOTIFYICON; 
00199                 lstrcpyn(tnid.szTip, TEXT("DirectVobSub"), sizeof(tnid.szTip)); 
00200 
00201                 BOOL res = Shell_NotifyIcon(NIM_ADD, &tnid); 
00202 
00203                 if(tnid.hIcon) DestroyIcon(tnid.hIcon); 
00204 
00205                 return res?0:-1;
00206         }
00207 
00208         return 0;
00209 }
00210 
00211 LRESULT CSystrayWindow::OnNotifyIcon(WPARAM wParam, LPARAM lParam)
00212 {
00213     if((UINT)wParam != IDI_ICON1)
00214                 return -1;
00215 
00216         HWND hWnd = m_hWnd;
00217         
00218         switch((UINT)lParam)
00219         {
00220                 case WM_LBUTTONDBLCLK:
00221                 {
00222                         // IMPORTANT: we must not hold the graph at the same time as showing the property page 
00223                         // or else when closing the app the graph doesn't get released and dvobsub's JoinFilterGraph
00224                         // is never called to close us down.
00225 
00226                         CComPtr<IBaseFilter> pBF2;
00227 
00228                         BeginEnumFilters(m_tbid->graph, pEF, pBF)
00229                         {
00230                                 if(!CComQIPtr<IDirectVobSub>(pBF))
00231                                         continue;
00232 
00233                                 if(CComQIPtr<IVideoWindow> pVW = m_tbid->graph) 
00234                                 {
00235                                         HWND hwnd;
00236                                         if(SUCCEEDED(pVW->get_Owner((OAHWND*)&hwnd))
00237                                         || SUCCEEDED(pVW->get_MessageDrain((OAHWND*)&hwnd)))
00238                                                 hWnd = hwnd;
00239                                 }
00240 
00241                                 pBF2 = pBF;
00242 
00243                                 break;
00244                         }
00245                         EndEnumFilters
00246 
00247                         if(pBF2)
00248                                 ShowPPage(pBF2, hWnd);
00249                 }
00250                 break;
00251 
00252                 case WM_RBUTTONDOWN:
00253                 {
00254                         POINT p;
00255                         GetCursorPos(&p);
00256 
00257                         CInterfaceArray<IAMStreamSelect> pStreams;
00258                         CStringArray names;
00259 
00260                         BeginEnumFilters(m_tbid->graph, pEF, pBF)
00261                         {
00262                                 CString name = GetFilterName(pBF);
00263                                 if(name.IsEmpty()) continue;
00264 
00265                                 if(CComQIPtr<IAMStreamSelect> pSS = pBF)
00266                                 {
00267                                         pStreams.Add(pSS);
00268                                         names.Add(name);
00269                                 }
00270                         }
00271                         EndEnumFilters
00272 
00273                         CMenu popup;
00274                         popup.CreatePopupMenu();
00275 
00276                         for(int j = 0; j < pStreams.GetCount(); j++)
00277                         {
00278                                 bool fMMSwitcher = !names[j].Compare(_T("Morgan Stream Switcher"));
00279 
00280                                 DWORD cStreams = 0;
00281                                 pStreams[j]->Count(&cStreams);
00282 
00283                                 DWORD flags, group, prevgroup = -1;
00284                                 
00285                                 for(UINT i = 0; i < cStreams; i++)
00286                                 {
00287                                         WCHAR* pName = NULL;
00288 
00289                                         if(S_OK == pStreams[j]->Info(i, 0, &flags, 0, &group, &pName, 0, 0))
00290                                         {
00291                                                 if(prevgroup != group && i > 1) 
00292                                                 {
00293                                                         if(fMMSwitcher) {cStreams = i; break;}
00294                                                         popup.AppendMenu(MF_SEPARATOR);
00295                                                 }
00296                                                 prevgroup = group;
00297 
00298                                                 if(pName)
00299                                                 {
00300                                                         popup.AppendMenu(MF_ENABLED|MF_STRING|(flags?MF_CHECKED:MF_UNCHECKED), (1<<15)|(j<<8)|(i), CString(pName));
00301                                                         CoTaskMemFree(pName);
00302                                                 }
00303                                         }
00304                                 }
00305 
00306                                 if(cStreams > 0) popup.AppendMenu(MF_SEPARATOR);
00307                         }
00308 
00309                         int i;
00310 
00311                         TCHAR* str;
00312                         for(i = 0; str = CallPPage(m_tbid->graph, i, (HWND)INVALID_HANDLE_VALUE); i++)
00313                         {
00314                                 if(_tcsncmp(str, _T("DivX MPEG"), 9) || m_tbid->fRunOnce) // divx3's ppage will crash if the graph hasn't been run at least once yet
00315                                         popup.AppendMenu(MF_ENABLED|MF_STRING|MF_UNCHECKED, (1<<14)|(i), str);
00316 
00317                                 delete [] str;
00318                         }
00319 
00320                         SetForegroundWindow();
00321                         UINT id = popup.TrackPopupMenu(TPM_LEFTBUTTON|TPM_RETURNCMD, p.x, p.y, CWnd::FromHandle(hWnd), 0);
00322                         PostMessage(WM_NULL);
00323 
00324                         if(id & (1<<15)) 
00325                         {
00326                                 pStreams[(id>>8)&0x3f]->Enable(id&0xff, AMSTREAMSELECTENABLE_ENABLE);
00327                         }
00328                         else if(id & (1<<14))
00329                         {
00330                                 if(CComQIPtr<IVideoWindow> pVW = m_tbid->graph)
00331                                 {
00332                                         HWND hwnd;
00333                                         if(SUCCEEDED(pVW->get_Owner((OAHWND*)&hwnd))
00334                                         || SUCCEEDED(pVW->get_MessageDrain((OAHWND*)&hwnd)))
00335                                                 hWnd = hwnd;
00336                                 }
00337 
00338                                 CallPPage(m_tbid->graph, id&0xff, hWnd);
00339                         }
00340                 }
00341                 break; 
00342 
00343                 default: 
00344                         break; 
00345         }
00346 
00347         return 0;
00348 }
00349 
00350 //
00351 
00352 DWORD CALLBACK SystrayThreadProc(void* pParam)
00353 {
00354         AFX_MANAGE_STATE(AfxGetStaticModuleState());
00355 
00356         CSystrayWindow wnd((SystrayIconData*)pParam);
00357         if(!wnd.CreateEx(0, AfxRegisterWndClass(0), _T("DVSWND"), WS_OVERLAPPED, CRect(0, 0, 0, 0), NULL, 0, NULL))
00358                 return -1;
00359 
00360         ((SystrayIconData*)pParam)->hSystrayWnd = wnd.m_hWnd;
00361 
00362         MSG msg;
00363         while(GetMessage(&msg, NULL/*wnd.m_hWnd*/, 0, 0))
00364         {
00365                 TranslateMessage(&msg);
00366                 DispatchMessage(&msg);
00367         }
00368 
00369         return 0;
00370 }
00371 
00372 // TODO: replace this function
00373 
00374 // hWnd == INVALID_HANDLE_VALUE - get name, hWnd != INVALID_HANDLE_VALUE - show ppage
00375 static TCHAR* CallPPage(IFilterGraph* pGraph, int idx, HWND hWnd)
00376 {
00377         int i = 0;
00378         bool fFound = false;
00379 
00380         WCHAR* wstr = NULL;
00381         CComPtr<IBaseFilter> pFilter;
00382         CAUUID caGUID;
00383         caGUID.pElems = NULL;
00384 
00385         BeginEnumFilters(pGraph, pEF, pBF)
00386         {
00387                 CComQIPtr<ISpecifyPropertyPages> pSPS = pBF;
00388                 if(!pSPS) continue;
00389 
00390                 if(i == idx)
00391                 { 
00392                         pFilter = pBF;
00393                         pSPS->GetPages(&caGUID);
00394                         wstr = _wcsdup(CStringW(GetFilterName(pBF))); // double char-wchar conversion happens in the non-unicode build, but anyway... :)
00395                         break;
00396                 }
00397 
00398                 i++;
00399         }
00400         EndEnumFilters
00401 
00402         TCHAR* ret = NULL;
00403 
00404         if(pFilter)
00405         {
00406                 if(hWnd != INVALID_HANDLE_VALUE)
00407                 {
00408                         ShowPPage(pFilter, hWnd);
00409                 }
00410                 else
00411                 {
00412                         if(ret = new TCHAR[wcslen(wstr)+1])
00413                                 _tcscpy(ret, CString(wstr));
00414                 }
00415         }
00416 
00417         if(caGUID.pElems) CoTaskMemFree(caGUID.pElems);
00418         if(wstr) free(wstr);
00419 
00420         return(ret);
00421 }

Generated on Tue Dec 13 14:47:52 2005 for guliverkli by  doxygen 1.4.5