@@ -64,6 +64,7 @@ extern const struct wl_registry_listener gio_registry_listener;
64
64
extern const struct wl_surface_listener gio_surface_listener;
65
65
extern const struct xdg_surface_listener gio_xdg_surface_listener;
66
66
extern const struct xdg_toplevel_listener gio_xdg_toplevel_listener;
67
+ extern const struct zxdg_toplevel_decoration_v1_listener gio_zxdg_toplevel_decoration_v1_listener;
67
68
extern const struct xdg_wm_base_listener gio_xdg_wm_base_listener;
68
69
extern const struct wl_callback_listener gio_callback_listener;
69
70
extern const struct wl_output_listener gio_output_listener;
@@ -149,6 +150,7 @@ type repeatState struct {
149
150
type window struct {
150
151
w * callbacks
151
152
disp * wlDisplay
153
+ seat * wlSeat
152
154
surf * C.struct_wl_surface
153
155
wmSurf * C.struct_xdg_surface
154
156
topLvl * C.struct_xdg_toplevel
@@ -188,9 +190,10 @@ type window struct {
188
190
newScale bool
189
191
scale int
190
192
// size is the unscaled window size (unlike config.Size which is scaled).
191
- size image.Point
192
- config Config
193
- wsize image.Point // window config size before going fullscreen
193
+ size image.Point
194
+ config Config
195
+ wsize image.Point // window config size before going fullscreen or maximized
196
+ inCompositor bool // window is moving or being resized
194
197
195
198
wakeups chan struct {}
196
199
}
@@ -212,7 +215,7 @@ type wlOutput struct {
212
215
}
213
216
214
217
// callbackMap maps Wayland native handles to corresponding Go
215
- // references. It is necessary because the the Wayland client API
218
+ // references. It is necessary because the Wayland client API
216
219
// forces the use of callbacks and storing pointers to Go values
217
220
// in C is forbidden.
218
221
var callbackMap sync.Map
@@ -369,9 +372,8 @@ func (d *wlDisplay) createNativeWindow(options []Option) (*window, error) {
369
372
C .xdg_toplevel_add_listener (w .topLvl , & C .gio_xdg_toplevel_listener , unsafe .Pointer (w .surf ))
370
373
371
374
if d .decor != nil {
372
- // Request server side decorations.
373
375
w .decor = C .zxdg_decoration_manager_v1_get_toplevel_decoration (d .decor , w .topLvl )
374
- C .zxdg_toplevel_decoration_v1_set_mode (w .decor , C . ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE )
376
+ C .zxdg_toplevel_decoration_v1_add_listener (w .decor , & C . gio_zxdg_toplevel_decoration_v1_listener , unsafe . Pointer ( w . surf ) )
375
377
}
376
378
w .updateOpaqueRegion ()
377
379
return w , nil
@@ -499,6 +501,24 @@ func gio_onToplevelConfigure(data unsafe.Pointer, topLvl *C.struct_xdg_toplevel,
499
501
w .size = image .Pt (int (width ), int (height ))
500
502
w .updateOpaqueRegion ()
501
503
}
504
+ w .needAck = true
505
+ }
506
+
507
+ //export gio_onToplevelDecorationConfigure
508
+ func gio_onToplevelDecorationConfigure (data unsafe.Pointer , deco * C.struct_zxdg_toplevel_decoration_v1 , mode C.uint32_t ) {
509
+ w := callbackLoad (data ).(* window )
510
+ decorated := w .config .Decorated
511
+ switch mode {
512
+ case C .ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE :
513
+ w .config .Decorated = false
514
+ case C .ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE :
515
+ w .config .Decorated = true
516
+ }
517
+ if decorated != w .config .Decorated {
518
+ w .w .Event (ConfigEvent {Config : w .config })
519
+ }
520
+ w .needAck = true
521
+ w .draw (true )
502
522
}
503
523
504
524
//export gio_onOutputMode
@@ -772,15 +792,22 @@ func gio_onPointerEnter(data unsafe.Pointer, pointer *C.struct_wl_pointer, seria
772
792
s := callbackLoad (data ).(* wlSeat )
773
793
s .serial = serial
774
794
w := callbackLoad (unsafe .Pointer (surf )).(* window )
795
+ w .seat = s
775
796
s .pointerFocus = w
776
797
w .setCursor (pointer , serial )
777
798
w .lastPos = f32.Point {X : fromFixed (x ), Y : fromFixed (y )}
778
799
}
779
800
780
801
//export gio_onPointerLeave
781
- func gio_onPointerLeave (data unsafe.Pointer , p * C.struct_wl_pointer , serial C.uint32_t , surface * C.struct_wl_surface ) {
802
+ func gio_onPointerLeave (data unsafe.Pointer , p * C.struct_wl_pointer , serial C.uint32_t , surf * C.struct_wl_surface ) {
803
+ w := callbackLoad (unsafe .Pointer (surf )).(* window )
804
+ w .seat = nil
782
805
s := callbackLoad (data ).(* wlSeat )
783
806
s .serial = serial
807
+ if w .inCompositor {
808
+ w .inCompositor = false
809
+ w .w .Event (pointer.Event {Type : pointer .Cancel })
810
+ }
784
811
}
785
812
786
813
//export gio_onPointerMotion
@@ -818,6 +845,8 @@ func gio_onPointerButton(data unsafe.Pointer, p *C.struct_wl_pointer, serial, t,
818
845
case 0 :
819
846
w .pointerBtns &^= btn
820
847
typ = pointer .Release
848
+ // Move or resize gestures no longer applies.
849
+ w .inCompositor = false
821
850
case 1 :
822
851
w .pointerBtns |= btn
823
852
typ = pointer .Press
@@ -978,6 +1007,9 @@ func (w *window) Configure(options []Option) {
978
1007
C .xdg_toplevel_set_max_size (w .topLvl , C .int32_t (cnf .MaxSize .X ), C .int32_t (cnf .MaxSize .Y ))
979
1008
}
980
1009
}
1010
+ if cnf .Decorated != prev .Decorated {
1011
+ w .config .Decorated = cnf .Decorated
1012
+ }
981
1013
if w .config != prev {
982
1014
w .w .Event (ConfigEvent {Config : w .config })
983
1015
}
@@ -992,6 +1024,63 @@ func (w *window) setTitle(prev, cnf Config) {
992
1024
}
993
1025
}
994
1026
1027
+ func (w * window ) Perform (actions system.Action ) {
1028
+ walkActions (actions , func (action system.Action ) {
1029
+ switch action {
1030
+ case system .ActionMinimize :
1031
+ w .Configure ([]Option {Minimized .Option ()})
1032
+ case system .ActionMaximize :
1033
+ w .Configure ([]Option {Maximized .Option ()})
1034
+ case system .ActionUnmaximize :
1035
+ w .Configure ([]Option {Windowed .Option ()})
1036
+ case system .ActionClose :
1037
+ w .Close ()
1038
+ case system .ActionMove :
1039
+ w .move ()
1040
+ default :
1041
+ w .resize (action )
1042
+ }
1043
+ })
1044
+ }
1045
+
1046
+ func (w * window ) move () {
1047
+ if ! w .inCompositor && w .seat != nil {
1048
+ w .inCompositor = true
1049
+ s := w .seat
1050
+ C .xdg_toplevel_move (w .topLvl , s .seat , s .serial )
1051
+ }
1052
+ }
1053
+
1054
+ func (w * window ) resize (a system.Action ) {
1055
+ if w .inCompositor || w .seat == nil {
1056
+ return
1057
+ }
1058
+ var edge int
1059
+ switch a {
1060
+ case system .ActionResizeNorth :
1061
+ edge = C .XDG_TOPLEVEL_RESIZE_EDGE_TOP
1062
+ case system .ActionResizeSouth :
1063
+ edge = C .XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM
1064
+ case system .ActionResizeEast :
1065
+ edge = C .XDG_TOPLEVEL_RESIZE_EDGE_LEFT
1066
+ case system .ActionResizeWest :
1067
+ edge = C .XDG_TOPLEVEL_RESIZE_EDGE_RIGHT
1068
+ case system .ActionResizeNorthWest :
1069
+ edge = C .XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT
1070
+ case system .ActionResizeNorthEast :
1071
+ edge = C .XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT
1072
+ case system .ActionResizeSouthEast :
1073
+ edge = C .XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT
1074
+ case system .ActionResizeSouthWest :
1075
+ edge = C .XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT
1076
+ default :
1077
+ return
1078
+ }
1079
+ w .inCompositor = true
1080
+ s := w .seat
1081
+ C .xdg_toplevel_resize (w .topLvl , s .seat , s .serial , C .uint32_t (edge ))
1082
+ }
1083
+
995
1084
func (w * window ) Raise () {
996
1085
// NB. there is no way for a minimized window to be unminimized.
997
1086
// https://wayland.app/protocols/xdg-shell#xdg_toplevel:request:set_minimized
0 commit comments