github.com/cybriq/giocore@v0.0.7-0.20210703034601-cfb9cb5f3900/app/internal/wm/os_wayland.go (about)

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