24#include <wx/dataview.h>
26#include <wx/nonownedwnd.h>
27#include <wx/settings.h>
34#ifdef GDK_WINDOWING_X11
39#ifdef GDK_WINDOWING_WAYLAND
40#include <gdk/gdkwayland.h>
53 wxColour bg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW );
56 double brightness = ( bg.Red() / 255.0 ) * 0.299 +
57 ( bg.Green() / 255.0 ) * 0.587 +
58 ( bg.Blue() / 255.0 ) * 0.117;
60 return brightness < 0.5;
66 return wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
74#if( GTK_CHECK_VERSION( 3, 24, 0 ) )
76 GtkWidgetPath*
path = gtk_widget_path_new();
77 GtkStyleContext* sc = gtk_style_context_new();
79 gtk_widget_path_append_type(
path, GTK_TYPE_WINDOW );
80 gtk_widget_path_iter_set_object_name(
path, -1,
"infobar" );
81 gtk_widget_path_iter_add_class(
path, -1,
"info" );
83 gtk_style_context_set_path( sc,
path );
84 gtk_style_context_set_state( sc, GTK_STATE_FLAG_NORMAL );
86 gtk_style_context_get( sc, GTK_STATE_FLAG_NORMAL,
"background-color", &rgba, NULL );
87 aBgColour = wxColour( *rgba );
88 gdk_rgba_free( rgba );
90 gtk_style_context_get( sc, GTK_STATE_FLAG_NORMAL,
"color", &rgba, NULL );
91 aFgColour = wxColour( *rgba );
92 gdk_rgba_free( rgba );
97 if( aBgColour.Alpha() == 0 )
99 gtk_widget_path_append_type(
path, G_TYPE_NONE );
100 gtk_widget_path_iter_set_object_name(
path, -1,
"revealer" );
101 gtk_widget_path_append_type(
path, G_TYPE_NONE );
102 gtk_widget_path_iter_set_object_name(
path, -1,
"box" );
104 gtk_style_context_set_path( sc,
path );
105 gtk_style_context_set_state( sc, GTK_STATE_FLAG_NORMAL );
107 gtk_style_context_get( sc, GTK_STATE_FLAG_NORMAL,
"background-color", &rgba, NULL );
108 aBgColour = wxColour( *rgba );
109 gdk_rgba_free( rgba );
111 gtk_style_context_get( sc, GTK_STATE_FLAG_NORMAL,
"color", &rgba, NULL );
112 aFgColour = wxColour( *rgba );
113 gdk_rgba_free( rgba );
116 gtk_widget_path_free(
path );
117 g_object_unref( sc );
120 aBgColour = wxSystemSettings::GetColour( wxSYS_COLOUR_INFOBK );
121 aFgColour = wxSystemSettings::GetColour( wxSYS_COLOUR_INFOTEXT );
134 wxWindow* tlw = aWindow;
136 while( tlw && !tlw->IsTopLevel() )
137 tlw = tlw->GetParent();
141 GtkWidget* widget =
static_cast<GtkWidget*
>( tlw->GetHandle() );
143 if( widget && GTK_IS_WINDOW( widget ) )
144 gtk_window_present( GTK_WINDOW( widget ) );
154 GtkWindow* window = GTK_WINDOW( aWindow->GetHandle() );
157 return gtk_window_is_active( window );
175 GtkWidget* widget =
static_cast<GtkWidget*
>( aWindow->GetHandle() );
177 if( widget && GTK_IS_WINDOW( widget ) )
178 gtk_window_set_gravity( GTK_WINDOW( widget ), GDK_GRAVITY_STATIC );
191 const char*
id =
static_cast<const char*
>( g_object_get_data( G_OBJECT( aWidget ),
197 GdkWindow* window = gtk_widget_get_window( aWidget );
202#ifdef GDK_WINDOWING_X11
203 if( GDK_IS_X11_WINDOW( window ) )
207 if( XClassHint* hints = XAllocClassHint() )
209 hints->res_name =
const_cast<char*
>( id );
210 hints->res_class =
const_cast<char*
>( id );
212 XSetClassHint( GDK_WINDOW_XDISPLAY( window ), GDK_WINDOW_XID( window ), hints );
218#if defined( GDK_WINDOWING_WAYLAND ) && GTK_CHECK_VERSION( 3, 24, 22 )
220 if( GDK_IS_WAYLAND_WINDOW( window ) && gtk_check_version( 3, 24, 22 ) ==
nullptr )
221 gdk_wayland_window_set_application_id( window,
id );
228 if( !aWindow || aClass.IsEmpty() )
231 GtkWidget* widget =
static_cast<GtkWidget*
>( aWindow->GetHandle() );
238 g_object_set_data_full( G_OBJECT( widget ),
WM_CLASS_DATA_KEY, g_strdup( aClass.utf8_str() ),
242 g_signal_handlers_disconnect_by_func( widget,
reinterpret_cast<void*
>(
setWindowClassHint ),
245 g_signal_connect_after( widget,
"realize", G_CALLBACK(
setWindowClassHint ),
nullptr );
249 if( gtk_widget_get_realized( widget ) )
276 case wxCURSOR_BULLSEYE:
298 GtkMenuItem* pMenuItem = GTK_MENU_ITEM( pItem );
299 GtkWidget* child = gtk_bin_get_child( GTK_BIN( pMenuItem ) );
300 GtkCellView* pCellView = GTK_CELL_VIEW( child );
301 GtkCellLayout* pCellLayout = GTK_CELL_LAYOUT( pCellView );
302 GtkCellArea* pCellArea = gtk_cell_layout_get_area( pCellLayout );
304 g_signal_handlers_block_matched( pCellArea, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, userdata );
310 AtkObject* atkObj = gtk_combo_box_get_popup_accessible( GTK_COMBO_BOX( aChoice->m_widget ) );
312 if( !atkObj || !GTK_IS_ACCESSIBLE( atkObj ) )
315 GtkWidget* widget = gtk_accessible_get_widget( GTK_ACCESSIBLE( atkObj ) );
317 if( !widget || !GTK_IS_MENU( widget ) )
320 GtkMenu* menu = GTK_MENU( widget );
330 GList* cells = gtk_cell_layout_get_cells( GTK_CELL_LAYOUT( aChoice->m_widget ) );
335 GtkCellRenderer* cell = (GtkCellRenderer*) cells->data;
340 g_object_set( G_OBJECT( cell ),
"ellipsize", PANGO_ELLIPSIZE_END,
nullptr );
343 g_list_free( cells );
351 GtkWidget* widget =
static_cast<GtkWidget*
>( aWindow->GetHandle() );
353 if( widget && gtk_check_version( 3, 10, 0 ) ==
nullptr )
354 val = gtk_widget_get_scale_factor( widget );
369 return wxSize( aWindow->GetSize().GetX() - wxSystemSettings::GetMetric( wxSYS_VSCROLL_X ),
370 aWindow->GetSize().GetY() - wxSystemSettings::GetMetric( wxSYS_HSCROLL_Y ) );
376 gtk_scrolled_window_set_overlay_scrolling( GTK_SCROLLED_WINDOW( aWindow->GetHandle() ),
383 gboolean allowed = 1;
385 g_object_get( gtk_settings_get_default(),
"gtk-menu-images", &allowed, NULL );
393#ifdef GDK_WINDOWING_X11
394 GdkDisplay* display = gdk_display_get_default();
396 return display && GDK_IS_X11_DISPLAY( display );
403#if defined( GDK_WINDOWING_WAYLAND ) && defined( KICAD_WAYLAND )
405static bool wayland_warp_pointer( GtkWidget* aWidget, GdkDisplay* aDisplay, GdkWindow* aWindow,
406 GdkDevice* aPtrDev,
int aX,
int aY );
410static wxPoint s_warped_from;
411static wxPoint s_warped_to;
415 wxPoint wx_pos = wxGetMousePosition();
417 if( wx_pos == s_warped_from )
419 wxLogTrace(
traceWayland, wxS(
"Faked mouse pos %d %d -> %d %d" ), wx_pos.x, wx_pos.y,
420 s_warped_to.x, s_warped_to.y );
427 s_warped_from = wxPoint();
428 s_warped_to = wxPoint();
439 if( !wxGetEnv( wxT(
"WAYLAND_DISPLAY" ),
nullptr ) )
441 aWindow->WarpPointer( aX, aY );
446 GtkWidget* widget =
static_cast<GtkWidget*
>( aWindow->GetHandle() );
448 GdkDisplay* disp = gtk_widget_get_display( widget );
449 GdkSeat* seat = gdk_display_get_default_seat( disp );
450 GdkDevice* ptrdev = gdk_seat_get_pointer( seat );
452#if defined( GDK_WINDOWING_WAYLAND ) && defined( KICAD_WAYLAND )
453 if( GDK_IS_WAYLAND_DISPLAY( disp ) )
455 wxPoint initialPos = wxGetMousePosition();
456 GdkWindow* win = aWindow->GTKGetDrawingWindow();
458 if( wayland_warp_pointer( widget, disp, win, ptrdev, aX, aY ) )
460 s_warped_from = initialPos;
461 s_warped_to = aWindow->ClientToScreen( wxPoint( aX, aY ) );
463 wxLogTrace(
traceWayland, wxS(
"Set warped from %d %d to %d %d" ), s_warped_from.x,
464 s_warped_from.y, s_warped_to.x, s_warped_to.y );
469 wxLogTrace(
traceWayland, wxS(
"*** Warp to %d %d failed ***" ), aX, aY );
474#ifdef GDK_WINDOWING_X11
475 if( GDK_IS_X11_DISPLAY( disp ) )
477 GdkWindow* win = gdk_device_get_window_at_position( ptrdev,
nullptr,
nullptr );
478 GdkCursor* blank_cursor = gdk_cursor_new_for_display( disp, GDK_BLANK_CURSOR );
479 GdkCursor* cur_cursor = gdk_window_get_cursor( win );
482 g_object_ref( cur_cursor );
484 gdk_window_set_cursor( win, blank_cursor );
485 aWindow->WarpPointer( aX, aY );
486 gdk_window_set_cursor( win, cur_cursor );
489 g_object_unref( cur_cursor );
492 g_object_unref( blank_cursor );
510 wxWindowGTK* win =
static_cast<wxWindowGTK*
>( aWindow );
513 GtkIMContext* imContext = win->m_imContext;
516 gtk_im_context_focus_out( imContext );
535 GtkWidget* widget =
static_cast<GtkWidget*
>( aDialog->GetHandle() );
537 if( widget && GTK_IS_FILE_CHOOSER( widget ) )
538 gtk_file_chooser_set_local_only( GTK_FILE_CHOOSER( widget ), FALSE );
547 GtkWidget* widget = aCtrl->GtkGetTreeView();
549 if( !widget || !GTK_IS_TREE_VIEW( widget ) )
552 GtkTreeView* view = GTK_TREE_VIEW( widget );
555 if( !gtk_tree_view_get_model( view ) )
558 GtkTreeViewColumn* column = gtk_tree_view_get_column( view, 0 );
569 gtk_widget_queue_resize( widget );
570 gtk_tree_view_scroll_to_cell( view,
nullptr, column, FALSE, 0.0, 0.0 );
577#if defined( GDK_WINDOWING_WAYLAND ) && defined( KICAD_WAYLAND )
579static bool s_wl_initialized =
false;
580static struct wl_compositor* s_wl_compositor = NULL;
581static struct zwp_pointer_constraints_v1* s_wl_pointer_constraints = NULL;
582static struct zwp_confined_pointer_v1* s_wl_confined_pointer = NULL;
583static struct wl_region* s_wl_confinement_region = NULL;
584static bool s_wl_locked_flag =
false;
586static void handle_global(
void* data,
struct wl_registry* registry, uint32_t
name,
587 const char* interface, uint32_t version )
589 wxLogTrace(
traceWayland,
"handle_global received %s name %u version %u", interface,
590 (
unsigned int)
name, (
unsigned int) version );
592 if( strcmp( interface, wl_compositor_interface.name ) == 0 )
594 s_wl_compositor =
static_cast<wl_compositor*
>(
595 wl_registry_bind( registry,
name, &wl_compositor_interface, version ) );
599 s_wl_pointer_constraints =
static_cast<zwp_pointer_constraints_v1*
>( wl_registry_bind(
604static void handle_global_remove(
void*,
struct wl_registry*, uint32_t
name )
606 wxLogTrace(
traceWayland,
"handle_global_remove name %u", (
unsigned int)
name );
609static const struct wl_registry_listener registry_listener = {
610 .global = handle_global,
611 .global_remove = handle_global_remove,
614static void confined_handler(
void* data,
struct zwp_confined_pointer_v1* zwp_confined_pointer_v1 )
619static void unconfined_handler(
void* data,
620 struct zwp_confined_pointer_v1* zwp_confined_pointer_v1 )
622 wxLogTrace(
traceWayland, wxS(
"Pointer unconfined" ) );
626 .confined = confined_handler,
627 .unconfined = unconfined_handler
630static void locked_handler(
void* data,
struct zwp_locked_pointer_v1* zwp_locked_pointer_v1 )
632 s_wl_locked_flag =
true;
636static void unlocked_handler(
void* data,
struct zwp_locked_pointer_v1* zwp_locked_pointer_v1 )
642 .locked = locked_handler,
643 .unlocked = unlocked_handler
650static void initialize_wayland( wl_display* wldisp )
652 if( s_wl_initialized )
657 struct wl_registry* registry = wl_display_get_registry( wldisp );
658 wl_registry_add_listener( registry, ®istry_listener, NULL );
659 wl_display_roundtrip( wldisp );
660 s_wl_initialized =
true;
664struct zwp_locked_pointer_v1* s_wl_locked_pointer = NULL;
666static int s_after_paint_handler_id = 0;
668static void on_frame_clock_after_paint( GdkFrameClock* clock, GtkWidget* widget )
670 if( s_wl_locked_pointer )
673 s_wl_locked_pointer = NULL;
675 wxLogTrace(
traceWayland, wxS(
"after-paint: locked_pointer destroyed" ) );
677 g_signal_handler_disconnect( (gpointer) clock, s_after_paint_handler_id );
678 s_after_paint_handler_id = 0;
681 if( s_wl_confinement_region != NULL )
683 wxLogTrace(
traceWayland, wxS(
"after-paint: Restoring confinement" ) );
685 GdkDisplay* disp = gtk_widget_get_display( widget );
686 GdkSeat* seat = gdk_display_get_default_seat( disp );
687 GdkDevice* ptrdev = gdk_seat_get_pointer( seat );
688 GdkWindow* window = gtk_widget_get_window( widget );
690 wl_display* wldisp = gdk_wayland_display_get_wl_display( disp );
691 wl_surface* wlsurf = gdk_wayland_window_get_wl_surface( window );
692 wl_pointer* wlptr = gdk_wayland_device_get_wl_pointer( ptrdev );
695 s_wl_pointer_constraints, wlsurf, wlptr, s_wl_confinement_region,
698 wl_display_roundtrip( wldisp );
704static bool wayland_warp_pointer( GtkWidget* aWidget, GdkDisplay* aDisplay, GdkWindow* aWindow,
705 GdkDevice* aPtrDev,
int aX,
int aY )
707 wl_display* wldisp = gdk_wayland_display_get_wl_display( aDisplay );
708 wl_surface* wlsurf = gdk_wayland_window_get_wl_surface( aWindow );
709 wl_pointer* wlptr = gdk_wayland_device_get_wl_pointer( aPtrDev );
711 if( s_after_paint_handler_id )
714 wxLogTrace(
traceWayland, wxS(
"Not warping: after-paint pending" ) );
718 initialize_wayland( wldisp );
720 if( s_wl_locked_pointer )
723 wxLogTrace(
traceWayland, wxS(
"** Destroying previous locked_pointer **" ) );
725 wl_display_roundtrip( wldisp );
726 s_wl_locked_pointer = NULL;
731 GdkFrameClock* frame_clock = gdk_window_get_frame_clock( aWindow );
732 s_after_paint_handler_id = g_signal_connect_after(
733 frame_clock,
"after-paint", G_CALLBACK( on_frame_clock_after_paint ), aWidget );
736 if( s_wl_confinement_region && s_wl_confined_pointer )
739 wl_display_roundtrip( wldisp );
740 s_wl_confined_pointer = NULL;
743 s_wl_locked_flag =
false;
745 s_wl_locked_pointer =
752 gtk_widget_translate_coordinates( aWidget, gtk_widget_get_toplevel( aWidget ), 0, 0, &wx, &wy );
755 wl_fixed_from_int( aY + wy ) );
758 wl_display_roundtrip( wldisp );
759 gtk_widget_queue_draw( aWidget );
762 return s_wl_locked_flag;
768 wxLogTrace(
traceWayland, wxS(
"InfiniteDragPrepareWindow" ) );
770 GtkWidget* widget =
static_cast<GtkWidget*
>( aWindow->GetHandle() );
771 GdkDisplay* disp = gtk_widget_get_display( widget );
773 if( GDK_IS_WAYLAND_DISPLAY( disp ) )
775 if( s_wl_confined_pointer != NULL )
780 GdkSeat* seat = gdk_display_get_default_seat( disp );
781 GdkDevice* ptrdev = gdk_seat_get_pointer( seat );
782 GdkWindow* win = aWindow->GTKGetDrawingWindow();
784 wl_display* wldisp = gdk_wayland_display_get_wl_display( disp );
785 wl_surface* wlsurf = gdk_wayland_window_get_wl_surface( win );
786 wl_pointer* wlptr = gdk_wayland_device_get_wl_pointer( ptrdev );
788 initialize_wayland( wldisp );
790 gint x, y, width, height;
791 gdk_window_get_geometry( gdk_window_get_toplevel( win ), &x, &y, &width, &height );
793 wxLogTrace(
traceWayland, wxS(
"Confine region: %d %d %d %d" ), x, y, width, height );
795 s_wl_confinement_region = wl_compositor_create_region( s_wl_compositor );
796 wl_region_add( s_wl_confinement_region, x, y, width, height );
799 s_wl_pointer_constraints, wlsurf, wlptr, s_wl_confinement_region,
805 wl_display_roundtrip( wldisp );
807 else if( wxGetEnv( wxT(
"WAYLAND_DISPLAY" ),
nullptr ) )
819 wxLogTrace(
traceWayland, wxS(
"InfiniteDragReleaseWindow" ) );
821 if( s_wl_confined_pointer )
824 s_wl_confined_pointer = NULL;
827 if( s_wl_confinement_region )
829 wl_region_destroy( s_wl_confinement_region );
830 s_wl_confinement_region = NULL;
841 return !wxGetEnv( wxT(
"WAYLAND_DISPLAY" ),
nullptr );
853 return wxGetMousePosition();
static void zwp_confined_pointer_v1_destroy(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1)
Destroy the confined pointer object.
static int zwp_confined_pointer_v1_add_listener(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1, const struct zwp_confined_pointer_v1_listener *listener, void *data)
static void zwp_locked_pointer_v1_set_cursor_position_hint(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1, wl_fixed_t surface_x, wl_fixed_t surface_y)
Set the cursor position hint relative to the top left corner of the surface.
static int zwp_locked_pointer_v1_add_listener(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1, const struct zwp_locked_pointer_v1_listener *listener, void *data)
static void zwp_locked_pointer_v1_destroy(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1)
Destroy the locked pointer object.
static struct zwp_locked_pointer_v1 * zwp_pointer_constraints_v1_lock_pointer(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1, struct wl_surface *surface, struct wl_pointer *pointer, struct wl_region *region, uint32_t lifetime)
The lock_pointer request lets the client request to disable movements of the virtual pointer (i....
static struct zwp_confined_pointer_v1 * zwp_pointer_constraints_v1_confine_pointer(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1, struct wl_surface *surface, struct wl_pointer *pointer, struct wl_region *region, uint32_t lifetime)
The confine_pointer request lets the client request to confine the pointer cursor to a given region.
@ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT
the pointer constraint is defunct once deactivated
std::shared_ptr< PNS_LOG_VIEWER_OVERLAY > overlay
const struct wl_interface zwp_pointer_constraints_v1_interface
static const char *const WM_CLASS_DATA_KEY
static void setWindowClassHint(GtkWidget *aWidget, gpointer)
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