Bug 596094 - Restore plugin subclass when Flash resets it in full screen mode (ipc...
[mozilla-central.git] / modules / plugin / base / src / nsPluginNativeWindowWin.cpp
blob8a7bc14a0af2be9845bb989f536ff985633f84ce
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Andrei Volkov <av@netscape.com>
24 * Brian Stell <bstell@netscape.com>
25 * Peter Lubczynski <peterl@netscape.com>
26 * Jim Mathies <jmathies@mozilla.com>
28 * Alternatively, the contents of this file may be used under the terms of
29 * either the GNU General Public License Version 2 or later (the "GPL"), or
30 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
42 #include "windows.h"
43 #include "windowsx.h"
45 // XXXbz windowsx.h defines GetFirstChild, GetNextSibling,
46 // GetPrevSibling are macros, apparently... Eeevil. We have functions
47 // called that on some classes, so undef them.
48 #undef GetFirstChild
49 #undef GetNextSibling
50 #undef GetPrevSibling
52 #include "nsDebug.h"
54 #include "nsGUIEvent.h"
55 #include "nsWindowsDllInterceptor.h"
56 #include "nsPluginSafety.h"
57 #include "nsPluginNativeWindow.h"
58 #include "nsThreadUtils.h"
59 #include "nsAutoPtr.h"
60 #include "nsTWeakRef.h"
62 #define NP_POPUP_API_VERSION 16
64 #define nsMajorVersion(v) (((PRInt32)(v) >> 16) & 0xffff)
65 #define nsMinorVersion(v) ((PRInt32)(v) & 0xffff)
66 #define versionOK(suppliedV, requiredV) \
67 (nsMajorVersion(suppliedV) == nsMajorVersion(requiredV) \
68 && nsMinorVersion(suppliedV) >= nsMinorVersion(requiredV))
71 #define NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION TEXT("MozillaPluginWindowPropertyAssociation")
72 #define NS_PLUGIN_CUSTOM_MSG_ID TEXT("MozFlashUserRelay")
73 #define WM_USER_FLASH WM_USER+1
74 static UINT sWM_FLASHBOUNCEMSG = 0;
76 typedef nsTWeakRef<class nsPluginNativeWindowWin> PluginWindowWeakRef;
78 /**
79 * PLEvent handling code
81 class PluginWindowEvent : public nsRunnable {
82 public:
83 PluginWindowEvent();
84 void Init(const PluginWindowWeakRef &ref, HWND hWnd, UINT msg, WPARAM wParam,
85 LPARAM lParam);
86 void Clear();
87 HWND GetWnd() { return mWnd; };
88 UINT GetMsg() { return mMsg; };
89 WPARAM GetWParam() { return mWParam; };
90 LPARAM GetLParam() { return mLParam; };
91 PRBool InUse() { return (mWnd!=NULL); };
93 NS_DECL_NSIRUNNABLE
95 protected:
96 PluginWindowWeakRef mPluginWindowRef;
97 HWND mWnd;
98 UINT mMsg;
99 WPARAM mWParam;
100 LPARAM mLParam;
103 PluginWindowEvent::PluginWindowEvent()
105 Clear();
108 void PluginWindowEvent::Clear()
110 mWnd = NULL;
111 mMsg = 0;
112 mWParam = 0;
113 mLParam = 0;
116 void PluginWindowEvent::Init(const PluginWindowWeakRef &ref, HWND aWnd,
117 UINT aMsg, WPARAM aWParam, LPARAM aLParam)
119 NS_ASSERTION(aWnd != NULL, "invalid plugin event value");
120 NS_ASSERTION(mWnd == NULL, "event already in use");
121 mPluginWindowRef = ref;
122 mWnd = aWnd;
123 mMsg = aMsg;
124 mWParam = aWParam;
125 mLParam = aLParam;
129 * nsPluginNativeWindow Windows specific class declaration
132 typedef enum {
133 nsPluginType_Unknown = 0,
134 nsPluginType_Flash,
135 nsPluginType_Real,
136 nsPluginType_PDF,
137 nsPluginType_Other
138 } nsPluginType;
140 class nsPluginNativeWindowWin : public nsPluginNativeWindow {
141 public:
142 nsPluginNativeWindowWin();
143 virtual ~nsPluginNativeWindowWin();
145 virtual nsresult CallSetWindow(nsCOMPtr<nsIPluginInstance> &aPluginInstance);
147 private:
148 #ifndef WINCE
149 nsresult SubclassAndAssociateWindow();
150 nsresult UndoSubclassAndAssociateWindow();
151 #endif
153 public:
154 // locals
155 WNDPROC GetPrevWindowProc();
156 void SetPrevWindowProc(WNDPROC proc) { mPluginWinProc = proc; }
157 WNDPROC GetWindowProc();
158 PluginWindowEvent * GetPluginWindowEvent(HWND aWnd,
159 UINT aMsg,
160 WPARAM aWParam,
161 LPARAM aLParam);
163 private:
164 WNDPROC mPluginWinProc;
165 WNDPROC mPrevWinProc;
166 PluginWindowWeakRef mWeakRef;
167 nsRefPtr<PluginWindowEvent> mCachedPluginWindowEvent;
169 HWND mParentWnd;
170 LONG_PTR mParentProc;
171 public:
172 nsPluginType mPluginType;
175 static PRBool sInMessageDispatch = PR_FALSE;
176 static PRBool sInPreviousMessageDispatch = PR_FALSE;
177 static UINT sLastMsg = 0;
179 static PRBool ProcessFlashMessageDelayed(nsPluginNativeWindowWin * aWin, nsIPluginInstance * aInst,
180 HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
182 NS_ENSURE_TRUE(aWin, NS_ERROR_NULL_POINTER);
183 NS_ENSURE_TRUE(aInst, NS_ERROR_NULL_POINTER);
185 if (msg == sWM_FLASHBOUNCEMSG) {
186 // See PluginWindowEvent::Run() below.
187 NS_ASSERTION((sWM_FLASHBOUNCEMSG != 0), "RegisterWindowMessage failed in flash plugin WM_USER message handling!");
188 NS_TRY_SAFE_CALL_VOID(::CallWindowProc((WNDPROC)aWin->GetWindowProc(), hWnd, WM_USER_FLASH, wParam, lParam),
189 aInst);
190 return TRUE;
193 if (msg != WM_USER_FLASH)
194 return PR_FALSE; // no need to delay
196 // do stuff
197 nsCOMPtr<nsIRunnable> pwe = aWin->GetPluginWindowEvent(hWnd, msg, wParam, lParam);
198 if (pwe) {
199 NS_DispatchToCurrentThread(pwe);
200 return PR_TRUE;
202 return PR_FALSE;
205 class nsDelayedPopupsEnabledEvent : public nsRunnable
207 public:
208 nsDelayedPopupsEnabledEvent(nsIPluginInstance *inst)
209 : mInst(inst)
212 NS_DECL_NSIRUNNABLE
214 private:
215 nsCOMPtr<nsIPluginInstance> mInst;
218 NS_IMETHODIMP nsDelayedPopupsEnabledEvent::Run()
220 mInst->PushPopupsEnabledState(PR_FALSE);
221 return NS_OK;
225 * New plugin window procedure
227 static LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
229 nsPluginNativeWindowWin * win = (nsPluginNativeWindowWin *)::GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION);
230 if (!win)
231 return TRUE;
233 // The DispatchEvent(NS_PLUGIN_ACTIVATE) below can trigger a reentrant focus
234 // event which might destroy us. Hold a strong ref on the plugin instance
235 // to prevent that, bug 374229.
236 nsCOMPtr<nsIPluginInstance> inst;
237 win->GetPluginInstance(inst);
239 // Real may go into a state where it recursivly dispatches the same event
240 // when subclassed. If this is Real, lets examine the event and drop it
241 // on the floor if we get into this recursive situation. See bug 192914.
242 if (win->mPluginType == nsPluginType_Real) {
243 if (sInMessageDispatch && msg == sLastMsg)
244 return PR_TRUE;
245 // Cache the last message sent
246 sLastMsg = msg;
249 PRBool enablePopups = PR_FALSE;
251 // Activate/deactivate mouse capture on the plugin widget
252 // here, before we pass the Windows event to the plugin
253 // because its possible our widget won't get paired events
254 // (see bug 131007) and we'll look frozen. Note that this
255 // is also done in ChildWindow::DispatchMouseEvent.
256 switch (msg) {
257 case WM_LBUTTONDOWN:
258 case WM_MBUTTONDOWN:
259 case WM_RBUTTONDOWN: {
260 nsCOMPtr<nsIWidget> widget;
261 win->GetPluginWidget(getter_AddRefs(widget));
262 if (widget)
263 widget->CaptureMouse(PR_TRUE);
264 break;
266 case WM_LBUTTONUP:
267 enablePopups = PR_TRUE;
269 // fall through
270 case WM_MBUTTONUP:
271 case WM_RBUTTONUP: {
272 nsCOMPtr<nsIWidget> widget;
273 win->GetPluginWidget(getter_AddRefs(widget));
274 if (widget)
275 widget->CaptureMouse(PR_FALSE);
276 break;
278 case WM_KEYDOWN:
279 // Ignore repeating keydown messages...
280 if ((lParam & 0x40000000) != 0) {
281 break;
284 // fall through
285 case WM_KEYUP:
286 enablePopups = PR_TRUE;
288 break;
290 #ifndef WINCE
291 case WM_MOUSEACTIVATE: {
292 // If a child window of this plug-in is already focused,
293 // don't focus the parent to avoid focus dance. We'll
294 // receive a follow up WM_SETFOCUS which will notify
295 // the appropriate window anyway.
296 HWND focusedWnd = ::GetFocus();
297 if (!::IsChild((HWND)win->window, focusedWnd)) {
298 // Notify the dom / focus manager the plugin has focus when one of
299 // it's child windows receives it. OOPP specific - this code is
300 // critical in notifying the dom of focus changes when the plugin
301 // window in the child process receives focus via a mouse click.
302 // WM_MOUSEACTIVATE is sent by nsWindow via a custom window event
303 // sent from PluginInstanceParent in response to focus events sent
304 // from the child. (bug 540052) Note, this gui event could also be
305 // sent directly from widget.
306 nsCOMPtr<nsIWidget> widget;
307 win->GetPluginWidget(getter_AddRefs(widget));
308 if (widget) {
309 nsGUIEvent event(PR_TRUE, NS_PLUGIN_ACTIVATE, widget);
310 nsEventStatus status;
311 widget->DispatchEvent(&event, status);
315 break;
317 case WM_SETFOCUS:
318 case WM_KILLFOCUS: {
319 // RealPlayer can crash, don't process the message for those,
320 // see bug 328675.
321 if (win->mPluginType == nsPluginType_Real && msg == sLastMsg)
322 return TRUE;
323 // Make sure setfocus and killfocus get through to the widget procedure
324 // even if they are eaten by the plugin. Also make sure we aren't calling
325 // recursively.
326 WNDPROC prevWndProc = win->GetPrevWindowProc();
327 if (prevWndProc && !sInPreviousMessageDispatch) {
328 sInPreviousMessageDispatch = PR_TRUE;
329 ::CallWindowProc(prevWndProc, hWnd, msg, wParam, lParam);
330 sInPreviousMessageDispatch = PR_FALSE;
332 break;
334 #endif
337 // Macromedia Flash plugin may flood the message queue with some special messages
338 // (WM_USER+1) causing 100% CPU consumption and GUI freeze, see mozilla bug 132759;
339 // we can prevent this from happening by delaying the processing such messages;
340 if (win->mPluginType == nsPluginType_Flash) {
341 if (ProcessFlashMessageDelayed(win, inst, hWnd, msg, wParam, lParam))
342 return TRUE;
345 if (enablePopups && inst) {
346 PRUint16 apiVersion;
347 if (NS_SUCCEEDED(inst->GetPluginAPIVersion(&apiVersion)) &&
348 !versionOK(apiVersion, NP_POPUP_API_VERSION)) {
349 inst->PushPopupsEnabledState(PR_TRUE);
353 sInMessageDispatch = PR_TRUE;
355 LRESULT res = TRUE;
356 NS_TRY_SAFE_CALL_RETURN(res,
357 ::CallWindowProc((WNDPROC)win->GetWindowProc(), hWnd, msg, wParam, lParam),
358 inst);
360 sInMessageDispatch = PR_FALSE;
362 if (inst) {
363 // Popups are enabled (were enabled before the call to
364 // CallWindowProc()). Some plugins (at least the flash player)
365 // post messages from their key handlers etc that delay the actual
366 // processing, so we need to delay the disabling of popups so that
367 // popups remain enabled when the flash player ends up processing
368 // the actual key handlers. We do this by posting an event that
369 // does the disabling, this way our disabling will happen after
370 // the handlers in the plugin are done.
372 // Note that it's not fatal if any of this fails (which won't
373 // happen unless we're out of memory anyways) since the plugin
374 // code will pop any popup state pushed by this plugin on
375 // destruction.
377 nsCOMPtr<nsIRunnable> event = new nsDelayedPopupsEnabledEvent(inst);
378 if (event)
379 NS_DispatchToCurrentThread(event);
382 return res;
386 * Flash will reset the subclass of our widget at various times.
387 * (Notably when entering and exiting full screen mode.) This
388 * occurs independent of the main plugin window event procedure.
389 * We trap these subclass calls to prevent our subclass hook from
390 * getting dropped.
391 * Note, ascii versions can be nixed once flash versions < 10.1
392 * are considered obsolete.
394 static WindowsDllInterceptor sUser32Intercept;
396 #ifdef _WIN64
397 typedef LONG_PTR
398 (WINAPI *User32SetWindowLongPtrA)(HWND hWnd,
399 int nIndex,
400 LONG_PTR dwNewLong);
401 typedef LONG_PTR
402 (WINAPI *User32SetWindowLongPtrW)(HWND hWnd,
403 int nIndex,
404 LONG_PTR dwNewLong);
405 static User32SetWindowLongPtrA sUser32SetWindowLongAHookStub = NULL;
406 static User32SetWindowLongPtrW sUser32SetWindowLongWHookStub = NULL;
407 #else
408 typedef LONG
409 (WINAPI *User32SetWindowLongA)(HWND hWnd,
410 int nIndex,
411 LONG dwNewLong);
412 typedef LONG
413 (WINAPI *User32SetWindowLongW)(HWND hWnd,
414 int nIndex,
415 LONG dwNewLong);
416 static User32SetWindowLongA sUser32SetWindowLongAHookStub = NULL;
417 static User32SetWindowLongW sUser32SetWindowLongWHookStub = NULL;
418 #endif
419 static inline PRBool
420 SetWindowLongHookCheck(HWND hWnd,
421 int nIndex,
422 LONG_PTR newLong)
424 nsPluginNativeWindowWin * win =
425 (nsPluginNativeWindowWin *)GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION);
426 if (!win || (win && win->mPluginType != nsPluginType_Flash) ||
427 (nIndex == GWLP_WNDPROC &&
428 newLong == reinterpret_cast<LONG_PTR>(PluginWndProc)))
429 return PR_TRUE;
430 return PR_FALSE;
433 #ifdef _WIN64
434 LONG_PTR WINAPI
435 SetWindowLongPtrAHook(HWND hWnd,
436 int nIndex,
437 LONG_PTR newLong)
438 #else
439 LONG WINAPI
440 SetWindowLongAHook(HWND hWnd,
441 int nIndex,
442 LONG newLong)
443 #endif
445 if (SetWindowLongHookCheck(hWnd, nIndex, newLong))
446 return sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong);
448 // Set flash's new subclass to get the result.
449 LONG_PTR proc = sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong);
451 // We already checked this in SetWindowLongHookCheck
452 nsPluginNativeWindowWin * win =
453 (nsPluginNativeWindowWin *)GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION);
455 // Hook our subclass back up, just like we do on setwindow.
456 win->SetPrevWindowProc(
457 reinterpret_cast<WNDPROC>(sUser32SetWindowLongAHookStub(hWnd, nIndex,
458 reinterpret_cast<LONG_PTR>(PluginWndProc))));
459 return proc;
462 #ifdef _WIN64
463 LONG_PTR WINAPI
464 SetWindowLongPtrWHook(HWND hWnd,
465 int nIndex,
466 LONG_PTR newLong)
467 #else
468 LONG WINAPI
469 SetWindowLongWHook(HWND hWnd,
470 int nIndex,
471 LONG newLong)
472 #endif
474 if (SetWindowLongHookCheck(hWnd, nIndex, newLong))
475 return sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong);
477 // Set flash's new subclass to get the result.
478 LONG_PTR proc = sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong);
480 // We already checked this in SetWindowLongHookCheck
481 nsPluginNativeWindowWin * win =
482 (nsPluginNativeWindowWin *)GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION);
484 // Hook our subclass back up, just like we do on setwindow.
485 win->SetPrevWindowProc(
486 reinterpret_cast<WNDPROC>(sUser32SetWindowLongWHookStub(hWnd, nIndex,
487 reinterpret_cast<LONG_PTR>(PluginWndProc))));
488 return proc;
491 static void
492 HookSetWindowLongPtr()
494 #ifdef _WIN64
495 // XXX WindowsDllInterceptor doesn't support hooks
496 // in 64-bit builds, disabling this code for now.
497 return;
498 #endif
500 sUser32Intercept.Init("user32.dll");
501 #ifdef _WIN64
502 sUser32Intercept.AddHook("SetWindowLongPtrA", SetWindowLongPtrAHook,
503 (void**) &sUser32SetWindowLongAHookStub);
504 sUser32Intercept.AddHook("SetWindowLongPtrW", SetWindowLongPtrWHook,
505 (void**) &sUser32SetWindowLongWHookStub);
506 #else
507 sUser32Intercept.AddHook("SetWindowLongA", SetWindowLongAHook,
508 (void**) &sUser32SetWindowLongAHookStub);
509 sUser32Intercept.AddHook("SetWindowLongW", SetWindowLongWHook,
510 (void**) &sUser32SetWindowLongWHookStub);
511 #endif
515 * nsPluginNativeWindowWin implementation
517 nsPluginNativeWindowWin::nsPluginNativeWindowWin() : nsPluginNativeWindow()
519 // initialize the struct fields
520 window = nsnull;
521 x = 0;
522 y = 0;
523 width = 0;
524 height = 0;
526 mPrevWinProc = NULL;
527 mPluginWinProc = NULL;
528 mPluginType = nsPluginType_Unknown;
530 mParentWnd = NULL;
531 mParentProc = NULL;
533 if (!sWM_FLASHBOUNCEMSG) {
534 sWM_FLASHBOUNCEMSG = ::RegisterWindowMessage(NS_PLUGIN_CUSTOM_MSG_ID);
538 nsPluginNativeWindowWin::~nsPluginNativeWindowWin()
540 // clear weak reference to self to prevent any pending events from
541 // dereferencing this.
542 mWeakRef.forget();
545 WNDPROC nsPluginNativeWindowWin::GetPrevWindowProc()
547 return mPrevWinProc;
550 WNDPROC nsPluginNativeWindowWin::GetWindowProc()
552 return mPluginWinProc;
555 NS_IMETHODIMP PluginWindowEvent::Run()
557 nsPluginNativeWindowWin *win = mPluginWindowRef.get();
558 if (!win)
559 return NS_OK;
561 HWND hWnd = GetWnd();
562 if (!hWnd)
563 return NS_OK;
565 nsCOMPtr<nsIPluginInstance> inst;
566 win->GetPluginInstance(inst);
568 if (GetMsg() == WM_USER_FLASH) {
569 // XXX Unwind issues related to runnable event callback depth for this
570 // event and destruction of the plugin. (Bug 493601)
571 ::PostMessage(hWnd, sWM_FLASHBOUNCEMSG, GetWParam(), GetLParam());
573 else {
574 // Currently not used, but added so that processing events here
575 // is more generic.
576 NS_TRY_SAFE_CALL_VOID(::CallWindowProc(win->GetWindowProc(),
577 hWnd,
578 GetMsg(),
579 GetWParam(),
580 GetLParam()),
581 inst);
584 Clear();
585 return NS_OK;
588 PluginWindowEvent *
589 nsPluginNativeWindowWin::GetPluginWindowEvent(HWND aWnd, UINT aMsg, WPARAM aWParam, LPARAM aLParam)
591 if (!mWeakRef) {
592 mWeakRef = this;
593 if (!mWeakRef)
594 return nsnull;
597 PluginWindowEvent *event;
599 // We have the ability to alloc if needed in case in the future some plugin
600 // should post multiple PostMessages. However, this could lead to many
601 // alloc's per second which could become a performance issue. See bug 169247.
602 if (!mCachedPluginWindowEvent)
604 event = new PluginWindowEvent();
605 if (!event) return nsnull;
606 mCachedPluginWindowEvent = event;
608 else if (mCachedPluginWindowEvent->InUse())
610 event = new PluginWindowEvent();
611 if (!event) return nsnull;
613 else
615 event = mCachedPluginWindowEvent;
618 event->Init(mWeakRef, aWnd, aMsg, aWParam, aLParam);
619 return event;
622 nsresult nsPluginNativeWindowWin::CallSetWindow(nsCOMPtr<nsIPluginInstance> &aPluginInstance)
624 // Note, 'window' can be null
626 // check the incoming instance, null indicates that window is going away and we are
627 // not interested in subclassing business any more, undo and don't subclass
628 if (!aPluginInstance) {
629 UndoSubclassAndAssociateWindow();
630 nsPluginNativeWindow::CallSetWindow(aPluginInstance);
631 return NS_OK;
634 // check plugin mime type and cache it if it will need special treatment later
635 if (mPluginType == nsPluginType_Unknown) {
636 const char* mimetype = nsnull;
637 aPluginInstance->GetMIMEType(&mimetype);
638 if (mimetype) {
639 if (!strcmp(mimetype, "application/x-shockwave-flash"))
640 mPluginType = nsPluginType_Flash;
641 else if (!strcmp(mimetype, "audio/x-pn-realaudio-plugin"))
642 mPluginType = nsPluginType_Real;
643 else if (!strcmp(mimetype, "application/pdf"))
644 mPluginType = nsPluginType_PDF;
645 else
646 mPluginType = nsPluginType_Other;
650 // WINCE does not subclass windows. See bug 300011 for the details.
651 #ifndef WINCE
652 if (window) {
653 // grab the widget procedure before the plug-in does a subclass in
654 // setwindow. We'll use this in PluginWndProc for forwarding focus
655 // events to the widget.
656 WNDPROC currentWndProc =
657 (WNDPROC)::GetWindowLongPtr((HWND)window, GWLP_WNDPROC);
658 if (!mPrevWinProc && currentWndProc != PluginWndProc)
659 mPrevWinProc = currentWndProc;
661 // PDF plugin v7.0.9, v8.1.3, and v9.0 subclass parent window, bug 531551
662 // V8.2.2 and V9.1 don't have such problem.
663 if (mPluginType == nsPluginType_PDF) {
664 HWND parent = ::GetParent((HWND)window);
665 if (mParentWnd != parent) {
666 NS_ASSERTION(!mParentWnd, "Plugin's parent window changed");
667 mParentWnd = parent;
668 mParentProc = ::GetWindowLongPtr(mParentWnd, GWLP_WNDPROC);
672 #endif
674 nsPluginNativeWindow::CallSetWindow(aPluginInstance);
676 #ifndef WINCE
677 SubclassAndAssociateWindow();
679 if (window && mPluginType == nsPluginType_Flash &&
680 !GetPropW((HWND)window, L"PluginInstanceParentProperty")) {
681 HookSetWindowLongPtr();
683 #endif
685 return NS_OK;
688 #ifndef WINCE
690 nsresult nsPluginNativeWindowWin::SubclassAndAssociateWindow()
692 if (type != NPWindowTypeWindow || !window)
693 return NS_ERROR_FAILURE;
695 HWND hWnd = (HWND)window;
697 // check if we need to subclass
698 WNDPROC currentWndProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_WNDPROC);
699 if (currentWndProc == PluginWndProc)
700 return NS_OK;
702 // If the plugin reset the subclass, set it back.
703 if (mPluginWinProc) {
704 #ifdef DEBUG
705 NS_WARNING("A plugin cleared our subclass - resetting.");
706 if (currentWndProc != mPluginWinProc) {
707 NS_WARNING("Procedures do not match up, discarding old subclass value.");
709 if (mPrevWinProc && currentWndProc == mPrevWinProc) {
710 NS_WARNING("The new procedure is our widget procedure?");
712 #endif
713 SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)PluginWndProc);
714 return NS_OK;
717 LONG_PTR style = GetWindowLongPtr(hWnd, GWL_STYLE);
718 #ifdef MOZ_IPC
719 // Out of process plugins must not have the WS_CLIPCHILDREN style set on their
720 // parent windows or else synchronous paints (via UpdateWindow() and others)
721 // will cause deadlocks.
722 if (::GetPropW(hWnd, L"PluginInstanceParentProperty"))
723 style &= ~WS_CLIPCHILDREN;
724 else
725 style |= WS_CLIPCHILDREN;
726 #else
727 style |= WS_CLIPCHILDREN;
728 #endif
729 SetWindowLongPtr(hWnd, GWL_STYLE, style);
731 mPluginWinProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)PluginWndProc);
732 if (!mPluginWinProc)
733 return NS_ERROR_FAILURE;
735 nsPluginNativeWindowWin * win = (nsPluginNativeWindowWin *)::GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION);
736 NS_ASSERTION(!win || (win == this), "plugin window already has property and this is not us");
738 if (!::SetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION, (HANDLE)this))
739 return NS_ERROR_FAILURE;
741 return NS_OK;
744 nsresult nsPluginNativeWindowWin::UndoSubclassAndAssociateWindow()
746 // release plugin instance
747 SetPluginInstance(nsnull);
749 // remove window property
750 HWND hWnd = (HWND)window;
751 if (IsWindow(hWnd))
752 ::RemoveProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION);
754 // restore the original win proc
755 // but only do this if this were us last time
756 if (mPluginWinProc) {
757 WNDPROC currentWndProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_WNDPROC);
758 if (currentWndProc == PluginWndProc)
759 SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)mPluginWinProc);
760 mPluginWinProc = NULL;
762 LONG_PTR style = GetWindowLongPtr(hWnd, GWL_STYLE);
763 style &= ~WS_CLIPCHILDREN;
764 SetWindowLongPtr(hWnd, GWL_STYLE, style);
767 if (mPluginType == nsPluginType_PDF && mParentWnd) {
768 ::SetWindowLongPtr(mParentWnd, GWLP_WNDPROC, mParentProc);
769 mParentWnd = NULL;
770 mParentProc = NULL;
773 return NS_OK;
775 #endif // WINCE
777 nsresult PLUG_NewPluginNativeWindow(nsPluginNativeWindow ** aPluginNativeWindow)
779 NS_ENSURE_ARG_POINTER(aPluginNativeWindow);
781 *aPluginNativeWindow = new nsPluginNativeWindowWin();
783 return *aPluginNativeWindow ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
786 nsresult PLUG_DeletePluginNativeWindow(nsPluginNativeWindow * aPluginNativeWindow)
788 NS_ENSURE_ARG_POINTER(aPluginNativeWindow);
789 nsPluginNativeWindowWin *p = (nsPluginNativeWindowWin *)aPluginNativeWindow;
790 delete p;
791 return NS_OK;