- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# 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 }