1package wayland
2
3import (
4 "github.com/bnema/go-wayland-bindings/server/serverdecoration"
5 "github.com/bnema/go-wayland-bindings/server/wayland"
6 "github.com/bnema/go-wayland-bindings/server/xdgdecoration"
7 "github.com/bnema/go-wayland-bindings/server/xdgshell"
8 "github.com/bnema/purego-libwayland/server"
9)
10
11// Server-side decorations: neferwl draws the border, so clients must not draw
12// their own title bar or shadow (which would shrink the visible content).
13type decorationManager struct{ s *Server }
14
15func registerDecoration(d *server.Display, s *Server) error {
16 err := xdgdecoration.NewZxdgDecorationManagerV1Global(d, 1, func(c server.Client, v, id uint32) {
17 _, _ = xdgdecoration.NewZxdgDecorationManagerV1(c, int32(v), id, decorationManager{s})
18 })
19 if err != nil {
20 return err
21 }
22 // GTK only speaks KDE's older protocol: without it GTK4 draws its own
23 // title bar.
24 return serverdecoration.NewOrgKdeKwinServerDecorationManagerGlobal(d, 1, func(c server.Client, v, id uint32) {
25 m, err := serverdecoration.NewOrgKdeKwinServerDecorationManager(c, int32(v), id, kdeManager{})
26 if err == nil {
27 m.SendDefaultMode(uint32(serverdecoration.OrgKdeKwinServerDecorationManagerModeServer))
28 }
29 })
30}
31
32type kdeManager struct{}
33
34func (kdeManager) Create(r *serverdecoration.OrgKdeKwinServerDecorationManager, id uint32, _ *wayland.Surface) {
35 if d, err := serverdecoration.NewOrgKdeKwinServerDecoration(r.Client(), r.Version(), id, kdeDecoration{}); err == nil {
36 d.SendMode(uint32(serverdecoration.OrgKdeKwinServerDecorationModeServer))
37 }
38}
39
40type kdeDecoration struct{}
41
42func (kdeDecoration) Release(*serverdecoration.OrgKdeKwinServerDecoration) {}
43
44// A requested mode is acknowledged as is: the protocol has no way to
45// refuse, and answering server to a client that insists on client-side
46// (Firefox) makes it ask again forever. The server default already makes
47// GTK drop its title bar.
48// Unknown modes are ignored: replacing them would restart the loop.
49func (kdeDecoration) RequestMode(r *serverdecoration.OrgKdeKwinServerDecoration, mode uint32) {
50 if mode > uint32(serverdecoration.OrgKdeKwinServerDecorationModeServer) {
51 return
52 }
53 r.SendMode(mode)
54}
55
56func (decorationManager) Destroy(*xdgdecoration.ZxdgDecorationManagerV1) {}
57
58func (m decorationManager) GetToplevelDecoration(r *xdgdecoration.ZxdgDecorationManagerV1, id uint32, t *xdgshell.Toplevel) {
59 d := &decoration{s: m.s, toplevel: t}
60 res, err := xdgdecoration.NewZxdgToplevelDecorationV1(r.Client(), r.Version(), id, d)
61 if err != nil {
62 return
63 }
64 d.send(res)
65}
66
67type decoration struct {
68 s *Server
69 toplevel *xdgshell.Toplevel
70}
71
72func (*decoration) Destroy(*xdgdecoration.ZxdgToplevelDecorationV1) {}
73
74// Any requested mode is answered with server-side.
75func (d *decoration) SetMode(r *xdgdecoration.ZxdgToplevelDecorationV1, _ uint32) { d.send(r) }
76func (d *decoration) UnsetMode(r *xdgdecoration.ZxdgToplevelDecorationV1) { d.send(r) }
77
78// send answers server-side. The mode applies on the next xdg_surface.configure,
79// so a window already configured is configured again with its last size.
80func (d *decoration) send(r *xdgdecoration.ZxdgToplevelDecorationV1) {
81 r.SendConfigure(uint32(xdgdecoration.ZxdgToplevelDecorationV1ModeServerSide))
82 for _, w := range d.s.windows {
83 if w.toplevel == d.toplevel && w.hasLast && w.toplevel.Resource.Alive() && w.xdg.resource.Resource.Alive() {
84 w.sendConfigure()
85 return
86 }
87 }
88}