os_wayland.go raw

   1  // SPDX-License-Identifier: Unlicense OR MIT
   2  
   3  // +build linux,!android,!nowayland freebsd
   4  
   5  package wm
   6  
   7  import (
   8  	"bytes"
   9  	"errors"
  10  	"fmt"
  11  	"image"
  12  	"io"
  13  	"io/ioutil"
  14  	"math"
  15  	"os"
  16  	"os/exec"
  17  	"strconv"
  18  	"sync"
  19  	"time"
  20  	"unsafe"
  21  
  22  	syscall "golang.org/x/sys/unix"
  23  
  24  	"github.com/p9c/p9/pkg/gel/gio/app/internal/xkb"
  25  	"github.com/p9c/p9/pkg/gel/gio/f32"
  26  	"github.com/p9c/p9/pkg/gel/gio/internal/fling"
  27  	"github.com/p9c/p9/pkg/gel/gio/io/clipboard"
  28  	"github.com/p9c/p9/pkg/gel/gio/io/key"
  29  	"github.com/p9c/p9/pkg/gel/gio/io/pointer"
  30  	"github.com/p9c/p9/pkg/gel/gio/io/system"
  31  	"github.com/p9c/p9/pkg/gel/gio/unit"
  32  )
  33  
  34  // Use wayland-scanner to generate glue code for the xdg-shell and xdg-decoration extensions.
  35  //go:generate wayland-scanner client-header /usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml wayland_xdg_shell.h
  36  //go:generate wayland-scanner private-code /usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml wayland_xdg_shell.c
  37  
  38  //go:generate wayland-scanner client-header /usr/share/wayland-protocols/unstable/text-input/text-input-unstable-v3.xml wayland_text_input.h
  39  //go:generate wayland-scanner private-code /usr/share/wayland-protocols/unstable/text-input/text-input-unstable-v3.xml wayland_text_input.c
  40  
  41  //go:generate wayland-scanner client-header /usr/share/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml wayland_xdg_decoration.h
  42  //go:generate wayland-scanner private-code /usr/share/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml wayland_xdg_decoration.c
  43  
  44  //go:generate sed -i "1s;^;// +build linux,!android,!nowayland freebsd\\n\\n;" wayland_xdg_shell.c
  45  //go:generate sed -i "1s;^;// +build linux,!android,!nowayland freebsd\\n\\n;" wayland_xdg_decoration.c
  46  //go:generate sed -i "1s;^;// +build linux,!android,!nowayland freebsd\\n\\n;" wayland_text_input.c
  47  
  48  /*
  49  #cgo linux pkg-config: wayland-client wayland-cursor
  50  #cgo freebsd openbsd LDFLAGS: -lwayland-client -lwayland-cursor
  51  #cgo freebsd CFLAGS: -I/usr/local/include
  52  #cgo freebsd LDFLAGS: -L/usr/local/lib
  53  
  54  #include <stdlib.h>
  55  #include <wayland-client.h>
  56  #include <wayland-cursor.h>
  57  #include "wayland_text_input.h"
  58  #include "wayland_xdg_shell.h"
  59  #include "wayland_xdg_decoration.h"
  60  
  61  extern const struct wl_registry_listener gio_registry_listener;
  62  extern const struct wl_surface_listener gio_surface_listener;
  63  extern const struct xdg_surface_listener gio_xdg_surface_listener;
  64  extern const struct xdg_toplevel_listener gio_xdg_toplevel_listener;
  65  extern const struct xdg_wm_base_listener gio_xdg_wm_base_listener;
  66  extern const struct wl_callback_listener gio_callback_listener;
  67  extern const struct wl_output_listener gio_output_listener;
  68  extern const struct wl_seat_listener gio_seat_listener;
  69  extern const struct wl_pointer_listener gio_pointer_listener;
  70  extern const struct wl_touch_listener gio_touch_listener;
  71  extern const struct wl_keyboard_listener gio_keyboard_listener;
  72  extern const struct zwp_text_input_v3_listener gio_zwp_text_input_v3_listener;
  73  extern const struct wl_data_device_listener gio_data_device_listener;
  74  extern const struct wl_data_offer_listener gio_data_offer_listener;
  75  extern const struct wl_data_source_listener gio_data_source_listener;
  76  */
  77  import "C"
  78  
  79  type wlDisplay struct {
  80  	disp              *C.struct_wl_display
  81  	reg               *C.struct_wl_registry
  82  	compositor        *C.struct_wl_compositor
  83  	wm                *C.struct_xdg_wm_base
  84  	imm               *C.struct_zwp_text_input_manager_v3
  85  	shm               *C.struct_wl_shm
  86  	dataDeviceManager *C.struct_wl_data_device_manager
  87  	decor             *C.struct_zxdg_decoration_manager_v1
  88  	seat              *wlSeat
  89  	xkb               *xkb.Context
  90  	outputMap         map[C.uint32_t]*C.struct_wl_output
  91  	outputConfig      map[*C.struct_wl_output]*wlOutput
  92  
  93  	// Notification pipe fds.
  94  	notify struct {
  95  		read, write int
  96  	}
  97  
  98  	repeat repeatState
  99  }
 100  
 101  type wlSeat struct {
 102  	disp     *wlDisplay
 103  	seat     *C.struct_wl_seat
 104  	name     C.uint32_t
 105  	pointer  *C.struct_wl_pointer
 106  	touch    *C.struct_wl_touch
 107  	keyboard *C.struct_wl_keyboard
 108  	im       *C.struct_zwp_text_input_v3
 109  
 110  	// The most recent input serial.
 111  	serial C.uint32_t
 112  
 113  	pointerFocus  *window
 114  	keyboardFocus *window
 115  	touchFoci     map[C.int32_t]*window
 116  
 117  	// Clipboard support.
 118  	dataDev *C.struct_wl_data_device
 119  	// offers is a map from active wl_data_offers to
 120  	// the list of mime types they support.
 121  	offers map[*C.struct_wl_data_offer][]string
 122  	// clipboard is the wl_data_offer for the clipboard.
 123  	clipboard *C.struct_wl_data_offer
 124  	// mimeType is the chosen mime type of clipboard.
 125  	mimeType string
 126  	// source represents the clipboard content of the most recent
 127  	// clipboard write, if any.
 128  	source *C.struct_wl_data_source
 129  	// content is the data belonging to source.
 130  	content []byte
 131  }
 132  
 133  type repeatState struct {
 134  	rate  int
 135  	delay time.Duration
 136  
 137  	key   uint32
 138  	win   Callbacks
 139  	stopC chan struct{}
 140  
 141  	start time.Duration
 142  	last  time.Duration
 143  	mu    sync.Mutex
 144  	now   time.Duration
 145  }
 146  
 147  type window struct {
 148  	w          Callbacks
 149  	disp       *wlDisplay
 150  	surf       *C.struct_wl_surface
 151  	wmSurf     *C.struct_xdg_surface
 152  	topLvl     *C.struct_xdg_toplevel
 153  	decor      *C.struct_zxdg_toplevel_decoration_v1
 154  	ppdp, ppsp float32
 155  	scroll     struct {
 156  		time  time.Duration
 157  		steps image.Point
 158  		dist  f32.Point
 159  	}
 160  	pointerBtns pointer.Buttons
 161  	lastPos     f32.Point
 162  	lastTouch   f32.Point
 163  
 164  	cursor struct {
 165  		theme  *C.struct_wl_cursor_theme
 166  		cursor *C.struct_wl_cursor
 167  		surf   *C.struct_wl_surface
 168  	}
 169  
 170  	fling struct {
 171  		yExtrapolation fling.Extrapolation
 172  		xExtrapolation fling.Extrapolation
 173  		anim           fling.Animation
 174  		start          bool
 175  		dir            f32.Point
 176  	}
 177  
 178  	stage             system.Stage
 179  	dead              bool
 180  	lastFrameCallback *C.struct_wl_callback
 181  
 182  	mu        sync.Mutex
 183  	animating bool
 184  	opts      *Options
 185  	needAck   bool
 186  	// The most recent configure serial waiting to be ack'ed.
 187  	serial   C.uint32_t
 188  	width    int
 189  	height   int
 190  	newScale bool
 191  	scale    int
 192  	// readClipboard tracks whether a ClipboardEvent is requested.
 193  	readClipboard bool
 194  	// writeClipboard is set whenever a clipboard write is requested.
 195  	writeClipboard *string
 196  }
 197  
 198  type poller struct {
 199  	pollfds [2]syscall.PollFd
 200  	// buf is scratch space for draining the notification pipe.
 201  	buf [100]byte
 202  }
 203  
 204  type wlOutput struct {
 205  	width      int
 206  	height     int
 207  	physWidth  int
 208  	physHeight int
 209  	transform  C.int32_t
 210  	scale      int
 211  	windows    []*window
 212  }
 213  
 214  // callbackMap maps Wayland native handles to corresponding Go
 215  // references. It is necessary because the the Wayland client API
 216  // forces the use of callbacks and storing pointers to Go values
 217  // in C is forbidden.
 218  var callbackMap sync.Map
 219  
 220  // clipboardMimeTypes is a list of supported clipboard mime types, in
 221  // order of preference.
 222  var clipboardMimeTypes = []string{"text/plain;charset=utf8", "UTF8_STRING", "text/plain", "TEXT", "STRING"}
 223  
 224  func init() {
 225  	wlDriver = newWLWindow
 226  }
 227  
 228  func newWLWindow(window Callbacks, opts *Options) error {
 229  	d, err := newWLDisplay()
 230  	if err != nil {
 231  		return err
 232  	}
 233  	w, err := d.createNativeWindow(opts)
 234  	if err != nil {
 235  		d.destroy()
 236  		return err
 237  	}
 238  	w.w = window
 239  	go func() {
 240  		defer d.destroy()
 241  		defer w.destroy()
 242  		w.w.SetDriver(w)
 243  		if err := w.loop(); err != nil {
 244  			panic(err)
 245  		}
 246  	}()
 247  	return nil
 248  }
 249  
 250  func (d *wlDisplay) writeClipboard(content []byte) error {
 251  	s := d.seat
 252  	if s == nil {
 253  		return nil
 254  	}
 255  	// Clear old offer.
 256  	if s.source != nil {
 257  		C.wl_data_source_destroy(s.source)
 258  		s.source = nil
 259  		s.content = nil
 260  	}
 261  	if d.dataDeviceManager == nil || s.dataDev == nil {
 262  		return nil
 263  	}
 264  	s.content = content
 265  	s.source = C.wl_data_device_manager_create_data_source(d.dataDeviceManager)
 266  	C.wl_data_source_add_listener(s.source, &C.gio_data_source_listener, unsafe.Pointer(s.seat))
 267  	for _, mime := range clipboardMimeTypes {
 268  		C.wl_data_source_offer(s.source, C.CString(mime))
 269  	}
 270  	C.wl_data_device_set_selection(s.dataDev, s.source, s.serial)
 271  	return nil
 272  }
 273  
 274  func (d *wlDisplay) readClipboard() (io.ReadCloser, error) {
 275  	s := d.seat
 276  	if s == nil {
 277  		return nil, nil
 278  	}
 279  	if s.clipboard == nil {
 280  		return nil, nil
 281  	}
 282  	r, w, err := os.Pipe()
 283  	if err != nil {
 284  		return nil, err
 285  	}
 286  	// wl_data_offer_receive performs and implicit dup(2) of the write end
 287  	// of the pipe. Close our version.
 288  	defer w.Close()
 289  	cmimeType := C.CString(s.mimeType)
 290  	defer C.free(unsafe.Pointer(cmimeType))
 291  	C.wl_data_offer_receive(s.clipboard, cmimeType, C.int(w.Fd()))
 292  	return r, nil
 293  }
 294  
 295  func (d *wlDisplay) createNativeWindow(opts *Options) (*window, error) {
 296  	if d.compositor == nil {
 297  		return nil, errors.New("wayland: no compositor available")
 298  	}
 299  	if d.wm == nil {
 300  		return nil, errors.New("wayland: no xdg_wm_base available")
 301  	}
 302  	if d.shm == nil {
 303  		return nil, errors.New("wayland: no wl_shm available")
 304  	}
 305  	if len(d.outputMap) == 0 {
 306  		return nil, errors.New("wayland: no outputs available")
 307  	}
 308  	var scale int
 309  	for _, conf := range d.outputConfig {
 310  		if s := conf.scale; s > scale {
 311  			scale = s
 312  		}
 313  	}
 314  	ppdp := detectUIScale()
 315  
 316  	w := &window{
 317  		disp:     d,
 318  		scale:    scale,
 319  		newScale: scale != 1,
 320  		ppdp:     ppdp,
 321  		ppsp:     ppdp,
 322  	}
 323  	w.surf = C.wl_compositor_create_surface(d.compositor)
 324  	if w.surf == nil {
 325  		w.destroy()
 326  		return nil, errors.New("wayland: wl_compositor_create_surface failed")
 327  	}
 328  	callbackStore(unsafe.Pointer(w.surf), w)
 329  	w.wmSurf = C.xdg_wm_base_get_xdg_surface(d.wm, w.surf)
 330  	if w.wmSurf == nil {
 331  		w.destroy()
 332  		return nil, errors.New("wayland: xdg_wm_base_get_xdg_surface failed")
 333  	}
 334  	w.topLvl = C.xdg_surface_get_toplevel(w.wmSurf)
 335  	if w.topLvl == nil {
 336  		w.destroy()
 337  		return nil, errors.New("wayland: xdg_surface_get_toplevel failed")
 338  	}
 339  	w.cursor.theme = C.wl_cursor_theme_load(nil, 32, d.shm)
 340  	if w.cursor.theme == nil {
 341  		w.destroy()
 342  		return nil, errors.New("wayland: wl_cursor_theme_load failed")
 343  	}
 344  	cname := C.CString("left_ptr")
 345  	defer C.free(unsafe.Pointer(cname))
 346  	w.cursor.cursor = C.wl_cursor_theme_get_cursor(w.cursor.theme, cname)
 347  	if w.cursor.cursor == nil {
 348  		w.destroy()
 349  		return nil, errors.New("wayland: wl_cursor_theme_get_cursor failed")
 350  	}
 351  	w.cursor.surf = C.wl_compositor_create_surface(d.compositor)
 352  	if w.cursor.surf == nil {
 353  		w.destroy()
 354  		return nil, errors.New("wayland: wl_compositor_create_surface failed")
 355  	}
 356  	C.xdg_wm_base_add_listener(d.wm, &C.gio_xdg_wm_base_listener, unsafe.Pointer(w.surf))
 357  	C.wl_surface_add_listener(w.surf, &C.gio_surface_listener, unsafe.Pointer(w.surf))
 358  	C.xdg_surface_add_listener(w.wmSurf, &C.gio_xdg_surface_listener, unsafe.Pointer(w.surf))
 359  	C.xdg_toplevel_add_listener(w.topLvl, &C.gio_xdg_toplevel_listener, unsafe.Pointer(w.surf))
 360  
 361  	w.setOptions(opts)
 362  
 363  	if d.decor != nil {
 364  		// Request server side decorations.
 365  		w.decor = C.zxdg_decoration_manager_v1_get_toplevel_decoration(d.decor, w.topLvl)
 366  		C.zxdg_toplevel_decoration_v1_set_mode(w.decor, C.ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE)
 367  	}
 368  	w.updateOpaqueRegion()
 369  	C.wl_surface_commit(w.surf)
 370  	return w, nil
 371  }
 372  
 373  func callbackDelete(k unsafe.Pointer) {
 374  	callbackMap.Delete(k)
 375  }
 376  
 377  func callbackStore(k unsafe.Pointer, v interface{}) {
 378  	callbackMap.Store(k, v)
 379  }
 380  
 381  func callbackLoad(k unsafe.Pointer) interface{} {
 382  	v, exists := callbackMap.Load(k)
 383  	if !exists {
 384  		panic("missing callback entry")
 385  	}
 386  	return v
 387  }
 388  
 389  //export gio_onSeatCapabilities
 390  func gio_onSeatCapabilities(data unsafe.Pointer, seat *C.struct_wl_seat, caps C.uint32_t) {
 391  	s := callbackLoad(data).(*wlSeat)
 392  	s.updateCaps(caps)
 393  }
 394  
 395  // flushOffers remove all wl_data_offers that isn't the clipboard
 396  // content.
 397  func (s *wlSeat) flushOffers() {
 398  	for o := range s.offers {
 399  		if o == s.clipboard {
 400  			continue
 401  		}
 402  		// We're only interested in clipboard offers.
 403  		delete(s.offers, o)
 404  		callbackDelete(unsafe.Pointer(o))
 405  		C.wl_data_offer_destroy(o)
 406  	}
 407  }
 408  
 409  func (s *wlSeat) destroy() {
 410  	if s.source != nil {
 411  		C.wl_data_source_destroy(s.source)
 412  		s.source = nil
 413  	}
 414  	if s.im != nil {
 415  		C.zwp_text_input_v3_destroy(s.im)
 416  		s.im = nil
 417  	}
 418  	if s.pointer != nil {
 419  		C.wl_pointer_release(s.pointer)
 420  	}
 421  	if s.touch != nil {
 422  		C.wl_touch_release(s.touch)
 423  	}
 424  	if s.keyboard != nil {
 425  		C.wl_keyboard_release(s.keyboard)
 426  	}
 427  	s.clipboard = nil
 428  	s.flushOffers()
 429  	if s.dataDev != nil {
 430  		C.wl_data_device_release(s.dataDev)
 431  	}
 432  	if s.seat != nil {
 433  		callbackDelete(unsafe.Pointer(s.seat))
 434  		C.wl_seat_release(s.seat)
 435  	}
 436  }
 437  
 438  func (s *wlSeat) updateCaps(caps C.uint32_t) {
 439  	if s.im == nil && s.disp.imm != nil {
 440  		s.im = C.zwp_text_input_manager_v3_get_text_input(s.disp.imm, s.seat)
 441  		C.zwp_text_input_v3_add_listener(s.im, &C.gio_zwp_text_input_v3_listener, unsafe.Pointer(s.seat))
 442  	}
 443  	switch {
 444  	case s.pointer == nil && caps&C.WL_SEAT_CAPABILITY_POINTER != 0:
 445  		s.pointer = C.wl_seat_get_pointer(s.seat)
 446  		C.wl_pointer_add_listener(s.pointer, &C.gio_pointer_listener, unsafe.Pointer(s.seat))
 447  	case s.pointer != nil && caps&C.WL_SEAT_CAPABILITY_POINTER == 0:
 448  		C.wl_pointer_release(s.pointer)
 449  		s.pointer = nil
 450  	}
 451  	switch {
 452  	case s.touch == nil && caps&C.WL_SEAT_CAPABILITY_TOUCH != 0:
 453  		s.touch = C.wl_seat_get_touch(s.seat)
 454  		C.wl_touch_add_listener(s.touch, &C.gio_touch_listener, unsafe.Pointer(s.seat))
 455  	case s.touch != nil && caps&C.WL_SEAT_CAPABILITY_TOUCH == 0:
 456  		C.wl_touch_release(s.touch)
 457  		s.touch = nil
 458  	}
 459  	switch {
 460  	case s.keyboard == nil && caps&C.WL_SEAT_CAPABILITY_KEYBOARD != 0:
 461  		s.keyboard = C.wl_seat_get_keyboard(s.seat)
 462  		C.wl_keyboard_add_listener(s.keyboard, &C.gio_keyboard_listener, unsafe.Pointer(s.seat))
 463  	case s.keyboard != nil && caps&C.WL_SEAT_CAPABILITY_KEYBOARD == 0:
 464  		C.wl_keyboard_release(s.keyboard)
 465  		s.keyboard = nil
 466  	}
 467  }
 468  
 469  //export gio_onSeatName
 470  func gio_onSeatName(data unsafe.Pointer, seat *C.struct_wl_seat, name *C.char) {
 471  }
 472  
 473  //export gio_onXdgSurfaceConfigure
 474  func gio_onXdgSurfaceConfigure(data unsafe.Pointer, wmSurf *C.struct_xdg_surface, serial C.uint32_t) {
 475  	w := callbackLoad(data).(*window)
 476  	w.mu.Lock()
 477  	w.serial = serial
 478  	w.needAck = true
 479  	w.mu.Unlock()
 480  	w.setStage(system.StageRunning)
 481  	w.draw(true)
 482  }
 483  
 484  //export gio_onToplevelClose
 485  func gio_onToplevelClose(data unsafe.Pointer, topLvl *C.struct_xdg_toplevel) {
 486  	w := callbackLoad(data).(*window)
 487  	w.dead = true
 488  }
 489  
 490  //export gio_onToplevelConfigure
 491  func gio_onToplevelConfigure(data unsafe.Pointer, topLvl *C.struct_xdg_toplevel, width, height C.int32_t, states *C.struct_wl_array) {
 492  	w := callbackLoad(data).(*window)
 493  	if width != 0 && height != 0 {
 494  		w.mu.Lock()
 495  		defer w.mu.Unlock()
 496  		w.width = int(width)
 497  		w.height = int(height)
 498  		w.updateOpaqueRegion()
 499  	}
 500  }
 501  
 502  //export gio_onOutputMode
 503  func gio_onOutputMode(data unsafe.Pointer, output *C.struct_wl_output, flags C.uint32_t, width, height, refresh C.int32_t) {
 504  	if flags&C.WL_OUTPUT_MODE_CURRENT == 0 {
 505  		return
 506  	}
 507  	d := callbackLoad(data).(*wlDisplay)
 508  	c := d.outputConfig[output]
 509  	c.width = int(width)
 510  	c.height = int(height)
 511  }
 512  
 513  //export gio_onOutputGeometry
 514  func gio_onOutputGeometry(data unsafe.Pointer, output *C.struct_wl_output, x, y, physWidth, physHeight, subpixel C.int32_t, make, model *C.char, transform C.int32_t) {
 515  	d := callbackLoad(data).(*wlDisplay)
 516  	c := d.outputConfig[output]
 517  	c.transform = transform
 518  	c.physWidth = int(physWidth)
 519  	c.physHeight = int(physHeight)
 520  }
 521  
 522  //export gio_onOutputScale
 523  func gio_onOutputScale(data unsafe.Pointer, output *C.struct_wl_output, scale C.int32_t) {
 524  	d := callbackLoad(data).(*wlDisplay)
 525  	c := d.outputConfig[output]
 526  	c.scale = int(scale)
 527  }
 528  
 529  //export gio_onOutputDone
 530  func gio_onOutputDone(data unsafe.Pointer, output *C.struct_wl_output) {
 531  	d := callbackLoad(data).(*wlDisplay)
 532  	conf := d.outputConfig[output]
 533  	for _, w := range conf.windows {
 534  		w.draw(true)
 535  	}
 536  }
 537  
 538  //export gio_onSurfaceEnter
 539  func gio_onSurfaceEnter(data unsafe.Pointer, surf *C.struct_wl_surface, output *C.struct_wl_output) {
 540  	w := callbackLoad(data).(*window)
 541  	conf := w.disp.outputConfig[output]
 542  	var found bool
 543  	for _, w2 := range conf.windows {
 544  		if w2 == w {
 545  			found = true
 546  			break
 547  		}
 548  	}
 549  	if !found {
 550  		conf.windows = append(conf.windows, w)
 551  	}
 552  	w.updateOutputs()
 553  }
 554  
 555  //export gio_onSurfaceLeave
 556  func gio_onSurfaceLeave(data unsafe.Pointer, surf *C.struct_wl_surface, output *C.struct_wl_output) {
 557  	w := callbackLoad(data).(*window)
 558  	conf := w.disp.outputConfig[output]
 559  	for i, w2 := range conf.windows {
 560  		if w2 == w {
 561  			conf.windows = append(conf.windows[:i], conf.windows[i+1:]...)
 562  			break
 563  		}
 564  	}
 565  	w.updateOutputs()
 566  }
 567  
 568  //export gio_onRegistryGlobal
 569  func gio_onRegistryGlobal(data unsafe.Pointer, reg *C.struct_wl_registry, name C.uint32_t, cintf *C.char, version C.uint32_t) {
 570  	d := callbackLoad(data).(*wlDisplay)
 571  	switch C.GoString(cintf) {
 572  	case "wl_compositor":
 573  		d.compositor = (*C.struct_wl_compositor)(C.wl_registry_bind(reg, name, &C.wl_compositor_interface, 3))
 574  	case "wl_output":
 575  		output := (*C.struct_wl_output)(C.wl_registry_bind(reg, name, &C.wl_output_interface, 2))
 576  		C.wl_output_add_listener(output, &C.gio_output_listener, unsafe.Pointer(d.disp))
 577  		d.outputMap[name] = output
 578  		d.outputConfig[output] = new(wlOutput)
 579  	case "wl_seat":
 580  		if d.seat != nil {
 581  			break
 582  		}
 583  		s := (*C.struct_wl_seat)(C.wl_registry_bind(reg, name, &C.wl_seat_interface, 5))
 584  		if s == nil {
 585  			// No support for v5 protocol.
 586  			break
 587  		}
 588  		d.seat = &wlSeat{
 589  			disp:      d,
 590  			name:      name,
 591  			seat:      s,
 592  			offers:    make(map[*C.struct_wl_data_offer][]string),
 593  			touchFoci: make(map[C.int32_t]*window),
 594  		}
 595  		callbackStore(unsafe.Pointer(s), d.seat)
 596  		C.wl_seat_add_listener(s, &C.gio_seat_listener, unsafe.Pointer(s))
 597  		if d.dataDeviceManager == nil {
 598  			break
 599  		}
 600  		d.seat.dataDev = C.wl_data_device_manager_get_data_device(d.dataDeviceManager, s)
 601  		if d.seat.dataDev == nil {
 602  			break
 603  		}
 604  		callbackStore(unsafe.Pointer(d.seat.dataDev), d.seat)
 605  		C.wl_data_device_add_listener(d.seat.dataDev, &C.gio_data_device_listener, unsafe.Pointer(d.seat.dataDev))
 606  	case "wl_shm":
 607  		d.shm = (*C.struct_wl_shm)(C.wl_registry_bind(reg, name, &C.wl_shm_interface, 1))
 608  	case "xdg_wm_base":
 609  		d.wm = (*C.struct_xdg_wm_base)(C.wl_registry_bind(reg, name, &C.xdg_wm_base_interface, 1))
 610  	case "zxdg_decoration_manager_v1":
 611  		d.decor = (*C.struct_zxdg_decoration_manager_v1)(C.wl_registry_bind(reg, name, &C.zxdg_decoration_manager_v1_interface, 1))
 612  		// TODO: Implement and test text-input support.
 613  		/*case "zwp_text_input_manager_v3":
 614  		d.imm = (*C.struct_zwp_text_input_manager_v3)(C.wl_registry_bind(reg, name, &C.zwp_text_input_manager_v3_interface, 1))*/
 615  	case "wl_data_device_manager":
 616  		d.dataDeviceManager = (*C.struct_wl_data_device_manager)(C.wl_registry_bind(reg, name, &C.wl_data_device_manager_interface, 3))
 617  	}
 618  }
 619  
 620  //export gio_onDataOfferOffer
 621  func gio_onDataOfferOffer(data unsafe.Pointer, offer *C.struct_wl_data_offer, mime *C.char) {
 622  	s := callbackLoad(data).(*wlSeat)
 623  	s.offers[offer] = append(s.offers[offer], C.GoString(mime))
 624  }
 625  
 626  //export gio_onDataOfferSourceActions
 627  func gio_onDataOfferSourceActions(data unsafe.Pointer, offer *C.struct_wl_data_offer, acts C.uint32_t) {
 628  }
 629  
 630  //export gio_onDataOfferAction
 631  func gio_onDataOfferAction(data unsafe.Pointer, offer *C.struct_wl_data_offer, act C.uint32_t) {
 632  }
 633  
 634  //export gio_onDataDeviceOffer
 635  func gio_onDataDeviceOffer(data unsafe.Pointer, dataDev *C.struct_wl_data_device, id *C.struct_wl_data_offer) {
 636  	s := callbackLoad(data).(*wlSeat)
 637  	callbackStore(unsafe.Pointer(id), s)
 638  	C.wl_data_offer_add_listener(id, &C.gio_data_offer_listener, unsafe.Pointer(id))
 639  	s.offers[id] = nil
 640  }
 641  
 642  //export gio_onDataDeviceEnter
 643  func gio_onDataDeviceEnter(data unsafe.Pointer, dataDev *C.struct_wl_data_device, serial C.uint32_t, surf *C.struct_wl_surface, x, y C.wl_fixed_t, id *C.struct_wl_data_offer) {
 644  	s := callbackLoad(data).(*wlSeat)
 645  	s.serial = serial
 646  	s.flushOffers()
 647  }
 648  
 649  //export gio_onDataDeviceLeave
 650  func gio_onDataDeviceLeave(data unsafe.Pointer, dataDev *C.struct_wl_data_device) {
 651  }
 652  
 653  //export gio_onDataDeviceMotion
 654  func gio_onDataDeviceMotion(data unsafe.Pointer, dataDev *C.struct_wl_data_device, t C.uint32_t, x, y C.wl_fixed_t) {
 655  }
 656  
 657  //export gio_onDataDeviceDrop
 658  func gio_onDataDeviceDrop(data unsafe.Pointer, dataDev *C.struct_wl_data_device) {
 659  }
 660  
 661  //export gio_onDataDeviceSelection
 662  func gio_onDataDeviceSelection(data unsafe.Pointer, dataDev *C.struct_wl_data_device, id *C.struct_wl_data_offer) {
 663  	s := callbackLoad(data).(*wlSeat)
 664  	defer s.flushOffers()
 665  	s.clipboard = nil
 666  loop:
 667  	for _, want := range clipboardMimeTypes {
 668  		for _, got := range s.offers[id] {
 669  			if want != got {
 670  				continue
 671  			}
 672  			s.clipboard = id
 673  			s.mimeType = got
 674  			break loop
 675  		}
 676  	}
 677  }
 678  
 679  //export gio_onRegistryGlobalRemove
 680  func gio_onRegistryGlobalRemove(data unsafe.Pointer, reg *C.struct_wl_registry, name C.uint32_t) {
 681  	d := callbackLoad(data).(*wlDisplay)
 682  	if s := d.seat; s != nil && name == s.name {
 683  		s.destroy()
 684  		d.seat = nil
 685  	}
 686  	if output, exists := d.outputMap[name]; exists {
 687  		C.wl_output_destroy(output)
 688  		delete(d.outputMap, name)
 689  		delete(d.outputConfig, output)
 690  	}
 691  }
 692  
 693  //export gio_onTouchDown
 694  func gio_onTouchDown(data unsafe.Pointer, touch *C.struct_wl_touch, serial, t C.uint32_t, surf *C.struct_wl_surface, id C.int32_t, x, y C.wl_fixed_t) {
 695  	s := callbackLoad(data).(*wlSeat)
 696  	s.serial = serial
 697  	w := callbackLoad(unsafe.Pointer(surf)).(*window)
 698  	s.touchFoci[id] = w
 699  	w.lastTouch = f32.Point{
 700  		X: fromFixed(x) * float32(w.scale),
 701  		Y: fromFixed(y) * float32(w.scale),
 702  	}
 703  	w.w.Event(pointer.Event{
 704  		Type:      pointer.Press,
 705  		Source:    pointer.Touch,
 706  		Position:  w.lastTouch,
 707  		PointerID: pointer.ID(id),
 708  		Time:      time.Duration(t) * time.Millisecond,
 709  		Modifiers: w.disp.xkb.Modifiers(),
 710  	})
 711  }
 712  
 713  //export gio_onTouchUp
 714  func gio_onTouchUp(data unsafe.Pointer, touch *C.struct_wl_touch, serial, t C.uint32_t, id C.int32_t) {
 715  	s := callbackLoad(data).(*wlSeat)
 716  	s.serial = serial
 717  	w := s.touchFoci[id]
 718  	delete(s.touchFoci, id)
 719  	w.w.Event(pointer.Event{
 720  		Type:      pointer.Release,
 721  		Source:    pointer.Touch,
 722  		Position:  w.lastTouch,
 723  		PointerID: pointer.ID(id),
 724  		Time:      time.Duration(t) * time.Millisecond,
 725  		Modifiers: w.disp.xkb.Modifiers(),
 726  	})
 727  }
 728  
 729  //export gio_onTouchMotion
 730  func gio_onTouchMotion(data unsafe.Pointer, touch *C.struct_wl_touch, t C.uint32_t, id C.int32_t, x, y C.wl_fixed_t) {
 731  	s := callbackLoad(data).(*wlSeat)
 732  	w := s.touchFoci[id]
 733  	w.lastTouch = f32.Point{
 734  		X: fromFixed(x) * float32(w.scale),
 735  		Y: fromFixed(y) * float32(w.scale),
 736  	}
 737  	w.w.Event(pointer.Event{
 738  		Type:      pointer.Move,
 739  		Position:  w.lastTouch,
 740  		Source:    pointer.Touch,
 741  		PointerID: pointer.ID(id),
 742  		Time:      time.Duration(t) * time.Millisecond,
 743  		Modifiers: w.disp.xkb.Modifiers(),
 744  	})
 745  }
 746  
 747  //export gio_onTouchFrame
 748  func gio_onTouchFrame(data unsafe.Pointer, touch *C.struct_wl_touch) {
 749  }
 750  
 751  //export gio_onTouchCancel
 752  func gio_onTouchCancel(data unsafe.Pointer, touch *C.struct_wl_touch) {
 753  	s := callbackLoad(data).(*wlSeat)
 754  	for id, w := range s.touchFoci {
 755  		delete(s.touchFoci, id)
 756  		w.w.Event(pointer.Event{
 757  			Type:   pointer.Cancel,
 758  			Source: pointer.Touch,
 759  		})
 760  	}
 761  }
 762  
 763  //export gio_onPointerEnter
 764  func gio_onPointerEnter(data unsafe.Pointer, pointer *C.struct_wl_pointer, serial C.uint32_t, surf *C.struct_wl_surface, x, y C.wl_fixed_t) {
 765  	s := callbackLoad(data).(*wlSeat)
 766  	s.serial = serial
 767  	w := callbackLoad(unsafe.Pointer(surf)).(*window)
 768  	s.pointerFocus = w
 769  	w.setCursor(pointer, serial)
 770  	w.lastPos = f32.Point{X: fromFixed(x), Y: fromFixed(y)}
 771  }
 772  
 773  //export gio_onPointerLeave
 774  func gio_onPointerLeave(data unsafe.Pointer, p *C.struct_wl_pointer, serial C.uint32_t, surface *C.struct_wl_surface) {
 775  	s := callbackLoad(data).(*wlSeat)
 776  	s.serial = serial
 777  }
 778  
 779  //export gio_onPointerMotion
 780  func gio_onPointerMotion(data unsafe.Pointer, p *C.struct_wl_pointer, t C.uint32_t, x, y C.wl_fixed_t) {
 781  	s := callbackLoad(data).(*wlSeat)
 782  	w := s.pointerFocus
 783  	w.resetFling()
 784  	w.onPointerMotion(x, y, t)
 785  }
 786  
 787  //export gio_onPointerButton
 788  func gio_onPointerButton(data unsafe.Pointer, p *C.struct_wl_pointer, serial, t, wbtn, state C.uint32_t) {
 789  	s := callbackLoad(data).(*wlSeat)
 790  	s.serial = serial
 791  	w := s.pointerFocus
 792  	// From linux-event-codes.h.
 793  	const (
 794  		BTN_LEFT   = 0x110
 795  		BTN_RIGHT  = 0x111
 796  		BTN_MIDDLE = 0x112
 797  	)
 798  	var btn pointer.Buttons
 799  	switch wbtn {
 800  	case BTN_LEFT:
 801  		btn = pointer.ButtonPrimary
 802  	case BTN_RIGHT:
 803  		btn = pointer.ButtonSecondary
 804  	case BTN_MIDDLE:
 805  		btn = pointer.ButtonTertiary
 806  	default:
 807  		return
 808  	}
 809  	var typ pointer.Type
 810  	switch state {
 811  	case 0:
 812  		w.pointerBtns &^= btn
 813  		typ = pointer.Release
 814  	case 1:
 815  		w.pointerBtns |= btn
 816  		typ = pointer.Press
 817  	}
 818  	w.flushScroll()
 819  	w.resetFling()
 820  	w.w.Event(pointer.Event{
 821  		Type:      typ,
 822  		Source:    pointer.Mouse,
 823  		Buttons:   w.pointerBtns,
 824  		Position:  w.lastPos,
 825  		Time:      time.Duration(t) * time.Millisecond,
 826  		Modifiers: w.disp.xkb.Modifiers(),
 827  	})
 828  }
 829  
 830  //export gio_onPointerAxis
 831  func gio_onPointerAxis(data unsafe.Pointer, p *C.struct_wl_pointer, t, axis C.uint32_t, value C.wl_fixed_t) {
 832  	s := callbackLoad(data).(*wlSeat)
 833  	w := s.pointerFocus
 834  	v := fromFixed(value)
 835  	w.resetFling()
 836  	if w.scroll.dist == (f32.Point{}) {
 837  		w.scroll.time = time.Duration(t) * time.Millisecond
 838  	}
 839  	switch axis {
 840  	case C.WL_POINTER_AXIS_HORIZONTAL_SCROLL:
 841  		w.scroll.dist.X += v
 842  	case C.WL_POINTER_AXIS_VERTICAL_SCROLL:
 843  		w.scroll.dist.Y += v
 844  	}
 845  }
 846  
 847  //export gio_onPointerFrame
 848  func gio_onPointerFrame(data unsafe.Pointer, p *C.struct_wl_pointer) {
 849  	s := callbackLoad(data).(*wlSeat)
 850  	w := s.pointerFocus
 851  	w.flushScroll()
 852  	w.flushFling()
 853  }
 854  
 855  func (w *window) flushFling() {
 856  	if !w.fling.start {
 857  		return
 858  	}
 859  	w.fling.start = false
 860  	estx, esty := w.fling.xExtrapolation.Estimate(), w.fling.yExtrapolation.Estimate()
 861  	w.fling.xExtrapolation = fling.Extrapolation{}
 862  	w.fling.yExtrapolation = fling.Extrapolation{}
 863  	vel := float32(math.Sqrt(float64(estx.Velocity*estx.Velocity + esty.Velocity*esty.Velocity)))
 864  	_, _, c := w.config()
 865  	if !w.fling.anim.Start(c, time.Now(), vel) {
 866  		return
 867  	}
 868  	invDist := 1 / vel
 869  	w.fling.dir.X = estx.Velocity * invDist
 870  	w.fling.dir.Y = esty.Velocity * invDist
 871  	// Wake up the window loop.
 872  	w.disp.wakeup()
 873  }
 874  
 875  //export gio_onPointerAxisSource
 876  func gio_onPointerAxisSource(data unsafe.Pointer, pointer *C.struct_wl_pointer, source C.uint32_t) {
 877  }
 878  
 879  //export gio_onPointerAxisStop
 880  func gio_onPointerAxisStop(data unsafe.Pointer, p *C.struct_wl_pointer, t, axis C.uint32_t) {
 881  	s := callbackLoad(data).(*wlSeat)
 882  	w := s.pointerFocus
 883  	w.fling.start = true
 884  }
 885  
 886  //export gio_onPointerAxisDiscrete
 887  func gio_onPointerAxisDiscrete(data unsafe.Pointer, p *C.struct_wl_pointer, axis C.uint32_t, discrete C.int32_t) {
 888  	s := callbackLoad(data).(*wlSeat)
 889  	w := s.pointerFocus
 890  	w.resetFling()
 891  	switch axis {
 892  	case C.WL_POINTER_AXIS_HORIZONTAL_SCROLL:
 893  		w.scroll.steps.X += int(discrete)
 894  	case C.WL_POINTER_AXIS_VERTICAL_SCROLL:
 895  		w.scroll.steps.Y += int(discrete)
 896  	}
 897  }
 898  
 899  func (w *window) ReadClipboard() {
 900  	w.mu.Lock()
 901  	w.readClipboard = true
 902  	w.mu.Unlock()
 903  	w.disp.wakeup()
 904  }
 905  
 906  func (w *window) WriteClipboard(s string) {
 907  	w.mu.Lock()
 908  	w.writeClipboard = &s
 909  	w.mu.Unlock()
 910  	w.disp.wakeup()
 911  }
 912  
 913  func (w *window) Option(opts *Options) {
 914  	w.mu.Lock()
 915  	w.opts = opts
 916  	w.mu.Unlock()
 917  	w.disp.wakeup()
 918  }
 919  
 920  func (w *window) setOptions(opts *Options) {
 921  	_, _, cfg := w.config()
 922  	if o := opts.Size; o != nil {
 923  		w.width = cfg.Px(o.Width)
 924  		w.height = cfg.Px(o.Height)
 925  	}
 926  	if o := opts.Title; o != nil {
 927  		title := C.CString(*o)
 928  		C.xdg_toplevel_set_title(w.topLvl, title)
 929  		C.free(unsafe.Pointer(title))
 930  	}
 931  }
 932  
 933  func (w *window) SetCursor(name pointer.CursorName) {
 934  	if name == pointer.CursorNone {
 935  		C.wl_pointer_set_cursor(w.disp.seat.pointer, w.serial, nil, 0, 0)
 936  		return
 937  	}
 938  	switch name {
 939  	default:
 940  		fallthrough
 941  	case pointer.CursorDefault:
 942  		name = "left_ptr"
 943  	case pointer.CursorText:
 944  		name = "xterm"
 945  	case pointer.CursorPointer:
 946  		name = "hand1"
 947  	case pointer.CursorCrossHair:
 948  		name = "crosshair"
 949  	case pointer.CursorRowResize:
 950  		name = "top_side"
 951  	case pointer.CursorColResize:
 952  		name = "left_side"
 953  	case pointer.CursorGrab:
 954  		name = "hand1"
 955  	}
 956  	cname := C.CString(string(name))
 957  	defer C.free(unsafe.Pointer(cname))
 958  	c := C.wl_cursor_theme_get_cursor(w.cursor.theme, cname)
 959  	if c == nil {
 960  		return
 961  	}
 962  	w.cursor.cursor = c
 963  	w.setCursor(w.disp.seat.pointer, w.serial)
 964  }
 965  
 966  func (w *window) setCursor(pointer *C.struct_wl_pointer, serial C.uint32_t) {
 967  	// Get images[0].
 968  	img := *w.cursor.cursor.images
 969  	buf := C.wl_cursor_image_get_buffer(img)
 970  	if buf == nil {
 971  		return
 972  	}
 973  	C.wl_pointer_set_cursor(pointer, serial, w.cursor.surf, C.int32_t(img.hotspot_x), C.int32_t(img.hotspot_y))
 974  	C.wl_surface_attach(w.cursor.surf, buf, 0, 0)
 975  	C.wl_surface_damage(w.cursor.surf, 0, 0, C.int32_t(img.width), C.int32_t(img.height))
 976  	C.wl_surface_commit(w.cursor.surf)
 977  }
 978  
 979  func (w *window) resetFling() {
 980  	w.fling.start = false
 981  	w.fling.anim = fling.Animation{}
 982  }
 983  
 984  //export gio_onKeyboardKeymap
 985  func gio_onKeyboardKeymap(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, format C.uint32_t, fd C.int32_t, size C.uint32_t) {
 986  	defer syscall.Close(int(fd))
 987  	s := callbackLoad(data).(*wlSeat)
 988  	s.disp.repeat.Stop(0)
 989  	s.disp.xkb.DestroyKeymapState()
 990  	if format != C.WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 {
 991  		return
 992  	}
 993  	if err := s.disp.xkb.LoadKeymap(int(format), int(fd), int(size)); err != nil {
 994  		// TODO: Do better.
 995  		panic(err)
 996  	}
 997  }
 998  
 999  //export gio_onKeyboardEnter
