/* * Common implementation of IVideoWindow * * Copyright 2012 Aric Stewart, CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "quartz_private.h" WINE_DEFAULT_DEBUG_CHANNEL(quartz); static const WCHAR class_name[] = L"wine_quartz_window"; static inline struct video_window *impl_from_IVideoWindow(IVideoWindow *iface) { return CONTAINING_RECORD(iface, struct video_window, IVideoWindow_iface); } static LRESULT CALLBACK WndProcW(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { struct video_window *window = (struct video_window *)GetWindowLongPtrW(hwnd, 0); if (!window) return DefWindowProcW(hwnd, message, wparam, lparam); switch (message) { case WM_KEYDOWN: case WM_KEYUP: case WM_LBUTTONDBLCLK: case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_MBUTTONDBLCLK: case WM_MBUTTONDOWN: case WM_MBUTTONUP: case WM_MOUSEACTIVATE: case WM_MOUSEMOVE: case WM_NCLBUTTONDBLCLK: case WM_NCLBUTTONDOWN: case WM_NCLBUTTONUP: case WM_NCMBUTTONDBLCLK: case WM_NCMBUTTONDOWN: case WM_NCMBUTTONUP: case WM_NCMOUSEMOVE: case WM_NCRBUTTONDBLCLK: case WM_NCRBUTTONDOWN: case WM_NCRBUTTONUP: case WM_RBUTTONDBLCLK: case WM_RBUTTONDOWN: case WM_RBUTTONUP: if (window->hwndDrain) { PostMessageW(window->hwndDrain, message, wparam, lparam); return 0; } break; case WM_SIZE: if (window->default_dst) GetClientRect(window->hwnd, &window->dst); break; } return DefWindowProcW(hwnd, message, wparam, lparam); } HRESULT video_window_create_window(struct video_window *window) { WNDCLASSW winclass = {0}; winclass.lpfnWndProc = WndProcW; winclass.cbWndExtra = sizeof(window); winclass.hbrBackground = GetStockObject(BLACK_BRUSH); winclass.lpszClassName = class_name; if (!RegisterClassW(&winclass) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) { ERR("Unable to register window class: %u\n", GetLastError()); return E_FAIL; } if (!(window->hwnd = CreateWindowExW(0, class_name, L"ActiveMovie Window", WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL))) { ERR("Unable to create window\n"); return E_FAIL; } SetWindowLongPtrW(window->hwnd, 0, (LONG_PTR)window); return S_OK; } HRESULT WINAPI BaseControlWindowImpl_QueryInterface(IVideoWindow *iface, REFIID iid, void **out) { struct video_window *window = impl_from_IVideoWindow(iface); return IUnknown_QueryInterface(window->pFilter->outer_unk, iid, out); } ULONG WINAPI BaseControlWindowImpl_AddRef(IVideoWindow *iface) { struct video_window *window = impl_from_IVideoWindow(iface); return IUnknown_AddRef(window->pFilter->outer_unk); } ULONG WINAPI BaseControlWindowImpl_Release(IVideoWindow *iface) { struct video_window *window = impl_from_IVideoWindow(iface); return IUnknown_Release(window->pFilter->outer_unk); } HRESULT WINAPI BaseControlWindowImpl_GetTypeInfoCount(IVideoWindow *iface, UINT *count) { TRACE("iface %p, count %p.\n", iface, count); *count = 1; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_GetTypeInfo(IVideoWindow *iface, UINT index, LCID lcid, ITypeInfo **typeinfo) { TRACE("iface %p, index %u, lcid %#x, typeinfo %p.\n", iface, index, lcid, typeinfo); return strmbase_get_typeinfo(IVideoWindow_tid, typeinfo); } HRESULT WINAPI BaseControlWindowImpl_GetIDsOfNames(IVideoWindow *iface, REFIID iid, LPOLESTR *names, UINT count, LCID lcid, DISPID *ids) { ITypeInfo *typeinfo; HRESULT hr; TRACE("iface %p, iid %s, names %p, count %u, lcid %#x, ids %p.\n", iface, debugstr_guid(iid), names, count, lcid, ids); if (SUCCEEDED(hr = strmbase_get_typeinfo(IVideoWindow_tid, &typeinfo))) { hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, ids); ITypeInfo_Release(typeinfo); } return hr; } HRESULT WINAPI BaseControlWindowImpl_Invoke(IVideoWindow *iface, DISPID id, REFIID iid, LCID lcid, WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *error_arg) { ITypeInfo *typeinfo; HRESULT hr; TRACE("iface %p, id %d, iid %s, lcid %#x, flags %#x, params %p, result %p, excepinfo %p, error_arg %p.\n", iface, id, debugstr_guid(iid), lcid, flags, params, result, excepinfo, error_arg); if (SUCCEEDED(hr = strmbase_get_typeinfo(IVideoWindow_tid, &typeinfo))) { hr = ITypeInfo_Invoke(typeinfo, iface, id, flags, params, result, excepinfo, error_arg); ITypeInfo_Release(typeinfo); } return hr; } HRESULT WINAPI BaseControlWindowImpl_put_Caption(IVideoWindow *iface, BSTR caption) { struct video_window *window = impl_from_IVideoWindow(iface); TRACE("window %p, caption %s.\n", window, debugstr_w(caption)); if (!SetWindowTextW(window->hwnd, caption)) return E_FAIL; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_get_Caption(IVideoWindow *iface, BSTR *caption) { struct video_window *window = impl_from_IVideoWindow(iface); WCHAR *str; int len; TRACE("window %p, caption %p.\n", window, caption); *caption = NULL; len = GetWindowTextLengthW(window->hwnd) + 1; if (!(str = heap_alloc(len * sizeof(WCHAR)))) return E_OUTOFMEMORY; GetWindowTextW(window->hwnd, str, len); *caption = SysAllocString(str); heap_free(str); return *caption ? S_OK : E_OUTOFMEMORY; } HRESULT WINAPI BaseControlWindowImpl_put_WindowStyle(IVideoWindow *iface, LONG style) { struct video_window *window = impl_from_IVideoWindow(iface); TRACE("window %p, style %#x.\n", window, style); if (style & (WS_DISABLED|WS_HSCROLL|WS_MAXIMIZE|WS_MINIMIZE|WS_VSCROLL)) return E_INVALIDARG; SetWindowLongW(window->hwnd, GWL_STYLE, style); SetWindowPos(window->hwnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); return S_OK; } HRESULT WINAPI BaseControlWindowImpl_get_WindowStyle(IVideoWindow *iface, LONG *style) { struct video_window *window = impl_from_IVideoWindow(iface); TRACE("window %p, style %p.\n", window, style); *style = GetWindowLongW(window->hwnd, GWL_STYLE); return S_OK; } HRESULT WINAPI BaseControlWindowImpl_put_WindowStyleEx(IVideoWindow *iface, LONG style) { struct video_window *window = impl_from_IVideoWindow(iface); TRACE("window %p, style %#x.\n", window, style); if (!SetWindowLongW(window->hwnd, GWL_EXSTYLE, style)) return E_FAIL; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_get_WindowStyleEx(IVideoWindow *iface, LONG *style) { struct video_window *window = impl_from_IVideoWindow(iface); TRACE("window %p, style %p.\n", window, style); *style = GetWindowLongW(window->hwnd, GWL_EXSTYLE); return S_OK; } HRESULT WINAPI BaseControlWindowImpl_put_AutoShow(IVideoWindow *iface, LONG AutoShow) { struct video_window *This = impl_from_IVideoWindow(iface); TRACE("(%p/%p)->(%d)\n", This, iface, AutoShow); This->AutoShow = AutoShow; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_get_AutoShow(IVideoWindow *iface, LONG *AutoShow) { struct video_window *This = impl_from_IVideoWindow(iface); TRACE("(%p/%p)->(%p)\n", This, iface, AutoShow); *AutoShow = This->AutoShow; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_put_WindowState(IVideoWindow *iface, LONG state) { struct video_window *window = impl_from_IVideoWindow(iface); TRACE("window %p, state %#x.\n", window, state); ShowWindow(window->hwnd, state); return S_OK; } HRESULT WINAPI BaseControlWindowImpl_get_WindowState(IVideoWindow *iface, LONG *state) { struct video_window *window = impl_from_IVideoWindow(iface); DWORD style; TRACE("window %p, state %p.\n", window, state); style = GetWindowLongPtrW(window->hwnd, GWL_STYLE); if (!(style & WS_VISIBLE)) *state = SW_HIDE; else if (style & WS_MINIMIZE) *state = SW_MINIMIZE; else if (style & WS_MAXIMIZE) *state = SW_MAXIMIZE; else *state = SW_SHOW; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_put_BackgroundPalette(IVideoWindow *iface, LONG BackgroundPalette) { struct video_window *This = impl_from_IVideoWindow(iface); FIXME("(%p/%p)->(%d): stub !!!\n", This, iface, BackgroundPalette); return S_OK; } HRESULT WINAPI BaseControlWindowImpl_get_BackgroundPalette(IVideoWindow *iface, LONG *pBackgroundPalette) { struct video_window *This = impl_from_IVideoWindow(iface); FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pBackgroundPalette); return S_OK; } HRESULT WINAPI BaseControlWindowImpl_put_Visible(IVideoWindow *iface, LONG visible) { struct video_window *window = impl_from_IVideoWindow(iface); TRACE("window %p, visible %d.\n", window, visible); ShowWindow(window->hwnd, visible ? SW_SHOW : SW_HIDE); return S_OK; } HRESULT WINAPI BaseControlWindowImpl_get_Visible(IVideoWindow *iface, LONG *visible) { struct video_window *window = impl_from_IVideoWindow(iface); TRACE("window %p, visible %p.\n", window, visible); *visible = IsWindowVisible(window->hwnd) ? OATRUE : OAFALSE; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_put_Left(IVideoWindow *iface, LONG left) { struct video_window *window = impl_from_IVideoWindow(iface); RECT rect; TRACE("window %p, left %d.\n", window, left); GetWindowRect(window->hwnd, &rect); if (!SetWindowPos(window->hwnd, NULL, left, rect.top, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE)) return E_FAIL; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_get_Left(IVideoWindow *iface, LONG *left) { struct video_window *window = impl_from_IVideoWindow(iface); RECT rect; TRACE("window %p, left %p.\n", window, left); GetWindowRect(window->hwnd, &rect); *left = rect.left; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_put_Width(IVideoWindow *iface, LONG width) { struct video_window *window = impl_from_IVideoWindow(iface); RECT rect; TRACE("window %p, width %d.\n", window, width); GetWindowRect(window->hwnd, &rect); if (!SetWindowPos(window->hwnd, NULL, 0, 0, width, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE)) return E_FAIL; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_get_Width(IVideoWindow *iface, LONG *width) { struct video_window *window = impl_from_IVideoWindow(iface); RECT rect; TRACE("window %p, width %p.\n", window, width); GetWindowRect(window->hwnd, &rect); *width = rect.right - rect.left; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_put_Top(IVideoWindow *iface, LONG top) { struct video_window *window = impl_from_IVideoWindow(iface); RECT rect; TRACE("window %p, top %d.\n", window, top); GetWindowRect(window->hwnd, &rect); if (!SetWindowPos(window->hwnd, NULL, rect.left, top, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE)) return E_FAIL; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_get_Top(IVideoWindow *iface, LONG *top) { struct video_window *window = impl_from_IVideoWindow(iface); RECT rect; TRACE("window %p, top %p.\n", window, top); GetWindowRect(window->hwnd, &rect); *top = rect.top; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_put_Height(IVideoWindow *iface, LONG height) { struct video_window *window = impl_from_IVideoWindow(iface); RECT rect; TRACE("window %p, height %d.\n", window, height); GetWindowRect(window->hwnd, &rect); if (!SetWindowPos(window->hwnd, NULL, 0, 0, rect.right - rect.left, height, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE)) return E_FAIL; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_get_Height(IVideoWindow *iface, LONG *height) { struct video_window *window = impl_from_IVideoWindow(iface); RECT rect; TRACE("window %p, height %p.\n", window, height); GetWindowRect(window->hwnd, &rect); *height = rect.bottom - rect.top; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_put_Owner(IVideoWindow *iface, OAHWND owner) { struct video_window *window = impl_from_IVideoWindow(iface); HWND hwnd = window->hwnd; TRACE("window %p, owner %#lx.\n", window, owner); /* Make sure we are marked as WS_CHILD before reparenting ourselves, so that * we do not steal focus. LEGO Island depends on this. */ window->hwndOwner = (HWND)owner; if (owner) SetWindowLongPtrW(hwnd, GWL_STYLE, GetWindowLongPtrW(hwnd, GWL_STYLE) | WS_CHILD); else SetWindowLongPtrW(hwnd, GWL_STYLE, GetWindowLongPtrW(hwnd, GWL_STYLE) & ~WS_CHILD); SetParent(hwnd, (HWND)owner); return S_OK; } HRESULT WINAPI BaseControlWindowImpl_get_Owner(IVideoWindow *iface, OAHWND *Owner) { struct video_window *This = impl_from_IVideoWindow(iface); TRACE("(%p/%p)->(%p)\n", This, iface, Owner); *(HWND*)Owner = This->hwndOwner; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_put_MessageDrain(IVideoWindow *iface, OAHWND Drain) { struct video_window *This = impl_from_IVideoWindow(iface); TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Drain); This->hwndDrain = (HWND)Drain; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_get_MessageDrain(IVideoWindow *iface, OAHWND *Drain) { struct video_window *This = impl_from_IVideoWindow(iface); TRACE("(%p/%p)->(%p)\n", This, iface, Drain); *Drain = (OAHWND)This->hwndDrain; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_get_BorderColor(IVideoWindow *iface, LONG *Color) { struct video_window *This = impl_from_IVideoWindow(iface); FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, Color); return S_OK; } HRESULT WINAPI BaseControlWindowImpl_put_BorderColor(IVideoWindow *iface, LONG Color) { struct video_window *This = impl_from_IVideoWindow(iface); FIXME("(%p/%p)->(%d): stub !!!\n", This, iface, Color); return S_OK; } HRESULT WINAPI BaseControlWindowImpl_get_FullScreenMode(IVideoWindow *iface, LONG *FullScreenMode) { TRACE("(%p)->(%p)\n", iface, FullScreenMode); return E_NOTIMPL; } HRESULT WINAPI BaseControlWindowImpl_put_FullScreenMode(IVideoWindow *iface, LONG FullScreenMode) { TRACE("(%p)->(%d)\n", iface, FullScreenMode); return E_NOTIMPL; } HRESULT WINAPI BaseControlWindowImpl_SetWindowForeground(IVideoWindow *iface, LONG focus) { struct video_window *window = impl_from_IVideoWindow(iface); UINT flags = SWP_NOMOVE | SWP_NOSIZE; TRACE("window %p, focus %d.\n", window, focus); if (focus != OAFALSE && focus != OATRUE) return E_INVALIDARG; if (!window->pPin->peer) return VFW_E_NOT_CONNECTED; if (!focus) flags |= SWP_NOACTIVATE; SetWindowPos(window->hwnd, HWND_TOP, 0, 0, 0, 0, flags); return S_OK; } HRESULT WINAPI BaseControlWindowImpl_SetWindowPosition(IVideoWindow *iface, LONG left, LONG top, LONG width, LONG height) { struct video_window *window = impl_from_IVideoWindow(iface); TRACE("window %p, left %d, top %d, width %d, height %d.\n", window, left, top, width, height); if (!SetWindowPos(window->hwnd, NULL, left, top, width, height, SWP_NOACTIVATE | SWP_NOZORDER)) return E_FAIL; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_GetWindowPosition(IVideoWindow *iface, LONG *left, LONG *top, LONG *width, LONG *height) { struct video_window *window = impl_from_IVideoWindow(iface); RECT rect; TRACE("window %p, left %p, top %p, width %p, height %p.\n", window, left, top, width, height); GetWindowRect(window->hwnd, &rect); *left = rect.left; *top = rect.top; *width = rect.right - rect.left; *height = rect.bottom - rect.top; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_NotifyOwnerMessage(IVideoWindow *iface, OAHWND hwnd, LONG message, LONG_PTR wparam, LONG_PTR lparam) { struct video_window *window = impl_from_IVideoWindow(iface); TRACE("window %p, hwnd %#lx, message %#x, wparam %#lx, lparam %#lx.\n", window, hwnd, message, wparam, lparam); /* That these messages are forwarded, and no others, is stated by the * DirectX documentation, and supported by manual testing. */ switch (message) { case WM_ACTIVATEAPP: case WM_DEVMODECHANGE: case WM_DISPLAYCHANGE: case WM_PALETTECHANGED: case WM_PALETTEISCHANGING: case WM_QUERYNEWPALETTE: case WM_SYSCOLORCHANGE: SendMessageW(window->hwnd, message, wparam, lparam); break; } return S_OK; } HRESULT WINAPI BaseControlWindowImpl_GetMinIdealImageSize(IVideoWindow *iface, LONG *width, LONG *height) { struct video_window *window = impl_from_IVideoWindow(iface); RECT rect; TRACE("window %p, width %p, height %p.\n", window, width, height); rect = window->ops->get_default_rect(window); *width = rect.right - rect.left; *height = rect.bottom - rect.top; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_GetMaxIdealImageSize(IVideoWindow *iface, LONG *width, LONG *height) { struct video_window *window = impl_from_IVideoWindow(iface); RECT rect; TRACE("window %p, width %p, height %p.\n", window, width, height); rect = window->ops->get_default_rect(window); *width = rect.right - rect.left; *height = rect.bottom - rect.top; return S_OK; } HRESULT WINAPI BaseControlWindowImpl_GetRestorePosition(IVideoWindow *iface, LONG *pLeft, LONG *pTop, LONG *pWidth, LONG *pHeight) { struct video_window *This = impl_from_IVideoWindow(iface); FIXME("(%p/%p)->(%p, %p, %p, %p): stub !!!\n", This, iface, pLeft, pTop, pWidth, pHeight); return S_OK; } HRESULT WINAPI BaseControlWindowImpl_HideCursor(IVideoWindow *iface, LONG HideCursor) { struct video_window *This = impl_from_IVideoWindow(iface); FIXME("(%p/%p)->(%d): stub !!!\n", This, iface, HideCursor); return S_OK; } HRESULT WINAPI BaseControlWindowImpl_IsCursorHidden(IVideoWindow *iface, LONG *CursorHidden) { struct video_window *This = impl_from_IVideoWindow(iface); FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, CursorHidden); return S_OK; } static inline struct video_window *impl_from_IBasicVideo(IBasicVideo *iface) { return CONTAINING_RECORD(iface, struct video_window, IBasicVideo_iface); } static HRESULT WINAPI basic_video_QueryInterface(IBasicVideo *iface, REFIID iid, void **out) { struct video_window *window = impl_from_IBasicVideo(iface); return IUnknown_QueryInterface(window->pFilter->outer_unk, iid, out); } static ULONG WINAPI basic_video_AddRef(IBasicVideo *iface) { struct video_window *window = impl_from_IBasicVideo(iface); return IUnknown_AddRef(window->pFilter->outer_unk); } static ULONG WINAPI basic_video_Release(IBasicVideo *iface) { struct video_window *window = impl_from_IBasicVideo(iface); return IUnknown_Release(window->pFilter->outer_unk); } static HRESULT WINAPI basic_video_GetTypeInfoCount(IBasicVideo *iface, UINT *count) { TRACE("iface %p, count %p.\n", iface, count); *count = 1; return S_OK; } static HRESULT WINAPI basic_video_GetTypeInfo(IBasicVideo *iface, UINT index, LCID lcid, ITypeInfo **typeinfo) { TRACE("iface %p, index %u, lcid %#x, typeinfo %p.\n", iface, index, lcid, typeinfo); return strmbase_get_typeinfo(IBasicVideo_tid, typeinfo); } static HRESULT WINAPI basic_video_GetIDsOfNames(IBasicVideo *iface, REFIID iid, LPOLESTR *names, UINT count, LCID lcid, DISPID *ids) { ITypeInfo *typeinfo; HRESULT hr; TRACE("iface %p, iid %s, names %p, count %u, lcid %#x, ids %p.\n", iface, debugstr_guid(iid), names, count, lcid, ids); if (SUCCEEDED(hr = strmbase_get_typeinfo(IBasicVideo_tid, &typeinfo))) { hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, ids); ITypeInfo_Release(typeinfo); } return hr; } static HRESULT WINAPI basic_video_Invoke(IBasicVideo *iface, DISPID id, REFIID iid, LCID lcid, WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *error_arg) { ITypeInfo *typeinfo; HRESULT hr; TRACE("iface %p, id %d, iid %s, lcid %#x, flags %#x, params %p, result %p, excepinfo %p, error_arg %p.\n", iface, id, debugstr_guid(iid), lcid, flags, params, result, excepinfo, error_arg); if (SUCCEEDED(hr = strmbase_get_typeinfo(IBasicVideo_tid, &typeinfo))) { hr = ITypeInfo_Invoke(typeinfo, iface, id, flags, params, result, excepinfo, error_arg); ITypeInfo_Release(typeinfo); } return hr; } static const VIDEOINFOHEADER *get_video_format(struct video_window *window) { /* Members of VIDEOINFOHEADER up to bmiHeader are identical to those of * VIDEOINFOHEADER2. */ return (const VIDEOINFOHEADER *)window->pPin->mt.pbFormat; } static const BITMAPINFOHEADER *get_bitmap_header(struct video_window *window) { const AM_MEDIA_TYPE *mt = &window->pPin->mt; if (IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo)) return &((VIDEOINFOHEADER *)mt->pbFormat)->bmiHeader; else return &((VIDEOINFOHEADER2 *)mt->pbFormat)->bmiHeader; } static HRESULT WINAPI basic_video_get_AvgTimePerFrame(IBasicVideo *iface, REFTIME *reftime) { struct video_window *window = impl_from_IBasicVideo(iface); if (!reftime) return E_POINTER; if (!window->pPin->peer) return VFW_E_NOT_CONNECTED; TRACE("window %p, reftime %p.\n", window, reftime); *reftime = get_video_format(window)->AvgTimePerFrame; return S_OK; } static HRESULT WINAPI basic_video_get_BitRate(IBasicVideo *iface, LONG *rate) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, rate %p.\n", window, rate); if (!rate) return E_POINTER; if (!window->pPin->peer) return VFW_E_NOT_CONNECTED; *rate = get_video_format(window)->dwBitRate; return S_OK; } static HRESULT WINAPI basic_video_get_BitErrorRate(IBasicVideo *iface, LONG *rate) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, rate %p.\n", window, rate); if (!rate) return E_POINTER; if (!window->pPin->peer) return VFW_E_NOT_CONNECTED; *rate = get_video_format(window)->dwBitErrorRate; return S_OK; } static HRESULT WINAPI basic_video_get_VideoWidth(IBasicVideo *iface, LONG *width) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, width %p.\n", window, width); if (!width) return E_POINTER; *width = get_bitmap_header(window)->biWidth; return S_OK; } static HRESULT WINAPI basic_video_get_VideoHeight(IBasicVideo *iface, LONG *height) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, height %p.\n", window, height); if (!height) return E_POINTER; *height = abs(get_bitmap_header(window)->biHeight); return S_OK; } static HRESULT WINAPI basic_video_put_SourceLeft(IBasicVideo *iface, LONG left) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, left %d.\n", window, left); if (left < 0 || window->src.right + left - window->src.left > get_bitmap_header(window)->biWidth) return E_INVALIDARG; OffsetRect(&window->src, left - window->src.left, 0); return S_OK; } static HRESULT WINAPI basic_video_get_SourceLeft(IBasicVideo *iface, LONG *left) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, left %p.\n", window, left); if (!left) return E_POINTER; *left = window->src.left; return S_OK; } static HRESULT WINAPI basic_video_put_SourceWidth(IBasicVideo *iface, LONG width) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, width %d.\n", window, width); if (width <= 0 || window->src.left + width > get_bitmap_header(window)->biWidth) return E_INVALIDARG; window->src.right = window->src.left + width; return S_OK; } static HRESULT WINAPI basic_video_get_SourceWidth(IBasicVideo *iface, LONG *width) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, width %p.\n", window, width); if (!width) return E_POINTER; *width = window->src.right - window->src.left; return S_OK; } static HRESULT WINAPI basic_video_put_SourceTop(IBasicVideo *iface, LONG top) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, top %d.\n", window, top); if (top < 0 || window->src.bottom + top - window->src.top > get_bitmap_header(window)->biHeight) return E_INVALIDARG; OffsetRect(&window->src, 0, top - window->src.top); return S_OK; } static HRESULT WINAPI basic_video_get_SourceTop(IBasicVideo *iface, LONG *top) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, top %p.\n", window, top); if (!top) return E_POINTER; *top = window->src.top; return S_OK; } static HRESULT WINAPI basic_video_put_SourceHeight(IBasicVideo *iface, LONG height) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, height %d.\n", window, height); if (height <= 0 || window->src.top + height > get_bitmap_header(window)->biHeight) return E_INVALIDARG; window->src.bottom = window->src.top + height; return S_OK; } static HRESULT WINAPI basic_video_get_SourceHeight(IBasicVideo *iface, LONG *height) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, height %p\n", window, height); if (!height) return E_POINTER; *height = window->src.bottom - window->src.top; return S_OK; } static HRESULT WINAPI basic_video_put_DestinationLeft(IBasicVideo *iface, LONG left) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, left %d.\n", window, left); window->default_dst = FALSE; OffsetRect(&window->dst, left - window->dst.left, 0); return S_OK; } static HRESULT WINAPI basic_video_get_DestinationLeft(IBasicVideo *iface, LONG *left) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, left %p.\n", window, left); if (!left) return E_POINTER; *left = window->dst.left; return S_OK; } static HRESULT WINAPI basic_video_put_DestinationWidth(IBasicVideo *iface, LONG width) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, width %d.\n", window, width); if (width <= 0) return E_INVALIDARG; window->default_dst = FALSE; window->dst.right = window->dst.left + width; return S_OK; } static HRESULT WINAPI basic_video_get_DestinationWidth(IBasicVideo *iface, LONG *width) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, width %p.\n", window, width); if (!width) return E_POINTER; *width = window->dst.right - window->dst.left; return S_OK; } static HRESULT WINAPI basic_video_put_DestinationTop(IBasicVideo *iface, LONG top) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, top %d.\n", window, top); window->default_dst = FALSE; OffsetRect(&window->dst, 0, top - window->dst.top); return S_OK; } static HRESULT WINAPI basic_video_get_DestinationTop(IBasicVideo *iface, LONG *top) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, top %p.\n", window, top); if (!top) return E_POINTER; *top = window->dst.top; return S_OK; } static HRESULT WINAPI basic_video_put_DestinationHeight(IBasicVideo *iface, LONG height) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, height %d.\n", window, height); if (height <= 0) return E_INVALIDARG; window->default_dst = FALSE; window->dst.bottom = window->dst.top + height; return S_OK; } static HRESULT WINAPI basic_video_get_DestinationHeight(IBasicVideo *iface, LONG *height) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, height %p.\n", window, height); if (!height) return E_POINTER; *height = window->dst.bottom - window->dst.top; return S_OK; } static HRESULT WINAPI basic_video_SetSourcePosition(IBasicVideo *iface, LONG left, LONG top, LONG width, LONG height) { struct video_window *window = impl_from_IBasicVideo(iface); const BITMAPINFOHEADER *bitmap_header = get_bitmap_header(window); TRACE("window %p, left %d, top %d, width %d, height %d.\n", window, left, top, width, height); if (left < 0 || left + width > bitmap_header->biWidth || width <= 0) return E_INVALIDARG; if (top < 0 || top + height > bitmap_header->biHeight || height <= 0) return E_INVALIDARG; SetRect(&window->src, left, top, left + width, top + height); return S_OK; } static HRESULT WINAPI basic_video_GetSourcePosition(IBasicVideo *iface, LONG *left, LONG *top, LONG *width, LONG *height) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, left %p, top %p, width %p, height %p.\n", window, left, top, width, height); if (!left || !top || !width || !height) return E_POINTER; *left = window->src.left; *top = window->src.top; *width = window->src.right - window->src.left; *height = window->src.bottom - window->src.top; return S_OK; } static HRESULT WINAPI basic_video_SetDefaultSourcePosition(IBasicVideo *iface) { struct video_window *window = impl_from_IBasicVideo(iface); const BITMAPINFOHEADER *bitmap_header = get_bitmap_header(window); TRACE("window %p.\n", window); SetRect(&window->src, 0, 0, bitmap_header->biWidth, bitmap_header->biHeight); return S_OK; } static HRESULT WINAPI basic_video_SetDestinationPosition(IBasicVideo *iface, LONG left, LONG top, LONG width, LONG height) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, left %d, top %d, width %d, height %d.\n", window, left, top, width, height); if (width <= 0 || height <= 0) return E_INVALIDARG; window->default_dst = FALSE; SetRect(&window->dst, left, top, left + width, top + height); return S_OK; } static HRESULT WINAPI basic_video_GetDestinationPosition(IBasicVideo *iface, LONG *left, LONG *top, LONG *width, LONG *height) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, left %p, top %p, width %p, height %p.\n", window, left, top, width, height); if (!left || !top || !width || !height) return E_POINTER; *left = window->dst.left; *top = window->dst.top; *width = window->dst.right - window->dst.left; *height = window->dst.bottom - window->dst.top; return S_OK; } static HRESULT WINAPI basic_video_SetDefaultDestinationPosition(IBasicVideo *iface) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p.\n", window); window->default_dst = TRUE; GetClientRect(window->hwnd, &window->dst); return S_OK; } static HRESULT WINAPI basic_video_GetVideoSize(IBasicVideo *iface, LONG *width, LONG *height) { struct video_window *window = impl_from_IBasicVideo(iface); const BITMAPINFOHEADER *bitmap_header = get_bitmap_header(window); TRACE("window %p, width %p, height %p.\n", window, width, height); if (!width || !height) return E_POINTER; *width = bitmap_header->biWidth; *height = bitmap_header->biHeight; return S_OK; } static HRESULT WINAPI basic_video_GetVideoPaletteEntries(IBasicVideo *iface, LONG start, LONG count, LONG *ret_count, LONG *palette) { struct video_window *window = impl_from_IBasicVideo(iface); FIXME("window %p, start %d, count %d, ret_count %p, palette %p, stub!\n", window, start, count, ret_count, palette); if (!ret_count || !palette) return E_POINTER; *ret_count = 0; return VFW_E_NO_PALETTE_AVAILABLE; } static HRESULT WINAPI basic_video_GetCurrentImage(IBasicVideo *iface, LONG *size, LONG *image) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p, size %p, image %p.\n", window, size, image); if (!size || !image) return E_POINTER; return window->ops->get_current_image(window, size, image); } static HRESULT WINAPI basic_video_IsUsingDefaultSource(IBasicVideo *iface) { struct video_window *window = impl_from_IBasicVideo(iface); const BITMAPINFOHEADER *bitmap_header = get_bitmap_header(window); TRACE("window %p.\n", window); if (!window->src.left && !window->src.top && window->src.right == bitmap_header->biWidth && window->src.bottom == bitmap_header->biHeight) return S_OK; return S_FALSE; } static HRESULT WINAPI basic_video_IsUsingDefaultDestination(IBasicVideo *iface) { struct video_window *window = impl_from_IBasicVideo(iface); TRACE("window %p.\n", window); return window->default_dst ? S_OK : S_FALSE; } static const IBasicVideoVtbl basic_video_vtbl = { basic_video_QueryInterface, basic_video_AddRef, basic_video_Release, basic_video_GetTypeInfoCount, basic_video_GetTypeInfo, basic_video_GetIDsOfNames, basic_video_Invoke, basic_video_get_AvgTimePerFrame, basic_video_get_BitRate, basic_video_get_BitErrorRate, basic_video_get_VideoWidth, basic_video_get_VideoHeight, basic_video_put_SourceLeft, basic_video_get_SourceLeft, basic_video_put_SourceWidth, basic_video_get_SourceWidth, basic_video_put_SourceTop, basic_video_get_SourceTop, basic_video_put_SourceHeight, basic_video_get_SourceHeight, basic_video_put_DestinationLeft, basic_video_get_DestinationLeft, basic_video_put_DestinationWidth, basic_video_get_DestinationWidth, basic_video_put_DestinationTop, basic_video_get_DestinationTop, basic_video_put_DestinationHeight, basic_video_get_DestinationHeight, basic_video_SetSourcePosition, basic_video_GetSourcePosition, basic_video_SetDefaultSourcePosition, basic_video_SetDestinationPosition, basic_video_GetDestinationPosition, basic_video_SetDefaultDestinationPosition, basic_video_GetVideoSize, basic_video_GetVideoPaletteEntries, basic_video_GetCurrentImage, basic_video_IsUsingDefaultSource, basic_video_IsUsingDefaultDestination }; void video_window_unregister_class(void) { if (!UnregisterClassW(class_name, NULL) && GetLastError() != ERROR_CLASS_DOES_NOT_EXIST) ERR("Failed to unregister class, error %u.\n", GetLastError()); } void video_window_init(struct video_window *window, const IVideoWindowVtbl *vtbl, struct strmbase_filter *owner, struct strmbase_pin *pin, const struct video_window_ops *ops) { memset(window, 0, sizeof(*window)); window->ops = ops; window->IVideoWindow_iface.lpVtbl = vtbl; window->IBasicVideo_iface.lpVtbl = &basic_video_vtbl; window->default_dst = TRUE; window->AutoShow = OATRUE; window->pFilter = owner; window->pPin = pin; } void video_window_cleanup(struct video_window *window) { if (window->hwnd) { /* Media Player Classic deadlocks if WM_PARENTNOTIFY is sent, so clear * the child style first. Just like Windows, we don't actually unparent * the window, to prevent extra focus events from being generated since * it would become top-level for a brief period before being destroyed. */ SetWindowLongW(window->hwnd, GWL_STYLE, GetWindowLongW(window->hwnd, GWL_STYLE) & ~WS_CHILD); SendMessageW(window->hwnd, WM_CLOSE, 0, 0); window->hwnd = NULL; } }