fix(cef): honor invisible cursor requests from web content (#424)
Map CEF CursorTypeCtNone to the "none" cursor name so sites that hide their cursor (e.g. video players during idle playback) propagate through the GTK bridge instead of falling back to "default". Add TestCEFCursorToGDKName covering none, pointer, hand, ibeam, and the unknown-type fallback.
- commit
- 635dc6958e3383a9d60ec686653d4c2ff97688d4
- author
- bnema · · 2026-09-10 04:09 UTC
- committer
- GitHub · · 2026-09-10 04:09 UTC
- parent
- 69f40e2
- signature
- GPG Unverified
B5690EEEBB952194The key is unknown
2 files · +21 -0
M internal/infrastructure/cef/webview_handlers.go +1 -0
| @@ -1392,6 +1392,7 @@ var cefCursorNames = map[purecef.CursorType]string{ | |||
| 1392 | 1392 | purecef.CursorTypeCtGrabbing: "grabbing", | |
| 1393 | 1393 | purecef.CursorTypeCtZoomin: "zoom-in", | |
| 1394 | 1394 | purecef.CursorTypeCtZoomout: "zoom-out", | |
| 1395 | + | purecef.CursorTypeCtNone: "none", | |
| 1395 | 1396 | } | |
| 1396 | 1397 | ||
| 1397 | 1398 | // cefCursorToGDKName maps a CEF cursor type to a GDK/CSS cursor name. | |
| @@ -1392,6 +1392,7 @@ var cefCursorNames = map[purecef.CursorType]string{ | |||||
| 1392 | purecef.CursorTypeCtGrabbing: "grabbing", | 1392 | purecef.CursorTypeCtGrabbing: "grabbing", | ||
| 1393 | purecef.CursorTypeCtZoomin: "zoom-in", | 1393 | purecef.CursorTypeCtZoomin: "zoom-in", | ||
| 1394 | purecef.CursorTypeCtZoomout: "zoom-out", | 1394 | purecef.CursorTypeCtZoomout: "zoom-out", | ||
| 1395 | + | purecef.CursorTypeCtNone: "none", | |||
| 1395 | } | 1396 | } | ||
| 1396 | 1397 | ||||
| 1397 | // cefCursorToGDKName maps a CEF cursor type to a GDK/CSS cursor name. | 1398 | // cefCursorToGDKName maps a CEF cursor type to a GDK/CSS cursor name. | ||
M internal/infrastructure/cef/webview_handlers_test.go +20 -0
| @@ -679,3 +679,23 @@ type selectionRenderHandlerForTest struct{ wv *WebView } | |||
| 679 | 679 | func (h *selectionRenderHandlerForTest) OnTextSelectionChanged(_ purecef.Browser, selectedText string, _ *purecef.Range) { | |
| 680 | 680 | handleRenderTextSelectionChanged(h.wv, selectedText) | |
| 681 | 681 | } | |
| 682 | + | ||
| 683 | + | func TestCEFCursorToGDKName(t *testing.T) { | |
| 684 | + | tests := []struct { | |
| 685 | + | name string | |
| 686 | + | cursor purecef.CursorType | |
| 687 | + | expected string | |
| 688 | + | }{ | |
| 689 | + | {name: "none maps to invisible cursor", cursor: purecef.CursorTypeCtNone, expected: "none"}, | |
| 690 | + | {name: "pointer maps to default", cursor: purecef.CursorTypeCtPointer, expected: "default"}, | |
| 691 | + | {name: "hand maps to pointer", cursor: purecef.CursorTypeCtHand, expected: "pointer"}, | |
| 692 | + | {name: "ibeam maps to text", cursor: purecef.CursorTypeCtIbeam, expected: "text"}, | |
| 693 | + | {name: "unknown falls back to default", cursor: purecef.CursorType(-1), expected: "default"}, | |
| 694 | + | } | |
| 695 | + | ||
| 696 | + | for _, tt := range tests { | |
| 697 | + | t.Run(tt.name, func(t *testing.T) { | |
| 698 | + | require.Equal(t, tt.expected, cefCursorToGDKName(tt.cursor)) | |
| 699 | + | }) | |
| 700 | + | } | |
| 701 | + | } | |
| @@ -679,3 +679,23 @@ type selectionRenderHandlerForTest struct{ wv *WebView } | |||||
| 679 | func (h *selectionRenderHandlerForTest) OnTextSelectionChanged(_ purecef.Browser, selectedText string, _ *purecef.Range) { | 679 | func (h *selectionRenderHandlerForTest) OnTextSelectionChanged(_ purecef.Browser, selectedText string, _ *purecef.Range) { | ||
| 680 | handleRenderTextSelectionChanged(h.wv, selectedText) | 680 | handleRenderTextSelectionChanged(h.wv, selectedText) | ||
| 681 | } | 681 | } | ||
| 682 | + | ||||
| 683 | + | func TestCEFCursorToGDKName(t *testing.T) { | |||
| 684 | + | tests := []struct { | |||
| 685 | + | name string | |||
| 686 | + | cursor purecef.CursorType | |||
| 687 | + | expected string | |||
| 688 | + | }{ | |||
| 689 | + | {name: "none maps to invisible cursor", cursor: purecef.CursorTypeCtNone, expected: "none"}, | |||
| 690 | + | {name: "pointer maps to default", cursor: purecef.CursorTypeCtPointer, expected: "default"}, | |||
| 691 | + | {name: "hand maps to pointer", cursor: purecef.CursorTypeCtHand, expected: "pointer"}, | |||
| 692 | + | {name: "ibeam maps to text", cursor: purecef.CursorTypeCtIbeam, expected: "text"}, | |||
| 693 | + | {name: "unknown falls back to default", cursor: purecef.CursorType(-1), expected: "default"}, | |||
| 694 | + | } | |||
| 695 | + | ||||
| 696 | + | for _, tt := range tests { | |||
| 697 | + | t.Run(tt.name, func(t *testing.T) { | |||
| 698 | + | require.Equal(t, tt.expected, cefCursorToGDKName(tt.cursor)) | |||
| 699 | + | }) | |||
| 700 | + | } | |||
| 701 | + | } | |||