Generate wxEVT_ENTER_WINDOW in icon part of wxSearchCtrl in wxGTK

Mouse motion events happening over GtkEntry icons are consumed by this
class "event" callback, which simply returns GDK_EVENT_STOP for them if
the icon is insensitive (which is the case for GtkSearchEntry) and so
our "enter-notify-event" callback is never called.

Fix this by handling "event" signal ourselves and generating
wxEVT_ENTER_WINDOW from it if necessary.

Doing this required adding a global pointer to the window currently
under mouse, which is also used for generating wxEVT_LEAVE_WINDOW if
necessary.

See #24245.
This commit is contained in:
Vadim Zeitlin 2024-02-18 20:18:42 +01:00
parent a8b4753d1d
commit 9205da74db
3 changed files with 74 additions and 0 deletions

View file

@ -88,6 +88,12 @@ template<typename T> void InitMouseEvent(wxWindowGTK *win,
event.SetTimestamp( gdk_event->time ); event.SetTimestamp( gdk_event->time );
} }
// Update the window currently known to be under the mouse pointer.
//
// Returns true if it was updated, false if this window was already known to
// contain the mouse pointer.
bool SetWindowUnderMouse(wxWindowGTK* win);
} // namespace wxGTKImpl } // namespace wxGTKImpl
#endif // _GTK_PRIVATE_EVENT_H_ #endif // _GTK_PRIVATE_EVENT_H_

View file

@ -20,6 +20,7 @@
#include "wx/utils.h" #include "wx/utils.h"
#include "wx/gtk/private.h" #include "wx/gtk/private.h"
#include "wx/gtk/private/event.h"
#include "wx/gtk/private/gtk3-compat.h" #include "wx/gtk/private/gtk3-compat.h"
@ -93,6 +94,28 @@ wx_gtk_icon_press(GtkEntry* WXUNUSED(entry),
} }
} }
static gboolean
wx_gtk_entry_event(GtkEntry* WXUNUSED(entry),
GdkEvent* event,
wxSearchCtrl* ctrl)
{
if ( event->type == GDK_MOTION_NOTIFY )
{
// GtkEntry "event" signal handler ignores motion events happening over
// inactive icons, but we want to notify the window about the mouse
// entering it when they happen.
if ( wxGTKImpl::SetWindowUnderMouse(ctrl) )
{
wxMouseEvent mouseEvent(wxEVT_ENTER_WINDOW);
wxGTKImpl::InitMouseEvent(ctrl, mouseEvent, (GdkEventMotion*)event);
ctrl->GTKProcessEvent(mouseEvent);
}
}
return FALSE;
}
} }
// ============================================================================ // ============================================================================
@ -209,6 +232,8 @@ void wxSearchCtrl::GTKCreateSearchEntryWidget()
} }
g_signal_connect(m_entry, "icon-press", G_CALLBACK(wx_gtk_icon_press), this); g_signal_connect(m_entry, "icon-press", G_CALLBACK(wx_gtk_icon_press), this);
g_signal_connect(m_entry, "event", G_CALLBACK(wx_gtk_entry_event), this);
} }
GtkEditable *wxSearchCtrl::GetEditable() const GtkEditable *wxSearchCtrl::GetEditable() const

View file

@ -234,6 +234,23 @@ static wxWindowGTK *gs_deferredFocusOut = nullptr;
GdkEvent *g_lastMouseEvent = nullptr; GdkEvent *g_lastMouseEvent = nullptr;
int g_lastButtonNumber = 0; int g_lastButtonNumber = 0;
static wxWindowGTK* g_windowUnderMouse = nullptr;
namespace wxGTKImpl
{
bool SetWindowUnderMouse(wxWindowGTK* win)
{
if ( g_windowUnderMouse == win )
return false;
g_windowUnderMouse = win;
return true;
}
} // namespace wxGTKImpl
#ifdef wxHAS_XKB #ifdef wxHAS_XKB
namespace namespace
{ {
@ -2251,6 +2268,26 @@ gtk_window_enter_callback( GtkWidget* widget,
return FALSE; return FALSE;
} }
if ( g_windowUnderMouse == win )
{
// This can happen if the enter event was generated from another
// callback, as is the case for wxSearchCtrl, for example.
wxLogTrace(TRACE_MOUSE, "Reentering window %s", wxDumpWindow(win));
return FALSE;
}
if ( g_windowUnderMouse )
{
// We must not have got the leave event for the previous window, so
// generate it now -- better late than never.
wxMouseEvent event( wxEVT_LEAVE_WINDOW );
InitMouseEvent(g_windowUnderMouse, event, gdk_event);
(void)g_windowUnderMouse->GTKProcessEvent(event);
}
g_windowUnderMouse = win;
wxMouseEvent event( wxEVT_ENTER_WINDOW ); wxMouseEvent event( wxEVT_ENTER_WINDOW );
InitMouseEvent(win, event, gdk_event); InitMouseEvent(win, event, gdk_event);
@ -2285,6 +2322,9 @@ gtk_window_leave_callback( GtkWidget* widget,
return FALSE; return FALSE;
} }
if ( win == g_windowUnderMouse )
g_windowUnderMouse = nullptr;
wxMouseEvent event( wxEVT_LEAVE_WINDOW ); wxMouseEvent event( wxEVT_LEAVE_WINDOW );
InitMouseEvent(win, event, gdk_event); InitMouseEvent(win, event, gdk_event);
@ -2914,6 +2954,9 @@ wxWindowGTK::~wxWindowGTK()
if ( g_captureWindow == this ) if ( g_captureWindow == this )
g_captureWindow = nullptr; g_captureWindow = nullptr;
if ( g_windowUnderMouse == this )
g_windowUnderMouse = nullptr;
if (m_wxwindow) if (m_wxwindow)
{ {
GTKDisconnect(m_wxwindow); GTKDisconnect(m_wxwindow);