Kaydet (Commit) 27473d1c authored tarafından Maxim Monastirsky's avatar Maxim Monastirsky

tdf#114935 Move the focus back to the document

... after selecting a color from a floating picker, similar
to what we do for the font name/size toolbar controls.

But moving the focus didn't work properly under gtk2, as it
was cycling the focus between the floater and the main
window with each click. The cause for this was the
GrabFocus call made by ValueSet/PushButton upon clicking,
which resulted in a XSetInputFocus in GtkSalFrame::ToTop.
But removing this XSetInputFocus would break keyboard
handling inside floating windows (as in tdf#104368),
given that GtkSalFrame::Init sets the input hint to false.
Setting the input hint to false is a hack needed for some
WMs to not steal the focus from the main window, when
showing floating toolbars. This mostly affects Compiz and
Metacity (and its forks Marco and Muffin, but fixed in
recent Mutter - see gnome#773210). Other WMs nowadays seems
to deduce the desired no-focus initial state, from the
toolbar window type hint.

According to wm-spec, one way to make a newly mapped window
not steal the focus is to set 0 to _NET_WM_USER_TIME (and
this method is indeed used by gtk). This helps for Compiz
(w/o messing with the input hint), but not for Metacity,
which will anyway unfocus the parent window.

The only solution that seems to work so far, is to start
with the input hint as false, and change it to true after
the window is mapped. And do this craziness only for
Metacity and its forks, just in case... (although I didn't
actually notice any problems with this in place, under
other WMs.)

(I also considered fixing tdf#114935 by making ValueSet/
PushButton not grab the focus on click, by setting
WB_NOPOINTERFOCUS on them. But that will be just a partial
solution, as e.g. if a user selects a different palette
from the palettes list, the focus will stuck in that list.)

Change-Id: Id8241bc809c445ff4e46f1a747b9af5ed57e5a1c
Reviewed-on: https://gerrit.libreoffice.org/47690Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarMaxim Monastirsky <momonasmon@gmail.com>
üst 1ec49f8a
...@@ -333,7 +333,8 @@ void PaletteManager::DispatchColorCommand(const OUString& aCommand, const NamedC ...@@ -333,7 +333,8 @@ void PaletteManager::DispatchColorCommand(const OUString& aCommand, const NamedC
Reference<XComponentContext> xContext(comphelper::getProcessComponentContext()); Reference<XComponentContext> xContext(comphelper::getProcessComponentContext());
Reference<XDesktop2> xDesktop = Desktop::create(xContext); Reference<XDesktop2> xDesktop = Desktop::create(xContext);
Reference<XDispatchProvider> xDispatchProvider(xDesktop->getCurrentFrame(), UNO_QUERY ); Reference<XFrame> xFrame(xDesktop->getCurrentFrame());
Reference<XDispatchProvider> xDispatchProvider(xFrame, UNO_QUERY);
if (xDispatchProvider.is()) if (xDispatchProvider.is())
{ {
INetURLObject aObj( aCommand ); INetURLObject aObj( aCommand );
...@@ -349,7 +350,11 @@ void PaletteManager::DispatchColorCommand(const OUString& aCommand, const NamedC ...@@ -349,7 +350,11 @@ void PaletteManager::DispatchColorCommand(const OUString& aCommand, const NamedC
Reference<XDispatch> xDispatch = xDispatchProvider->queryDispatch(aTargetURL, OUString(), 0); Reference<XDispatch> xDispatch = xDispatchProvider->queryDispatch(aTargetURL, OUString(), 0);
if (xDispatch.is()) if (xDispatch.is())
{
xDispatch->dispatch(aTargetURL, aArgs); xDispatch->dispatch(aTargetURL, aArgs);
if (xFrame->getContainerWindow().is())
xFrame->getContainerWindow()->setFocus();
}
} }
} }
......
...@@ -1051,33 +1051,26 @@ void GtkSalFrame::InitCommon() ...@@ -1051,33 +1051,26 @@ void GtkSalFrame::InitCommon()
None ); None );
} }
static void lcl_set_accept_focus( GtkWindow* pWindow, gboolean bAccept, bool bBeforeRealize ) static void lcl_set_accept_focus( GtkWindow* pWindow )
{ {
if (bBeforeRealize) if (GetGtkSalData()->GetGtkDisplay()->getWMAdaptor()->getWindowManagerName().startsWith("Metacity") ||
gtk_window_set_accept_focus( pWindow, bAccept ); GetGtkSalData()->GetGtkDisplay()->getWMAdaptor()->getWindowManagerName().endsWith("Muffin)") )
else if( ! bBeforeRealize )
{ {
Display* pDisplay = GetGtkSalData()->GetGtkDisplay()->GetDisplay(); /* Metacity considers a toolbar type window as should not
::Window aWindow = widget_get_xid(GTK_WIDGET(pWindow)); * have focus on mapping, yet it believes it should unfocus
XWMHints* pHints = XGetWMHints( pDisplay, aWindow ); * the parent window... So convince Metacity to not do so,
if( ! pHints ) * by disabling the focus until the window is mapped. We
{ * will restore the focus later in the map signal.
pHints = XAllocWMHints(); */
pHints->flags = 0; gtk_window_set_accept_focus( pWindow, false );
}
pHints->flags |= InputHint;
pHints->input = bAccept ? True : False;
XSetWMHints( pDisplay, aWindow, pHints );
XFree( pHints );
if (GetGtkSalData()->GetGtkDisplay()->getWMAdaptor()->getWindowManagerName() == "compiz")
return;
/* remove WM_TAKE_FOCUS protocol; this would usually be the /* remove WM_TAKE_FOCUS protocol; this would usually be the
* right thing, but gtk handles it internally whereas we * right thing, but gtk handles it internally whereas we
* want to handle it ourselves (as to sometimes not get * want to handle it ourselves (as to sometimes not get
* the focus) * the focus)
*/ */
Display* pDisplay = GetGtkSalData()->GetGtkDisplay()->GetDisplay();
::Window aWindow = widget_get_xid(GTK_WIDGET(pWindow));
Atom* pProtocols = nullptr; Atom* pProtocols = nullptr;
int nProtocols = 0; int nProtocols = 0;
XGetWMProtocols( pDisplay, XGetWMProtocols( pDisplay,
...@@ -1106,25 +1099,12 @@ static void lcl_set_accept_focus( GtkWindow* pWindow, gboolean bAccept, bool bBe ...@@ -1106,25 +1099,12 @@ static void lcl_set_accept_focus( GtkWindow* pWindow, gboolean bAccept, bool bBe
XFree( pProtocols ); XFree( pProtocols );
} }
} }
}
static void lcl_set_user_time( GtkWindow* i_pWindow, guint32 i_nTime )
{
GdkWindow* pWin = widget_get_window(GTK_WIDGET(i_pWindow));
if (pWin) // only if the window is realized.
gdk_x11_window_set_user_time( pWin, i_nTime );
else else
{ {
Display* pDisplay = GetGtkSalData()->GetGtkDisplay()->GetDisplay(); // Only needed for Compiz. The toolbar type hint seems to be enough for other WMs.
Atom nUserTime = XInternAtom( pDisplay, "_NET_WM_USER_TIME", True ); gtk_window_set_focus_on_map( pWindow, false );
if( nUserTime )
{
XChangeProperty( pDisplay, widget_get_xid(GTK_WIDGET(i_pWindow)),
nUserTime, XA_CARDINAL, 32,
PropModeReplace, reinterpret_cast<unsigned char*>(&i_nTime), 1 );
}
} }
}; }
GtkSalFrame *GtkSalFrame::getFromWindow( GtkWindow *pWindow ) GtkSalFrame *GtkSalFrame::getFromWindow( GtkWindow *pWindow )
{ {
...@@ -1214,7 +1194,7 @@ void GtkSalFrame::Init( SalFrame* pParent, SalFrameStyleFlags nStyle ) ...@@ -1214,7 +1194,7 @@ void GtkSalFrame::Init( SalFrame* pParent, SalFrameStyleFlags nStyle )
else if( nStyle & SalFrameStyleFlags::OWNERDRAWDECORATION ) else if( nStyle & SalFrameStyleFlags::OWNERDRAWDECORATION )
{ {
eType = GDK_WINDOW_TYPE_HINT_TOOLBAR; eType = GDK_WINDOW_TYPE_HINT_TOOLBAR;
lcl_set_accept_focus( GTK_WINDOW(m_pWindow), false, true ); lcl_set_accept_focus( GTK_WINDOW(m_pWindow) );
gtk_window_set_decorated( GTK_WINDOW(m_pWindow), false ); gtk_window_set_decorated( GTK_WINDOW(m_pWindow), false );
} }
if( (nStyle & SalFrameStyleFlags::PARTIAL_FULLSCREEN ) if( (nStyle & SalFrameStyleFlags::PARTIAL_FULLSCREEN )
...@@ -1225,31 +1205,18 @@ void GtkSalFrame::Init( SalFrame* pParent, SalFrameStyleFlags nStyle ) ...@@ -1225,31 +1205,18 @@ void GtkSalFrame::Init( SalFrame* pParent, SalFrameStyleFlags nStyle )
} }
gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), eType ); gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), eType );
gtk_window_set_gravity( GTK_WINDOW(m_pWindow), GDK_GRAVITY_STATIC ); gtk_window_set_gravity( GTK_WINDOW(m_pWindow), GDK_GRAVITY_STATIC );
gtk_window_set_resizable( GTK_WINDOW(m_pWindow), bool(nStyle & SalFrameStyleFlags::SIZEABLE) );
} }
else if( nStyle & SalFrameStyleFlags::FLOAT ) else if( nStyle & SalFrameStyleFlags::FLOAT )
gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), GDK_WINDOW_TYPE_HINT_POPUP_MENU ); gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), GDK_WINDOW_TYPE_HINT_POPUP_MENU );
#ifdef ENABLE_GMENU_INTEGRATION
if( eWinType == GTK_WINDOW_TOPLEVEL ) if( eWinType == GTK_WINDOW_TOPLEVEL )
{ {
#ifdef ENABLE_GMENU_INTEGRATION
// Enable DBus native menu if available. // Enable DBus native menu if available.
ensure_dbus_setup( this ); ensure_dbus_setup( this );
#endif
guint32 nUserTime = 0;
if( (nStyle & (SalFrameStyleFlags::OWNERDRAWDECORATION|SalFrameStyleFlags::TOOLWINDOW)) == SalFrameStyleFlags::NONE )
{
nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
}
lcl_set_user_time(GTK_WINDOW(m_pWindow), nUserTime);
}
if( bDecoHandling )
{
gtk_window_set_resizable( GTK_WINDOW(m_pWindow), bool(nStyle & SalFrameStyleFlags::SIZEABLE) );
if( nStyle & SalFrameStyleFlags::OWNERDRAWDECORATION )
lcl_set_accept_focus( GTK_WINDOW(m_pWindow), false, false );
} }
#endif
} }
GdkNativeWindow GtkSalFrame::findTopLevelSystemWindow(GdkNativeWindow aWindow) GdkNativeWindow GtkSalFrame::findTopLevelSystemWindow(GdkNativeWindow aWindow)
...@@ -1521,37 +1488,6 @@ void GtkSalFrame::Show( bool bVisible, bool bNoActivate ) ...@@ -1521,37 +1488,6 @@ void GtkSalFrame::Show( bool bVisible, bool bNoActivate )
m_pParent->grabPointer( true, true ); m_pParent->grabPointer( true, true );
} }
guint32 nUserTime = 0;
if( ! bNoActivate && !(m_nStyle & (SalFrameStyleFlags::OWNERDRAWDECORATION|SalFrameStyleFlags::TOOLWINDOW)) )
nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
//For these floating windows we don't want the main window to lose focus, and metacity has...
// metacity-2.24.0/src/core/window.c
// if ((focus_window != NULL) && XSERVER_TIME_IS_BEFORE (compare, focus_window->net_wm_user_time))
// "compare" window focus prevented by other activity
// where "compare" is this window
// which leads to...
// /* This happens for error dialogs or alerts; these need to remain on
// * top, but it would be confusing to have its ancestor remain
// * focused.
// */
// if (meta_window_is_ancestor_of_transient (focus_window, window))
// "The focus window %s is an ancestor of the newly mapped "
// "window %s which isn't being focused. Unfocusing the "
// "ancestor.\n",
// i.e. having a time < that of the toplevel frame means that the toplevel frame gets unfocused.
// awesome.
if( nUserTime == 0 )
{
nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
}
lcl_set_user_time(GTK_WINDOW(m_pWindow), nUserTime );
if( ! bNoActivate && (m_nStyle & SalFrameStyleFlags::TOOLWINDOW) ) if( ! bNoActivate && (m_nStyle & SalFrameStyleFlags::TOOLWINDOW) )
m_bSetFocusOnMap = true; m_bSetFocusOnMap = true;
...@@ -2121,21 +2057,6 @@ void GtkSalFrame::ToTop( SalFrameToTop nFlags ) ...@@ -2121,21 +2057,6 @@ void GtkSalFrame::ToTop( SalFrameToTop nFlags )
guint32 nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window); guint32 nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
gdk_window_focus( widget_get_window(m_pWindow), nUserTime ); gdk_window_focus( widget_get_window(m_pWindow), nUserTime );
} }
/* need to do an XSetInputFocus here because
* gdk_window_focus will ask a EWMH compliant WM to put the focus
* to our window - which it of course won't since our input hint
* is set to false.
*/
if (m_nStyle & SalFrameStyleFlags::OWNERDRAWDECORATION)
{
// sad but true: this can cause an XError, we need to catch that
// to do this we need to synchronize with the XServer
GetGenericUnixSalData()->ErrorTrapPush();
XSetInputFocus( getDisplay()->GetDisplay(), widget_get_xid(m_pWindow), RevertToParent, CurrentTime );
// fdo#46687 - an XSync should not be necessary - but for some reason it is.
XSync( getDisplay()->GetDisplay(), False );
GetGenericUnixSalData()->ErrorTrapPop();
}
} }
else else
{ {
...@@ -3038,18 +2959,14 @@ gboolean GtkSalFrame::signalMap( GtkWidget *pWidget, GdkEvent*, gpointer frame ) ...@@ -3038,18 +2959,14 @@ gboolean GtkSalFrame::signalMap( GtkWidget *pWidget, GdkEvent*, gpointer frame )
} }
} }
if ( pThis->m_nStyle & SalFrameStyleFlags::OWNERDRAWDECORATION )
gtk_window_set_accept_focus( GTK_WINDOW(pWidget), true );
bool bSetFocus = pThis->m_bSetFocusOnMap; bool bSetFocus = pThis->m_bSetFocusOnMap;
pThis->m_bSetFocusOnMap = false; pThis->m_bSetFocusOnMap = false;
if( bSetFocus ) if( bSetFocus )
{ pThis->ToTop( SalFrameToTop::GrabFocus );
GetGenericUnixSalData()->ErrorTrapPush();
XSetInputFocus( GtkSalFrame::getDisplay()->GetDisplay(),
widget_get_xid(pWidget),
RevertToParent, CurrentTime );
XSync( GtkSalFrame::getDisplay()->GetDisplay(), False );
GetGenericUnixSalData()->ErrorTrapPop();
}
pThis->CallCallback( SalEvent::Resize, nullptr ); pThis->CallCallback( SalEvent::Resize, nullptr );
pThis->TriggerPaintEvent(); pThis->TriggerPaintEvent();
......
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