1000  func gio_onKeyboardEnter(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, serial C.uint32_t, surf *C.struct_wl_surface, keys *C.struct_wl_array) {
1001  	s := callbackLoad(data).(*wlSeat)
1002  	s.serial = serial
1003  	w := callbackLoad(unsafe.Pointer(surf)).(*window)
1004  	s.keyboardFocus = w
1005  	s.disp.repeat.Stop(0)
1006  	w.w.Event(key.FocusEvent{Focus: true})
1007  }
1008  
1009  //export gio_onKeyboardLeave
1010  func gio_onKeyboardLeave(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, serial C.uint32_t, surf *C.struct_wl_surface) {
1011  	s := callbackLoad(data).(*wlSeat)
1012  	s.serial = serial
1013  	s.disp.repeat.Stop(0)
1014  	w := s.keyboardFocus
1015  	w.w.Event(key.FocusEvent{Focus: false})
1016  }
1017  
1018  //export gio_onKeyboardKey
1019  func gio_onKeyboardKey(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, serial, timestamp, keyCode, state C.uint32_t) {
1020  	s := callbackLoad(data).(*wlSeat)
1021  	s.serial = serial
1022  	w := s.keyboardFocus
1023  	t := time.Duration(timestamp) * time.Millisecond
1024  	s.disp.repeat.Stop(t)
1025  	w.resetFling()
1026  	kc := mapXKBKeycode(uint32(keyCode))
1027  	ks := mapXKBKeyState(uint32(state))
1028  	for _, e := range w.disp.xkb.DispatchKey(kc, ks) {
1029  		w.w.Event(e)
1030  	}
1031  	if state != C.WL_KEYBOARD_KEY_STATE_PRESSED {
1032  		return
1033  	}
1034  	if w.disp.xkb.IsRepeatKey(kc) {
1035  		w.disp.repeat.Start(w, kc, t)
1036  	}
1037  }
1038  
1039  func mapXKBKeycode(keyCode uint32) uint32 {
1040  	// According to the xkb_v1 spec: "to determine the xkb keycode, clients must add 8 to the key event keycode."
1041  	return keyCode + 8
1042  }
1043  
1044  func mapXKBKeyState(state uint32) key.State {
1045  	switch state {
1046  	case C.WL_KEYBOARD_KEY_STATE_RELEASED:
1047  		return key.Release
1048  	default:
1049  		return key.Press
1050  	}
1051  }
1052  
1053  func (r *repeatState) Start(w *window, keyCode uint32, t time.Duration) {
1054  	if r.rate <= 0 {
1055  		return
1056  	}
1057  	stopC := make(chan struct{})
1058  	r.start = t
1059  	r.last = 0
1060  	r.now = 0
1061  	r.stopC = stopC
1062  	r.key = keyCode
1063  	r.win = w.w
1064  	rate, delay := r.rate, r.delay
1065  	go func() {
1066  		timer := time.NewTimer(delay)
1067  		for {
1068  			select {
1069  			case <-timer.C:
1070  			case <-stopC:
1071  				close(stopC)
1072  				return
1073  			}
1074  			r.Advance(delay)
1075  			w.disp.wakeup()
1076  			delay = time.Second / time.Duration(rate)
1077  			timer.Reset(delay)
1078  		}
1079  	}()
1080  }
1081  
1082  func (r *repeatState) Stop(t time.Duration) {
1083  	if r.stopC == nil {
1084  		return
1085  	}
1086  	r.stopC <- struct{}{}
1087  	<-r.stopC
1088  	r.stopC = nil
1089  	t -= r.start
1090  	if r.now > t {
1091  		r.now = t
1092  	}
1093  }
1094  
1095  func (r *repeatState) Advance(dt time.Duration) {
1096  	r.mu.Lock()
1097  	defer r.mu.Unlock()
1098  	r.now += dt
1099  }
1100  
1101  func (r *repeatState) Repeat(d *wlDisplay) {
1102  	if r.rate <= 0 {
1103  		return
1104  	}
1105  	r.mu.Lock()
1106  	now := r.now
1107  	r.mu.Unlock()
1108  	for {
1109  		var delay time.Duration
1110  		if r.last < r.delay {
1111  			delay = r.delay
1112  		} else {
1113  			delay = time.Second / time.Duration(r.rate)
1114  		}
1115  		if r.last+delay > now {
1116  			break
1117  		}
1118  		for _, e := range d.xkb.DispatchKey(r.key, key.Press) {
1119  			r.win.Event(e)
1120  		}
1121  		r.last += delay
1122  	}
1123  }
1124  
1125  //export gio_onFrameDone
1126  func gio_onFrameDone(data unsafe.Pointer, callback *C.struct_wl_callback, t C.uint32_t) {
1127  	C.wl_callback_destroy(callback)
1128  	w := callbackLoad(data).(*window)
1129  	if w.lastFrameCallback == callback {
1130  		w.lastFrameCallback = nil
1131  		w.draw(false)
1132  	}
1133  }
1134  
1135  func (w *window) loop() error {
1136  	var p poller
1137  	for {
1138  		if err := w.disp.dispatch(&p); err != nil {
1139  			return err
1140  		}
1141  		if w.dead {
1142  			w.w.Event(system.DestroyEvent{})
1143  			break
1144  		}
1145  		w.process()
1146  	}
1147  	return nil
1148  }
1149  
1150  func (w *window) process() {
1151  	w.mu.Lock()
1152  	readClipboard := w.readClipboard
1153  	writeClipboard := w.writeClipboard
1154  	opts := w.opts
1155  	w.readClipboard = false
1156  	w.writeClipboard = nil
1157  	w.opts = nil
1158  	w.mu.Unlock()
1159  	if readClipboard {
1160  		r, err := w.disp.readClipboard()
1161  		// Send empty responses on unavailable clipboards or errors.
1162  		if r == nil || err != nil {
1163  			w.w.Event(clipboard.Event{})
1164  			return
1165  		}
1166  		// Don't let slow clipboard transfers block event loop.
1167  		go func() {
1168  			defer r.Close()
1169  			data, _ := ioutil.ReadAll(r)
1170  			w.w.Event(clipboard.Event{Text: string(data)})
1171  		}()
1172  	}
1173  	if writeClipboard != nil {
1174  		w.disp.writeClipboard([]byte(*writeClipboard))
1175  	}
1176  	if opts != nil {
1177  		w.setOptions(opts)
1178  	}
1179  	// pass false to skip unnecessary drawing.
1180  	w.draw(false)
1181  }
1182  
1183  func (d *wlDisplay) dispatch(p *poller) error {
1184  	dispfd := C.wl_display_get_fd(d.disp)
1185  	// Poll for events and notifications.
1186  	pollfds := append(p.pollfds[:0],
1187  		syscall.PollFd{Fd: int32(dispfd), Events: syscall.POLLIN | syscall.POLLERR},
1188  		syscall.PollFd{Fd: int32(d.notify.read), Events: syscall.POLLIN | syscall.POLLERR},
1189  	)
1190  	dispFd := &pollfds[0]
1191  	if ret, err := C.wl_display_flush(d.disp); ret < 0 {
1192  		if err != syscall.EAGAIN {
1193  			return fmt.Errorf("wayland: wl_display_flush failed: %v", err)
1194  		}
1195  		// EAGAIN means the output buffer was full. Poll for
1196  		// POLLOUT to know when we can write again.
1197  		dispFd.Events |= syscall.POLLOUT
1198  	}
1199  	if _, err := syscall.Poll(pollfds, -1); err != nil && err != syscall.EINTR {
1200  		return fmt.Errorf("wayland: poll failed: %v", err)
1201  	}
1202  	// Clear notifications.
1203  	for {
1204  		_, err := syscall.Read(d.notify.read, p.buf[:])
1205  		if err == syscall.EAGAIN {
1206  			break
1207  		}
1208  		if err != nil {
1209  			return fmt.Errorf("wayland: read from notify pipe failed: %v", err)
1210  		}
1211  	}
1212  	// Handle events
1213  	switch {
1214  	case dispFd.Revents&syscall.POLLIN != 0:
1215  		if ret, err := C.wl_display_dispatch(d.disp); ret < 0 {
1216  			return fmt.Errorf("wayland: wl_display_dispatch failed: %v", err)
1217  		}
1218  	case dispFd.Revents&(syscall.POLLERR|syscall.POLLHUP) != 0:
1219  		return errors.New("wayland: display file descriptor gone")
1220  	}
1221  	d.repeat.Repeat(d)
1222  	return nil
1223  }
1224  
1225  func (w *window) SetAnimating(anim bool) {
1226  	w.mu.Lock()
1227  	w.animating = anim
1228  	w.mu.Unlock()
1229  	w.disp.wakeup()
1230  }
1231  
1232  // Wakeup wakes up the event loop through the notification pipe.
1233  func (d *wlDisplay) wakeup() {
1234  	oneByte := make([]byte, 1)
1235  	if _, err := syscall.Write(d.notify.write, oneByte); err != nil && err != syscall.EAGAIN {
1236  		panic(fmt.Errorf("failed to write to pipe: %v", err))
1237  	}
1238  }
1239  
1240  func (w *window) destroy() {
1241  	if w.cursor.surf != nil {
1242  		C.wl_surface_destroy(w.cursor.surf)
1243  	}
1244  	if w.cursor.theme != nil {
1245  		C.wl_cursor_theme_destroy(w.cursor.theme)
1246  	}
1247  	if w.topLvl != nil {
1248  		C.xdg_toplevel_destroy(w.topLvl)
1249  	}
1250  	if w.surf != nil {
1251  		C.wl_surface_destroy(w.surf)
1252  	}
1253  	if w.wmSurf != nil {
1254  		C.xdg_surface_destroy(w.wmSurf)
1255  	}
1256  	if w.decor != nil {
1257  		C.zxdg_toplevel_decoration_v1_destroy(w.decor)
1258  	}
1259  	callbackDelete(unsafe.Pointer(w.surf))
1260  }
1261  
1262  //export gio_onKeyboardModifiers
1263  func gio_onKeyboardModifiers(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, serial, depressed, latched, locked, group C.uint32_t) {
1264  	s := callbackLoad(data).(*wlSeat)
1265  	s.serial = serial
1266  	d := s.disp
1267  	d.repeat.Stop(0)
1268  	if d.xkb == nil {
1269  		return
1270  	}
1271  	d.xkb.UpdateMask(uint32(depressed), uint32(latched), uint32(locked), uint32(group), uint32(group), uint32(group))
1272  }
1273  
1274  //export gio_onKeyboardRepeatInfo
1275  func gio_onKeyboardRepeatInfo(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, rate, delay C.int32_t) {
1276  	s := callbackLoad(data).(*wlSeat)
1277  	d := s.disp
1278  	d.repeat.Stop(0)
1279  	d.repeat.rate = int(rate)
1280  	d.repeat.delay = time.Duration(delay) * time.Millisecond
1281  }
1282  
1283  //export gio_onTextInputEnter
1284  func gio_onTextInputEnter(data unsafe.Pointer, im *C.struct_zwp_text_input_v3, surf *C.struct_wl_surface) {
1285  }
1286  
1287  //export gio_onTextInputLeave
1288  func gio_onTextInputLeave(data unsafe.Pointer, im *C.struct_zwp_text_input_v3, surf *C.struct_wl_surface) {
1289  }
1290  
1291  //export gio_onTextInputPreeditString
1292  func gio_onTextInputPreeditString(data unsafe.Pointer, im *C.struct_zwp_text_input_v3, ctxt *C.char, begin, end C.int32_t) {
1293  }
1294  
1295  //export gio_onTextInputCommitString
1296  func gio_onTextInputCommitString(data unsafe.Pointer, im *C.struct_zwp_text_input_v3, ctxt *C.char) {
1297  }
1298  
1299  //export gio_onTextInputDeleteSurroundingText
1300  func gio_onTextInputDeleteSurroundingText(data unsafe.Pointer, im *C.struct_zwp_text_input_v3, before, after C.uint32_t) {
1301  }
1302  
1303  //export gio_onTextInputDone
1304  func gio_onTextInputDone(data unsafe.Pointer, im *C.struct_zwp_text_input_v3, serial C.uint32_t) {
1305  	s := callbackLoad(data).(*wlSeat)
1306  	s.serial = serial
1307  }
1308  
1309  //export gio_onDataSourceTarget
1310  func gio_onDataSourceTarget(data unsafe.Pointer, source *C.struct_wl_data_source, mime *C.char) {
1311  }
1312  
1313  //export gio_onDataSourceSend
1314  func gio_onDataSourceSend(data unsafe.Pointer, source *C.struct_wl_data_source, mime *C.char, fd C.int32_t) {
1315  	s := callbackLoad(data).(*wlSeat)
1316  	content := s.content
1317  	go func() {
1318  		defer syscall.Close(int(fd))
1319  		syscall.Write(int(fd), content)
1320  	}()
1321  }
1322  
1323  //export gio_onDataSourceCancelled
1324  func gio_onDataSourceCancelled(data unsafe.Pointer, source *C.struct_wl_data_source) {
1325  	s := callbackLoad(data).(*wlSeat)
1326  	if s.source == source {
1327  		s.content = nil
1328  		s.source = nil
1329  	}
1330  	C.wl_data_source_destroy(source)
1331  }
1332  
1333  //export gio_onDataSourceDNDDropPerformed
1334  func gio_onDataSourceDNDDropPerformed(data unsafe.Pointer, source *C.struct_wl_data_source) {
1335  }
1336  
1337  //export gio_onDataSourceDNDFinished
1338  func gio_onDataSourceDNDFinished(data unsafe.Pointer, source *C.struct_wl_data_source) {
1339  }
1340  
1341  //export gio_onDataSourceAction
1342  func gio_onDataSourceAction(data unsafe.Pointer, source *C.struct_wl_data_source, act C.uint32_t) {
1343  }
1344  
1345  func (w *window) flushScroll() {
1346  	var fling f32.Point
1347  	if w.fling.anim.Active() {
1348  		dist := float32(w.fling.anim.Tick(time.Now()))
1349  		fling = w.fling.dir.Mul(dist)
1350  	}
1351  	// The Wayland reported scroll distance for
1352  	// discrete scroll axes is only 10 pixels, where
1353  	// 100 seems more appropriate.
1354  	const discreteScale = 10
1355  	if w.scroll.steps.X != 0 {
1356  		w.scroll.dist.X *= discreteScale
1357  	}
1358  	if w.scroll.steps.Y != 0 {
1359  		w.scroll.dist.Y *= discreteScale
1360  	}
1361  	total := w.scroll.dist.Add(fling)
1362  	if total == (f32.Point{}) {
1363  		return
1364  	}
1365  	w.w.Event(pointer.Event{
1366  		Type:      pointer.Scroll,
1367  		Source:    pointer.Mouse,
1368  		Buttons:   w.pointerBtns,
1369  		Position:  w.lastPos,
1370  		Scroll:    total,
1371  		Time:      w.scroll.time,
1372  		Modifiers: w.disp.xkb.Modifiers(),
1373  	})
1374  	if w.scroll.steps == (image.Point{}) {
1375  		w.fling.xExtrapolation.SampleDelta(w.scroll.time, -w.scroll.dist.X)
1376  		w.fling.yExtrapolation.SampleDelta(w.scroll.time, -w.scroll.dist.Y)
1377  	}
1378  	w.scroll.dist = f32.Point{}
1379  	w.scroll.steps = image.Point{}
1380  }
1381  
1382  func (w *window) onPointerMotion(x, y C.wl_fixed_t, t C.uint32_t) {
1383  	w.flushScroll()
1384  	w.lastPos = f32.Point{
1385  		X: fromFixed(x) * float32(w.scale),
1386  		Y: fromFixed(y) * float32(w.scale),
1387  	}
1388  	w.w.Event(pointer.Event{
1389  		Type:      pointer.Move,
1390  		Position:  w.lastPos,
1391  		Buttons:   w.pointerBtns,
1392  		Source:    pointer.Mouse,
1393  		Time:      time.Duration(t) * time.Millisecond,
1394  		Modifiers: w.disp.xkb.Modifiers(),
1395  	})
1396  }
1397  
1398  func (w *window) updateOpaqueRegion() {
1399  	reg := C.wl_compositor_create_region(w.disp.compositor)
1400  	C.wl_region_add(reg, 0, 0, C.int32_t(w.width), C.int32_t(w.height))
1401  	C.wl_surface_set_opaque_region(w.surf, reg)
1402  	C.wl_region_destroy(reg)
1403  }
1404  
1405  func (w *window) updateOutputs() {
1406  	scale := 1
1407  	var found bool
1408  	for _, conf := range w.disp.outputConfig {
1409  		for _, w2 := range conf.windows {
1410  			if w2 == w {
1411  				found = true
1412  				if conf.scale > scale {
1413  					scale = conf.scale
1414  				}
1415  			}
1416  		}
1417  	}
1418  	w.mu.Lock()
1419  	if found && scale != w.scale {
1420  		w.scale = scale
1421  		w.newScale = true
1422  	}
1423  	w.mu.Unlock()
1424  	if !found {
1425  		w.setStage(system.StagePaused)
1426  	} else {
1427  		w.setStage(system.StageRunning)
1428  		w.draw(true)
1429  	}
1430  }
1431  
1432  func (w *window) config() (int, int, unit.Metric) {
1433  	width, height := w.width*w.scale, w.height*w.scale
1434  	return width, height, unit.Metric{
1435  		PxPerDp: w.ppdp * float32(w.scale),
1436  		PxPerSp: w.ppsp * float32(w.scale),
1437  	}
1438  }
1439  
1440  func (w *window) draw(sync bool) {
1441  	w.flushScroll()
1442  	w.mu.Lock()
1443  	anim := w.animating || w.fling.anim.Active()
1444  	dead := w.dead
1445  	w.mu.Unlock()
1446  	if dead || (!anim && !sync) {
1447  		return
1448  	}
1449  	width, height, cfg := w.config()
1450  	if cfg == (unit.Metric{}) {
1451  		return
1452  	}
1453  	if anim && w.lastFrameCallback == nil {
1454  		w.lastFrameCallback = C.wl_surface_frame(w.surf)
1455  		// Use the surface as listener data for gio_onFrameDone.
1456  		C.wl_callback_add_listener(w.lastFrameCallback, &C.gio_callback_listener, unsafe.Pointer(w.surf))
1457  	}
1458  	w.w.Event(FrameEvent{
1459  		FrameEvent: system.FrameEvent{
1460  			Now: time.Now(),
1461  			Size: image.Point{
1462  				X: width,
1463  				Y: height,
1464  			},
1465  			Metric: cfg,
1466  		},
1467  		Sync: sync,
1468  	})
1469  }
1470  
1471  func (w *window) setStage(s system.Stage) {
1472  	if s == w.stage {
1473  		return
1474  	}
1475  	w.stage = s
1476  	w.w.Event(system.StageEvent{Stage: s})
1477  }
1478  
1479  func (w *window) display() *C.struct_wl_display {
1480  	return w.disp.disp
1481  }
1482  
1483  func (w *window) surface() (*C.struct_wl_surface, int, int) {
1484  	if w.needAck {
1485  		C.xdg_surface_ack_configure(w.wmSurf, w.serial)
1486  		w.needAck = false
1487  	}
1488  	width, height, scale := w.width, w.height, w.scale
1489  	if w.newScale {
1490  		C.wl_surface_set_buffer_scale(w.surf, C.int32_t(scale))
1491  		w.newScale = false
1492  	}
1493  	return w.surf, width * scale, height * scale
1494  }
1495  
1496  func (w *window) ShowTextInput(show bool) {}
1497  
1498  // Close the window. Not implemented for Wayland.
1499  func (w *window) Close() {}
1500  
1501  // detectUIScale reports the system UI scale, or 1.0 if it fails.
1502  func detectUIScale() float32 {
1503  	// TODO: What about other window environments?
1504  	out, err := exec.Command("gsettings", "get", "org.gnome.desktop.interface", "text-scaling-factor").Output()
1505  	if err != nil {
1506  		return 1.0
1507  	}
1508  	scale, err := strconv.ParseFloat(string(bytes.TrimSpace(out)), 32)
1509  	if err != nil {
1510  		return 1.0
1511  	}
1512  	return float32(scale)
1513  }
1514  
1515  func newWLDisplay() (*wlDisplay, error) {
1516  	d := &wlDisplay{
1517  		outputMap:    make(map[C.uint32_t]*C.struct_wl_output),
1518  		outputConfig: make(map[*C.struct_wl_output]*wlOutput),
1519  	}
1520  	pipe := make([]int, 2)
1521  	if err := syscall.Pipe2(pipe, syscall.O_NONBLOCK|syscall.O_CLOEXEC); err != nil {
1522  		return nil, fmt.Errorf("wayland: failed to create pipe: %v", err)
1523  	}
1524  	d.notify.read = pipe[0]
1525  	d.notify.write = pipe[1]
1526  	xkb, err := xkb.New()
1527  	if err != nil {
1528  		d.destroy()
1529  		return nil, fmt.Errorf("wayland: %v", err)
1530  	}
1531  	d.xkb = xkb
1532  	d.disp, err = C.wl_display_connect(nil)
1533  	if d.disp == nil {
1534  		d.destroy()
1535  		return nil, fmt.Errorf("wayland: wl_display_connect failed: %v", err)
1536  	}
1537  	callbackMap.Store(unsafe.Pointer(d.disp), d)
1538  	d.reg = C.wl_display_get_registry(d.disp)
1539  	if d.reg == nil {
1540  		d.destroy()
1541  		return nil, errors.New("wayland: wl_display_get_registry failed")
1542  	}
1543  	C.wl_registry_add_listener(d.reg, &C.gio_registry_listener, unsafe.Pointer(d.disp))
1544  	// Wait for the server to register all its globals to the
1545  	// registry listener (gio_onRegistryGlobal).
1546  	C.wl_display_roundtrip(d.disp)
1547  	// Configuration listeners are added to outputs by gio_onRegistryGlobal.
1548  	// We need another roundtrip to get the initial output configurations
1549  	// through the gio_onOutput* callbacks.
1550  	C.wl_display_roundtrip(d.disp)
1551  	return d, nil
1552  }
1553  
1554  func (d *wlDisplay) destroy() {
1555  	if d.notify.write != 0 {
1556  		syscall.Close(d.notify.write)
1557  		d.notify.write = 0
1558  	}
1559  	if d.notify.read != 0 {
1560  		syscall.Close(d.notify.read)
1561  		d.notify.read = 0
1562  	}
1563  	d.repeat.Stop(0)
1564  	if d.xkb != nil {
1565  		d.xkb.Destroy()
1566  		d.xkb = nil
1567  	}
1568  	if d.seat != nil {
1569  		d.seat.destroy()
1570  		d.seat = nil
1571  	}
1572  	if d.imm != nil {
1573  		C.zwp_text_input_manager_v3_destroy(d.imm)
1574  	}
1575  	if d.decor != nil {
1576  		C.zxdg_decoration_manager_v1_destroy(d.decor)
1577  	}
1578  	if d.shm != nil {
1579  		C.wl_shm_destroy(d.shm)
1580  	}
1581  	if d.compositor != nil {
1582  		C.wl_compositor_destroy(d.compositor)
1583  	}
1584  	if d.wm != nil {
1585  		C.xdg_wm_base_destroy(d.wm)
1586  	}
1587  	for _, output := range d.outputMap {
1588  		C.wl_output_destroy(output)
1589  	}
1590  	if d.reg != nil {
1591  		C.wl_registry_destroy(d.reg)
1592  	}
1593  	if d.disp != nil {
1594  		C.wl_display_disconnect(d.disp)
1595  		callbackDelete(unsafe.Pointer(d.disp))
1596  	}
1597  }
1598  
1599  // fromFixed converts a Wayland wl_fixed_t 23.8 number to float32.
1600  func fromFixed(v C.wl_fixed_t) float32 {
1601  	// Convert to float64 to avoid overflow.
1602  	// From wayland-util.h.
1603  	b := ((1023 + 44) << 52) + (1 << 51) + uint64(v)
1604  	f := math.Float64frombits(b) - (3 << 43)
1605  	return float32(f)
1606  }
1607