|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim:expandtab:shiftwidth=2:tabstop=2: |
|
3 */ |
|
4 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
5 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
7 |
|
8 #include "nsWinUtils.h" |
|
9 |
|
10 #include "Compatibility.h" |
|
11 #include "DocAccessible.h" |
|
12 #include "nsCoreUtils.h" |
|
13 |
|
14 #include "mozilla/Preferences.h" |
|
15 #include "nsArrayUtils.h" |
|
16 #include "nsIArray.h" |
|
17 #include "nsIDocument.h" |
|
18 #include "nsIDocShellTreeItem.h" |
|
19 #include "nsXULAppAPI.h" |
|
20 |
|
21 using namespace mozilla; |
|
22 using namespace mozilla::a11y; |
|
23 |
|
24 // Window property used by ipc related code in identifying accessible |
|
25 // tab windows. |
|
26 const wchar_t* kPropNameTabContent = L"AccessibleTabWindow"; |
|
27 |
|
28 /** |
|
29 * WindowProc to process WM_GETOBJECT messages, used in windows emulation mode. |
|
30 */ |
|
31 static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, |
|
32 WPARAM wParam, LPARAM lParam); |
|
33 |
|
34 nsRefPtrHashtable<nsPtrHashKey<void>, DocAccessible>* nsWinUtils::sHWNDCache = nullptr; |
|
35 |
|
36 already_AddRefed<nsIDOMCSSStyleDeclaration> |
|
37 nsWinUtils::GetComputedStyleDeclaration(nsIContent* aContent) |
|
38 { |
|
39 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aContent); |
|
40 if (!elm) |
|
41 return nullptr; |
|
42 |
|
43 // Returns number of items in style declaration |
|
44 nsCOMPtr<nsIDOMWindow> window = |
|
45 do_QueryInterface(elm->OwnerDoc()->GetWindow()); |
|
46 if (!window) |
|
47 return nullptr; |
|
48 |
|
49 nsCOMPtr<nsIDOMCSSStyleDeclaration> cssDecl; |
|
50 nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(elm)); |
|
51 window->GetComputedStyle(domElement, EmptyString(), getter_AddRefs(cssDecl)); |
|
52 return cssDecl.forget(); |
|
53 } |
|
54 |
|
55 bool |
|
56 nsWinUtils::MaybeStartWindowEmulation() |
|
57 { |
|
58 // Register window class that'll be used for document accessibles associated |
|
59 // with tabs. |
|
60 if (Compatibility::IsJAWS() || Compatibility::IsWE() || |
|
61 Compatibility::IsDolphin() || |
|
62 XRE_GetProcessType() == GeckoProcessType_Content) { |
|
63 RegisterNativeWindow(kClassNameTabContent); |
|
64 sHWNDCache = new nsRefPtrHashtable<nsPtrHashKey<void>, DocAccessible>(4); |
|
65 return true; |
|
66 } |
|
67 |
|
68 return false; |
|
69 } |
|
70 |
|
71 void |
|
72 nsWinUtils::ShutdownWindowEmulation() |
|
73 { |
|
74 // Unregister window call that's used for document accessibles associated |
|
75 // with tabs. |
|
76 if (IsWindowEmulationStarted()) |
|
77 ::UnregisterClassW(kClassNameTabContent, GetModuleHandle(nullptr)); |
|
78 } |
|
79 |
|
80 bool |
|
81 nsWinUtils::IsWindowEmulationStarted() |
|
82 { |
|
83 return sHWNDCache != nullptr; |
|
84 } |
|
85 |
|
86 void |
|
87 nsWinUtils::RegisterNativeWindow(LPCWSTR aWindowClass) |
|
88 { |
|
89 WNDCLASSW wc; |
|
90 wc.style = CS_GLOBALCLASS; |
|
91 wc.lpfnWndProc = WindowProc; |
|
92 wc.cbClsExtra = 0; |
|
93 wc.cbWndExtra = 0; |
|
94 wc.hInstance = GetModuleHandle(nullptr); |
|
95 wc.hIcon = nullptr; |
|
96 wc.hCursor = nullptr; |
|
97 wc.hbrBackground = nullptr; |
|
98 wc.lpszMenuName = nullptr; |
|
99 wc.lpszClassName = aWindowClass; |
|
100 ::RegisterClassW(&wc); |
|
101 } |
|
102 |
|
103 HWND |
|
104 nsWinUtils::CreateNativeWindow(LPCWSTR aWindowClass, HWND aParentWnd, |
|
105 int aX, int aY, int aWidth, int aHeight, |
|
106 bool aIsActive) |
|
107 { |
|
108 HWND hwnd = ::CreateWindowExW(WS_EX_TRANSPARENT, aWindowClass, |
|
109 L"NetscapeDispatchWnd", |
|
110 WS_CHILD | (aIsActive ? WS_VISIBLE : 0), |
|
111 aX, aY, aWidth, aHeight, |
|
112 aParentWnd, |
|
113 nullptr, |
|
114 GetModuleHandle(nullptr), |
|
115 nullptr); |
|
116 if (hwnd) { |
|
117 // Mark this window so that ipc related code can identify it. |
|
118 ::SetPropW(hwnd, kPropNameTabContent, (HANDLE)1); |
|
119 } |
|
120 return hwnd; |
|
121 } |
|
122 |
|
123 void |
|
124 nsWinUtils::ShowNativeWindow(HWND aWnd) |
|
125 { |
|
126 ::ShowWindow(aWnd, SW_SHOW); |
|
127 } |
|
128 |
|
129 void |
|
130 nsWinUtils::HideNativeWindow(HWND aWnd) |
|
131 { |
|
132 ::SetWindowPos(aWnd, nullptr, 0, 0, 0, 0, |
|
133 SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | |
|
134 SWP_NOZORDER | SWP_NOACTIVATE); |
|
135 } |
|
136 |
|
137 LRESULT CALLBACK |
|
138 WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) |
|
139 { |
|
140 // Note, this window's message handling should not invoke any call that |
|
141 // may result in a cross-process ipc call. Doing so may violate RPC |
|
142 // message semantics. |
|
143 |
|
144 switch (msg) { |
|
145 case WM_GETOBJECT: |
|
146 { |
|
147 if (lParam == OBJID_CLIENT) { |
|
148 DocAccessible* document = |
|
149 nsWinUtils::sHWNDCache->GetWeak(static_cast<void*>(hWnd)); |
|
150 if (document) { |
|
151 IAccessible* msaaAccessible = nullptr; |
|
152 document->GetNativeInterface((void**)&msaaAccessible); // does an addref |
|
153 if (msaaAccessible) { |
|
154 LRESULT result = ::LresultFromObject(IID_IAccessible, wParam, |
|
155 msaaAccessible); // does an addref |
|
156 msaaAccessible->Release(); // release extra addref |
|
157 return result; |
|
158 } |
|
159 } |
|
160 } |
|
161 return 0; |
|
162 } |
|
163 case WM_NCHITTEST: |
|
164 { |
|
165 LRESULT lRet = ::DefWindowProc(hWnd, msg, wParam, lParam); |
|
166 if (HTCLIENT == lRet) |
|
167 lRet = HTTRANSPARENT; |
|
168 return lRet; |
|
169 } |
|
170 } |
|
171 |
|
172 return ::DefWindowProcW(hWnd, msg, wParam, lParam); |
|
173 } |