24#include <wx/nonownedwnd.h>
25#include <wx/settings.h>
32#ifdef GDK_WINDOWING_X11
36#ifdef GDK_WINDOWING_WAYLAND
37#include <gdk/gdkwayland.h>
41#include "wayland-pointer-constraints-unstable-v1.h"
50 wxColour bg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW );
53 double brightness = ( bg.Red() / 255.0 ) * 0.299 +
54 ( bg.Green() / 255.0 ) * 0.587 +
55 ( bg.Blue() / 255.0 ) * 0.117;
57 return brightness < 0.5;
63 return wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
78 GtkWindow* window = GTK_WINDOW( aWindow->GetHandle() );
81 return gtk_window_is_active( window );
104 case wxCURSOR_BULLSEYE:
126 GtkMenuItem* pMenuItem = GTK_MENU_ITEM( pItem );
127 GtkWidget* child = gtk_bin_get_child( GTK_BIN( pMenuItem ) );
128 GtkCellView* pCellView = GTK_CELL_VIEW( child );
129 GtkCellLayout* pCellLayout = GTK_CELL_LAYOUT( pCellView );
130 GtkCellArea* pCellArea = gtk_cell_layout_get_area( pCellLayout );
132 g_signal_handlers_block_matched( pCellArea, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, userdata );
138 AtkObject* atkObj = gtk_combo_box_get_popup_accessible( GTK_COMBO_BOX( aChoice->m_widget ) );
140 if( !atkObj || !GTK_IS_ACCESSIBLE( atkObj ) )
143 GtkWidget* widget = gtk_accessible_get_widget( GTK_ACCESSIBLE( atkObj ) );
145 if( !widget || !GTK_IS_MENU( widget ) )
148 GtkMenu* menu = GTK_MENU( widget );
158 GList* cells = gtk_cell_layout_get_cells( GTK_CELL_LAYOUT( aChoice->m_widget ) );
163 GtkCellRenderer* cell = (GtkCellRenderer*) cells->data;
168 g_object_set( G_OBJECT( cell ),
"ellipsize", PANGO_ELLIPSIZE_END,
nullptr );
171 g_list_free( cells );
179 GtkWidget* widget =
static_cast<GtkWidget*
>( aWindow->GetHandle() );
181 if( widget && gtk_check_version( 3, 10, 0 ) == nullptr )
182 val = gtk_widget_get_scale_factor( widget );
197 return wxSize( aWindow->GetSize().GetX() - wxSystemSettings::GetMetric( wxSYS_VSCROLL_X ),
198 aWindow->GetSize().GetY() - wxSystemSettings::GetMetric( wxSYS_HSCROLL_Y ) );
204 gtk_scrolled_window_set_overlay_scrolling( GTK_SCROLLED_WINDOW( aWindow->GetHandle() ),
211 gboolean allowed = 1;
213 g_object_get( gtk_settings_get_default(),
"gtk-menu-images", &allowed, NULL );
219#if defined( GDK_WINDOWING_WAYLAND ) && defined( KICAD_WAYLAND )
221static bool wayland_warp_pointer( GtkWidget* aWidget, GdkDisplay* aDisplay, GdkWindow* aWindow,
222 GdkDevice* aPtrDev,
int aX,
int aY );
226static wxPoint s_warped_from;
227static wxPoint s_warped_to;
231 wxPoint wx_pos = wxGetMousePosition();
233 if( wx_pos == s_warped_from )
235 wxLogTrace(
traceWayland, wxS(
"Faked mouse pos %d %d -> %d %d" ), wx_pos.x, wx_pos.y,
236 s_warped_to.x, s_warped_to.y );
243 s_warped_from = wxPoint();
244 s_warped_to = wxPoint();
255 if( !wxGetEnv( wxT(
"WAYLAND_DISPLAY" ),
nullptr ) )
257 aWindow->WarpPointer( aX, aY );
262 GtkWidget* widget =
static_cast<GtkWidget*
>( aWindow->GetHandle() );
264 GdkDisplay* disp = gtk_widget_get_display( widget );
265 GdkSeat* seat = gdk_display_get_default_seat( disp );
266 GdkDevice* ptrdev = gdk_seat_get_pointer( seat );
268#if defined( GDK_WINDOWING_WAYLAND ) && defined( KICAD_WAYLAND )
269 if( GDK_IS_WAYLAND_DISPLAY( disp ) )
271 wxPoint initialPos = wxGetMousePosition();
272 GdkWindow* win = aWindow->GTKGetDrawingWindow();
274 if( wayland_warp_pointer( widget, disp, win, ptrdev, aX, aY ) )
276 s_warped_from = initialPos;
277 s_warped_to = aWindow->ClientToScreen( wxPoint( aX, aY ) );
279 wxLogTrace(
traceWayland, wxS(
"Set warped from %d %d to %d %d" ), s_warped_from.x,
280 s_warped_from.y, s_warped_to.x, s_warped_to.y );
285 wxLogTrace(
traceWayland, wxS(
"*** Warp to %d %d failed ***" ), aX, aY );
290#ifdef GDK_WINDOWING_X11
291 if( GDK_IS_X11_DISPLAY( disp ) )
293 GdkWindow* win = gdk_device_get_window_at_position( ptrdev,
nullptr,
nullptr );
294 GdkCursor* blank_cursor = gdk_cursor_new_for_display( disp, GDK_BLANK_CURSOR );
295 GdkCursor* cur_cursor = gdk_window_get_cursor( win );
298 g_object_ref( cur_cursor );
300 gdk_window_set_cursor( win, blank_cursor );
301 aWindow->WarpPointer( aX, aY );
302 gdk_window_set_cursor( win, cur_cursor );
305 g_object_unref( cur_cursor );
308 g_object_unref( blank_cursor );
332#if defined( GDK_WINDOWING_WAYLAND ) && defined( KICAD_WAYLAND )
334static bool s_wl_initialized =
false;
335static struct wl_compositor* s_wl_compositor = NULL;
336static struct zwp_pointer_constraints_v1* s_wl_pointer_constraints = NULL;
337static struct zwp_confined_pointer_v1* s_wl_confined_pointer = NULL;
338static struct wl_region* s_wl_confinement_region = NULL;
339static bool s_wl_locked_flag =
false;
341static void handle_global(
void* data,
struct wl_registry* registry, uint32_t
name,
342 const char* interface, uint32_t version )
344 wxLogTrace(
traceWayland,
"handle_global received %s name %u version %u", interface,
345 (
unsigned int)
name, (
unsigned int) version );
347 if( strcmp( interface, wl_compositor_interface.name ) == 0 )
349 s_wl_compositor =
static_cast<wl_compositor*
>(
350 wl_registry_bind( registry,
name, &wl_compositor_interface, version ) );
352 else if( strcmp( interface, zwp_pointer_constraints_v1_interface.name ) == 0 )
354 s_wl_pointer_constraints =
static_cast<zwp_pointer_constraints_v1*
>( wl_registry_bind(
355 registry,
name, &zwp_pointer_constraints_v1_interface, version ) );
359static void handle_global_remove(
void*,
struct wl_registry*, uint32_t
name )
361 wxLogTrace(
traceWayland,
"handle_global_remove name %u", (
unsigned int)
name );
364static const struct wl_registry_listener registry_listener = {
365 .global = handle_global,
366 .global_remove = handle_global_remove,
369static void confined_handler(
void* data,
struct zwp_confined_pointer_v1* zwp_confined_pointer_v1 )
374static void unconfined_handler(
void* data,
375 struct zwp_confined_pointer_v1* zwp_confined_pointer_v1 )
377 wxLogTrace(
traceWayland, wxS(
"Pointer unconfined" ) );
380static const struct zwp_confined_pointer_v1_listener confined_pointer_listener = {
381 .confined = confined_handler,
382 .unconfined = unconfined_handler
385static void locked_handler(
void* data,
struct zwp_locked_pointer_v1* zwp_locked_pointer_v1 )
387 s_wl_locked_flag =
true;
391static void unlocked_handler(
void* data,
struct zwp_locked_pointer_v1* zwp_locked_pointer_v1 )
396static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = {
397 .locked = locked_handler,
398 .unlocked = unlocked_handler
405static void initialize_wayland( wl_display* wldisp )
407 if( s_wl_initialized )
412 struct wl_registry* registry = wl_display_get_registry( wldisp );
413 wl_registry_add_listener( registry, ®istry_listener, NULL );
414 wl_display_roundtrip( wldisp );
415 s_wl_initialized =
true;
419struct zwp_locked_pointer_v1* s_wl_locked_pointer = NULL;
421static int s_after_paint_handler_id = 0;
423static void on_frame_clock_after_paint( GdkFrameClock* clock, GtkWidget* widget )
425 if( s_wl_locked_pointer )
427 zwp_locked_pointer_v1_destroy( s_wl_locked_pointer );
428 s_wl_locked_pointer = NULL;
430 wxLogTrace(
traceWayland, wxS(
"after-paint: locked_pointer destroyed" ) );
432 g_signal_handler_disconnect( (gpointer) clock, s_after_paint_handler_id );
433 s_after_paint_handler_id = 0;
436 if( s_wl_confinement_region != NULL )
438 wxLogTrace(
traceWayland, wxS(
"after-paint: Restoring confinement" ) );
440 GdkDisplay* disp = gtk_widget_get_display( widget );
441 GdkSeat* seat = gdk_display_get_default_seat( disp );
442 GdkDevice* ptrdev = gdk_seat_get_pointer( seat );
443 GdkWindow* window = gtk_widget_get_window( widget );
445 wl_display* wldisp = gdk_wayland_display_get_wl_display( disp );
446 wl_surface* wlsurf = gdk_wayland_window_get_wl_surface( window );
447 wl_pointer* wlptr = gdk_wayland_device_get_wl_pointer( ptrdev );
449 s_wl_confined_pointer = zwp_pointer_constraints_v1_confine_pointer(
450 s_wl_pointer_constraints, wlsurf, wlptr, s_wl_confinement_region,
451 ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT );
453 wl_display_roundtrip( wldisp );
459static bool wayland_warp_pointer( GtkWidget* aWidget, GdkDisplay* aDisplay, GdkWindow* aWindow,
460 GdkDevice* aPtrDev,
int aX,
int aY )
462 wl_display* wldisp = gdk_wayland_display_get_wl_display( aDisplay );
463 wl_surface* wlsurf = gdk_wayland_window_get_wl_surface( aWindow );
464 wl_pointer* wlptr = gdk_wayland_device_get_wl_pointer( aPtrDev );
466 if( s_after_paint_handler_id )
469 wxLogTrace(
traceWayland, wxS(
"Not warping: after-paint pending" ) );
473 initialize_wayland( wldisp );
475 if( s_wl_locked_pointer )
478 wxLogTrace(
traceWayland, wxS(
"** Destroying previous locked_pointer **" ) );
479 zwp_locked_pointer_v1_destroy( s_wl_locked_pointer );
480 wl_display_roundtrip( wldisp );
481 s_wl_locked_pointer = NULL;
486 GdkFrameClock* frame_clock = gdk_window_get_frame_clock( aWindow );
487 s_after_paint_handler_id = g_signal_connect_after(
488 frame_clock,
"after-paint", G_CALLBACK( on_frame_clock_after_paint ), aWidget );
491 if( s_wl_confinement_region && s_wl_confined_pointer )
493 zwp_confined_pointer_v1_destroy( s_wl_confined_pointer );
494 wl_display_roundtrip( wldisp );
495 s_wl_confined_pointer = NULL;
498 s_wl_locked_flag =
false;
500 s_wl_locked_pointer =
501 zwp_pointer_constraints_v1_lock_pointer( s_wl_pointer_constraints, wlsurf, wlptr, NULL,
502 ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT );
504 zwp_locked_pointer_v1_add_listener(s_wl_locked_pointer, &locked_pointer_listener, NULL);
507 gtk_widget_translate_coordinates( aWidget, gtk_widget_get_toplevel( aWidget ), 0, 0, &wx, &wy );
509 zwp_locked_pointer_v1_set_cursor_position_hint( s_wl_locked_pointer, wl_fixed_from_int( aX + wx ),
510 wl_fixed_from_int( aY + wy ) );
513 wl_display_roundtrip( wldisp );
514 gtk_widget_queue_draw( aWidget );
517 return s_wl_locked_flag;
523 wxLogTrace(
traceWayland, wxS(
"InfiniteDragPrepareWindow" ) );
525 GtkWidget* widget =
static_cast<GtkWidget*
>( aWindow->GetHandle() );
526 GdkDisplay* disp = gtk_widget_get_display( widget );
528 if( GDK_IS_WAYLAND_DISPLAY( disp ) )
530 if( s_wl_confined_pointer != NULL )
535 GdkSeat* seat = gdk_display_get_default_seat( disp );
536 GdkDevice* ptrdev = gdk_seat_get_pointer( seat );
537 GdkWindow* win = aWindow->GTKGetDrawingWindow();
539 wl_display* wldisp = gdk_wayland_display_get_wl_display( disp );
540 wl_surface* wlsurf = gdk_wayland_window_get_wl_surface( win );
541 wl_pointer* wlptr = gdk_wayland_device_get_wl_pointer( ptrdev );
543 initialize_wayland( wldisp );
545 gint x, y, width, height;
546 gdk_window_get_geometry( gdk_window_get_toplevel( win ), &x, &y, &width, &height );
548 wxLogTrace(
traceWayland, wxS(
"Confine region: %d %d %d %d" ), x, y, width, height );
550 s_wl_confinement_region = wl_compositor_create_region( s_wl_compositor );
551 wl_region_add( s_wl_confinement_region, x, y, width, height );
553 s_wl_confined_pointer = zwp_pointer_constraints_v1_confine_pointer(
554 s_wl_pointer_constraints, wlsurf, wlptr, s_wl_confinement_region,
555 ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT );
557 zwp_confined_pointer_v1_add_listener( s_wl_confined_pointer, &confined_pointer_listener,
560 wl_display_roundtrip( wldisp );
562 else if( wxGetEnv( wxT(
"WAYLAND_DISPLAY" ),
nullptr ) )
574 wxLogTrace(
traceWayland, wxS(
"InfiniteDragReleaseWindow" ) );
576 if( s_wl_confined_pointer )
578 zwp_confined_pointer_v1_destroy( s_wl_confined_pointer );
579 s_wl_confined_pointer = NULL;
582 if( s_wl_confinement_region )
584 wl_region_destroy( s_wl_confinement_region );
585 s_wl_confinement_region = NULL;
596 return !wxGetEnv( wxT(
"WAYLAND_DISPLAY" ),
nullptr );
608 return wxGetMousePosition();
static void disable_area_apply_attributes_cb(GtkWidget *pItem, gpointer userdata)
The following two functions are based on the "hack" contained in the attached patch at https://gitlab...
const wxString traceWayland
std::shared_ptr< PNS_LOG_VIEWER_OVERLAY > overlay