KiCad PCB EDA Suite
Loading...
Searching...
No Matches
wxgtk/ui.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2020 Ian McInerney <Ian.S.McInerney at ieee.org>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <kiplatform/ui.h>
22
23#include <wx/choice.h>
24#include <wx/dataview.h>
25#include <wx/dialog.h>
26#include <wx/nonownedwnd.h>
27#include <wx/settings.h>
28#include <wx/window.h>
29#include <wx/log.h>
30
31#include <gtk/gtk.h>
32#include <gdk/gdk.h>
33
34#ifdef GDK_WINDOWING_X11
35#include <gdk/gdkx.h>
36#endif
37
38#ifdef GDK_WINDOWING_WAYLAND
39#include <gdk/gdkwayland.h>
40#endif
41
42#ifdef KICAD_WAYLAND
44#endif
45
46// Set WXTRACE=KICAD_WAYLAND to see logs
47const wxString traceWayland = wxS( "KICAD_WAYLAND" );
48
49
51{
52 wxColour bg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW );
53
54 // Weighted W3C formula
55 double brightness = ( bg.Red() / 255.0 ) * 0.299 +
56 ( bg.Green() / 255.0 ) * 0.587 +
57 ( bg.Blue() / 255.0 ) * 0.117;
58
59 return brightness < 0.5;
60}
61
62
64{
65 return wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
66}
67
68
69void KIPLATFORM::UI::GetInfoBarColours( wxColour& aFgColour, wxColour& aBgColour )
70{
71 // The GTK3.24 way of getting the colours is to use the style context
72 // Earlier GTKs should be able to use the system settings
73#if( GTK_CHECK_VERSION( 3, 24, 0 ) )
74 GdkRGBA* rgba;
75 GtkWidgetPath* path = gtk_widget_path_new();
76 GtkStyleContext* sc = gtk_style_context_new();
77
78 gtk_widget_path_append_type( path, GTK_TYPE_WINDOW );
79 gtk_widget_path_iter_set_object_name( path, -1, "infobar" );
80 gtk_widget_path_iter_add_class( path, -1, "info" );
81
82 gtk_style_context_set_path( sc, path );
83 gtk_style_context_set_state( sc, GTK_STATE_FLAG_NORMAL );
84
85 gtk_style_context_get( sc, GTK_STATE_FLAG_NORMAL, "background-color", &rgba, NULL );
86 aBgColour = wxColour( *rgba );
87 gdk_rgba_free( rgba );
88
89 gtk_style_context_get( sc, GTK_STATE_FLAG_NORMAL, "color", &rgba, NULL );
90 aFgColour = wxColour( *rgba );
91 gdk_rgba_free( rgba );
92
93 // Some GTK themes use the plain infobar style, but if they don't, the background alpha
94 // is generally 0. In this case, try the revealer and box as these are used for Adwaita
95 // and other themes.
96 if( aBgColour.Alpha() == 0 )
97 {
98 gtk_widget_path_append_type( path, G_TYPE_NONE );
99 gtk_widget_path_iter_set_object_name( path, -1, "revealer" );
100 gtk_widget_path_append_type( path, G_TYPE_NONE );
101 gtk_widget_path_iter_set_object_name( path, -1, "box" );
102
103 gtk_style_context_set_path( sc, path );
104 gtk_style_context_set_state( sc, GTK_STATE_FLAG_NORMAL );
105
106 gtk_style_context_get( sc, GTK_STATE_FLAG_NORMAL, "background-color", &rgba, NULL );
107 aBgColour = wxColour( *rgba );
108 gdk_rgba_free( rgba );
109
110 gtk_style_context_get( sc, GTK_STATE_FLAG_NORMAL, "color", &rgba, NULL );
111 aFgColour = wxColour( *rgba );
112 gdk_rgba_free( rgba );
113 }
114
115 gtk_widget_path_free( path );
116 g_object_unref( sc );
117
118#else
119 aBgColour = wxSystemSettings::GetColour( wxSYS_COLOUR_INFOBK );
120 aFgColour = wxSystemSettings::GetColour( wxSYS_COLOUR_INFOTEXT );
121#endif
122
123}
124
125
126void KIPLATFORM::UI::ForceFocus( wxWindow* aWindow )
127{
128 aWindow->SetFocus();
129
130 // On GTK, SetFocus() on a dialog may not be sufficient to receive keyboard events
131 // (like ESC for closing). We need to ensure the window is presented and active.
132 // Find the top-level window and present it to ensure keyboard focus.
133 wxWindow* tlw = aWindow;
134
135 while( tlw && !tlw->IsTopLevel() )
136 tlw = tlw->GetParent();
137
138 if( tlw )
139 {
140 GtkWidget* widget = static_cast<GtkWidget*>( tlw->GetHandle() );
141
142 if( widget && GTK_IS_WINDOW( widget ) )
143 gtk_window_present( GTK_WINDOW( widget ) );
144 }
145}
146
147
148bool KIPLATFORM::UI::IsWindowActive( wxWindow* aWindow )
149{
150 if( !aWindow )
151 return false;
152
153 GtkWindow* window = GTK_WINDOW( aWindow->GetHandle() );
154
155 if( window )
156 return gtk_window_is_active( window );
157
158 // We shouldn't really ever reach this point
159 return false;
160}
161
162
163void KIPLATFORM::UI::EnsureVisible( wxWindow* aWindow )
164{
165 // Not needed on this platform
166}
167
168
170{
171 if( !aWindow )
172 return;
173
174 GtkWidget* widget = static_cast<GtkWidget*>( aWindow->GetHandle() );
175
176 if( widget && GTK_IS_WINDOW( widget ) )
177 gtk_window_set_gravity( GTK_WINDOW( widget ), GDK_GRAVITY_STATIC );
178}
179
180
181void KIPLATFORM::UI::ReparentModal( wxNonOwnedWindow* aWindow )
182{
183 // Not needed on this platform
184}
185
186
187void KIPLATFORM::UI::ReparentWindow( wxNonOwnedWindow* aWindow, wxTopLevelWindow* aParent )
188{
189 // Not needed on this platform (only relevant for macOS child window ordering)
190}
191
192
194{
195 // Not needed on this platform
196}
197
198
199bool KIPLATFORM::UI::IsStockCursorOk( wxStockCursor aCursor )
200{
201 switch( aCursor )
202 {
203 case wxCURSOR_BULLSEYE:
204 case wxCURSOR_HAND:
205 case wxCURSOR_ARROW:
206 case wxCURSOR_BLANK:
207 return true;
208 default:
209 return false;
210 }
211}
212
213
222static void disable_area_apply_attributes_cb( GtkWidget* pItem, gpointer userdata )
223{
224 // GTK needs this enormous chain to get the actual type of item that we want
225 GtkMenuItem* pMenuItem = GTK_MENU_ITEM( pItem );
226 GtkWidget* child = gtk_bin_get_child( GTK_BIN( pMenuItem ) );
227 GtkCellView* pCellView = GTK_CELL_VIEW( child );
228 GtkCellLayout* pCellLayout = GTK_CELL_LAYOUT( pCellView );
229 GtkCellArea* pCellArea = gtk_cell_layout_get_area( pCellLayout );
230
231 g_signal_handlers_block_matched( pCellArea, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, userdata );
232}
233
234
235void KIPLATFORM::UI::LargeChoiceBoxHack( wxChoice* aChoice )
236{
237 AtkObject* atkObj = gtk_combo_box_get_popup_accessible( GTK_COMBO_BOX( aChoice->m_widget ) );
238
239 if( !atkObj || !GTK_IS_ACCESSIBLE( atkObj ) )
240 return;
241
242 GtkWidget* widget = gtk_accessible_get_widget( GTK_ACCESSIBLE( atkObj ) );
243
244 if( !widget || !GTK_IS_MENU( widget ) )
245 return;
246
247 GtkMenu* menu = GTK_MENU( widget );
248
249 gtk_container_foreach( GTK_CONTAINER( menu ), disable_area_apply_attributes_cb, menu );
250}
251
252
253void KIPLATFORM::UI::EllipsizeChoiceBox( wxChoice* aChoice )
254{
255 // This function is based on the code inside the function post_process_ui in
256 // gtkfilechooserwidget.c
257 GList* cells = gtk_cell_layout_get_cells( GTK_CELL_LAYOUT( aChoice->m_widget ) );
258
259 if( !cells )
260 return;
261
262 GtkCellRenderer* cell = (GtkCellRenderer*) cells->data;
263
264 if( !cell )
265 return;
266
267 g_object_set( G_OBJECT( cell ), "ellipsize", PANGO_ELLIPSIZE_END, nullptr );
268
269 // Only the list of cells must be freed, the renderer isn't ours to free
270 g_list_free( cells );
271}
272
273
274double KIPLATFORM::UI::GetPixelScaleFactor( const wxWindow* aWindow )
275{
276 double val = 1.0;
277
278 GtkWidget* widget = static_cast<GtkWidget*>( aWindow->GetHandle() );
279
280 if( widget && gtk_check_version( 3, 10, 0 ) == nullptr )
281 val = gtk_widget_get_scale_factor( widget );
282
283 return val;
284}
285
286
287double KIPLATFORM::UI::GetContentScaleFactor( const wxWindow* aWindow )
288{
289 // TODO: Do we need something different here?
290 return GetPixelScaleFactor( aWindow );
291}
292
293
294wxSize KIPLATFORM::UI::GetUnobscuredSize( const wxWindow* aWindow )
295{
296 return wxSize( aWindow->GetSize().GetX() - wxSystemSettings::GetMetric( wxSYS_VSCROLL_X ),
297 aWindow->GetSize().GetY() - wxSystemSettings::GetMetric( wxSYS_HSCROLL_Y ) );
298}
299
300
301void KIPLATFORM::UI::SetOverlayScrolling( const wxWindow* aWindow, bool overlay )
302{
303 gtk_scrolled_window_set_overlay_scrolling( GTK_SCROLLED_WINDOW( aWindow->GetHandle() ),
304 overlay );
305}
306
307
309{
310 gboolean allowed = 1;
311
312 g_object_get( gtk_settings_get_default(), "gtk-menu-images", &allowed, NULL );
313
314 return !!allowed;
315}
316
317
318#if defined( GDK_WINDOWING_WAYLAND ) && defined( KICAD_WAYLAND )
319
320static bool wayland_warp_pointer( GtkWidget* aWidget, GdkDisplay* aDisplay, GdkWindow* aWindow,
321 GdkDevice* aPtrDev, int aX, int aY );
322
323// GDK doesn't know if we've moved the cursor using Wayland pointer constraints.
324// So emulate the actual position here
325static wxPoint s_warped_from;
326static wxPoint s_warped_to;
327
329{
330 wxPoint wx_pos = wxGetMousePosition();
331
332 if( wx_pos == s_warped_from )
333 {
334 wxLogTrace( traceWayland, wxS( "Faked mouse pos %d %d -> %d %d" ), wx_pos.x, wx_pos.y,
335 s_warped_to.x, s_warped_to.y );
336
337 return s_warped_to;
338 }
339 else
340 {
341 // Mouse has moved
342 s_warped_from = wxPoint();
343 s_warped_to = wxPoint();
344 }
345
346 return wx_pos;
347}
348
349#endif
350
351
352bool KIPLATFORM::UI::WarpPointer( wxWindow* aWindow, int aX, int aY )
353{
354 if( !wxGetEnv( wxT( "WAYLAND_DISPLAY" ), nullptr ) )
355 {
356 aWindow->WarpPointer( aX, aY );
357 return true;
358 }
359 else
360 {
361 GtkWidget* widget = static_cast<GtkWidget*>( aWindow->GetHandle() );
362
363 GdkDisplay* disp = gtk_widget_get_display( widget );
364 GdkSeat* seat = gdk_display_get_default_seat( disp );
365 GdkDevice* ptrdev = gdk_seat_get_pointer( seat );
366
367#if defined( GDK_WINDOWING_WAYLAND ) && defined( KICAD_WAYLAND )
368 if( GDK_IS_WAYLAND_DISPLAY( disp ) )
369 {
370 wxPoint initialPos = wxGetMousePosition();
371 GdkWindow* win = aWindow->GTKGetDrawingWindow();
372
373 if( wayland_warp_pointer( widget, disp, win, ptrdev, aX, aY ) )
374 {
375 s_warped_from = initialPos;
376 s_warped_to = aWindow->ClientToScreen( wxPoint( aX, aY ) );
377
378 wxLogTrace( traceWayland, wxS( "Set warped from %d %d to %d %d" ), s_warped_from.x,
379 s_warped_from.y, s_warped_to.x, s_warped_to.y );
380
381 return true;
382 }
383
384 wxLogTrace( traceWayland, wxS( "*** Warp to %d %d failed ***" ), aX, aY );
385
386 return false;
387 }
388#endif
389#ifdef GDK_WINDOWING_X11
390 if( GDK_IS_X11_DISPLAY( disp ) )
391 {
392 GdkWindow* win = gdk_device_get_window_at_position( ptrdev, nullptr, nullptr );
393 GdkCursor* blank_cursor = gdk_cursor_new_for_display( disp, GDK_BLANK_CURSOR );
394 GdkCursor* cur_cursor = gdk_window_get_cursor( win );
395
396 if( cur_cursor )
397 g_object_ref( cur_cursor );
398
399 gdk_window_set_cursor( win, blank_cursor );
400 aWindow->WarpPointer( aX, aY );
401 gdk_window_set_cursor( win, cur_cursor );
402
403 if( cur_cursor )
404 g_object_unref( cur_cursor );
405
406 if( blank_cursor )
407 g_object_unref( blank_cursor );
408
409 return true;
410 }
411#endif
412 }
413
414 return false;
415}
416
417
418void KIPLATFORM::UI::ImmControl( wxWindow* aWindow, bool aEnable )
419{
420}
421
422
424{
425 wxWindowGTK* win = static_cast<wxWindowGTK*>( aWindow );
426 if( win )
427 {
428 GtkIMContext* imContext = win->m_imContext;
429 if( imContext )
430 {
431 gtk_im_context_focus_out( imContext );
432 }
433 }
434}
435
436
437void KIPLATFORM::UI::SetFloatLevel( wxWindow* aWindow )
438{
439}
440
441
442void KIPLATFORM::UI::ReleaseChildWindow( wxNonOwnedWindow* aWindow )
443{
444 // Not needed on this platform
445}
446
447
449{
450 GtkWidget* widget = static_cast<GtkWidget*>( aDialog->GetHandle() );
451
452 if( widget && GTK_IS_FILE_CHOOSER( widget ) )
453 gtk_file_chooser_set_local_only( GTK_FILE_CHOOSER( widget ), FALSE );
454}
455
456
457void KIPLATFORM::UI::CancelPendingScroll( wxDataViewCtrl* aCtrl )
458{
459 if( !aCtrl )
460 return;
461
462 GtkWidget* widget = aCtrl->GtkGetTreeView();
463
464 if( !widget || !GTK_IS_TREE_VIEW( widget ) )
465 return;
466
467 GtkTreeView* view = GTK_TREE_VIEW( widget );
468
469 // Need a live model and rbtree for the assertions in scroll_to_cell.
470 if( !gtk_tree_view_get_model( view ) )
471 return;
472
473 GtkTreeViewColumn* column = gtk_tree_view_get_column( view, 0 );
474
475 if( !column )
476 return;
477
478 // A column-only scroll_to_cell enters GTK's deferred-scroll path, which frees
479 // priv->scroll_to_path and only installs scroll_to_column. That breaks the race
480 // where validate_visible_area dereferences a stale row reference after a model
481 // reset. The deferred branch is taken when the widget is not yet allocated, when
482 // alloc is pending, or when rows are invalid -- queue_resize forces the latter so
483 // a steady-state widget also takes that branch and actually clears the reference.
484 gtk_widget_queue_resize( widget );
485 gtk_tree_view_scroll_to_cell( view, nullptr, column, FALSE, 0.0, 0.0 );
486}
487
488//
489// **** Wayland hacks ahead ****
490//
491
492#if defined( GDK_WINDOWING_WAYLAND ) && defined( KICAD_WAYLAND )
493
494static bool s_wl_initialized = false;
495static struct wl_compositor* s_wl_compositor = NULL;
496static struct zwp_pointer_constraints_v1* s_wl_pointer_constraints = NULL;
497static struct zwp_confined_pointer_v1* s_wl_confined_pointer = NULL;
498static struct wl_region* s_wl_confinement_region = NULL;
499static bool s_wl_locked_flag = false;
500
501static void handle_global( void* data, struct wl_registry* registry, uint32_t name,
502 const char* interface, uint32_t version )
503{
504 wxLogTrace( traceWayland, "handle_global received %s name %u version %u", interface,
505 (unsigned int) name, (unsigned int) version );
506
507 if( strcmp( interface, wl_compositor_interface.name ) == 0 )
508 {
509 s_wl_compositor = static_cast<wl_compositor*>(
510 wl_registry_bind( registry, name, &wl_compositor_interface, version ) );
511 }
512 else if( strcmp( interface, zwp_pointer_constraints_v1_interface.name ) == 0 )
513 {
514 s_wl_pointer_constraints = static_cast<zwp_pointer_constraints_v1*>( wl_registry_bind(
515 registry, name, &zwp_pointer_constraints_v1_interface, version ) );
516 }
517}
518
519static void handle_global_remove( void*, struct wl_registry*, uint32_t name )
520{
521 wxLogTrace( traceWayland, "handle_global_remove name %u", (unsigned int) name );
522}
523
524static const struct wl_registry_listener registry_listener = {
525 .global = handle_global,
526 .global_remove = handle_global_remove,
527};
528
529static void confined_handler( void* data, struct zwp_confined_pointer_v1* zwp_confined_pointer_v1 )
530{
531 wxLogTrace( traceWayland, wxS( "Pointer confined" ) );
532}
533
534static void unconfined_handler( void* data,
535 struct zwp_confined_pointer_v1* zwp_confined_pointer_v1 )
536{
537 wxLogTrace( traceWayland, wxS( "Pointer unconfined" ) );
538}
539
540static const struct zwp_confined_pointer_v1_listener confined_pointer_listener = {
541 .confined = confined_handler,
542 .unconfined = unconfined_handler
543};
544
545static void locked_handler( void* data, struct zwp_locked_pointer_v1* zwp_locked_pointer_v1 )
546{
547 s_wl_locked_flag = true;
548 wxLogTrace( traceWayland, wxS( "Pointer locked" ) );
549}
550
551static void unlocked_handler( void* data, struct zwp_locked_pointer_v1* zwp_locked_pointer_v1 )
552{
553 wxLogTrace( traceWayland, wxS( "Pointer unlocked" ) );
554}
555
556static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = {
557 .locked = locked_handler,
558 .unlocked = unlocked_handler
559};
560
561
565static void initialize_wayland( wl_display* wldisp )
566{
567 if( s_wl_initialized )
568 {
569 return;
570 }
571
572 struct wl_registry* registry = wl_display_get_registry( wldisp );
573 wl_registry_add_listener( registry, &registry_listener, NULL );
574 wl_display_roundtrip( wldisp );
575 s_wl_initialized = true;
576}
577
578
579struct zwp_locked_pointer_v1* s_wl_locked_pointer = NULL;
580
581static int s_after_paint_handler_id = 0;
582
583static void on_frame_clock_after_paint( GdkFrameClock* clock, GtkWidget* widget )
584{
585 if( s_wl_locked_pointer )
586 {
587 zwp_locked_pointer_v1_destroy( s_wl_locked_pointer );
588 s_wl_locked_pointer = NULL;
589
590 wxLogTrace( traceWayland, wxS( "after-paint: locked_pointer destroyed" ) );
591
592 g_signal_handler_disconnect( (gpointer) clock, s_after_paint_handler_id );
593 s_after_paint_handler_id = 0;
594
595 // restore confinement
596 if( s_wl_confinement_region != NULL )
597 {
598 wxLogTrace( traceWayland, wxS( "after-paint: Restoring confinement" ) );
599
600 GdkDisplay* disp = gtk_widget_get_display( widget );
601 GdkSeat* seat = gdk_display_get_default_seat( disp );
602 GdkDevice* ptrdev = gdk_seat_get_pointer( seat );
603 GdkWindow* window = gtk_widget_get_window( widget );
604
605 wl_display* wldisp = gdk_wayland_display_get_wl_display( disp );
606 wl_surface* wlsurf = gdk_wayland_window_get_wl_surface( window );
607 wl_pointer* wlptr = gdk_wayland_device_get_wl_pointer( ptrdev );
608
609 s_wl_confined_pointer = zwp_pointer_constraints_v1_confine_pointer(
610 s_wl_pointer_constraints, wlsurf, wlptr, s_wl_confinement_region,
612
613 wl_display_roundtrip( wldisp );
614 }
615 }
616}
617
618
619static bool wayland_warp_pointer( GtkWidget* aWidget, GdkDisplay* aDisplay, GdkWindow* aWindow,
620 GdkDevice* aPtrDev, int aX, int aY )
621{
622 wl_display* wldisp = gdk_wayland_display_get_wl_display( aDisplay );
623 wl_surface* wlsurf = gdk_wayland_window_get_wl_surface( aWindow );
624 wl_pointer* wlptr = gdk_wayland_device_get_wl_pointer( aPtrDev );
625
626 if( s_after_paint_handler_id )
627 {
628 // Previous paint not done yet
629 wxLogTrace( traceWayland, wxS( "Not warping: after-paint pending" ) );
630 return false;
631 }
632
633 initialize_wayland( wldisp );
634
635 if( s_wl_locked_pointer )
636 {
637 // This shouldn't happen but let's be safe
638 wxLogTrace( traceWayland, wxS( "** Destroying previous locked_pointer **" ) );
639 zwp_locked_pointer_v1_destroy( s_wl_locked_pointer );
640 wl_display_roundtrip( wldisp );
641 s_wl_locked_pointer = NULL;
642 }
643
644 // wl_surface_commit causes an assert on GNOME, but has to be called on KDE
645 // before destroying the locked pointer, so wait until GDK commits the surface.
646 GdkFrameClock* frame_clock = gdk_window_get_frame_clock( aWindow );
647 s_after_paint_handler_id = g_signal_connect_after(
648 frame_clock, "after-paint", G_CALLBACK( on_frame_clock_after_paint ), aWidget );
649
650 // temporary disable confinement to allow pointer warping
651 if( s_wl_confinement_region && s_wl_confined_pointer )
652 {
653 zwp_confined_pointer_v1_destroy( s_wl_confined_pointer );
654 wl_display_roundtrip( wldisp );
655 s_wl_confined_pointer = NULL;
656 }
657
658 s_wl_locked_flag = false;
659
660 s_wl_locked_pointer =
661 zwp_pointer_constraints_v1_lock_pointer( s_wl_pointer_constraints, wlsurf, wlptr, NULL,
663
664 zwp_locked_pointer_v1_add_listener(s_wl_locked_pointer, &locked_pointer_listener, NULL);
665
666 gint wx, wy;
667 gtk_widget_translate_coordinates( aWidget, gtk_widget_get_toplevel( aWidget ), 0, 0, &wx, &wy );
668
669 zwp_locked_pointer_v1_set_cursor_position_hint( s_wl_locked_pointer, wl_fixed_from_int( aX + wx ),
670 wl_fixed_from_int( aY + wy ) );
671
672 // Don't call wl_surface_commit, wait for GDK because of an assert on GNOME.
673 wl_display_roundtrip( wldisp ); // To receive "locked" event.
674 gtk_widget_queue_draw( aWidget ); // Needed on some GNOME environment to trigger
675 // the "after-paint" event handler.
676
677 return s_wl_locked_flag;
678}
679
680
681bool KIPLATFORM::UI::InfiniteDragPrepareWindow( wxWindow* aWindow )
682{
683 wxLogTrace( traceWayland, wxS( "InfiniteDragPrepareWindow" ) );
684
685 GtkWidget* widget = static_cast<GtkWidget*>( aWindow->GetHandle() );
686 GdkDisplay* disp = gtk_widget_get_display( widget );
687
688 if( GDK_IS_WAYLAND_DISPLAY( disp ) )
689 {
690 if( s_wl_confined_pointer != NULL )
691 {
693 }
694
695 GdkSeat* seat = gdk_display_get_default_seat( disp );
696 GdkDevice* ptrdev = gdk_seat_get_pointer( seat );
697 GdkWindow* win = aWindow->GTKGetDrawingWindow();
698
699 wl_display* wldisp = gdk_wayland_display_get_wl_display( disp );
700 wl_surface* wlsurf = gdk_wayland_window_get_wl_surface( win );
701 wl_pointer* wlptr = gdk_wayland_device_get_wl_pointer( ptrdev );
702
703 initialize_wayland( wldisp );
704
705 gint x, y, width, height;
706 gdk_window_get_geometry( gdk_window_get_toplevel( win ), &x, &y, &width, &height );
707
708 wxLogTrace( traceWayland, wxS( "Confine region: %d %d %d %d" ), x, y, width, height );
709
710 s_wl_confinement_region = wl_compositor_create_region( s_wl_compositor );
711 wl_region_add( s_wl_confinement_region, x, y, width, height );
712
713 s_wl_confined_pointer = zwp_pointer_constraints_v1_confine_pointer(
714 s_wl_pointer_constraints, wlsurf, wlptr, s_wl_confinement_region,
716
717 zwp_confined_pointer_v1_add_listener( s_wl_confined_pointer, &confined_pointer_listener,
718 NULL );
719
720 wl_display_roundtrip( wldisp );
721 }
722 else if( wxGetEnv( wxT( "WAYLAND_DISPLAY" ), nullptr ) )
723 {
724 // Not working under XWayland
725 return false;
726 }
727
728 return true;
729};
730
731
733{
734 wxLogTrace( traceWayland, wxS( "InfiniteDragReleaseWindow" ) );
735
736 if( s_wl_confined_pointer )
737 {
738 zwp_confined_pointer_v1_destroy( s_wl_confined_pointer );
739 s_wl_confined_pointer = NULL;
740 }
741
742 if( s_wl_confinement_region )
743 {
744 wl_region_destroy( s_wl_confinement_region );
745 s_wl_confinement_region = NULL;
746 }
747};
748
749
750#else // No Wayland support
751
752
754{
755 // Not working under XWayland
756 return !wxGetEnv( wxT( "WAYLAND_DISPLAY" ), nullptr );
757};
758
759
761{
762 // Not needed on X11
763};
764
765
767{
768 return wxGetMousePosition();
769}
770
771
772#endif
const char * name
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
bool AllowIconsInMenus()
If the user has disabled icons system-wide, we check that here.
Definition wxgtk/ui.cpp:308
void SetFloatLevel(wxWindow *aWindow)
Intended to set the floating window level in macOS on a window.
Definition wxgtk/ui.cpp:437
void GetInfoBarColours(wxColour &aFGColour, wxColour &aBGColour)
Return the background and foreground colors for info bars in the current scheme.
Definition wxgtk/ui.cpp:69
void ReparentWindow(wxNonOwnedWindow *aWindow, wxTopLevelWindow *aParent)
Definition wxgtk/ui.cpp:187
void ReleaseChildWindow(wxNonOwnedWindow *aWindow)
Release a modal window's parent-child relationship with its parent window.
Definition wxgtk/ui.cpp:442
void EllipsizeChoiceBox(wxChoice *aChoice)
Configure a wxChoice control to ellipsize the shown text in the button with the ellipses placed at th...
Definition wxgtk/ui.cpp:253
void FixupCancelButtonCmdKeyCollision(wxWindow *aWindow)
Definition wxgtk/ui.cpp:193
void SetOverlayScrolling(const wxWindow *aWindow, bool overlay)
Used to set overlay/non-overlay scrolling mode in a window.
Definition wxgtk/ui.cpp:301
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition wxgtk/ui.cpp:766
void ImmControl(wxWindow *aWindow, bool aEnable)
Configures the IME mode of a given control handle.
Definition wxgtk/ui.cpp:418
void StabilizeWindowPosition(wxWindow *aWindow)
Prepare a top-level window for reliable position round-tripping.
Definition wxgtk/ui.cpp:169
double GetPixelScaleFactor(const wxWindow *aWindow)
Tries to determine the pixel scaling factor currently in use for the window.
Definition wxgtk/ui.cpp:274
void InfiniteDragReleaseWindow()
On Wayland, allows the cursor to freely move again after a drag (see InfiniteDragPrepareWindow).
Definition wxgtk/ui.cpp:760
void EnsureVisible(wxWindow *aWindow)
Ensure that a window is visible on the screen.
Definition wxgtk/ui.cpp:163
bool IsStockCursorOk(wxStockCursor aCursor)
Checks if we designated a stock cursor for this OS as "OK" or else we may need to load a custom one.
Definition wxgtk/ui.cpp:199
double GetContentScaleFactor(const wxWindow *aWindow)
Tries to determine the content scaling factor currently in use for the window.
Definition wxgtk/ui.cpp:287
void ImeNotifyCancelComposition(wxWindow *aWindow)
Asks the IME to cancel.
Definition wxgtk/ui.cpp:423
void LargeChoiceBoxHack(wxChoice *aChoice)
Configure a wxChoice control to support a lot of entries by disabling functionality that makes adding...
Definition wxgtk/ui.cpp:235
bool WarpPointer(wxWindow *aWindow, int aX, int aY)
Move the mouse cursor to a specific position relative to the window.
Definition wxgtk/ui.cpp:352
wxColour GetDialogBGColour()
Definition wxgtk/ui.cpp:63
bool IsWindowActive(wxWindow *aWindow)
Check to see if the given window is the currently active window (e.g.
Definition wxgtk/ui.cpp:148
wxSize GetUnobscuredSize(const wxWindow *aWindow)
Tries to determine the size of the viewport of a scrollable widget (wxDataViewCtrl,...
Definition wxgtk/ui.cpp:294
void ForceFocus(wxWindow *aWindow)
Pass the current focus to the window.
Definition wxgtk/ui.cpp:126
bool InfiniteDragPrepareWindow(wxWindow *aWindow)
On Wayland, restricts the pointer movement to a rectangle slightly bigger than the given wxWindow.
Definition wxgtk/ui.cpp:753
void ReparentModal(wxNonOwnedWindow *aWindow)
Move a window's parent to be the top-level window and force the window to be on top.
Definition wxgtk/ui.cpp:181
void CancelPendingScroll(wxDataViewCtrl *aCtrl)
Cancel any pending scroll-to-item request on aCtrl.
Definition wxgtk/ui.cpp:457
bool IsDarkTheme()
Determine if the desktop interface is currently using a dark theme or a light theme.
Definition wxgtk/ui.cpp:50
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:448
std::shared_ptr< PNS_LOG_VIEWER_OVERLAY > overlay
std::string path
const struct wl_interface zwp_pointer_constraints_v1_interface
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...
Definition wxgtk/ui.cpp:222
const wxString traceWayland
Definition wxgtk/ui.cpp:47