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
18 * along with this program. If not, see <https://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/popupwin.h>
28#include <wx/settings.h>
29#include <wx/window.h>
30#include <wx/log.h>
31
32#include <gtk/gtk.h>
33#include <gdk/gdk.h>
34
35#ifdef GDK_WINDOWING_X11
36#include <gdk/gdkx.h>
37#include <X11/Xlib.h>
38#include <X11/Xutil.h>
39#endif
40
41#ifdef GDK_WINDOWING_WAYLAND
42#include <gdk/gdkwayland.h>
43#endif
44
45#ifdef KICAD_WAYLAND
47#endif
48
49// Set WXTRACE=KICAD_WAYLAND to see logs
50const wxString traceWayland = wxS( "KICAD_WAYLAND" );
51static const wxChar traceRhi[] = wxT( "KICAD_RHI" );
52
53
55{
56 wxColour bg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW );
57
58 // Weighted W3C formula
59 double brightness = ( bg.Red() / 255.0 ) * 0.299 +
60 ( bg.Green() / 255.0 ) * 0.587 +
61 ( bg.Blue() / 255.0 ) * 0.117;
62
63 return brightness < 0.5;
64}
65
66
68{
69 return wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
70}
71
72
73void KIPLATFORM::UI::GetInfoBarColours( wxColour& aFgColour, wxColour& aBgColour )
74{
75 // The GTK3.24 way of getting the colours is to use the style context
76 // Earlier GTKs should be able to use the system settings
77#if( GTK_CHECK_VERSION( 3, 24, 0 ) )
78 GdkRGBA* rgba;
79 GtkWidgetPath* path = gtk_widget_path_new();
80 GtkStyleContext* sc = gtk_style_context_new();
81
82 gtk_widget_path_append_type( path, GTK_TYPE_WINDOW );
83 gtk_widget_path_iter_set_object_name( path, -1, "infobar" );
84 gtk_widget_path_iter_add_class( path, -1, "info" );
85
86 gtk_style_context_set_path( sc, path );
87 gtk_style_context_set_state( sc, GTK_STATE_FLAG_NORMAL );
88
89 gtk_style_context_get( sc, GTK_STATE_FLAG_NORMAL, "background-color", &rgba, NULL );
90 aBgColour = wxColour( *rgba );
91 gdk_rgba_free( rgba );
92
93 gtk_style_context_get( sc, GTK_STATE_FLAG_NORMAL, "color", &rgba, NULL );
94 aFgColour = wxColour( *rgba );
95 gdk_rgba_free( rgba );
96
97 // Some GTK themes use the plain infobar style, but if they don't, the background alpha
98 // is generally 0. In this case, try the revealer and box as these are used for Adwaita
99 // and other themes.
100 if( aBgColour.Alpha() == 0 )
101 {
102 gtk_widget_path_append_type( path, G_TYPE_NONE );
103 gtk_widget_path_iter_set_object_name( path, -1, "revealer" );
104 gtk_widget_path_append_type( path, G_TYPE_NONE );
105 gtk_widget_path_iter_set_object_name( path, -1, "box" );
106
107 gtk_style_context_set_path( sc, path );
108 gtk_style_context_set_state( sc, GTK_STATE_FLAG_NORMAL );
109
110 gtk_style_context_get( sc, GTK_STATE_FLAG_NORMAL, "background-color", &rgba, NULL );
111 aBgColour = wxColour( *rgba );
112 gdk_rgba_free( rgba );
113
114 gtk_style_context_get( sc, GTK_STATE_FLAG_NORMAL, "color", &rgba, NULL );
115 aFgColour = wxColour( *rgba );
116 gdk_rgba_free( rgba );
117 }
118
119 gtk_widget_path_free( path );
120 g_object_unref( sc );
121
122#else
123 aBgColour = wxSystemSettings::GetColour( wxSYS_COLOUR_INFOBK );
124 aFgColour = wxSystemSettings::GetColour( wxSYS_COLOUR_INFOTEXT );
125#endif
126
127}
128
129
130#ifdef GDK_WINDOWING_WAYLAND
131// Holds widgets over a canvas whose OpenGL subsurface covers everything GTK draws in the frame
132// Subsurfaces stack in the order they are mapped, so this one is remapped after the canvas
133class CANVAS_OVERLAY : public wxPopupWindow
134{
135public:
136 CANVAS_OVERLAY( wxWindow* aCanvas ) :
137 wxPopupWindow( aCanvas )
138 {
139 // wx asks for a compositor popup, and GDK maps a popup with any other hint as a subsurface
140 gtk_window_set_type_hint( GTK_WINDOW( m_widget ), GDK_WINDOW_TYPE_HINT_NORMAL );
141
142 aCanvas->Bind( wxEVT_SIZE, &CANVAS_OVERLAY::onCanvasSize, this );
143 g_signal_connect( aCanvas->GetHandle(), "map", G_CALLBACK( onCanvasMap ), this );
144 }
145
146 ~CANVAS_OVERLAY() override
147 {
148 GetParent()->Unbind( wxEVT_SIZE, &CANVAS_OVERLAY::onCanvasSize, this );
149 g_signal_handlers_disconnect_by_data( GetParent()->GetHandle(), this );
150 }
151
152 void Raise() override
153 {
154 // The canvas maps its surface from a queued event, so wait for that
155 CallAfter( &CANVAS_OVERLAY::remap );
156 }
157
158 bool Show( bool aShow = true ) override
159 {
160 if( aShow )
161 follow();
162
163 return wxPopupWindow::Show( aShow );
164 }
165
166private:
167 static void onCanvasMap( GtkWidget* aWidget, gpointer aOverlay )
168 {
169 static_cast<CANVAS_OVERLAY*>( aOverlay )->Raise();
170 }
171
172 void onCanvasSize( wxSizeEvent& aEvent )
173 {
174 follow();
175 aEvent.Skip();
176 }
177
178 void follow()
179 {
180 // There is no position to follow until the frame is mapped
181 if( gtk_widget_get_mapped( GetParent()->GetHandle() ) )
182 Move( GetParent()->ClientToScreen( wxPoint( 0, 0 ) ) );
183 }
184
185 void remap()
186 {
187 if( !IsShown() )
188 return;
189
190 Hide();
191 Show();
192 }
193};
194#endif
195
196
197wxWindow* KIPLATFORM::UI::CreateCanvasOverlay( wxWindow* aCanvas )
198{
199#ifdef GDK_WINDOWING_WAYLAND
200 if( GDK_IS_WAYLAND_DISPLAY( gdk_display_get_default() ) )
201 return new CANVAS_OVERLAY( aCanvas );
202#endif
203
204 return nullptr;
205}
206
207
208void KIPLATFORM::UI::ForceFocus( wxWindow* aWindow )
209{
210 aWindow->SetFocus();
211
212 // On GTK, SetFocus() on a dialog may not be sufficient to receive keyboard events
213 // (like ESC for closing). We need to ensure the window is presented and active.
214 // Find the top-level window and present it to ensure keyboard focus.
215 wxWindow* tlw = aWindow;
216
217 while( tlw && !tlw->IsTopLevel() )
218 tlw = tlw->GetParent();
219
220 if( tlw )
221 {
222 GtkWidget* widget = static_cast<GtkWidget*>( tlw->GetHandle() );
223
224 if( widget && GTK_IS_WINDOW( widget ) )
225 gtk_window_present( GTK_WINDOW( widget ) );
226 }
227}
228
229
230bool KIPLATFORM::UI::IsWindowActive( wxWindow* aWindow )
231{
232 if( !aWindow )
233 return false;
234
235 GtkWindow* window = GTK_WINDOW( aWindow->GetHandle() );
236
237 if( window )
238 return gtk_window_is_active( window );
239
240 // We shouldn't really ever reach this point
241 return false;
242}
243
244
245void KIPLATFORM::UI::EnsureVisible( wxWindow* aWindow )
246{
247 // Not needed on this platform
248}
249
250
252{
253 if( !aWindow )
254 return;
255
256 GtkWidget* widget = static_cast<GtkWidget*>( aWindow->GetHandle() );
257
258 if( widget && GTK_IS_WINDOW( widget ) )
259 gtk_window_set_gravity( GTK_WINDOW( widget ), GDK_GRAVITY_STATIC );
260}
261
262
263static const char* const WM_CLASS_DATA_KEY = "kicad-wm-class";
264
265
266// Re-assert our application id on the widget's window. Bound to "realize" and "map" because GTK
267// writes WM_CLASS from the program class when it realizes the window, so ours must be applied
268// afterwards to survive; the Wayland application id additionally requires a mapped surface. The
269// id is read from the widget's object data so its lifetime is not tied to the signal closures.
270static void setWindowClassHint( GtkWidget* aWidget, gpointer )
271{
272 const char* id = static_cast<const char*>( g_object_get_data( G_OBJECT( aWidget ),
274
275 if( !id || !*id )
276 return;
277
278 GdkWindow* window = gtk_widget_get_window( aWidget );
279
280 if( !window )
281 return;
282
283#ifdef GDK_WINDOWING_X11
284 if( GDK_IS_X11_WINDOW( window ) )
285 {
286 // wxGTK sets res_class from the app display name; overwrite both WM_CLASS fields with
287 // the desktop id so the window manager matches us to our installed .desktop launcher.
288 if( XClassHint* hints = XAllocClassHint() )
289 {
290 hints->res_name = const_cast<char*>( id );
291 hints->res_class = const_cast<char*>( id );
292
293 XSetClassHint( GDK_WINDOW_XDISPLAY( window ), GDK_WINDOW_XID( window ), hints );
294 XFree( hints );
295 }
296 }
297#endif
298
299#if defined( GDK_WINDOWING_WAYLAND ) && GTK_CHECK_VERSION( 3, 24, 22 )
300 // Covers wx < 3.3.1, which never propagates the class name to the Wayland application id.
301 if( GDK_IS_WAYLAND_WINDOW( window ) && gtk_check_version( 3, 24, 22 ) == nullptr )
302 gdk_wayland_window_set_application_id( window, id );
303#endif
304}
305
306
307void KIPLATFORM::UI::SetWMClass( wxWindow* aWindow, const wxString& aClass )
308{
309 if( !aWindow || aClass.IsEmpty() )
310 return;
311
312 GtkWidget* widget = static_cast<GtkWidget*>( aWindow->GetHandle() );
313
314 if( !widget )
315 return;
316
317 // Own a single copy of the id on the widget; it is freed when the widget is destroyed. The
318 // signal handlers read it back from here rather than capturing it, so repeated calls stay safe.
319 g_object_set_data_full( G_OBJECT( widget ), WM_CLASS_DATA_KEY, g_strdup( aClass.utf8_str() ),
320 g_free );
321
322 // Guard against stacking duplicate handlers if this is called more than once for a widget.
323 g_signal_handlers_disconnect_by_func( widget, reinterpret_cast<void*>( setWindowClassHint ),
324 nullptr );
325
326 g_signal_connect_after( widget, "realize", G_CALLBACK( setWindowClassHint ), nullptr );
327 g_signal_connect_after( widget, "map", G_CALLBACK( setWindowClassHint ), nullptr );
328
329 // Apply immediately for windows already realized when this is called.
330 if( gtk_widget_get_realized( widget ) )
331 setWindowClassHint( widget, nullptr );
332}
333
334
335void KIPLATFORM::UI::ReparentModal( wxNonOwnedWindow* aWindow )
336{
337 // Not needed on this platform
338}
339
340
341void KIPLATFORM::UI::ReparentWindow( wxNonOwnedWindow* aWindow, wxTopLevelWindow* aParent )
342{
343 // Not needed on this platform (only relevant for macOS child window ordering)
344}
345
346
348{
349 // Not needed on this platform
350}
351
352
353bool KIPLATFORM::UI::IsStockCursorOk( wxStockCursor aCursor )
354{
355 switch( aCursor )
356 {
357 case wxCURSOR_BULLSEYE:
358 case wxCURSOR_HAND:
359 case wxCURSOR_ARROW:
360 case wxCURSOR_BLANK:
361 return true;
362 default:
363 return false;
364 }
365}
366
367
376static void disable_area_apply_attributes_cb( GtkWidget* pItem, gpointer userdata )
377{
378 // GTK needs this enormous chain to get the actual type of item that we want
379 GtkMenuItem* pMenuItem = GTK_MENU_ITEM( pItem );
380 GtkWidget* child = gtk_bin_get_child( GTK_BIN( pMenuItem ) );
381 GtkCellView* pCellView = GTK_CELL_VIEW( child );
382 GtkCellLayout* pCellLayout = GTK_CELL_LAYOUT( pCellView );
383 GtkCellArea* pCellArea = gtk_cell_layout_get_area( pCellLayout );
384
385 g_signal_handlers_block_matched( pCellArea, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, userdata );
386}
387
388
389void KIPLATFORM::UI::LargeChoiceBoxHack( wxChoice* aChoice )
390{
391 AtkObject* atkObj = gtk_combo_box_get_popup_accessible( GTK_COMBO_BOX( aChoice->m_widget ) );
392
393 if( !atkObj || !GTK_IS_ACCESSIBLE( atkObj ) )
394 return;
395
396 GtkWidget* widget = gtk_accessible_get_widget( GTK_ACCESSIBLE( atkObj ) );
397
398 if( !widget || !GTK_IS_MENU( widget ) )
399 return;
400
401 GtkMenu* menu = GTK_MENU( widget );
402
403 gtk_container_foreach( GTK_CONTAINER( menu ), disable_area_apply_attributes_cb, menu );
404}
405
406
407void KIPLATFORM::UI::EllipsizeChoiceBox( wxChoice* aChoice )
408{
409 // This function is based on the code inside the function post_process_ui in
410 // gtkfilechooserwidget.c
411 GList* cells = gtk_cell_layout_get_cells( GTK_CELL_LAYOUT( aChoice->m_widget ) );
412
413 if( !cells )
414 return;
415
416 GtkCellRenderer* cell = (GtkCellRenderer*) cells->data;
417
418 if( !cell )
419 return;
420
421 g_object_set( G_OBJECT( cell ), "ellipsize", PANGO_ELLIPSIZE_END, nullptr );
422
423 // Only the list of cells must be freed, the renderer isn't ours to free
424 g_list_free( cells );
425}
426
427
428double KIPLATFORM::UI::GetPixelScaleFactor( const wxWindow* aWindow )
429{
430 double val = 1.0;
431
432 GtkWidget* widget = static_cast<GtkWidget*>( aWindow->GetHandle() );
433
434 if( widget && gtk_check_version( 3, 10, 0 ) == nullptr )
435 val = gtk_widget_get_scale_factor( widget );
436
437 return val;
438}
439
440
441double KIPLATFORM::UI::GetContentScaleFactor( const wxWindow* aWindow )
442{
443 // TODO: Do we need something different here?
444 return GetPixelScaleFactor( aWindow );
445}
446
447
448double KIPLATFORM::UI::GetDisplayRefreshRate( const wxWindow* aWindow )
449{
450#if GTK_CHECK_VERSION( 3, 22, 0 )
451 GtkWidget* widget = static_cast<GtkWidget*>( aWindow->GetHandle() );
452 GdkWindow* window = widget ? gtk_widget_get_window( widget ) : nullptr;
453
454 if( !window )
455 return 0.0;
456
457 GdkMonitor* monitor = gdk_display_get_monitor_at_window( gdk_window_get_display( window ), window );
458
459 // GDK reports millihertz, and 0 when it does not know
460 return monitor ? gdk_monitor_get_refresh_rate( monitor ) / 1000.0 : 0.0;
461#else
462 return 0.0;
463#endif
464}
465
466
467wxSize KIPLATFORM::UI::GetUnobscuredSize( const wxWindow* aWindow )
468{
469 return wxSize( aWindow->GetSize().GetX() - wxSystemSettings::GetMetric( wxSYS_VSCROLL_X ),
470 aWindow->GetSize().GetY() - wxSystemSettings::GetMetric( wxSYS_HSCROLL_Y ) );
471}
472
473
474void KIPLATFORM::UI::SetOverlayScrolling( const wxWindow* aWindow, bool overlay )
475{
476 gtk_scrolled_window_set_overlay_scrolling( GTK_SCROLLED_WINDOW( aWindow->GetHandle() ),
477 overlay );
478}
479
480
482{
483 gboolean allowed = 1;
484
485 g_object_get( gtk_settings_get_default(), "gtk-menu-images", &allowed, NULL );
486
487 return !!allowed;
488}
489
490
492{
493#ifdef GDK_WINDOWING_X11
494 GdkDisplay* display = gdk_display_get_default();
495
496 return display && GDK_IS_X11_DISPLAY( display );
497#else
498 return false;
499#endif
500}
501
502
503#if defined( GDK_WINDOWING_WAYLAND ) && defined( KICAD_WAYLAND )
504
505static bool wayland_warp_pointer( GtkWidget* aWidget, GdkDisplay* aDisplay, GdkWindow* aWindow,
506 GdkDevice* aPtrDev, int aX, int aY );
507
508// GDK doesn't know if we've moved the cursor using Wayland pointer constraints.
509// So emulate the actual position here
510static wxPoint s_warped_from;
511static wxPoint s_warped_to;
512
514{
515 wxPoint wx_pos = wxGetMousePosition();
516
517 if( wx_pos == s_warped_from )
518 {
519 wxLogTrace( traceWayland, wxS( "Faked mouse pos %d %d -> %d %d" ), wx_pos.x, wx_pos.y,
520 s_warped_to.x, s_warped_to.y );
521
522 return s_warped_to;
523 }
524 else
525 {
526 // Mouse has moved
527 s_warped_from = wxPoint();
528 s_warped_to = wxPoint();
529 }
530
531 return wx_pos;
532}
533
534#endif
535
536
537bool KIPLATFORM::UI::WarpPointer( wxWindow* aWindow, int aX, int aY )
538{
539 if( !wxGetEnv( wxT( "WAYLAND_DISPLAY" ), nullptr ) )
540 {
541 aWindow->WarpPointer( aX, aY );
542 return true;
543 }
544 else
545 {
546 GtkWidget* widget = static_cast<GtkWidget*>( aWindow->GetHandle() );
547
548 GdkDisplay* disp = gtk_widget_get_display( widget );
549 GdkSeat* seat = gdk_display_get_default_seat( disp );
550 GdkDevice* ptrdev = gdk_seat_get_pointer( seat );
551
552#if defined( GDK_WINDOWING_WAYLAND ) && defined( KICAD_WAYLAND )
553 if( GDK_IS_WAYLAND_DISPLAY( disp ) )
554 {
555 wxPoint initialPos = wxGetMousePosition();
556 GdkWindow* win = aWindow->GTKGetDrawingWindow();
557
558 if( wayland_warp_pointer( widget, disp, win, ptrdev, aX, aY ) )
559 {
560 s_warped_from = initialPos;
561 s_warped_to = aWindow->ClientToScreen( wxPoint( aX, aY ) );
562
563 wxLogTrace( traceWayland, wxS( "Set warped from %d %d to %d %d" ), s_warped_from.x,
564 s_warped_from.y, s_warped_to.x, s_warped_to.y );
565
566 return true;
567 }
568
569 wxLogTrace( traceWayland, wxS( "*** Warp to %d %d failed ***" ), aX, aY );
570
571 return false;
572 }
573#endif
574#ifdef GDK_WINDOWING_X11
575 if( GDK_IS_X11_DISPLAY( disp ) )
576 {
577 GdkWindow* win = gdk_device_get_window_at_position( ptrdev, nullptr, nullptr );
578
579 if( !win )
580 {
581 aWindow->WarpPointer( aX, aY );
582 return true;
583 }
584
585 GdkCursor* blank_cursor = gdk_cursor_new_for_display( disp, GDK_BLANK_CURSOR );
586 GdkCursor* cur_cursor = gdk_window_get_cursor( win );
587
588 if( cur_cursor )
589 g_object_ref( cur_cursor );
590
591 gdk_window_set_cursor( win, blank_cursor );
592 aWindow->WarpPointer( aX, aY );
593 gdk_window_set_cursor( win, cur_cursor );
594
595 if( cur_cursor )
596 g_object_unref( cur_cursor );
597
598 if( blank_cursor )
599 g_object_unref( blank_cursor );
600
601 return true;
602 }
603#endif
604 }
605
606 return false;
607}
608
609
610void KIPLATFORM::UI::ImmControl( wxWindow* aWindow, bool aEnable )
611{
612}
613
614
616{
617 wxWindowGTK* win = static_cast<wxWindowGTK*>( aWindow );
618 if( win )
619 {
620 GtkIMContext* imContext = win->m_imContext;
621 if( imContext )
622 {
623 gtk_im_context_focus_out( imContext );
624 }
625 }
626}
627
628
629void KIPLATFORM::UI::SetFloatLevel( wxWindow* aWindow )
630{
631}
632
633
634void KIPLATFORM::UI::ReleaseChildWindow( wxNonOwnedWindow* aWindow )
635{
636 // Not needed on this platform
637}
638
639
641{
642 GtkWidget* widget = static_cast<GtkWidget*>( aDialog->GetHandle() );
643
644 if( widget && GTK_IS_FILE_CHOOSER( widget ) )
645 gtk_file_chooser_set_local_only( GTK_FILE_CHOOSER( widget ), FALSE );
646}
647
648
649void KIPLATFORM::UI::CancelPendingScroll( wxDataViewCtrl* aCtrl )
650{
651 if( !aCtrl )
652 return;
653
654 GtkWidget* widget = aCtrl->GtkGetTreeView();
655
656 if( !widget || !GTK_IS_TREE_VIEW( widget ) )
657 return;
658
659 GtkTreeView* view = GTK_TREE_VIEW( widget );
660
661 // Need a live model and rbtree for the assertions in scroll_to_cell.
662 if( !gtk_tree_view_get_model( view ) )
663 return;
664
665 GtkTreeViewColumn* column = gtk_tree_view_get_column( view, 0 );
666
667 if( !column )
668 return;
669
670 // A column-only scroll_to_cell enters GTK's deferred-scroll path, which frees
671 // priv->scroll_to_path and only installs scroll_to_column. That breaks the race
672 // where validate_visible_area dereferences a stale row reference after a model
673 // reset. The deferred branch is taken when the widget is not yet allocated, when
674 // alloc is pending, or when rows are invalid -- queue_resize forces the latter so
675 // a steady-state widget also takes that branch and actually clears the reference.
676 gtk_widget_queue_resize( widget );
677 gtk_tree_view_scroll_to_cell( view, nullptr, column, FALSE, 0.0, 0.0 );
678}
679
680//
681// **** Wayland hacks ahead ****
682//
683
684#if defined( GDK_WINDOWING_WAYLAND ) && defined( KICAD_WAYLAND )
685
686static bool s_wl_initialized = false;
687static struct wl_compositor* s_wl_compositor = NULL;
688static struct zwp_pointer_constraints_v1* s_wl_pointer_constraints = NULL;
689static struct zwp_confined_pointer_v1* s_wl_confined_pointer = NULL;
690static struct wl_region* s_wl_confinement_region = NULL;
691static bool s_wl_locked_flag = false;
692
693static void handle_global( void* data, struct wl_registry* registry, uint32_t name,
694 const char* interface, uint32_t version )
695{
696 wxLogTrace( traceWayland, "handle_global received %s name %u version %u", interface,
697 (unsigned int) name, (unsigned int) version );
698
699 if( strcmp( interface, wl_compositor_interface.name ) == 0 )
700 {
701 s_wl_compositor = static_cast<wl_compositor*>(
702 wl_registry_bind( registry, name, &wl_compositor_interface, version ) );
703 }
704 else if( strcmp( interface, zwp_pointer_constraints_v1_interface.name ) == 0 )
705 {
706 s_wl_pointer_constraints = static_cast<zwp_pointer_constraints_v1*>( wl_registry_bind(
707 registry, name, &zwp_pointer_constraints_v1_interface, version ) );
708 }
709}
710
711static void handle_global_remove( void*, struct wl_registry*, uint32_t name )
712{
713 wxLogTrace( traceWayland, "handle_global_remove name %u", (unsigned int) name );
714}
715
716static const struct wl_registry_listener registry_listener = {
717 .global = handle_global,
718 .global_remove = handle_global_remove,
719};
720
721static void confined_handler( void* data, struct zwp_confined_pointer_v1* zwp_confined_pointer_v1 )
722{
723 wxLogTrace( traceWayland, wxS( "Pointer confined" ) );
724}
725
726static void unconfined_handler( void* data,
727 struct zwp_confined_pointer_v1* zwp_confined_pointer_v1 )
728{
729 wxLogTrace( traceWayland, wxS( "Pointer unconfined" ) );
730}
731
732static const struct zwp_confined_pointer_v1_listener confined_pointer_listener = {
733 .confined = confined_handler,
734 .unconfined = unconfined_handler
735};
736
737static void locked_handler( void* data, struct zwp_locked_pointer_v1* zwp_locked_pointer_v1 )
738{
739 s_wl_locked_flag = true;
740 wxLogTrace( traceWayland, wxS( "Pointer locked" ) );
741}
742
743static void unlocked_handler( void* data, struct zwp_locked_pointer_v1* zwp_locked_pointer_v1 )
744{
745 wxLogTrace( traceWayland, wxS( "Pointer unlocked" ) );
746}
747
748static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = {
749 .locked = locked_handler,
750 .unlocked = unlocked_handler
751};
752
753
757static void initialize_wayland( wl_display* wldisp )
758{
759 if( s_wl_initialized )
760 {
761 return;
762 }
763
764 struct wl_registry* registry = wl_display_get_registry( wldisp );
765 wl_registry_add_listener( registry, &registry_listener, NULL );
766 wl_display_roundtrip( wldisp );
767 s_wl_initialized = true;
768}
769
770
771struct zwp_locked_pointer_v1* s_wl_locked_pointer = NULL;
772
773static int s_after_paint_handler_id = 0;
774
775static void on_frame_clock_after_paint( GdkFrameClock* clock, GtkWidget* widget )
776{
777 if( s_wl_locked_pointer )
778 {
779 zwp_locked_pointer_v1_destroy( s_wl_locked_pointer );
780 s_wl_locked_pointer = NULL;
781
782 wxLogTrace( traceWayland, wxS( "after-paint: locked_pointer destroyed" ) );
783
784 g_signal_handler_disconnect( (gpointer) clock, s_after_paint_handler_id );
785 s_after_paint_handler_id = 0;
786
787 // restore confinement
788 if( s_wl_confinement_region != NULL )
789 {
790 wxLogTrace( traceWayland, wxS( "after-paint: Restoring confinement" ) );
791
792 GdkDisplay* disp = gtk_widget_get_display( widget );
793 GdkSeat* seat = gdk_display_get_default_seat( disp );
794 GdkDevice* ptrdev = gdk_seat_get_pointer( seat );
795 GdkWindow* window = gtk_widget_get_window( widget );
796
797 wl_display* wldisp = gdk_wayland_display_get_wl_display( disp );
798 wl_surface* wlsurf = gdk_wayland_window_get_wl_surface( window );
799 wl_pointer* wlptr = gdk_wayland_device_get_wl_pointer( ptrdev );
800
801 s_wl_confined_pointer = zwp_pointer_constraints_v1_confine_pointer(
802 s_wl_pointer_constraints, wlsurf, wlptr, s_wl_confinement_region,
804
805 wl_display_roundtrip( wldisp );
806 }
807 }
808}
809
810
811static bool wayland_warp_pointer( GtkWidget* aWidget, GdkDisplay* aDisplay, GdkWindow* aWindow,
812 GdkDevice* aPtrDev, int aX, int aY )
813{
814 wl_display* wldisp = gdk_wayland_display_get_wl_display( aDisplay );
815 wl_surface* wlsurf = gdk_wayland_window_get_wl_surface( aWindow );
816 wl_pointer* wlptr = gdk_wayland_device_get_wl_pointer( aPtrDev );
817
818 if( s_after_paint_handler_id )
819 {
820 // Previous paint not done yet
821 wxLogTrace( traceWayland, wxS( "Not warping: after-paint pending" ) );
822 return false;
823 }
824
825 initialize_wayland( wldisp );
826
827 if( s_wl_locked_pointer )
828 {
829 // This shouldn't happen but let's be safe
830 wxLogTrace( traceWayland, wxS( "** Destroying previous locked_pointer **" ) );
831 zwp_locked_pointer_v1_destroy( s_wl_locked_pointer );
832 wl_display_roundtrip( wldisp );
833 s_wl_locked_pointer = NULL;
834 }
835
836 // wl_surface_commit causes an assert on GNOME, but has to be called on KDE
837 // before destroying the locked pointer, so wait until GDK commits the surface.
838 GdkFrameClock* frame_clock = gdk_window_get_frame_clock( aWindow );
839 s_after_paint_handler_id = g_signal_connect_after(
840 frame_clock, "after-paint", G_CALLBACK( on_frame_clock_after_paint ), aWidget );
841
842 // temporary disable confinement to allow pointer warping
843 if( s_wl_confinement_region && s_wl_confined_pointer )
844 {
845 zwp_confined_pointer_v1_destroy( s_wl_confined_pointer );
846 wl_display_roundtrip( wldisp );
847 s_wl_confined_pointer = NULL;
848 }
849
850 s_wl_locked_flag = false;
851
852 s_wl_locked_pointer =
853 zwp_pointer_constraints_v1_lock_pointer( s_wl_pointer_constraints, wlsurf, wlptr, NULL,
855
856 zwp_locked_pointer_v1_add_listener(s_wl_locked_pointer, &locked_pointer_listener, NULL);
857
858 gint wx, wy;
859 gtk_widget_translate_coordinates( aWidget, gtk_widget_get_toplevel( aWidget ), 0, 0, &wx, &wy );
860
861 zwp_locked_pointer_v1_set_cursor_position_hint( s_wl_locked_pointer, wl_fixed_from_int( aX + wx ),
862 wl_fixed_from_int( aY + wy ) );
863
864 // Don't call wl_surface_commit, wait for GDK because of an assert on GNOME.
865 wl_display_roundtrip( wldisp ); // To receive "locked" event.
866 gtk_widget_queue_draw( aWidget ); // Needed on some GNOME environment to trigger
867 // the "after-paint" event handler.
868
869 return s_wl_locked_flag;
870}
871
872
873bool KIPLATFORM::UI::InfiniteDragPrepareWindow( wxWindow* aWindow )
874{
875 wxLogTrace( traceWayland, wxS( "InfiniteDragPrepareWindow" ) );
876
877 GtkWidget* widget = static_cast<GtkWidget*>( aWindow->GetHandle() );
878 GdkDisplay* disp = gtk_widget_get_display( widget );
879
880 if( GDK_IS_WAYLAND_DISPLAY( disp ) )
881 {
882 if( s_wl_confined_pointer != NULL )
883 {
885 }
886
887 GdkSeat* seat = gdk_display_get_default_seat( disp );
888 GdkDevice* ptrdev = gdk_seat_get_pointer( seat );
889 GdkWindow* win = aWindow->GTKGetDrawingWindow();
890
891 wl_display* wldisp = gdk_wayland_display_get_wl_display( disp );
892 wl_surface* wlsurf = gdk_wayland_window_get_wl_surface( win );
893 wl_pointer* wlptr = gdk_wayland_device_get_wl_pointer( ptrdev );
894
895 initialize_wayland( wldisp );
896
897 gint x, y, width, height;
898 gdk_window_get_geometry( gdk_window_get_toplevel( win ), &x, &y, &width, &height );
899
900 wxLogTrace( traceWayland, wxS( "Confine region: %d %d %d %d" ), x, y, width, height );
901
902 s_wl_confinement_region = wl_compositor_create_region( s_wl_compositor );
903 wl_region_add( s_wl_confinement_region, x, y, width, height );
904
905 s_wl_confined_pointer = zwp_pointer_constraints_v1_confine_pointer(
906 s_wl_pointer_constraints, wlsurf, wlptr, s_wl_confinement_region,
908
909 zwp_confined_pointer_v1_add_listener( s_wl_confined_pointer, &confined_pointer_listener,
910 NULL );
911
912 wl_display_roundtrip( wldisp );
913 }
914 else if( wxGetEnv( wxT( "WAYLAND_DISPLAY" ), nullptr ) )
915 {
916 // Not working under XWayland
917 return false;
918 }
919
920 return true;
921};
922
923
925{
926 wxLogTrace( traceWayland, wxS( "InfiniteDragReleaseWindow" ) );
927
928 if( s_wl_confined_pointer )
929 {
930 zwp_confined_pointer_v1_destroy( s_wl_confined_pointer );
931 s_wl_confined_pointer = NULL;
932 }
933
934 if( s_wl_confinement_region )
935 {
936 wl_region_destroy( s_wl_confinement_region );
937 s_wl_confinement_region = NULL;
938 }
939};
940
941
942#else // No Wayland support
943
944
946{
947 // Not working under XWayland
948 return !wxGetEnv( wxT( "WAYLAND_DISPLAY" ), nullptr );
949};
950
951
953{
954 // Not needed on X11
955};
956
957
959{
960 return wxGetMousePosition();
961}
962
963
964#endif
965
966
967void KIPLATFORM::UI::GetNativeWindowHandles( wxWindow* aWindow, void** aHandle, void** aDisplay,
968 int* aDisplayType )
969{
970 *aHandle = nullptr;
971 *aDisplay = nullptr;
972
973 if( aDisplayType )
975
976 if( !aWindow )
977 return;
978
979 GtkWidget* gtkWidget = static_cast<GtkWidget*>( aWindow->GetHandle() );
980
981 if( !gtkWidget )
982 return;
983
984 gtk_widget_realize( gtkWidget );
985 GdkWindow* gdkWindow = gtk_widget_get_window( gtkWidget );
986
987 if( !gdkWindow )
988 return;
989
990 if( !gdk_window_ensure_native( gdkWindow ) )
991 {
992 wxLogTrace( traceRhi, wxS( "GetNativeWindowHandles: gdk_window_ensure_native failed "
993 "widget=%p window=%p" ),
994 static_cast<void*>( gtkWidget ),
995 static_cast<void*>( gdkWindow ) );
996 return;
997 }
998
999 if( !gdk_window_is_viewable( gdkWindow ) )
1000 {
1001 // Hide() unmaps the GDK window, and mapping it anyway would put a hidden preview canvas back
1002 // on screen over its replacement.
1003 if( !gtk_widget_get_visible( gtkWidget ) )
1004 {
1005 wxLogTrace( traceRhi, wxS( "GetNativeWindowHandles: widget hidden, skipping "
1006 "native window map widget=%p window=%p" ),
1007 static_cast<void*>( gtkWidget ),
1008 static_cast<void*>( gdkWindow ) );
1009 return;
1010 }
1011
1012 wxLogTrace( traceRhi, wxS( "GetNativeWindowHandles: mapping native window "
1013 "widget=%p window=%p mapped=%s viewable=%s" ),
1014 static_cast<void*>( gtkWidget ),
1015 static_cast<void*>( gdkWindow ),
1016 gtk_widget_get_mapped( gtkWidget ) ? "yes" : "no",
1017 gdk_window_is_viewable( gdkWindow ) ? "yes" : "no" );
1018
1019 gdk_window_show_unraised( gdkWindow );
1020
1021 wxLogTrace( traceRhi, wxS( "GetNativeWindowHandles: native window map result "
1022 "window=%p viewable=%s" ),
1023 static_cast<void*>( gdkWindow ),
1024 gdk_window_is_viewable( gdkWindow ) ? "yes" : "no" );
1025 }
1026
1027 GdkDisplay* gdkDisplay = gtk_widget_get_display( gtkWidget );
1028
1029 // The render thread uses its own display connection and must see the window before creating a surface
1030 gdk_display_flush( gdkDisplay );
1031
1032#ifdef GDK_WINDOWING_X11
1033 if( GDK_IS_X11_DISPLAY( gdkDisplay ) )
1034 {
1035 *aHandle = reinterpret_cast<void*>( GDK_WINDOW_XID( gdkWindow ) );
1036 *aDisplay = gdk_x11_display_get_xdisplay( gdkDisplay );
1037
1038 if( aDisplayType )
1039 *aDisplayType = NATIVE_DISPLAY_TYPE::DISPLAY_X11;
1040
1041 wxLogTrace( traceRhi, wxS( "GetNativeWindowHandles: X11 widget=%p window=%p xid=0x%lx "
1042 "display=%p" ),
1043 static_cast<void*>( gtkWidget ),
1044 static_cast<void*>( gdkWindow ),
1045 static_cast<unsigned long>( GDK_WINDOW_XID( gdkWindow ) ),
1046 *aDisplay );
1047 return;
1048 }
1049#endif
1050
1051#ifdef GDK_WINDOWING_WAYLAND
1052 if( GDK_IS_WAYLAND_DISPLAY( gdkDisplay ) )
1053 {
1054 *aHandle = gdk_wayland_window_get_wl_surface( gdkWindow );
1055 *aDisplay = gdk_wayland_display_get_wl_display( gdkDisplay );
1056
1057 if( aDisplayType )
1059
1060 wxLogTrace( traceRhi, wxS( "GetNativeWindowHandles: Wayland widget=%p window=%p "
1061 "surface=%p display=%p" ),
1062 static_cast<void*>( gtkWidget ),
1063 static_cast<void*>( gdkWindow ),
1064 *aHandle,
1065 *aDisplay );
1066 return;
1067 }
1068#endif
1069}
1070
1071
1073{
1074 if( !aWindow )
1075 return;
1076
1077 GtkWidget* gtkWidget = static_cast<GtkWidget*>( aWindow->GetHandle() );
1078
1079 if( !gtkWidget )
1080 {
1081 wxLogTrace( traceRhi, wxS( "PrepareForExternalRendering: no GtkWidget handle" ) );
1082 return;
1083 }
1084
1085 bool realized = gtk_widget_get_realized( gtkWidget );
1086
1087 wxLogTrace( traceRhi, wxS( "PrepareForExternalRendering: widget=%p realized=%s" ),
1088 static_cast<void*>( gtkWidget ), realized ? "yes" : "no" );
1089
1090 // Do not realize here. Before layout that creates a 1x1 X11 window and poisons Vulkan's surface
1091 // capabilities, so GetNativeWindowHandles() realizes it on the first paint instead.
1092
1093 // GTK3's cairo backing surface would otherwise blit over the GPU output after every draw
1094 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1095 gtk_widget_set_double_buffered( gtkWidget, FALSE );
1096 G_GNUC_END_IGNORE_DEPRECATIONS
1097
1098 // Otherwise GTK clears to the GDK background before every draw and flashes black between presents
1099 gtk_widget_set_app_paintable( gtkWidget, TRUE );
1100
1101 wxLogTrace( traceRhi, wxS( "PrepareForExternalRendering: double-buffering disabled, "
1102 "app-paintable enabled" ) );
1103
1104 // Keep areas not yet presented from showing the GTK theme. This needs a realized widget.
1105 if( realized )
1106 {
1107 GdkWindow* gdkWindow = gtk_widget_get_window( gtkWidget );
1108
1109 if( gdkWindow )
1110 {
1111#ifdef GDK_WINDOWING_X11
1112 if( GDK_IS_X11_DISPLAY( gdk_display_get_default() ) )
1113 {
1114 // The X server repaints exposed regions with the BackgroundPixmap before the
1115 // client presents, flashing black; None leaves the previous frame in place.
1116 Display* xDisplay = GDK_DISPLAY_XDISPLAY( gdk_display_get_default() );
1117 Window xWindow = GDK_WINDOW_XID( gdkWindow );
1118 XSetWindowBackgroundPixmap( xDisplay, xWindow, None );
1119
1120 wxLogTrace( traceRhi, wxS( "PrepareForExternalRendering: X11 "
1121 "BackgroundPixmap set to None" ) );
1122 }
1123 else
1124#endif
1125 {
1126 GdkRGBA black = { 0.0, 0.0, 0.0, 1.0 };
1127
1128 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1129 gdk_window_set_background_rgba( gdkWindow, &black );
1130 G_GNUC_END_IGNORE_DEPRECATIONS
1131
1132 wxLogTrace( traceRhi, wxS( "PrepareForExternalRendering: GDK background "
1133 "set to black" ) );
1134 }
1135 }
1136 else
1137 {
1138 wxLogTrace( traceRhi, wxS( "PrepareForExternalRendering: no GdkWindow" ) );
1139 }
1140
1141 }
1142
1143 // Children shown earlier have been painting into the window the GPU now presents to
1144 for( wxWindow* child : aWindow->GetChildren() )
1146}
1147
1148
1150{
1151#ifdef GDK_WINDOWING_X11
1152 if( !aChild || !aChild->GetParent() )
1153 return;
1154
1155 GtkWidget* child = static_cast<GtkWidget*>( aChild->GetHandle() );
1156 GtkWidget* parent = static_cast<GtkWidget*>( aChild->GetParent()->GetHandle() );
1157
1158 if( !child || !parent || !GDK_IS_X11_DISPLAY( gtk_widget_get_display( child ) ) )
1159 return;
1160
1161 // PrepareForExternalRendering() is what turns double buffering off
1162 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1163 const bool external = !gtk_widget_get_double_buffered( parent );
1164 G_GNUC_END_IGNORE_DEPRECATIONS
1165
1166 if( !external )
1167 return;
1168
1169 GdkWindow* window = gtk_widget_get_window( child );
1170
1171 // A widget without a window of its own reports its parent's
1172 if( !window || window == gtk_widget_get_window( parent ) )
1173 return;
1174
1175 if( !gdk_window_ensure_native( window ) )
1176 wxLogTrace( traceRhi, wxS( "KeepAboveExternalRendering: gdk_window_ensure_native failed" ) );
1177#endif
1178}
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
const wxChar *const traceRhi
Flag to enable debug output of the RHI rendering backend.
double GetDisplayRefreshRate(const wxWindow *aWindow)
Return the refresh rate in Hz of the display showing most of the window, or 0 if unknown.
Definition wxgtk/ui.cpp:448
wxWindow * CreateCanvasOverlay(wxWindow *aCanvas)
Create a window for widgets that are shown over a canvas without taking space from it.
Definition wxgtk/ui.cpp:197
bool AllowIconsInMenus()
If the user has disabled icons system-wide, we check that here.
Definition wxgtk/ui.cpp:481
void GetNativeWindowHandles(wxWindow *aWindow, void **aHandle, void **aDisplay, int *aDisplayType=nullptr)
Get the native handles needed to create a GPU surface for aWindow.
Definition wxgtk/ui.cpp:967
void SetFloatLevel(wxWindow *aWindow)
Intended to set the floating window level in macOS on a window.
Definition wxgtk/ui.cpp:629
void GetInfoBarColours(wxColour &aFGColour, wxColour &aBGColour)
Return the background and foreground colors for info bars in the current scheme.
Definition wxgtk/ui.cpp:73
void ReparentWindow(wxNonOwnedWindow *aWindow, wxTopLevelWindow *aParent)
Definition wxgtk/ui.cpp:341
void ReleaseChildWindow(wxNonOwnedWindow *aWindow)
Release a modal window's parent-child relationship with its parent window.
Definition wxgtk/ui.cpp:634
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:407
void PrepareForExternalRendering(wxWindow *aWindow)
Prepare a realized widget for Vulkan or Metal rendering, before its first present.
void FixupCancelButtonCmdKeyCollision(wxWindow *aWindow)
Definition wxgtk/ui.cpp:347
void SetOverlayScrolling(const wxWindow *aWindow, bool overlay)
Used to set overlay/non-overlay scrolling mode in a window.
Definition wxgtk/ui.cpp:474
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition wxgtk/ui.cpp:958
void ImmControl(wxWindow *aWindow, bool aEnable)
Configures the IME mode of a given control handle.
Definition wxgtk/ui.cpp:610
void StabilizeWindowPosition(wxWindow *aWindow)
Prepare a top-level window for reliable position round-tripping.
Definition wxgtk/ui.cpp:251
double GetPixelScaleFactor(const wxWindow *aWindow)
Tries to determine the pixel scaling factor currently in use for the window.
Definition wxgtk/ui.cpp:428
@ DISPLAY_UNKNOWN
Definition ui.h:273
@ DISPLAY_X11
Definition ui.h:274
@ DISPLAY_WAYLAND
Definition ui.h:275
void InfiniteDragReleaseWindow()
On Wayland, allows the cursor to freely move again after a drag (see InfiniteDragPrepareWindow).
Definition wxgtk/ui.cpp:952
void EnsureVisible(wxWindow *aWindow)
Ensure that a window is visible on the screen.
Definition wxgtk/ui.cpp:245
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:353
bool SupportsKeyState()
Return whether wxGetKeyState() can query ordinary keys, beyond modifiers and lock keys.
Definition wxgtk/ui.cpp:491
void KeepAboveExternalRendering(wxWindow *aChild)
Keep a child visible on top of a parent prepared with PrepareForExternalRendering().
double GetContentScaleFactor(const wxWindow *aWindow)
Tries to determine the content scaling factor currently in use for the window.
Definition wxgtk/ui.cpp:441
void ImeNotifyCancelComposition(wxWindow *aWindow)
Asks the IME to cancel.
Definition wxgtk/ui.cpp:615
void LargeChoiceBoxHack(wxChoice *aChoice)
Configure a wxChoice control to support a lot of entries by disabling functionality that makes adding...
Definition wxgtk/ui.cpp:389
bool WarpPointer(wxWindow *aWindow, int aX, int aY)
Move the mouse cursor to a specific position relative to the window.
Definition wxgtk/ui.cpp:537
wxColour GetDialogBGColour()
Definition wxgtk/ui.cpp:67
bool IsWindowActive(wxWindow *aWindow)
Check to see if the given window is the currently active window (e.g.
Definition wxgtk/ui.cpp:230
wxSize GetUnobscuredSize(const wxWindow *aWindow)
Tries to determine the size of the viewport of a scrollable widget (wxDataViewCtrl,...
Definition wxgtk/ui.cpp:467
void ForceFocus(wxWindow *aWindow)
Pass the current focus to the window.
Definition wxgtk/ui.cpp:208
bool InfiniteDragPrepareWindow(wxWindow *aWindow)
On Wayland, restricts the pointer movement to a rectangle slightly bigger than the given wxWindow.
Definition wxgtk/ui.cpp:945
void SetWMClass(wxWindow *aWindow, const wxString &aClass)
Tag a top-level window with the freedesktop application id of its installed launcher,...
Definition wxgtk/ui.cpp:307
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:335
void CancelPendingScroll(wxDataViewCtrl *aCtrl)
Cancel any pending scroll-to-item request on aCtrl.
Definition wxgtk/ui.cpp:649
bool IsDarkTheme()
Determine if the desktop interface is currently using a dark theme or a light theme.
Definition wxgtk/ui.cpp:54
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:640
std::shared_ptr< PNS_LOG_VIEWER_OVERLAY > overlay
std::string path
const struct wl_interface zwp_pointer_constraints_v1_interface
static const char *const WM_CLASS_DATA_KEY
Definition wxgtk/ui.cpp:263
static void setWindowClassHint(GtkWidget *aWidget, gpointer)
Definition wxgtk/ui.cpp:270
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:376
const wxString traceWayland
Definition wxgtk/ui.cpp:50