Kaydet (Commit) 3ecf542a authored tarafından Maxim Monastirsky's avatar Maxim Monastirsky Kaydeden (comit) Miklos Vajna

Different approach for tdf#115227

This reverts the previous attempt of commit
250ad931 ("tdf#115227 svtools:
suppress UNO notifications for color selectors"), in favor of
a different fix. The advantage of this new approach is that
is doesn't affect events other than activate/deativate, and that
it covers more cases: Toolbar popups even if not based on
svtools::ToolbarPopup, or if closed by clicking outside them,
font name/size and paragraph style toolbar controls, notebookbar,
context and main menus (for the non gtk3 native case, the gtk3
native menus left for a future investigation). For now, keep this
logic inside toolkit, but ideally it should be in vcl (after
reviewing vcl internal listeners).

One side effect that I noticed after this change, is that there is
a deactivation/activation pair which suppressed when e.g. opening a
new document from the start center. But I'm not sure if that's a
problem, given that the focus state of the top window as a whole
wasn't changed, only its contents, and there are other APIs to track
activation of document components. This happens because the source
and the target windows of those events are the same, and we need to
suppress this case to fix the font name/size style controls, and also
the color picker after 27473d1c
("tdf#114935 Move the focus back to the document"). Otherwise we'll
need to find another way to move the focus to the document w/o
triggering listeners.

Another case that will see a change in behavior, is document event
listeners in dbaccess, as the Focus/UnFocus events there are based
on top window activation/deactivation. However, I think it's a good
change, as currently just opening of a toolbar popup or main/context
menus there triggers those document events, making them useless.

I would like to also mention here, that in fact those top window
activation events never really worked as tdf#115227 expects them, as
the superfluous events for at least the font name/size, style and
color toolbar buttons existed already in OOo. The behavior of the
color buttons changed in LO for a few years, but regressed again in
the work on a real focus grabbing for floating windows starting with
commit dd46727b ("Resolves; tdf#87120
no keyboard navigation inside floating windows"). That work also
introduced superfluous events when using menus.

And a note about the change in menubarwindow.cxx: When a menubar
popup is closed it's deleted using the lazydelete mechanism, which
reparents the popup window, so it doesn't appear anymore in the
hierarchy of the document window. Moreover, I suspect that at some
point the lazydelete thing will be replaced by a VclPtr mechanism,
which might break this even further, so the event won't appear as
coming from the popup window (which might be already disposed at
this stage). So instead, temporarily set the menubar window as the
current focus window, so the activation will appear as if it was
coming from the menu bar window itself.

Change-Id: I292232adfcbd1a31d66ce394cd2f1bf42a013ecb
Reviewed-on: https://gerrit.libreoffice.org/48746Reviewed-by: 's avatarMaxim Monastirsky <momonasmon@gmail.com>
Tested-by: 's avatarJenkins <ci@libreoffice.org>
üst 303f8e51
......@@ -233,23 +233,6 @@ public:
virtual css::uno::Reference< css::awt::XStyleSettings > SAL_CALL getStyleSettings() override;
};
class TOOLKIT_DLLPUBLIC VclListenerLock
{
private:
VCLXWindow* m_pLockWindow;
public:
explicit VclListenerLock(VCLXWindow* _pLockWindow);
/**
* @param bSystemWindow - if pVclWindow or its first system window parent
* is locked.
*/
explicit VclListenerLock(vcl::Window* pVclWindow, bool bSystemWindow);
~VclListenerLock();
VclListenerLock(const VclListenerLock&) = delete;
VclListenerLock& operator=(const VclListenerLock&) = delete;
};
#endif // INCLUDED_TOOLKIT_AWT_VCLXWINDOW_HXX
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
......@@ -35,7 +35,6 @@
#include <svtools/framestatuslistener.hxx>
#include <svtools/valueset.hxx>
#include <svtools/toolbarmenu.hxx>
#include <toolkit/awt/vclxwindow.hxx>
#include "toolbarmenuimp.hxx"
using namespace ::com::sun::star::uno;
......@@ -1487,7 +1486,6 @@ bool ToolbarPopup::IsInPopupMode()
void ToolbarPopup::EndPopupMode()
{
VclListenerLock aLock(this, /*bSystemWindow=*/true);
GetDockingManager()->EndPopupMode(this);
}
......
......@@ -19,7 +19,6 @@
#include <cppuhelper/supportsservice.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <toolkit/awt/vclxwindow.hxx>
#include <vcl/toolbox.hxx>
#include <vcl/svapp.hxx>
......@@ -214,8 +213,6 @@ Reference< awt::XWindow > SAL_CALL PopupWindowController::createPopupWindow()
pWin->EnableDocking();
mxImpl->SetPopupWindow(pWin,pToolBox);
VclListenerLock aLock(pWin, /*bSystemWindow=*/true);
vcl::Window::GetDockingManager()->StartPopupMode( pToolBox, pWin, eFloatFlags );
}
}
......
......@@ -517,23 +517,43 @@ void VCLXWindow::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
}
break;
case VclEventId::WindowActivate:
{
if ( mpImpl->getTopWindowListeners().getLength() )
{
css::lang::EventObject aEvent;
aEvent.Source = static_cast<cppu::OWeakObject*>(this);
mpImpl->getTopWindowListeners().windowActivated( aEvent );
}
}
break;
case VclEventId::WindowDeactivate:
{
if ( mpImpl->getTopWindowListeners().getLength() )
if (!mpImpl->getTopWindowListeners().getLength())
return;
// Suppress events which are unlikely to be interesting to our listeners.
vcl::Window* pWin = static_cast<vcl::Window*>(rVclWindowEvent.GetData());
bool bSuppress = false;
while (pWin)
{
css::lang::EventObject aEvent;
aEvent.Source = static_cast<cppu::OWeakObject*>(this);
mpImpl->getTopWindowListeners().windowDeactivated( aEvent );
// Either the event came from the same window, from its
// child, or from a child of its border window (e.g.
// menubar or notebookbar).
if (pWin->GetWindow(GetWindowType::Client) == GetWindow())
return;
if (pWin->IsMenuFloatingWindow())
bSuppress = true;
if (pWin->GetType() == WindowType::FLOATINGWINDOW &&
static_cast<FloatingWindow*>(pWin)->IsInPopupMode())
bSuppress = true;
// Otherwise, don't suppress if the event came from a different frame.
if (!bSuppress && pWin->GetWindow(GetWindowType::Frame) == pWin)
break;
pWin = pWin->GetWindow(GetWindowType::RealParent);
}
css::lang::EventObject aEvent;
aEvent.Source = static_cast<cppu::OWeakObject*>(this);
if (rVclWindowEvent.GetId() == VclEventId::WindowActivate)
mpImpl->getTopWindowListeners().windowActivated( aEvent );
else
mpImpl->getTopWindowListeners().windowDeactivated( aEvent );
}
break;
case VclEventId::WindowClose:
......
......@@ -94,50 +94,27 @@ static Sequence< OUString> lcl_ImplGetPropertyNames( const Reference< XMultiProp
return aNames;
}
namespace
{
VCLXWindow* GetParentSystemWindow(vcl::Window* pWindow)
{
while (pWindow)
{
if (pWindow->IsSystemWindow())
break;
pWindow = pWindow->GetParent();
}
uno::Reference<awt::XWindow> xWindow = VCLUnoHelper::GetInterface(pWindow);
return VCLXWindow::GetImplementation(xWindow);
}
}
VclListenerLock::VclListenerLock(VCLXWindow* _pLockWindow)
: m_pLockWindow(_pLockWindow)
class VclListenerLock
{
if (m_pLockWindow)
m_pLockWindow->suspendVclEventListening();
}
private:
VCLXWindow* m_pLockWindow;
VclListenerLock::VclListenerLock(vcl::Window* pVclWindow, bool bSystemWindow)
: m_pLockWindow(nullptr)
{
if (bSystemWindow)
m_pLockWindow = GetParentSystemWindow(pVclWindow);
else
public:
explicit VclListenerLock( VCLXWindow* _pLockWindow )
: m_pLockWindow( _pLockWindow )
{
uno::Reference<awt::XWindow> xWindow = VCLUnoHelper::GetInterface(pVclWindow);
m_pLockWindow = VCLXWindow::GetImplementation(xWindow);
if ( m_pLockWindow )
m_pLockWindow->suspendVclEventListening( );
}
if (m_pLockWindow)
m_pLockWindow->suspendVclEventListening();
}
VclListenerLock::~VclListenerLock()
{
if (m_pLockWindow)
m_pLockWindow->resumeVclEventListening();
}
~VclListenerLock()
{
if ( m_pLockWindow )
m_pLockWindow->resumeVclEventListening( );
}
VclListenerLock(const VclListenerLock&) = delete;
VclListenerLock& operator=(const VclListenerLock&) = delete;
};
typedef ::std::map< OUString, sal_Int32 > MapString2Int;
struct UnoControl_Data
......
......@@ -517,7 +517,14 @@ void MenuBarWindow::ChangeHighlightItem( sal_uInt16 n, bool bSelectEntry, bool b
VclPtr<vcl::Window> xTempFocusId = xSaveFocusId;
xSaveFocusId = nullptr;
if (bAllowRestoreFocus)
{
// tdf#115227 the popup is already killed, so temporarily set us as the
// focus window, so we could avoid sending superfluous activate events
// to top window listeners.
ImplGetSVData()->maWinData.mpFocusWin = this;
Window::EndSaveFocus(xTempFocusId);
assert(xTempFocusId == nullptr || ImplGetSVData()->maWinData.mpFocusWin != this);
}
// #105406# restore focus to document if we could not save focus before
if (bDefaultToDocument && xTempFocusId == nullptr && bAllowRestoreFocus)
GrabFocusToDocument();
......
......@@ -3258,7 +3258,7 @@ void Window::ImplCallDeactivateListeners( vcl::Window *pNew )
if ( !pNew || !ImplIsChild( pNew ) )
{
VclPtr<vcl::Window> xWindow(this);
CallEventListeners( VclEventId::WindowDeactivate );
CallEventListeners( VclEventId::WindowDeactivate, pNew );
if( xWindow->IsDisposed() )
return;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment