Fixed infinite mouse-drag with fast movement on Wayland.
This commit is contained in:
parent
b59910a749
commit
ad62b165fe
|
@ -447,6 +447,7 @@ void WX_VIEW_CONTROLS::onButton( wxMouseEvent& aEvent )
|
||||||
{
|
{
|
||||||
m_dragStartPoint = VECTOR2D( aEvent.GetX(), aEvent.GetY() );
|
m_dragStartPoint = VECTOR2D( aEvent.GetX(), aEvent.GetY() );
|
||||||
setState( DRAG_PANNING );
|
setState( DRAG_PANNING );
|
||||||
|
KIPLATFORM::UI::InfiniteDragPrepareWindow( m_parentPanel );
|
||||||
|
|
||||||
#if defined USE_MOUSE_CAPTURE
|
#if defined USE_MOUSE_CAPTURE
|
||||||
if( !m_parentPanel->HasCapture() )
|
if( !m_parentPanel->HasCapture() )
|
||||||
|
@ -476,6 +477,7 @@ void WX_VIEW_CONTROLS::onButton( wxMouseEvent& aEvent )
|
||||||
if( aEvent.MiddleUp() || aEvent.LeftUp() || aEvent.RightUp() )
|
if( aEvent.MiddleUp() || aEvent.LeftUp() || aEvent.RightUp() )
|
||||||
{
|
{
|
||||||
setState( IDLE );
|
setState( IDLE );
|
||||||
|
KIPLATFORM::UI::InfiniteDragReleaseWindow();
|
||||||
|
|
||||||
#if defined USE_MOUSE_CAPTURE
|
#if defined USE_MOUSE_CAPTURE
|
||||||
if( !m_settings.m_cursorCaptured && m_parentPanel->HasCapture() )
|
if( !m_settings.m_cursorCaptured && m_parentPanel->HasCapture() )
|
||||||
|
|
|
@ -212,12 +212,21 @@ bool KIPLATFORM::UI::AllowIconsInMenus()
|
||||||
|
|
||||||
#ifdef KICAD_WAYLAND
|
#ifdef KICAD_WAYLAND
|
||||||
|
|
||||||
|
static bool wl_initialized = false;
|
||||||
|
static struct wl_compositor* compositor = NULL;
|
||||||
static struct zwp_pointer_constraints_v1* pointer_constraints = NULL;
|
static struct zwp_pointer_constraints_v1* pointer_constraints = NULL;
|
||||||
|
static struct zwp_confined_pointer_v1* confined_pointer = NULL;
|
||||||
|
static struct wl_region* confinement_region = NULL;
|
||||||
|
|
||||||
static void handle_global( void* data, struct wl_registry* registry, uint32_t name,
|
static void handle_global( void* data, struct wl_registry* registry, uint32_t name,
|
||||||
const char* interface, uint32_t version )
|
const char* interface, uint32_t version )
|
||||||
{
|
{
|
||||||
if( strcmp( interface, zwp_pointer_constraints_v1_interface.name ) == 0 )
|
if( strcmp( interface, wl_compositor_interface.name ) == 0 )
|
||||||
|
{
|
||||||
|
compositor = static_cast<wl_compositor*>(
|
||||||
|
wl_registry_bind( registry, name, &wl_compositor_interface, version ) );
|
||||||
|
}
|
||||||
|
else if( strcmp( interface, zwp_pointer_constraints_v1_interface.name ) == 0 )
|
||||||
{
|
{
|
||||||
pointer_constraints = static_cast<zwp_pointer_constraints_v1*>( wl_registry_bind(
|
pointer_constraints = static_cast<zwp_pointer_constraints_v1*>( wl_registry_bind(
|
||||||
registry, name, &zwp_pointer_constraints_v1_interface, version ) );
|
registry, name, &zwp_pointer_constraints_v1_interface, version ) );
|
||||||
|
@ -229,6 +238,22 @@ static const struct wl_registry_listener registry_listener = {
|
||||||
.global_remove = NULL,
|
.global_remove = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes `compositor` and `pointer_constraints` global variables.
|
||||||
|
*/
|
||||||
|
static void initialize_wayland( wl_display* wldisp )
|
||||||
|
{
|
||||||
|
if( wl_initialized )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wl_registry* registry = wl_display_get_registry( wldisp );
|
||||||
|
wl_registry_add_listener( registry, ®istry_listener, NULL );
|
||||||
|
wl_display_roundtrip( wldisp );
|
||||||
|
wl_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -246,21 +271,24 @@ void KIPLATFORM::UI::WarpPointer( wxWindow* aWindow, int aX, int aY )
|
||||||
GdkSeat* seat = gdk_display_get_default_seat( disp );
|
GdkSeat* seat = gdk_display_get_default_seat( disp );
|
||||||
GdkDevice* ptrdev = gdk_seat_get_pointer( seat );
|
GdkDevice* ptrdev = gdk_seat_get_pointer( seat );
|
||||||
|
|
||||||
#if defined( GDK_WINDOWING_WAYLAND ) && defined KICAD_WAYLAND
|
#if defined( GDK_WINDOWING_WAYLAND ) && defined( KICAD_WAYLAND )
|
||||||
if( GDK_IS_WAYLAND_DISPLAY( disp ) )
|
if( GDK_IS_WAYLAND_DISPLAY( disp ) )
|
||||||
{
|
{
|
||||||
GdkWindow* win = aWindow->GTKGetDrawingWindow();
|
GdkWindow* win = aWindow->GTKGetDrawingWindow();
|
||||||
|
|
||||||
wl_display* wldisp = gdk_wayland_display_get_wl_display( disp );
|
wl_display* wldisp = gdk_wayland_display_get_wl_display( disp );
|
||||||
|
|
||||||
struct wl_registry* registry = wl_display_get_registry( wldisp );
|
|
||||||
int lret = wl_registry_add_listener( registry, ®istry_listener, NULL );
|
|
||||||
|
|
||||||
wl_display_roundtrip( wldisp );
|
|
||||||
|
|
||||||
wl_surface* wlsurf = gdk_wayland_window_get_wl_surface( win );
|
wl_surface* wlsurf = gdk_wayland_window_get_wl_surface( win );
|
||||||
wl_pointer* wlptr = gdk_wayland_device_get_wl_pointer( ptrdev );
|
wl_pointer* wlptr = gdk_wayland_device_get_wl_pointer( ptrdev );
|
||||||
|
|
||||||
|
initialize_wayland( wldisp );
|
||||||
|
|
||||||
|
// temporary disable confinement to allow pointer warping
|
||||||
|
if( confinement_region != NULL )
|
||||||
|
{
|
||||||
|
zwp_confined_pointer_v1_destroy( confined_pointer );
|
||||||
|
confined_pointer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
struct zwp_locked_pointer_v1* locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
|
struct zwp_locked_pointer_v1* locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
|
||||||
pointer_constraints, wlsurf, wlptr, NULL,
|
pointer_constraints, wlsurf, wlptr, NULL,
|
||||||
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT );
|
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT );
|
||||||
|
@ -272,10 +300,18 @@ void KIPLATFORM::UI::WarpPointer( wxWindow* aWindow, int aX, int aY )
|
||||||
zwp_locked_pointer_v1_set_cursor_position_hint(
|
zwp_locked_pointer_v1_set_cursor_position_hint(
|
||||||
locked_pointer, wl_fixed_from_int( aX + wx ), wl_fixed_from_int( aY + wy ) );
|
locked_pointer, wl_fixed_from_int( aX + wx ), wl_fixed_from_int( aY + wy ) );
|
||||||
|
|
||||||
|
zwp_locked_pointer_v1_destroy( locked_pointer );
|
||||||
|
|
||||||
|
// restore confinement
|
||||||
|
if( confinement_region != NULL )
|
||||||
|
{
|
||||||
|
confined_pointer = zwp_pointer_constraints_v1_confine_pointer(
|
||||||
|
pointer_constraints, wlsurf, wlptr, confinement_region,
|
||||||
|
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT );
|
||||||
|
}
|
||||||
|
|
||||||
wl_surface_commit( wlsurf );
|
wl_surface_commit( wlsurf );
|
||||||
wl_display_roundtrip( wldisp );
|
wl_display_roundtrip( wldisp );
|
||||||
|
|
||||||
zwp_locked_pointer_v1_destroy( locked_pointer );
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef GDK_WINDOWING_X11
|
#ifdef GDK_WINDOWING_X11
|
||||||
|
@ -300,3 +336,62 @@ void KIPLATFORM::UI::WarpPointer( wxWindow* aWindow, int aX, int aY )
|
||||||
void KIPLATFORM::UI::ImmControl( wxWindow* aWindow, bool aEnable )
|
void KIPLATFORM::UI::ImmControl( wxWindow* aWindow, bool aEnable )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void KIPLATFORM::UI::InfiniteDragPrepareWindow( wxWindow* aWindow )
|
||||||
|
{
|
||||||
|
#if defined( GDK_WINDOWING_WAYLAND ) && defined( KICAD_WAYLAND )
|
||||||
|
if( confined_pointer != NULL )
|
||||||
|
{
|
||||||
|
KIPLATFORM::UI::InfiniteDragReleaseWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkWidget* widget = static_cast<GtkWidget*>( aWindow->GetHandle() );
|
||||||
|
GdkDisplay* disp = gtk_widget_get_display( widget );
|
||||||
|
|
||||||
|
if( !GDK_IS_WAYLAND_DISPLAY( disp ) )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GdkSeat* seat = gdk_display_get_default_seat( disp );
|
||||||
|
GdkDevice* ptrdev = gdk_seat_get_pointer( seat );
|
||||||
|
GdkWindow* win = aWindow->GTKGetDrawingWindow();
|
||||||
|
|
||||||
|
wl_display* wldisp = gdk_wayland_display_get_wl_display( disp );
|
||||||
|
wl_surface* wlsurf = gdk_wayland_window_get_wl_surface( win );
|
||||||
|
wl_pointer* wlptr = gdk_wayland_device_get_wl_pointer( ptrdev );
|
||||||
|
|
||||||
|
initialize_wayland( wldisp );
|
||||||
|
|
||||||
|
gint x, y, width, height, wx, wy;
|
||||||
|
gdk_window_get_geometry( win, &x, &y, &width, &height );
|
||||||
|
gtk_widget_translate_coordinates( widget, gtk_widget_get_toplevel( widget ), 0, 0, &wx, &wy );
|
||||||
|
|
||||||
|
confinement_region = wl_compositor_create_region( compositor );
|
||||||
|
wl_region_add( confinement_region, x + wx - 1, y + wy - 1, width + 2, height + 2 );
|
||||||
|
|
||||||
|
confined_pointer = zwp_pointer_constraints_v1_confine_pointer(
|
||||||
|
pointer_constraints, wlsurf, wlptr, confinement_region,
|
||||||
|
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT );
|
||||||
|
|
||||||
|
wl_surface_commit( wlsurf );
|
||||||
|
wl_display_roundtrip( wldisp );
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
void KIPLATFORM::UI::InfiniteDragReleaseWindow()
|
||||||
|
{
|
||||||
|
#if defined( GDK_WINDOWING_WAYLAND ) && defined( KICAD_WAYLAND )
|
||||||
|
if( confined_pointer == NULL )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
zwp_confined_pointer_v1_destroy( confined_pointer );
|
||||||
|
wl_region_destroy( confinement_region );
|
||||||
|
|
||||||
|
confined_pointer = NULL;
|
||||||
|
confinement_region = NULL;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
|
@ -150,6 +150,20 @@ namespace KIPLATFORM
|
||||||
* Configures the IME mode of a given control handle
|
* Configures the IME mode of a given control handle
|
||||||
*/
|
*/
|
||||||
void ImmControl( wxWindow* aWindow, bool aEnable );
|
void ImmControl( wxWindow* aWindow, bool aEnable );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On Wayland, restricts the pointer movement to a rectangle slightly bigger than the given `wxWindow`.
|
||||||
|
* This way, the cursor doesn't exit the (bigger) application window and we retain control on it.
|
||||||
|
* Required to make the infinite mouse-drag work with fast movement.
|
||||||
|
* See https://gitlab.com/kicad/code/kicad/-/issues/7207#note_1562089503
|
||||||
|
* @param aWindow Window in which to position to mouse cursor
|
||||||
|
*/
|
||||||
|
void InfiniteDragPrepareWindow( wxWindow* aWindow );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On Wayland, allows the cursor to freely move again after a drag (see `InfiniteDragPrepareWindow`).
|
||||||
|
*/
|
||||||
|
void InfiniteDragReleaseWindow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -175,3 +175,15 @@ void KIPLATFORM::UI::ImmControl( wxWindow* aWindow, bool aEnable )
|
||||||
ImmAssociateContextEx( aWindow->GetHWND(), 0, IACE_DEFAULT );
|
ImmAssociateContextEx( aWindow->GetHWND(), 0, IACE_DEFAULT );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void KIPLATFORM::UI::InfiniteDragPrepareWindow( wxWindow* aWindow )
|
||||||
|
{
|
||||||
|
// Not needed on this platform
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void KIPLATFORM::UI::InfiniteDragReleaseWindow()
|
||||||
|
{
|
||||||
|
// Not needed on this platform
|
||||||
|
}
|
||||||
|
|
|
@ -175,3 +175,15 @@ void KIPLATFORM::UI::WarpPointer( wxWindow* aWindow, int aX, int aY )
|
||||||
void KIPLATFORM::UI::ImmControl( wxWindow* aWindow, bool aEnable )
|
void KIPLATFORM::UI::ImmControl( wxWindow* aWindow, bool aEnable )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void KIPLATFORM::UI::InfiniteDragPrepareWindow( wxWindow* aWindow )
|
||||||
|
{
|
||||||
|
// Not needed on this platform
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void KIPLATFORM::UI::InfiniteDragReleaseWindow()
|
||||||
|
{
|
||||||
|
// Not needed on this platform
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue