2 * Copyright (C) 2003-2006 Gabest
3 * http://www.gabest.org
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
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.
15 * You should have received a copy of the GNU General Public License
16 * along with GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
24 #include "DirectVobSubFilter.h"
25 #include "../../../DSUtil/DSUtil.h"
27 // hWnd == INVALID_HANDLE_VALUE - get name, hWnd != INVALID_HANDLE_VALUE - show ppage
28 static TCHAR
* CallPPage(IFilterGraph
* pGraph
, int idx
, HWND hWnd
);
30 static HHOOK g_hHook
= (HHOOK
)INVALID_HANDLE_VALUE
;
32 static UINT WM_DVSPREVSUB
= RegisterWindowMessage(TEXT("WM_DVSPREVSUB"));
33 static UINT WM_DVSNEXTSUB
= RegisterWindowMessage(TEXT("WM_DVSNEXTSUB"));
34 static UINT WM_DVSHIDESUB
= RegisterWindowMessage(TEXT("WM_DVSHIDESUB"));
35 static UINT WM_DVSSHOWSUB
= RegisterWindowMessage(TEXT("WM_DVSSHOWSUB"));
36 static UINT WM_DVSSHOWHIDESUB
= RegisterWindowMessage(TEXT("WM_DVSSHOWHIDESUB"));
37 static UINT s_uTaskbarRestart
= RegisterWindowMessage(TEXT("TaskbarCreated"));
38 static UINT WM_NOTIFYICON
= RegisterWindowMessage(TEXT("MYWM_NOTIFYICON"));
40 LRESULT CALLBACK
HookProc(UINT code
, WPARAM wParam
, LPARAM lParam
)
42 MSG
* msg
= (MSG
*)lParam
;
44 if(msg
->message
== WM_KEYDOWN
)
48 case VK_F13
: PostMessage(HWND_BROADCAST
, WM_DVSPREVSUB
, 0, 0); break;
49 case VK_F14
: PostMessage(HWND_BROADCAST
, WM_DVSNEXTSUB
, 0, 0); break;
50 case VK_F15
: PostMessage(HWND_BROADCAST
, WM_DVSHIDESUB
, 0, 0); break;
51 case VK_F16
: PostMessage(HWND_BROADCAST
, WM_DVSSHOWSUB
, 0, 0); break;
52 case VK_F17
: PostMessage(HWND_BROADCAST
, WM_DVSSHOWHIDESUB
, 0, 0); break;
57 // Always call next hook in chain
58 return CallNextHookEx(g_hHook
, code
, wParam
, lParam
);
61 class CSystrayWindow
: public CWnd
63 SystrayIconData
* m_tbid
;
67 int iSelected
, nLangs
;
68 if(FAILED(m_tbid
->dvs
->get_LanguageCount(&nLangs
))) return;
69 if(FAILED(m_tbid
->dvs
->get_SelectedLanguage(&iSelected
))) return;
70 if(nLangs
> 0) m_tbid
->dvs
->put_SelectedLanguage((iSelected
+dir
+nLangs
)%nLangs
);
73 void ShowSub(bool fShow
)
75 m_tbid
->dvs
->put_HideSubtitles(!fShow
);
81 if(FAILED(m_tbid
->dvs
->get_HideSubtitles(&fShow
))) return;
82 m_tbid
->dvs
->put_HideSubtitles(!fShow
);
86 CSystrayWindow(SystrayIconData
* tbid
) : m_tbid(tbid
) {}
92 afx_msg
int OnCreate(LPCREATESTRUCT lpCreateStruct
);
93 afx_msg
void OnClose();
94 afx_msg
void OnDestroy();
95 afx_msg LRESULT
OnDVSPrevSub(WPARAM
, LPARAM
);
96 afx_msg LRESULT
OnDVSNextSub(WPARAM
, LPARAM
);
97 afx_msg LRESULT
OnDVSHideSub(WPARAM
, LPARAM
);
98 afx_msg LRESULT
OnDVSShowSub(WPARAM
, LPARAM
);
99 afx_msg LRESULT
OnDVSShowHideSub(WPARAM
, LPARAM
);
100 afx_msg LRESULT
OnTaskBarRestart(WPARAM
, LPARAM
);
101 afx_msg LRESULT
OnNotifyIcon(WPARAM
, LPARAM
);
104 BEGIN_MESSAGE_MAP(CSystrayWindow
, CWnd
)
109 ON_REGISTERED_MESSAGE(WM_DVSPREVSUB
, OnDVSPrevSub
)
110 ON_REGISTERED_MESSAGE(WM_DVSNEXTSUB
, OnDVSNextSub
)
111 ON_REGISTERED_MESSAGE(WM_DVSHIDESUB
, OnDVSHideSub
)
112 ON_REGISTERED_MESSAGE(WM_DVSSHOWSUB
, OnDVSShowSub
)
113 ON_REGISTERED_MESSAGE(WM_DVSSHOWHIDESUB
, OnDVSShowHideSub
)
114 ON_REGISTERED_MESSAGE(s_uTaskbarRestart
, OnTaskBarRestart
)
115 ON_REGISTERED_MESSAGE(WM_NOTIFYICON
, OnNotifyIcon
)
118 int CSystrayWindow::OnCreate(LPCREATESTRUCT lpCreateStruct
)
120 if(CWnd::OnCreate(lpCreateStruct
) == -1)
123 if(g_hHook
== INVALID_HANDLE_VALUE
)
125 AFX_MANAGE_STATE(AfxGetStaticModuleState());
126 // g_hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)HookProc, AfxGetInstanceHandle(), 0);
129 SetTimer(1, 5000, NULL
);
131 PostMessage(s_uTaskbarRestart
);
136 void CSystrayWindow::OnClose()
141 void CSystrayWindow::OnDestroy()
144 ZeroMemory(&tnid
, sizeof(NOTIFYICONDATA
));
145 tnid
.cbSize
= sizeof(NOTIFYICONDATA
);
147 tnid
.uID
= IDI_ICON1
;
148 Shell_NotifyIcon(NIM_DELETE
, &tnid
);
150 if(g_hHook
!= INVALID_HANDLE_VALUE
)
152 UnhookWindowsHookEx(g_hHook
);
153 g_hHook
= (HHOOK
)INVALID_HANDLE_VALUE
;
159 LRESULT
CSystrayWindow::OnDVSPrevSub(WPARAM
, LPARAM
)
160 {StepSub(-1); return 0;}
161 LRESULT
CSystrayWindow::OnDVSNextSub(WPARAM
, LPARAM
)
162 {StepSub(+1); return 0;}
163 LRESULT
CSystrayWindow::OnDVSHideSub(WPARAM
, LPARAM
)
164 {ShowSub(false); return 0;}
165 LRESULT
CSystrayWindow::OnDVSShowSub(WPARAM
, LPARAM
)
166 {ShowSub(true); return 0;}
167 LRESULT
CSystrayWindow::OnDVSShowHideSub(WPARAM
, LPARAM
)
168 {ToggleSub(); return 0;}
170 LRESULT
CSystrayWindow::OnTaskBarRestart(WPARAM
, LPARAM
)
172 AFX_MANAGE_STATE(AfxGetStaticModuleState());
174 if(m_tbid
->fShowIcon
)
177 ZeroMemory(&tnid
, sizeof(NOTIFYICONDATA
));
178 tnid
.cbSize
= sizeof(NOTIFYICONDATA
);
180 tnid
.uID
= IDI_ICON1
;
181 tnid
.hIcon
= (HICON
)LoadIcon(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_ICON1
));
182 // tnid.hIcon = (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, 0, 0, LR_LOADTRANSPARENT);
183 tnid
.uFlags
= NIF_MESSAGE
| NIF_ICON
| NIF_TIP
;
184 tnid
.uCallbackMessage
= WM_NOTIFYICON
;
185 lstrcpyn(tnid
.szTip
, TEXT("DirectVobSub"), sizeof(tnid
.szTip
));
187 BOOL res
= Shell_NotifyIcon(NIM_ADD
, &tnid
);
189 if(tnid
.hIcon
) DestroyIcon(tnid
.hIcon
);
197 LRESULT
CSystrayWindow::OnNotifyIcon(WPARAM wParam
, LPARAM lParam
)
199 if((UINT
)wParam
!= IDI_ICON1
)
206 case WM_LBUTTONDBLCLK
:
208 // IMPORTANT: we must not hold the graph at the same time as showing the property page
209 // or else when closing the app the graph doesn't get released and dvobsub's JoinFilterGraph
210 // is never called to close us down.
212 CComPtr
<IBaseFilter
> pBF2
;
214 BeginEnumFilters(m_tbid
->graph
, pEF
, pBF
)
216 if(!CComQIPtr
<IDirectVobSub
>(pBF
))
219 if(CComQIPtr
<IVideoWindow
> pVW
= m_tbid
->graph
)
222 if(SUCCEEDED(pVW
->get_Owner((OAHWND
*)&hwnd
))
223 || SUCCEEDED(pVW
->get_MessageDrain((OAHWND
*)&hwnd
)))
234 ShowPPage(pBF2
, hWnd
);
243 CInterfaceArray
<IAMStreamSelect
> pStreams
;
246 BeginEnumFilters(m_tbid
->graph
, pEF
, pBF
)
248 CString name
= GetFilterName(pBF
);
249 if(name
.IsEmpty()) continue;
251 if(CComQIPtr
<IAMStreamSelect
> pSS
= pBF
)
260 popup
.CreatePopupMenu();
262 for(int j
= 0; j
< pStreams
.GetCount(); j
++)
264 bool fMMSwitcher
= !names
[j
].Compare(_T("Morgan Stream Switcher"));
267 pStreams
[j
]->Count(&cStreams
);
269 DWORD flags
, group
, prevgroup
= -1;
271 for(UINT i
= 0; i
< cStreams
; i
++)
275 if(S_OK
== pStreams
[j
]->Info(i
, 0, &flags
, 0, &group
, &pName
, 0, 0))
277 if(prevgroup
!= group
&& i
> 1)
279 if(fMMSwitcher
) {cStreams
= i
; break;}
280 popup
.AppendMenu(MF_SEPARATOR
);
286 popup
.AppendMenu(MF_ENABLED
|MF_STRING
|(flags
?MF_CHECKED
:MF_UNCHECKED
), (1<<15)|(j
<<8)|(i
), CString(pName
));
287 CoTaskMemFree(pName
);
292 if(cStreams
> 0) popup
.AppendMenu(MF_SEPARATOR
);
298 for(i
= 0; str
= CallPPage(m_tbid
->graph
, i
, (HWND
)INVALID_HANDLE_VALUE
); i
++)
300 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
301 popup
.AppendMenu(MF_ENABLED
|MF_STRING
|MF_UNCHECKED
, (1<<14)|(i
), str
);
306 SetForegroundWindow();
307 UINT id
= popup
.TrackPopupMenu(TPM_LEFTBUTTON
|TPM_RETURNCMD
, p
.x
, p
.y
, CWnd::FromHandle(hWnd
), 0);
308 PostMessage(WM_NULL
);
312 pStreams
[(id
>>8)&0x3f]->Enable(id
&0xff, AMSTREAMSELECTENABLE_ENABLE
);
314 else if(id
& (1<<14))
316 if(CComQIPtr
<IVideoWindow
> pVW
= m_tbid
->graph
)
319 if(SUCCEEDED(pVW
->get_Owner((OAHWND
*)&hwnd
))
320 || SUCCEEDED(pVW
->get_MessageDrain((OAHWND
*)&hwnd
)))
324 CallPPage(m_tbid
->graph
, id
&0xff, hWnd
);
338 DWORD CALLBACK
SystrayThreadProc(void* pParam
)
340 AFX_MANAGE_STATE(AfxGetStaticModuleState());
342 CSystrayWindow
wnd((SystrayIconData
*)pParam
);
343 if(!wnd
.CreateEx(0, AfxRegisterWndClass(0), _T("DVSWND"), WS_OVERLAPPED
, CRect(0, 0, 0, 0), NULL
, 0, NULL
))
346 ((SystrayIconData
*)pParam
)->hSystrayWnd
= wnd
.m_hWnd
;
349 while(GetMessage(&msg
, NULL
/*wnd.m_hWnd*/, 0, 0))
351 TranslateMessage(&msg
);
352 DispatchMessage(&msg
);
358 // TODO: replace this function
360 // hWnd == INVALID_HANDLE_VALUE - get name, hWnd != INVALID_HANDLE_VALUE - show ppage
361 static TCHAR
* CallPPage(IFilterGraph
* pGraph
, int idx
, HWND hWnd
)
364 //bool fFound = false;
367 CComPtr
<IBaseFilter
> pFilter
;
369 caGUID
.pElems
= NULL
;
371 BeginEnumFilters(pGraph
, pEF
, pBF
)
373 CComQIPtr
<ISpecifyPropertyPages
> pSPS
= pBF
;
379 pSPS
->GetPages(&caGUID
);
380 wstr
= _wcsdup(CStringW(GetFilterName(pBF
))); // double char-wchar conversion happens in the non-unicode build, but anyway... :)
392 if(hWnd
!= INVALID_HANDLE_VALUE
)
394 ShowPPage(pFilter
, hWnd
);
398 if(ret
= new TCHAR
[wcslen(wstr
)+1])
399 _tcscpy(ret
, CString(wstr
));
403 if(caGUID
.pElems
) CoTaskMemFree(caGUID
.pElems
);