mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
[OS/2] Bug 516274 - fix plugin focus issues, r=pweilbacher
This commit is contained in:
parent
e5e691bbe1
commit
bdab68be3d
@ -1667,7 +1667,7 @@ nsFocusManager::RaiseWindow(nsPIDOMWindow* aWindow)
|
||||
if (!aWindow || aWindow == mActiveWindow || aWindow == mWindowBeingLowered)
|
||||
return;
|
||||
|
||||
#ifdef XP_WIN
|
||||
#if defined(XP_WIN) || defined(XP_OS2)
|
||||
// Windows would rather we focus the child widget, otherwise, the toplevel
|
||||
// widget will always end up being focused. Fortunately, focusing the child
|
||||
// widget will also have the effect of raising the window this widget is in.
|
||||
|
@ -23,6 +23,7 @@
|
||||
* Andrei Volkov <av@netscape.com>
|
||||
* Brian Stell <bstell@netscape.com>
|
||||
* Peter Lubczynski <peterl@netscape.com>
|
||||
* Rich Walsh <dragtext@e-vertise.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -180,7 +181,6 @@ private:
|
||||
|
||||
public:
|
||||
// locals
|
||||
PFNWP GetPrevWindowProc();
|
||||
PFNWP GetWindowProc();
|
||||
PluginWindowEvent* GetPluginWindowEvent(HWND aWnd,
|
||||
ULONG aMsg,
|
||||
@ -188,7 +188,6 @@ public:
|
||||
MPARAM mp2);
|
||||
|
||||
private:
|
||||
PFNWP mPrevWinProc;
|
||||
PFNWP mPluginWinProc;
|
||||
PluginWindowWeakRef mWeakRef;
|
||||
nsRefPtr<PluginWindowEvent> mCachedPluginWindowEvent;
|
||||
@ -299,15 +298,27 @@ static MRESULT EXPENTRY PluginWndProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM m
|
||||
enablePopups = PR_TRUE;
|
||||
break;
|
||||
|
||||
case WM_SETFOCUS:
|
||||
case WM_FOCUSCHANGE:
|
||||
case WM_FOCUSCHANGED:
|
||||
case WM_ACTIVATE: {
|
||||
// Make sure setfocus and focuschange get through
|
||||
// even if they are eaten by the plugin
|
||||
PFNWP prevWndProc = win->GetPrevWindowProc();
|
||||
if (prevWndProc)
|
||||
prevWndProc(hWnd, msg, mp1, mp2);
|
||||
// When the child of a plugin gets the focus, nsWindow doesn't get
|
||||
// a WM_FOCUSCHANGED msg, so plugin and window activation events
|
||||
// don't happen. This fixes the problem by synthesizing a msg
|
||||
// that makes it look like the plugin widget just got the focus.
|
||||
case WM_FOCUSCHANGE: {
|
||||
|
||||
// Some plugins don't pass this msg on. If the default window proc
|
||||
// doesn't receive it, window activation/deactivation won't happen.
|
||||
WinDefWindowProc(hWnd, msg, mp1, mp2);
|
||||
|
||||
// If focus is being gained, and the plugin widget neither lost
|
||||
// nor gained the focus, then a child just got it from some other
|
||||
// window. Post a WM_FOCUSCHANGED msg that identifies the child
|
||||
// as the window losing focus. After nsWindow::ActivatePlugin()
|
||||
// activates the plugin, it will restore the focus to the child.
|
||||
if (SHORT1FROMMP(mp2) && (HWND)mp1 != hWnd) {
|
||||
HWND hFocus = WinQueryFocus(HWND_DESKTOP);
|
||||
if (hFocus != hWnd) {
|
||||
WinPostMsg(hWnd, WM_FOCUSCHANGED, (MPARAM)hFocus, mp2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -370,7 +381,6 @@ nsPluginNativeWindowOS2::nsPluginNativeWindowOS2() : nsPluginNativeWindow()
|
||||
width = 0;
|
||||
height = 0;
|
||||
|
||||
mPrevWinProc = NULL;
|
||||
mPluginWinProc = NULL;
|
||||
mPluginType = nsPluginType_Unknown;
|
||||
|
||||
@ -391,11 +401,6 @@ nsPluginNativeWindowOS2::~nsPluginNativeWindowOS2()
|
||||
mWeakRef.forget();
|
||||
}
|
||||
|
||||
PFNWP nsPluginNativeWindowOS2::GetPrevWindowProc()
|
||||
{
|
||||
return mPrevWinProc;
|
||||
}
|
||||
|
||||
PFNWP nsPluginNativeWindowOS2::GetWindowProc()
|
||||
{
|
||||
return mPluginWinProc;
|
||||
@ -468,14 +473,6 @@ nsresult nsPluginNativeWindowOS2::CallSetWindow(nsCOMPtr<nsIPluginInstance> &aPl
|
||||
// not interested in subclassing business any more, undo and don't subclass
|
||||
if (!aPluginInstance) {
|
||||
UndoSubclassAndAssociateWindow();
|
||||
mPrevWinProc = NULL;
|
||||
}
|
||||
|
||||
// We need WndProc before plug-ins do subclass in nsPluginNativeWindow::CallSetWindow.
|
||||
if (aPluginInstance) {
|
||||
PFNWP currentWndProc = (PFNWP)::WinQueryWindowPtr((HWND)window, QWP_PFNWP);
|
||||
if (currentWndProc != PluginWndProc)
|
||||
mPrevWinProc = currentWndProc;
|
||||
}
|
||||
|
||||
nsPluginNativeWindow::CallSetWindow(aPluginInstance);
|
||||
|
@ -70,6 +70,7 @@ nsFrameWindow::nsFrameWindow() : nsWindow()
|
||||
{
|
||||
fnwpDefFrame = 0;
|
||||
mWindowType = eWindowType_toplevel;
|
||||
mNeedActivation = PR_FALSE;
|
||||
}
|
||||
|
||||
nsFrameWindow::~nsFrameWindow()
|
||||
@ -322,6 +323,29 @@ nsresult nsFrameWindow::Show( PRBool bState)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// When WM_ACTIVATE is received with the "gaining activation" flag set,
|
||||
// the frame's wndproc sets mNeedActivation. Later, when an nsWindow
|
||||
// gets a WM_FOCUSCHANGED msg with the "gaining focus" flag set, it
|
||||
// invokes this method on nsFrameWindow to fire an NS_ACTIVATE event.
|
||||
|
||||
void nsFrameWindow::ActivateTopLevelWidget()
|
||||
{
|
||||
// Don't fire event if we're minimized or else the window will
|
||||
// be restored as soon as the user clicks on it. When the user
|
||||
// explicitly restores it, SetSizeMode() will call this method.
|
||||
|
||||
if (mNeedActivation) {
|
||||
PRInt32 sizeMode;
|
||||
GetSizeMode(&sizeMode);
|
||||
if (sizeMode != nsSizeMode_Minimized) {
|
||||
mNeedActivation = PR_FALSE;
|
||||
DEBUGFOCUS(NS_ACTIVATE);
|
||||
DispatchFocus(NS_ACTIVATE);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Subclass for frame window
|
||||
MRESULT EXPENTRY fnwpFrame( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
|
||||
{
|
||||
@ -468,11 +492,22 @@ MRESULT nsFrameWindow::FrameMessage( ULONG msg, MPARAM mp1, MPARAM mp2)
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// When the frame is activated, set a flag to be acted on after
|
||||
// PM has finished changing focus. When deactivated, dispatch
|
||||
// the event immediately because it doesn't affect the focus.
|
||||
case WM_ACTIVATE:
|
||||
DEBUGFOCUS(frame WM_ACTIVATE);
|
||||
if (SHORT1FROMMP(mp1) &&
|
||||
!(WinQueryWindowULong(mFrameWnd, QWL_STYLE) & WS_MINIMIZED)) {
|
||||
bDone = DispatchFocus(NS_ACTIVATE);
|
||||
DEBUGFOCUS(WM_ACTIVATE);
|
||||
if (mp1) {
|
||||
mNeedActivation = PR_TRUE;
|
||||
} else {
|
||||
mNeedActivation = PR_FALSE;
|
||||
DEBUGFOCUS(NS_DEACTIVATE);
|
||||
DispatchFocus(NS_DEACTIVATE);
|
||||
// Prevent the frame from automatically focusing any window
|
||||
// when it's reactivated. Let moz set the focus to avoid
|
||||
// having non-widget children of plugins focused in error.
|
||||
WinSetWindowULong(mFrameWnd, QWL_HWNDFOCUSSAVE, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -482,3 +517,4 @@ MRESULT nsFrameWindow::FrameMessage( ULONG msg, MPARAM mp1, MPARAM mp2)
|
||||
|
||||
return mresult;
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,10 @@ class nsFrameWindow : public nsWindow
|
||||
PFNWP fnwpDefFrame;
|
||||
nsSize mSizeClient;
|
||||
nsSize mSizeBorder;
|
||||
PRBool mNeedActivation;
|
||||
|
||||
// Fires NS_ACTIVATE is mNeedActivation is set
|
||||
virtual void ActivateTopLevelWidget();
|
||||
|
||||
// So we can create the frame, parent the client & position it right
|
||||
virtual void RealDoCreate( HWND hwndP, nsWindow *aParent,
|
||||
|
@ -124,9 +124,6 @@ nsIWidget * gRollupWidget = nsnull;
|
||||
PRBool gRollupConsumeRollupEvent = PR_FALSE;
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
PRBool gJustGotActivate = PR_FALSE;
|
||||
PRBool gJustGotDeactivate = PR_FALSE;
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// Mouse Clicks - static variable defintions
|
||||
// for figuring out 1 - 3 Clicks
|
||||
@ -185,6 +182,9 @@ static PRUint32 gDragStatus = 0;
|
||||
#define FAPPCOMMAND_MASK 0xF000
|
||||
#define GET_APPCOMMAND_LPARAM(lParam) ((USHORT)(HIUSHORT(lParam) & ~FAPPCOMMAND_MASK))
|
||||
|
||||
// used to identify plugin widgets (copied from nsPluginNativeWindowOS2.cpp)
|
||||
#define NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION "MozillaPluginWindowPropertyAssociation"
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// nsWindow constructor
|
||||
@ -1141,19 +1141,18 @@ NS_METHOD nsWindow::SetZIndex(PRInt32 aZIndex)
|
||||
|
||||
NS_IMETHODIMP nsWindow::SetSizeMode(PRInt32 aMode)
|
||||
{
|
||||
nsresult rv;
|
||||
PRInt32 previousMode;
|
||||
GetSizeMode(&previousMode);
|
||||
|
||||
// save the requested state
|
||||
rv = nsBaseWidget::SetSizeMode(aMode);
|
||||
// save the new state
|
||||
nsresult rv = nsBaseWidget::SetSizeMode(aMode);
|
||||
|
||||
// this is part of a kludge to keep minimized windows from getting
|
||||
// restored when they get the focus - we defer the activation event
|
||||
// until the window has actually been restored; see WM_FOCUSCHANGED
|
||||
if (gJustGotActivate) {
|
||||
// Minimized windows would get restored involuntarily if we fired an
|
||||
// NS_ACTIVATE when the user clicks on them. Instead, we defer the
|
||||
// activation event until the window has explicitly been restored.
|
||||
if (previousMode == nsSizeMode_Minimized && previousMode != aMode) {
|
||||
DEBUGFOCUS(deferred NS_ACTIVATE);
|
||||
gJustGotActivate = PR_FALSE;
|
||||
gJustGotDeactivate = PR_FALSE;
|
||||
DispatchFocus(NS_ACTIVATE);
|
||||
ActivateTopLevelWidget();
|
||||
}
|
||||
|
||||
// nothing to do in these cases
|
||||
@ -2384,6 +2383,7 @@ void nsWindow::ConstrainZLevel(HWND *aAfter) {
|
||||
NS_IF_RELEASE(event.mActualBelow);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
// 'Window procedure'
|
||||
PRBool nsWindow::ProcessMessage( ULONG msg, MPARAM mp1, MPARAM mp2, MRESULT &rc)
|
||||
@ -2499,12 +2499,10 @@ PRBool nsWindow::ProcessMessage( ULONG msg, MPARAM mp1, MPARAM mp2, MRESULT &rc)
|
||||
case WM_BUTTON1DOWN:
|
||||
if (!mIsScrollBar)
|
||||
WinSetCapture( HWND_DESKTOP, mWnd);
|
||||
result = DispatchMouseEvent( NS_MOUSE_BUTTON_DOWN, mp1, mp2);
|
||||
DispatchMouseEvent( NS_MOUSE_BUTTON_DOWN, mp1, mp2);
|
||||
// there's no need to clear this on button-up
|
||||
gLastButton1Down.x = XFROMMP(mp1);
|
||||
gLastButton1Down.y = YFROMMP(mp1);
|
||||
WinSetActiveWindow(HWND_DESKTOP, mWnd);
|
||||
result = PR_TRUE;
|
||||
break;
|
||||
case WM_BUTTON1UP:
|
||||
if (!mIsScrollBar)
|
||||
@ -2662,58 +2660,25 @@ PRBool nsWindow::ProcessMessage( ULONG msg, MPARAM mp1, MPARAM mp2, MRESULT &rc)
|
||||
result = OnScroll( msg, mp1, mp2);
|
||||
break;
|
||||
|
||||
case WM_ACTIVATE:
|
||||
DEBUGFOCUS(WM_ACTIVATE);
|
||||
if (mp1)
|
||||
gJustGotActivate = PR_TRUE;
|
||||
else
|
||||
gJustGotDeactivate = PR_TRUE;
|
||||
break;
|
||||
// Do not act on WM_ACTIVATE - it is handled by nsFrameWindow.
|
||||
// case WM_ACTIVATE:
|
||||
// break;
|
||||
|
||||
// This msg is used to activate top-level and plugin widgets
|
||||
// after PM is done changing the focus. We're only interested
|
||||
// in windows gaining focus, not in those losing it.
|
||||
case WM_FOCUSCHANGED:
|
||||
{
|
||||
DEBUGFOCUS(WM_FOCUSCHANGED);
|
||||
|
||||
// If the frame was activated earlier or mp1 is 0, dispatch
|
||||
// focus & activation events. However, if the frame is minimized,
|
||||
// defer activation and let SetSizeMode() dispatch it after the
|
||||
// window has been restored by the user - otherwise, Show() will
|
||||
// restore it involuntarily.
|
||||
|
||||
if (SHORT1FROMMP(mp2)) {
|
||||
if (gJustGotActivate || mp1 == 0) {
|
||||
HWND hActive = WinQueryActiveWindow( HWND_DESKTOP);
|
||||
if (!(WinQueryWindowULong( hActive, QWL_STYLE) & WS_MINIMIZED)) {
|
||||
DEBUGFOCUS(NS_ACTIVATE);
|
||||
gJustGotActivate = PR_FALSE;
|
||||
gJustGotDeactivate = PR_FALSE;
|
||||
result = DispatchFocus(NS_ACTIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
if ( WinIsChild( mWnd, HWNDFROMMP(mp1)) && mNextID == 1) {
|
||||
DEBUGFOCUS(NS_PLUGIN_ACTIVATE);
|
||||
result = DispatchFocus(NS_PLUGIN_ACTIVATE);
|
||||
WinSetFocus(HWND_DESKTOP, mWnd);
|
||||
}
|
||||
ActivateTopLevelWidget();
|
||||
ActivatePlugin(HWNDFROMMP(mp1));
|
||||
}
|
||||
// We are losing focus
|
||||
else {
|
||||
if (gJustGotDeactivate) {
|
||||
DEBUGFOCUS(NS_DEACTIVATE);
|
||||
gJustGotDeactivate = PR_FALSE;
|
||||
result = DispatchFocus(NS_DEACTIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
result = OnReposition( (PSWP) mp1);
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case WM_PRESPARAMCHANGED:
|
||||
// This is really for font-change notifies. Do that first.
|
||||
rc = GetPrevWP()( mWnd, msg, mp1, mp2);
|
||||
@ -2735,6 +2700,73 @@ PRBool nsWindow::ProcessMessage( ULONG msg, MPARAM mp1, MPARAM mp2, MRESULT &rc)
|
||||
return result;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// When a window gets the focus, call nsFrameWindow's version of this
|
||||
// method. It will fire an NS_ACTIVATE event on the top-level widget
|
||||
// if appropriate.
|
||||
|
||||
void nsWindow::ActivateTopLevelWidget()
|
||||
{
|
||||
nsWindow * top = static_cast<nsWindow*>(GetTopLevelWidget());
|
||||
if (top) {
|
||||
top->ActivateTopLevelWidget();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// Fire an NS_PLUGIN_ACTIVATE event whenever a window associated with
|
||||
// a plugin widget get the focus.
|
||||
|
||||
void nsWindow::ActivatePlugin(HWND aWnd)
|
||||
{
|
||||
// avoid acting on recursive WM_FOCUSCHANGED msgs
|
||||
static PRBool inPluginActivate = FALSE;
|
||||
if (inPluginActivate) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This property is used by the plugin window to store a pointer
|
||||
// to its plugin object. We just use it as a convenient marker.
|
||||
if (!WinQueryProperty(mWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fire a plugin activation event on the plugin widget.
|
||||
inPluginActivate = TRUE;
|
||||
DEBUGFOCUS(NS_PLUGIN_ACTIVATE);
|
||||
DispatchFocus(NS_PLUGIN_ACTIVATE);
|
||||
|
||||
// Activating the plugin moves the focus off the child that had it,
|
||||
// so try to restore it. If the WM_FOCUSCHANGED msg was synthesized
|
||||
// by the plugin, then mp1 contains the child window that lost focus.
|
||||
// Otherwise, just move it to the plugin's first child unless this
|
||||
// is the mplayer plugin - doing so will put us into an endless loop.
|
||||
// Since its children belong to another process, use the PID as a test.
|
||||
HWND hFocus = 0;
|
||||
if (WinIsChild(aWnd, mWnd)) {
|
||||
hFocus = aWnd;
|
||||
} else {
|
||||
hFocus = WinQueryWindow(mWnd, QW_TOP);
|
||||
if (hFocus) {
|
||||
PID pidFocus, pidThis;
|
||||
TID tid;
|
||||
WinQueryWindowProcess(hFocus, &pidFocus, &tid);
|
||||
WinQueryWindowProcess(mWnd, &pidThis, &tid);
|
||||
if (pidFocus != pidThis) {
|
||||
hFocus = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hFocus) {
|
||||
WinSetFocus(HWND_DESKTOP, hFocus);
|
||||
}
|
||||
|
||||
inPluginActivate = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
|
@ -65,7 +65,7 @@ class imgIContainer;
|
||||
//#define DEBUG_FOCUS
|
||||
|
||||
#ifdef DEBUG_FOCUS
|
||||
#define DEBUGFOCUS(what) printf("[%x] "#what" (%d)\n", (int)this, mWindowIdentifier)
|
||||
#define DEBUGFOCUS(what) fprintf(stderr, "[%8x] %8lx (%02d) "#what"\n", (int)this, mWnd, mWindowIdentifier)
|
||||
#else
|
||||
#define DEBUGFOCUS(what)
|
||||
#endif
|
||||
@ -206,6 +206,9 @@ protected:
|
||||
|
||||
// Return whether message has been processed.
|
||||
virtual PRBool ProcessMessage( ULONG m, MPARAM p1, MPARAM p2, MRESULT &r);
|
||||
|
||||
void ActivatePlugin(HWND aWnd);
|
||||
virtual void ActivateTopLevelWidget();
|
||||
virtual PRBool OnPaint();
|
||||
virtual void OnDestroy();
|
||||
virtual PRBool OnReposition( PSWP pNewSwp);
|
||||
|
Loading…
Reference in New Issue
Block a user