gtk3: New Folder dialog from Templates dialog doesn't get keyboard focus

ctrl+shift+N, and click new folder, no keyboard input is accepted.

The dialogs don't get keyboard events, because the keyboard events
go to the top level window because of...

commit 011ce226e8
Author: Caolán McNamara <caolanm@redhat.com>
Date:   Tue Jan 19 13:22:10 2016 +0000

    Resolves: tdf#99604 ungrab modal dialogs

(should be tdf#96604) which stripped away the grab from the sub dialog

but I did that because menu dropdowns from comboboxes inside modal
dialogs didn't receive mouse focus otherwise.

I had set our "modal" dialogs to be truly modal and triggering that
problem with

commit 8d5822983e
Author: Caolán McNamara <caolanm@redhat.com>
Date:   Mon Dec 14 11:36:50 2015 +0000

    Related: rhbz#1290014 gtk3: use gtk_window_set_modal on modal dialogs

    which makes modal dialogs (which are most of them) place correctly
    under wayland. Modeless ones are still uselessly shoved far to the
    left, but this makes things near usable and gives the same "graying
    into the bg" effect for the main window as other gtk apps

which I still contend is "a good thing"

if we stop removing the grab from the modal dialog, then we need to grab
the keyboard and mouse on to the menu on showing those. This then runs
into the problem that sometimes we want the keyboard to go to one window
and the mouse to go to another, i.e. mouse to the floating menu and the
keypresses to its parent combobox.

Which was the joy of...

commit 27e0fee7da
Author: Caolán McNamara <caolanm@redhat.com>
Date:   Fri Mar 27 15:28:28 2015 +0000

    gnome#745909 grab/ungrab keyboard for menus

and subsequent fix of

commit 57ec66e294
Author: Caolán McNamara <caolanm@redhat.com>
Date:   Thu Jul 23 09:55:01 2015 +0100

    Resolves: tdf#92689 grab keyboard focus to parent, not to earlier generations

so...

lets drop the ungrab on modal dialog attempt and leave that alone. That means
that the keyboard focus travels around the modal dialogs stack correctly.

For the mouse and keyboard events in menu problems, instead gtk_grab_add on the
menu itself, and convert the separate grab of keyboard and mouse to different
places with a single grab of everything to the menu, and in the keyInput of
such menus where the keyInput would have gone to their parent in the past,
forward it on ourselves directly.

Using the gtk_grab_add makes the bOwnerEvents mode of mouse grabbing not work
correctly anymore. So throw my hat at it, and instead use the simpler mouse
grabbing where all events go to the menu, and doesn't send the events outside
of it to the parent, the side effect is that now clicking outside the menu
doesn't make it go away automatically because its the parent window which used
to do that.

So instead of dismissing the menu within the gtk plugin when the button click
is outside the application, take it onto ourselves to dismiss the menu when the
button click is outside the menu.

and ditch some metacity hack around thing at this point too

I hate this crap

Change-Id: If10e758585f156b33680b8d40355302cc1ae72f3
This commit is contained in:
Caolán McNamara
2016-05-04 16:29:35 +01:00
parent 92f9ac2e2b
commit 72e6a1365c
2 changed files with 54 additions and 55 deletions

View File

@@ -271,6 +271,7 @@ class GtkSalFrame : public SalFrame
static void gestureSwipe(GtkGestureSwipe* gesture, gdouble velocity_x, gdouble velocity_y, gpointer frame);
static void gestureLongPress(GtkGestureLongPress* gesture, gpointer frame);
#endif
gboolean handleKey(GtkWidget* pWidget, GdkEventKey* pEvent);
#else
static gboolean signalExpose( GtkWidget*, GdkEventExpose*, gpointer );
#endif

View File

@@ -1424,21 +1424,6 @@ void GtkSalFrame::Show( bool bVisible, bool bNoActivate )
SetDefaultSize();
setMinMaxSize();
if( isFloatGrabWindow() &&
m_pParent &&
m_nFloats == 0 &&
! getDisplay()->GetCaptureFrame() )
{
/* #i63086#
* outsmart Metacity's "focus:mouse" mode
* which insists on taking the focus from the document
* to the new float. Grab focus to parent frame BEFORE
* showing the float (cannot grab it to the float
* before show).
*/
m_pParent->grabPointer( true, true );
}
if( ! bNoActivate && (m_nStyle & SalFrameStyleFlags::TOOLWINDOW) )
m_bSetFocusOnMap = true;
@@ -1449,9 +1434,9 @@ void GtkSalFrame::Show( bool bVisible, bool bNoActivate )
m_nFloats++;
if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 1 )
{
grabPointer(true, true);
GtkSalFrame *pKeyboardFrame = m_pParent ? m_pParent : this;
pKeyboardFrame->grabKeyboard(true);
gtk_grab_add(getMouseEventWidget());
grabPointer(true);
grabKeyboard(true);
}
// #i44068# reset parent's IM context
if( m_pParent )
@@ -1467,9 +1452,9 @@ void GtkSalFrame::Show( bool bVisible, bool bNoActivate )
m_nFloats--;
if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 0)
{
GtkSalFrame *pKeyboardFrame = m_pParent ? m_pParent : this;
pKeyboardFrame->grabKeyboard(false);
grabKeyboard(false);
grabPointer(false);
gtk_grab_remove(getMouseEventWidget());
}
}
gtk_widget_hide( m_pWindow );
@@ -2076,9 +2061,13 @@ void GtkSalFrame::grabPointer( bool bGrab, bool bOwnerEvents )
GdkDeviceManager* pDeviceManager = gdk_display_get_device_manager(getGdkDisplay());
GdkDevice* pPointer = gdk_device_manager_get_client_pointer(pDeviceManager);
if (bGrab)
{
gdk_device_grab(pPointer, widget_get_window(getMouseEventWidget()), GDK_OWNERSHIP_NONE, bOwnerEvents, (GdkEventMask) nMask, m_pCurrentCursor, gtk_get_current_event_time());
}
else
{
gdk_device_ungrab(pPointer, gtk_get_current_event_time());
}
}
void GtkSalFrame::grabKeyboard( bool bGrab )
@@ -2414,13 +2403,6 @@ void GtkSalFrame::SetModal(bool bModal)
if (!m_pWindow)
return;
gtk_window_set_modal(GTK_WINDOW(m_pWindow), bModal);
if (bModal)
{
//gtk_window_set_modal bTrue adds a grab, so ungrab here. Quite
//possibly we should alternatively call grab_add grab_ungrab on
//show/hide of menus ?
gtk_grab_remove(m_pWindow);
}
}
gboolean GtkSalFrame::signalTooltipQuery(GtkWidget*, gint /*x*/, gint /*y*/,
@@ -2600,9 +2582,12 @@ gboolean GtkSalFrame::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer
{
if( m_nFloats > 0 )
{
// close popups if user clicks outside our application
gint x, y;
bClosePopups = (gdk_display_get_window_at_pointer( GtkSalFrame::getGdkDisplay(), &x, &y ) == nullptr);
// close popups if user clicks outside our menu
if (aEvent.mnX < 0 || aEvent.mnY < 0 ||
aEvent.mnX > (long)pThis->maGeometry.nWidth || aEvent.mnY > (long)pThis->maGeometry.nHeight)
{
bClosePopups = true;
}
}
/* #i30306# release implicit pointer grab if no popups are open; else
* Drag cannot grab the pointer and will fail.
@@ -2795,7 +2780,7 @@ gboolean GtkSalFrame::signalMotion( GtkWidget*, GdkEventMotion* pEvent, gpointer
// ask for the next hint
gint x, y;
GdkModifierType mask;
gdk_window_get_pointer( widget_get_window(GTK_WIDGET(pThis->m_pWindow)), &x, &y, &mask );
gdk_window_get_pointer( widget_get_window(GTK_WIDGET(pThis->getMouseEventWidget())), &x, &y, &mask );
}
}
@@ -2977,15 +2962,28 @@ gboolean GtkSalFrame::signalUnmap( GtkWidget*, GdkEvent*, gpointer frame )
return false;
}
gboolean GtkSalFrame::signalKey( GtkWidget*, GdkEventKey* pEvent, gpointer frame )
gboolean GtkSalFrame::signalKey(GtkWidget* pWidget, GdkEventKey* pEvent, gpointer frame)
{
GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
return pThis->handleKey(pWidget, pEvent);
}
vcl::DeletionListener aDel( pThis );
if( pThis->m_pIMHandler )
gboolean GtkSalFrame::handleKey(GtkWidget* pWidget, GdkEventKey* pEvent)
{
//If we're the type of menu that wants to forward keypresses to our parent
//widget, do that here, this is related to the gtk_grab_add use in
//GtkSalFrame::Show where we want the mouse events to go to us, but
//the keyboard events to go to our parent
if (isFloatGrabWindow() && !getDisplay()->GetCaptureFrame() && m_nFloats == 1 && m_pParent)
{
if( pThis->m_pIMHandler->handleKeyEvent( pEvent ) )
return m_pParent->handleKey(pWidget, pEvent);
}
vcl::DeletionListener aDel(this);
if( m_pIMHandler )
{
if( m_pIMHandler->handleKeyEvent( pEvent ) )
return true;
}
@@ -3001,13 +2999,13 @@ gboolean GtkSalFrame::signalKey( GtkWidget*, GdkEventKey* pEvent, gpointer frame
sal_uInt16 nModCode = GetKeyModCode( pEvent->state );
aModEvt.mnModKeyCode = 0; // emit no MODKEYCHANGE events
if( pEvent->type == GDK_KEY_PRESS && !pThis->m_nKeyModifiers )
pThis->m_bSendModChangeOnRelease = true;
if( pEvent->type == GDK_KEY_PRESS && !m_nKeyModifiers )
m_bSendModChangeOnRelease = true;
else if( pEvent->type == GDK_KEY_RELEASE &&
pThis->m_bSendModChangeOnRelease )
m_bSendModChangeOnRelease )
{
aModEvt.mnModKeyCode = pThis->m_nKeyModifiers;
aModEvt.mnModKeyCode = m_nKeyModifiers;
}
sal_uInt16 nExtModMask = 0;
@@ -3058,37 +3056,37 @@ gboolean GtkSalFrame::signalKey( GtkWidget*, GdkEventKey* pEvent, gpointer frame
if( pEvent->type == GDK_KEY_RELEASE )
{
nModCode &= ~nModMask;
pThis->m_nKeyModifiers &= ~nExtModMask;
m_nKeyModifiers &= ~nExtModMask;
}
else
{
nModCode |= nModMask;
pThis->m_nKeyModifiers |= nExtModMask;
m_nKeyModifiers |= nExtModMask;
}
aModEvt.mnCode = nModCode;
aModEvt.mnTime = pEvent->time;
aModEvt.mnModKeyCode = pThis->m_nKeyModifiers;
aModEvt.mnModKeyCode = m_nKeyModifiers;
pThis->CallCallback( SALEVENT_KEYMODCHANGE, &aModEvt );
CallCallback( SALEVENT_KEYMODCHANGE, &aModEvt );
}
else
{
pThis->doKeyCallback( pEvent->state,
pEvent->keyval,
pEvent->hardware_keycode,
pEvent->group,
pEvent->time,
sal_Unicode(gdk_keyval_to_unicode( pEvent->keyval )),
(pEvent->type == GDK_KEY_PRESS),
false );
doKeyCallback( pEvent->state,
pEvent->keyval,
pEvent->hardware_keycode,
pEvent->group,
pEvent->time,
sal_Unicode(gdk_keyval_to_unicode( pEvent->keyval )),
(pEvent->type == GDK_KEY_PRESS),
false );
if( ! aDel.isDeleted() )
pThis->m_bSendModChangeOnRelease = false;
m_bSendModChangeOnRelease = false;
}
if( !aDel.isDeleted() && pThis->m_pIMHandler )
pThis->m_pIMHandler->updateIMSpotLocation();
if( !aDel.isDeleted() && m_pIMHandler )
m_pIMHandler->updateIMSpotLocation();
return false;
}