michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:expandtab:shiftwidth=2:tabstop=2: michael@0: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsWinUtils.h" michael@0: michael@0: #include "Compatibility.h" michael@0: #include "DocAccessible.h" michael@0: #include "nsCoreUtils.h" michael@0: michael@0: #include "mozilla/Preferences.h" michael@0: #include "nsArrayUtils.h" michael@0: #include "nsIArray.h" michael@0: #include "nsIDocument.h" michael@0: #include "nsIDocShellTreeItem.h" michael@0: #include "nsXULAppAPI.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::a11y; michael@0: michael@0: // Window property used by ipc related code in identifying accessible michael@0: // tab windows. michael@0: const wchar_t* kPropNameTabContent = L"AccessibleTabWindow"; michael@0: michael@0: /** michael@0: * WindowProc to process WM_GETOBJECT messages, used in windows emulation mode. michael@0: */ michael@0: static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, michael@0: WPARAM wParam, LPARAM lParam); michael@0: michael@0: nsRefPtrHashtable, DocAccessible>* nsWinUtils::sHWNDCache = nullptr; michael@0: michael@0: already_AddRefed michael@0: nsWinUtils::GetComputedStyleDeclaration(nsIContent* aContent) michael@0: { michael@0: nsIContent* elm = nsCoreUtils::GetDOMElementFor(aContent); michael@0: if (!elm) michael@0: return nullptr; michael@0: michael@0: // Returns number of items in style declaration michael@0: nsCOMPtr window = michael@0: do_QueryInterface(elm->OwnerDoc()->GetWindow()); michael@0: if (!window) michael@0: return nullptr; michael@0: michael@0: nsCOMPtr cssDecl; michael@0: nsCOMPtr domElement(do_QueryInterface(elm)); michael@0: window->GetComputedStyle(domElement, EmptyString(), getter_AddRefs(cssDecl)); michael@0: return cssDecl.forget(); michael@0: } michael@0: michael@0: bool michael@0: nsWinUtils::MaybeStartWindowEmulation() michael@0: { michael@0: // Register window class that'll be used for document accessibles associated michael@0: // with tabs. michael@0: if (Compatibility::IsJAWS() || Compatibility::IsWE() || michael@0: Compatibility::IsDolphin() || michael@0: XRE_GetProcessType() == GeckoProcessType_Content) { michael@0: RegisterNativeWindow(kClassNameTabContent); michael@0: sHWNDCache = new nsRefPtrHashtable, DocAccessible>(4); michael@0: return true; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: nsWinUtils::ShutdownWindowEmulation() michael@0: { michael@0: // Unregister window call that's used for document accessibles associated michael@0: // with tabs. michael@0: if (IsWindowEmulationStarted()) michael@0: ::UnregisterClassW(kClassNameTabContent, GetModuleHandle(nullptr)); michael@0: } michael@0: michael@0: bool michael@0: nsWinUtils::IsWindowEmulationStarted() michael@0: { michael@0: return sHWNDCache != nullptr; michael@0: } michael@0: michael@0: void michael@0: nsWinUtils::RegisterNativeWindow(LPCWSTR aWindowClass) michael@0: { michael@0: WNDCLASSW wc; michael@0: wc.style = CS_GLOBALCLASS; michael@0: wc.lpfnWndProc = WindowProc; michael@0: wc.cbClsExtra = 0; michael@0: wc.cbWndExtra = 0; michael@0: wc.hInstance = GetModuleHandle(nullptr); michael@0: wc.hIcon = nullptr; michael@0: wc.hCursor = nullptr; michael@0: wc.hbrBackground = nullptr; michael@0: wc.lpszMenuName = nullptr; michael@0: wc.lpszClassName = aWindowClass; michael@0: ::RegisterClassW(&wc); michael@0: } michael@0: michael@0: HWND michael@0: nsWinUtils::CreateNativeWindow(LPCWSTR aWindowClass, HWND aParentWnd, michael@0: int aX, int aY, int aWidth, int aHeight, michael@0: bool aIsActive) michael@0: { michael@0: HWND hwnd = ::CreateWindowExW(WS_EX_TRANSPARENT, aWindowClass, michael@0: L"NetscapeDispatchWnd", michael@0: WS_CHILD | (aIsActive ? WS_VISIBLE : 0), michael@0: aX, aY, aWidth, aHeight, michael@0: aParentWnd, michael@0: nullptr, michael@0: GetModuleHandle(nullptr), michael@0: nullptr); michael@0: if (hwnd) { michael@0: // Mark this window so that ipc related code can identify it. michael@0: ::SetPropW(hwnd, kPropNameTabContent, (HANDLE)1); michael@0: } michael@0: return hwnd; michael@0: } michael@0: michael@0: void michael@0: nsWinUtils::ShowNativeWindow(HWND aWnd) michael@0: { michael@0: ::ShowWindow(aWnd, SW_SHOW); michael@0: } michael@0: michael@0: void michael@0: nsWinUtils::HideNativeWindow(HWND aWnd) michael@0: { michael@0: ::SetWindowPos(aWnd, nullptr, 0, 0, 0, 0, michael@0: SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | michael@0: SWP_NOZORDER | SWP_NOACTIVATE); michael@0: } michael@0: michael@0: LRESULT CALLBACK michael@0: WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) michael@0: { michael@0: // Note, this window's message handling should not invoke any call that michael@0: // may result in a cross-process ipc call. Doing so may violate RPC michael@0: // message semantics. michael@0: michael@0: switch (msg) { michael@0: case WM_GETOBJECT: michael@0: { michael@0: if (lParam == OBJID_CLIENT) { michael@0: DocAccessible* document = michael@0: nsWinUtils::sHWNDCache->GetWeak(static_cast(hWnd)); michael@0: if (document) { michael@0: IAccessible* msaaAccessible = nullptr; michael@0: document->GetNativeInterface((void**)&msaaAccessible); // does an addref michael@0: if (msaaAccessible) { michael@0: LRESULT result = ::LresultFromObject(IID_IAccessible, wParam, michael@0: msaaAccessible); // does an addref michael@0: msaaAccessible->Release(); // release extra addref michael@0: return result; michael@0: } michael@0: } michael@0: } michael@0: return 0; michael@0: } michael@0: case WM_NCHITTEST: michael@0: { michael@0: LRESULT lRet = ::DefWindowProc(hWnd, msg, wParam, lParam); michael@0: if (HTCLIENT == lRet) michael@0: lRet = HTTRANSPARENT; michael@0: return lRet; michael@0: } michael@0: } michael@0: michael@0: return ::DefWindowProcW(hWnd, msg, wParam, lParam); michael@0: }