// package wl acts as a client for the wayland wayland protocol.

// generated by wl-scanner
// https://github.com/dkolbly/wl-scanner
// from: https://cgit.freedesktop.org/wayland/wayland/plain/protocol/wayland.xml
// on 2018-02-19 14:50:40 -0600
package wl

import (
	"context"
	"sync"
)

type DisplayErrorEvent struct {
	EventContext context.Context
	ObjectId     Proxy
	Code         uint32
	Message      string
}

type DisplayErrorHandler interface {
	HandleDisplayError(DisplayErrorEvent)
}

func (p *Display) AddErrorHandler(h DisplayErrorHandler) {
	if h != nil {
		p.mu.Lock()
		p.errorHandlers = append(p.errorHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Display) RemoveErrorHandler(h DisplayErrorHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.errorHandlers {
		if e == h {
			p.errorHandlers = append(p.errorHandlers[:i], p.errorHandlers[i+1:]...)
			break
		}
	}
}

type DisplayDeleteIdEvent struct {
	EventContext context.Context
	Id           uint32
}

type DisplayDeleteIdHandler interface {
	HandleDisplayDeleteId(DisplayDeleteIdEvent)
}

func (p *Display) AddDeleteIdHandler(h DisplayDeleteIdHandler) {
	if h != nil {
		p.mu.Lock()
		p.deleteIdHandlers = append(p.deleteIdHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Display) RemoveDeleteIdHandler(h DisplayDeleteIdHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.deleteIdHandlers {
		if e == h {
			p.deleteIdHandlers = append(p.deleteIdHandlers[:i], p.deleteIdHandlers[i+1:]...)
			break
		}
	}
}

func (p *Display) Dispatch(ctx context.Context, event *Event) {
	switch event.Opcode {
	case 0:
		if len(p.errorHandlers) > 0 {
			ev := DisplayErrorEvent{}
			ev.EventContext = ctx
			ev.ObjectId = event.Proxy(p.Context())
			ev.Code = event.Uint32()
			ev.Message = event.String()
			p.mu.RLock()
			for _, h := range p.errorHandlers {
				h.HandleDisplayError(ev)
			}
			p.mu.RUnlock()
		}
	case 1:
		if len(p.deleteIdHandlers) > 0 {
			ev := DisplayDeleteIdEvent{}
			ev.EventContext = ctx
			ev.Id = event.Uint32()
			p.mu.RLock()
			for _, h := range p.deleteIdHandlers {
				h.HandleDisplayDeleteId(ev)
			}
			p.mu.RUnlock()
		}
	}
}

type Display struct {
	BaseProxy
	mu               sync.RWMutex
	errorHandlers    []DisplayErrorHandler
	deleteIdHandlers []DisplayDeleteIdHandler
}

func NewDisplay(ctx *Context) *Display {
	ret := new(Display)
	ctx.Register(ret)
	return ret
}

// Sync will asynchronous roundtrip.
//
//
// The sync request asks the server to emit the 'done' event
// on the returned wl_callback object.  Since requests are
// handled in-order and events are delivered in-order, this can
// be used as a barrier to ensure all previous requests and the
// resulting events have been handled.
//
// The object returned by this request will be destroyed by the
// compositor after the callback is fired and as such the client must not
// attempt to use it after that point.
//
// The callback_data passed in the callback is the event serial.
//
func (p *Display) Sync() (*Callback, error) {
	ret := NewCallback(p.Context())
	return ret, p.Context().SendRequest(p, 0, Proxy(ret))
}

// GetRegistry will get global registry object.
//
//
// This request creates a registry object that allows the client
// to list and bind the global objects available from the
// compositor.
//
// It should be noted that the server side resources consumed in
// response to a get_registry request can only be released when the
// client disconnects, not when the client side proxy is destroyed.
// Therefore, clients should invoke get_registry as infrequently as
// possible to avoid wasting memory.
//
func (p *Display) GetRegistry() (*Registry, error) {
	ret := NewRegistry(p.Context())
	return ret, p.Context().SendRequest(p, 1, Proxy(ret))
}

const (
	DisplayErrorInvalidObject = 0
	DisplayErrorInvalidMethod = 1
	DisplayErrorNoMemory      = 2
)

type RegistryGlobalEvent struct {
	EventContext context.Context
	Name         uint32
	Interface    string
	Version      uint32
}

type RegistryGlobalHandler interface {
	HandleRegistryGlobal(RegistryGlobalEvent)
}

func (p *Registry) AddGlobalHandler(h RegistryGlobalHandler) {
	if h != nil {
		p.mu.Lock()
		p.globalHandlers = append(p.globalHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Registry) RemoveGlobalHandler(h RegistryGlobalHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.globalHandlers {
		if e == h {
			p.globalHandlers = append(p.globalHandlers[:i], p.globalHandlers[i+1:]...)
			break
		}
	}
}

type RegistryGlobalRemoveEvent struct {
	EventContext context.Context
	Name         uint32
}

type RegistryGlobalRemoveHandler interface {
	HandleRegistryGlobalRemove(RegistryGlobalRemoveEvent)
}

func (p *Registry) AddGlobalRemoveHandler(h RegistryGlobalRemoveHandler) {
	if h != nil {
		p.mu.Lock()
		p.globalRemoveHandlers = append(p.globalRemoveHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Registry) RemoveGlobalRemoveHandler(h RegistryGlobalRemoveHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.globalRemoveHandlers {
		if e == h {
			p.globalRemoveHandlers = append(p.globalRemoveHandlers[:i], p.globalRemoveHandlers[i+1:]...)
			break
		}
	}
}

func (p *Registry) Dispatch(ctx context.Context, event *Event) {
	switch event.Opcode {
	case 0:
		if len(p.globalHandlers) > 0 {
			ev := RegistryGlobalEvent{}
			ev.EventContext = ctx
			ev.Name = event.Uint32()
			ev.Interface = event.String()
			ev.Version = event.Uint32()
			p.mu.RLock()
			for _, h := range p.globalHandlers {
				h.HandleRegistryGlobal(ev)
			}
			p.mu.RUnlock()
		}
	case 1:
		if len(p.globalRemoveHandlers) > 0 {
			ev := RegistryGlobalRemoveEvent{}
			ev.EventContext = ctx
			ev.Name = event.Uint32()
			p.mu.RLock()
			for _, h := range p.globalRemoveHandlers {
				h.HandleRegistryGlobalRemove(ev)
			}
			p.mu.RUnlock()
		}
	}
}

type Registry struct {
	BaseProxy
	mu                   sync.RWMutex
	globalHandlers       []RegistryGlobalHandler
	globalRemoveHandlers []RegistryGlobalRemoveHandler
}

func NewRegistry(ctx *Context) *Registry {
	ret := new(Registry)
	ctx.Register(ret)
	return ret
}

// Bind will bind an object to the display.
//
//
// Binds a new, client-created object to the server using the
// specified name as the identifier.
//
func (p *Registry) Bind(name uint32, iface string, version uint32, id Proxy) error {
	return p.Context().SendRequest(p, 0, name, iface, version, id)
}

type CallbackDoneEvent struct {
	EventContext context.Context
	CallbackData uint32
}

type CallbackDoneHandler interface {
	HandleCallbackDone(CallbackDoneEvent)
}

func (p *Callback) AddDoneHandler(h CallbackDoneHandler) {
	if h != nil {
		p.mu.Lock()
		p.doneHandlers = append(p.doneHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Callback) RemoveDoneHandler(h CallbackDoneHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.doneHandlers {
		if e == h {
			p.doneHandlers = append(p.doneHandlers[:i], p.doneHandlers[i+1:]...)
			break
		}
	}
}

func (p *Callback) Dispatch(ctx context.Context, event *Event) {
	switch event.Opcode {
	case 0:
		if len(p.doneHandlers) > 0 {
			ev := CallbackDoneEvent{}
			ev.EventContext = ctx
			ev.CallbackData = event.Uint32()
			p.mu.RLock()
			for _, h := range p.doneHandlers {
				h.HandleCallbackDone(ev)
			}
			p.mu.RUnlock()
		}
	}
}

type Callback struct {
	BaseProxy
	mu           sync.RWMutex
	doneHandlers []CallbackDoneHandler
}

func NewCallback(ctx *Context) *Callback {
	ret := new(Callback)
	ctx.Register(ret)
	return ret
}

type Compositor struct {
	BaseProxy
}

func NewCompositor(ctx *Context) *Compositor {
	ret := new(Compositor)
	ctx.Register(ret)
	return ret
}

// CreateSurface will create new surface.
//
//
// Ask the compositor to create a new surface.
//
func (p *Compositor) CreateSurface() (*Surface, error) {
	ret := NewSurface(p.Context())
	return ret, p.Context().SendRequest(p, 0, Proxy(ret))
}

// CreateRegion will create new region.
//
//
// Ask the compositor to create a new region.
//
func (p *Compositor) CreateRegion() (*Region, error) {
	ret := NewRegion(p.Context())
	return ret, p.Context().SendRequest(p, 1, Proxy(ret))
}

type ShmPool struct {
	BaseProxy
}

func NewShmPool(ctx *Context) *ShmPool {
	ret := new(ShmPool)
	ctx.Register(ret)
	return ret
}

// CreateBuffer will create a buffer from the pool.
//
//
// Create a wl_buffer object from the pool.
//
// The buffer is created offset bytes into the pool and has
// width and height as specified.  The stride argument specifies
// the number of bytes from the beginning of one row to the beginning
// of the next.  The format is the pixel format of the buffer and
// must be one of those advertised through the wl_shm.format event.
//
// A buffer will keep a reference to the pool it was created from
// so it is valid to destroy the pool immediately after creating
// a buffer from it.
//
func (p *ShmPool) CreateBuffer(offset int32, width int32, height int32, stride int32, format uint32) (*Buffer, error) {
	ret := NewBuffer(p.Context())
	return ret, p.Context().SendRequest(p, 0, Proxy(ret), offset, width, height, stride, format)
}

// Destroy will destroy the pool.
//
//
// Destroy the shared memory pool.
//
// The mmapped memory will be released when all
// buffers that have been created from this pool
// are gone.
//
func (p *ShmPool) Destroy() error {
	return p.Context().SendRequest(p, 1)
}

// Resize will change the size of the pool mapping.
//
//
// This request will cause the server to remap the backing memory
// for the pool from the file descriptor passed when the pool was
// created, but using the new size.  This request can only be
// used to make the pool bigger.
//
func (p *ShmPool) Resize(size int32) error {
	return p.Context().SendRequest(p, 2, size)
}

type ShmFormatEvent struct {
	EventContext context.Context
	Format       uint32
}

type ShmFormatHandler interface {
	HandleShmFormat(ShmFormatEvent)
}

func (p *Shm) AddFormatHandler(h ShmFormatHandler) {
	if h != nil {
		p.mu.Lock()
		p.formatHandlers = append(p.formatHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Shm) RemoveFormatHandler(h ShmFormatHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.formatHandlers {
		if e == h {
			p.formatHandlers = append(p.formatHandlers[:i], p.formatHandlers[i+1:]...)
			break
		}
	}
}

func (p *Shm) Dispatch(ctx context.Context, event *Event) {
	switch event.Opcode {
	case 0:
		if len(p.formatHandlers) > 0 {
			ev := ShmFormatEvent{}
			ev.EventContext = ctx
			ev.Format = event.Uint32()
			p.mu.RLock()
			for _, h := range p.formatHandlers {
				h.HandleShmFormat(ev)
			}
			p.mu.RUnlock()
		}
	}
}

type Shm struct {
	BaseProxy
	mu             sync.RWMutex
	formatHandlers []ShmFormatHandler
}

func NewShm(ctx *Context) *Shm {
	ret := new(Shm)
	ctx.Register(ret)
	return ret
}

// CreatePool will create a shm pool.
//
//
// Create a new wl_shm_pool object.
//
// The pool can be used to create shared memory based buffer
// objects.  The server will mmap size bytes of the passed file
// descriptor, to use as backing memory for the pool.
//
func (p *Shm) CreatePool(fd uintptr, size int32) (*ShmPool, error) {
	ret := NewShmPool(p.Context())
	return ret, p.Context().SendRequest(p, 0, Proxy(ret), fd, size)
}

const (
	ShmErrorInvalidFormat = 0
	ShmErrorInvalidStride = 1
	ShmErrorInvalidFd     = 2
)

const (
	ShmFormatArgb8888    = 0
	ShmFormatXrgb8888    = 1
	ShmFormatC8          = 0x20203843
	ShmFormatRgb332      = 0x38424752
	ShmFormatBgr233      = 0x38524742
	ShmFormatXrgb4444    = 0x32315258
	ShmFormatXbgr4444    = 0x32314258
	ShmFormatRgbx4444    = 0x32315852
	ShmFormatBgrx4444    = 0x32315842
	ShmFormatArgb4444    = 0x32315241
	ShmFormatAbgr4444    = 0x32314241
	ShmFormatRgba4444    = 0x32314152
	ShmFormatBgra4444    = 0x32314142
	ShmFormatXrgb1555    = 0x35315258
	ShmFormatXbgr1555    = 0x35314258
	ShmFormatRgbx5551    = 0x35315852
	ShmFormatBgrx5551    = 0x35315842
	ShmFormatArgb1555    = 0x35315241
	ShmFormatAbgr1555    = 0x35314241
	ShmFormatRgba5551    = 0x35314152
	ShmFormatBgra5551    = 0x35314142
	ShmFormatRgb565      = 0x36314752
	ShmFormatBgr565      = 0x36314742
	ShmFormatRgb888      = 0x34324752
	ShmFormatBgr888      = 0x34324742
	ShmFormatXbgr8888    = 0x34324258
	ShmFormatRgbx8888    = 0x34325852
	ShmFormatBgrx8888    = 0x34325842
	ShmFormatAbgr8888    = 0x34324241
	ShmFormatRgba8888    = 0x34324152
	ShmFormatBgra8888    = 0x34324142
	ShmFormatXrgb2101010 = 0x30335258
	ShmFormatXbgr2101010 = 0x30334258
	ShmFormatRgbx1010102 = 0x30335852
	ShmFormatBgrx1010102 = 0x30335842
	ShmFormatArgb2101010 = 0x30335241
	ShmFormatAbgr2101010 = 0x30334241
	ShmFormatRgba1010102 = 0x30334152
	ShmFormatBgra1010102 = 0x30334142
	ShmFormatYuyv        = 0x56595559
	ShmFormatYvyu        = 0x55595659
	ShmFormatUyvy        = 0x59565955
	ShmFormatVyuy        = 0x59555956
	ShmFormatAyuv        = 0x56555941
	ShmFormatNv12        = 0x3231564e
	ShmFormatNv21        = 0x3132564e
	ShmFormatNv16        = 0x3631564e
	ShmFormatNv61        = 0x3136564e
	ShmFormatYuv410      = 0x39565559
	ShmFormatYvu410      = 0x39555659
	ShmFormatYuv411      = 0x31315559
	ShmFormatYvu411      = 0x31315659
	ShmFormatYuv420      = 0x32315559
	ShmFormatYvu420      = 0x32315659
	ShmFormatYuv422      = 0x36315559
	ShmFormatYvu422      = 0x36315659
	ShmFormatYuv444      = 0x34325559
	ShmFormatYvu444      = 0x34325659
)

type BufferReleaseEvent struct {
	EventContext context.Context
}

type BufferReleaseHandler interface {
	HandleBufferRelease(BufferReleaseEvent)
}

func (p *Buffer) AddReleaseHandler(h BufferReleaseHandler) {
	if h != nil {
		p.mu.Lock()
		p.releaseHandlers = append(p.releaseHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Buffer) RemoveReleaseHandler(h BufferReleaseHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.releaseHandlers {
		if e == h {
			p.releaseHandlers = append(p.releaseHandlers[:i], p.releaseHandlers[i+1:]...)
			break
		}
	}
}

func (p *Buffer) Dispatch(ctx context.Context, event *Event) {
	switch event.Opcode {
	case 0:
		if len(p.releaseHandlers) > 0 {
			ev := BufferReleaseEvent{}
			ev.EventContext = ctx
			p.mu.RLock()
			for _, h := range p.releaseHandlers {
				h.HandleBufferRelease(ev)
			}
			p.mu.RUnlock()
		}
	}
}

type Buffer struct {
	BaseProxy
	mu              sync.RWMutex
	releaseHandlers []BufferReleaseHandler
}

func NewBuffer(ctx *Context) *Buffer {
	ret := new(Buffer)
	ctx.Register(ret)
	return ret
}

// Destroy will destroy a buffer.
//
//
// Destroy a buffer. If and how you need to release the backing
// storage is defined by the buffer factory interface.
//
// For possible side-effects to a surface, see wl_surface.attach.
//
func (p *Buffer) Destroy() error {
	return p.Context().SendRequest(p, 0)
}

type DataOfferOfferEvent struct {
	EventContext context.Context
	MimeType     string
}

type DataOfferOfferHandler interface {
	HandleDataOfferOffer(DataOfferOfferEvent)
}

func (p *DataOffer) AddOfferHandler(h DataOfferOfferHandler) {
	if h != nil {
		p.mu.Lock()
		p.offerHandlers = append(p.offerHandlers, h)
		p.mu.Unlock()
	}
}

func (p *DataOffer) RemoveOfferHandler(h DataOfferOfferHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.offerHandlers {
		if e == h {
			p.offerHandlers = append(p.offerHandlers[:i], p.offerHandlers[i+1:]...)
			break
		}
	}
}

type DataOfferSourceActionsEvent struct {
	EventContext  context.Context
	SourceActions uint32
}

type DataOfferSourceActionsHandler interface {
	HandleDataOfferSourceActions(DataOfferSourceActionsEvent)
}

func (p *DataOffer) AddSourceActionsHandler(h DataOfferSourceActionsHandler) {
	if h != nil {
		p.mu.Lock()
		p.sourceActionsHandlers = append(p.sourceActionsHandlers, h)
		p.mu.Unlock()
	}
}

func (p *DataOffer) RemoveSourceActionsHandler(h DataOfferSourceActionsHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.sourceActionsHandlers {
		if e == h {
			p.sourceActionsHandlers = append(p.sourceActionsHandlers[:i], p.sourceActionsHandlers[i+1:]...)
			break
		}
	}
}

type DataOfferActionEvent struct {
	EventContext context.Context
	DndAction    uint32
}

type DataOfferActionHandler interface {
	HandleDataOfferAction(DataOfferActionEvent)
}

func (p *DataOffer) AddActionHandler(h DataOfferActionHandler) {
	if h != nil {
		p.mu.Lock()
		p.actionHandlers = append(p.actionHandlers, h)
		p.mu.Unlock()
	}
}

func (p *DataOffer) RemoveActionHandler(h DataOfferActionHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.actionHandlers {
		if e == h {
			p.actionHandlers = append(p.actionHandlers[:i], p.actionHandlers[i+1:]...)
			break
		}
	}
}

func (p *DataOffer) Dispatch(ctx context.Context, event *Event) {
	switch event.Opcode {
	case 0:
		if len(p.offerHandlers) > 0 {
			ev := DataOfferOfferEvent{}
			ev.EventContext = ctx
			ev.MimeType = event.String()
			p.mu.RLock()
			for _, h := range p.offerHandlers {
				h.HandleDataOfferOffer(ev)
			}
			p.mu.RUnlock()
		}
	case 1:
		if len(p.sourceActionsHandlers) > 0 {
			ev := DataOfferSourceActionsEvent{}
			ev.EventContext = ctx
			ev.SourceActions = event.Uint32()
			p.mu.RLock()
			for _, h := range p.sourceActionsHandlers {
				h.HandleDataOfferSourceActions(ev)
			}
			p.mu.RUnlock()
		}
	case 2:
		if len(p.actionHandlers) > 0 {
			ev := DataOfferActionEvent{}
			ev.EventContext = ctx
			ev.DndAction = event.Uint32()
			p.mu.RLock()
			for _, h := range p.actionHandlers {
				h.HandleDataOfferAction(ev)
			}
			p.mu.RUnlock()
		}
	}
}

type DataOffer struct {
	BaseProxy
	mu                    sync.RWMutex
	offerHandlers         []DataOfferOfferHandler
	sourceActionsHandlers []DataOfferSourceActionsHandler
	actionHandlers        []DataOfferActionHandler
}

func NewDataOffer(ctx *Context) *DataOffer {
	ret := new(DataOffer)
	ctx.Register(ret)
	return ret
}

// Accept will accept one of the offered mime types.
//
//
// Indicate that the client can accept the given mime type, or
// NULL for not accepted.
//
// For objects of version 2 or older, this request is used by the
// client to give feedback whether the client can receive the given
// mime type, or NULL if none is accepted; the feedback does not
// determine whether the drag-and-drop operation succeeds or not.
//
// For objects of version 3 or newer, this request determines the
// final result of the drag-and-drop operation. If the end result
// is that no mime types were accepted, the drag-and-drop operation
// will be cancelled and the corresponding drag source will receive
// wl_data_source.cancelled. Clients may still use this event in
// conjunction with wl_data_source.action for feedback.
//
func (p *DataOffer) Accept(serial uint32, mime_type string) error {
	return p.Context().SendRequest(p, 0, serial, mime_type)
}

// Receive will request that the data is transferred.
//
//
// To transfer the offered data, the client issues this request
// and indicates the mime type it wants to receive.  The transfer
// happens through the passed file descriptor (typically created
// with the pipe system call).  The source client writes the data
// in the mime type representation requested and then closes the
// file descriptor.
//
// The receiving client reads from the read end of the pipe until
// EOF and then closes its end, at which point the transfer is
// complete.
//
// This request may happen multiple times for different mime types,
// both before and after wl_data_device.drop. Drag-and-drop destination
// clients may preemptively fetch data or examine it more closely to
// determine acceptance.
//
func (p *DataOffer) Receive(mime_type string, fd uintptr) error {
	return p.Context().SendRequest(p, 1, mime_type, fd)
}

// Destroy will destroy data offer.
//
//
// Destroy the data offer.
//
func (p *DataOffer) Destroy() error {
	return p.Context().SendRequest(p, 2)
}

// Finish will the offer will no longer be used.
//
//
// Notifies the compositor that the drag destination successfully
// finished the drag-and-drop operation.
//
// Upon receiving this request, the compositor will emit
// wl_data_source.dnd_finished on the drag source client.
//
// It is a client error to perform other requests than
// wl_data_offer.destroy after this one. It is also an error to perform
// this request after a NULL mime type has been set in
// wl_data_offer.accept or no action was received through
// wl_data_offer.action.
//
func (p *DataOffer) Finish() error {
	return p.Context().SendRequest(p, 3)
}

// SetActions will set the available/preferred drag-and-drop actions.
//
//
// Sets the actions that the destination side client supports for
// this operation. This request may trigger the emission of
// wl_data_source.action and wl_data_offer.action events if the compositor
// needs to change the selected action.
//
// This request can be called multiple times throughout the
// drag-and-drop operation, typically in response to wl_data_device.enter
// or wl_data_device.motion events.
//
// This request determines the final result of the drag-and-drop
// operation. If the end result is that no action is accepted,
// the drag source will receive wl_drag_source.cancelled.
//
// The dnd_actions argument must contain only values expressed in the
// wl_data_device_manager.dnd_actions enum, and the preferred_action
// argument must only contain one of those values set, otherwise it
// will result in a protocol error.
//
// While managing an "ask" action, the destination drag-and-drop client
// may perform further wl_data_offer.receive requests, and is expected
// to perform one last wl_data_offer.set_actions request with a preferred
// action other than "ask" (and optionally wl_data_offer.accept) before
// requesting wl_data_offer.finish, in order to convey the action selected
// by the user. If the preferred action is not in the
// wl_data_offer.source_actions mask, an error will be raised.
//
// If the "ask" action is dismissed (e.g. user cancellation), the client
// is expected to perform wl_data_offer.destroy right away.
//
// This request can only be made on drag-and-drop offers, a protocol error
// will be raised otherwise.
//
func (p *DataOffer) SetActions(dnd_actions uint32, preferred_action uint32) error {
	return p.Context().SendRequest(p, 4, dnd_actions, preferred_action)
}

const (
	DataOfferErrorInvalidFinish     = 0
	DataOfferErrorInvalidActionMask = 1
	DataOfferErrorInvalidAction     = 2
	DataOfferErrorInvalidOffer      = 3
)

type DataSourceTargetEvent struct {
	EventContext context.Context
	MimeType     string
}

type DataSourceTargetHandler interface {
	HandleDataSourceTarget(DataSourceTargetEvent)
}

func (p *DataSource) AddTargetHandler(h DataSourceTargetHandler) {
	if h != nil {
		p.mu.Lock()
		p.targetHandlers = append(p.targetHandlers, h)
		p.mu.Unlock()
	}
}

func (p *DataSource) RemoveTargetHandler(h DataSourceTargetHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.targetHandlers {
		if e == h {
			p.targetHandlers = append(p.targetHandlers[:i], p.targetHandlers[i+1:]...)
			break
		}
	}
}

type DataSourceSendEvent struct {
	EventContext context.Context
	MimeType     string
	Fd           uintptr
}

type DataSourceSendHandler interface {
	HandleDataSourceSend(DataSourceSendEvent)
}

func (p *DataSource) AddSendHandler(h DataSourceSendHandler) {
	if h != nil {
		p.mu.Lock()
		p.sendHandlers = append(p.sendHandlers, h)
		p.mu.Unlock()
	}
}

func (p *DataSource) RemoveSendHandler(h DataSourceSendHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.sendHandlers {
		if e == h {
			p.sendHandlers = append(p.sendHandlers[:i], p.sendHandlers[i+1:]...)
			break
		}
	}
}

type DataSourceCancelledEvent struct {
	EventContext context.Context
}

type DataSourceCancelledHandler interface {
	HandleDataSourceCancelled(DataSourceCancelledEvent)
}

func (p *DataSource) AddCancelledHandler(h DataSourceCancelledHandler) {
	if h != nil {
		p.mu.Lock()
		p.cancelledHandlers = append(p.cancelledHandlers, h)
		p.mu.Unlock()
	}
}

func (p *DataSource) RemoveCancelledHandler(h DataSourceCancelledHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.cancelledHandlers {
		if e == h {
			p.cancelledHandlers = append(p.cancelledHandlers[:i], p.cancelledHandlers[i+1:]...)
			break
		}
	}
}

type DataSourceDndDropPerformedEvent struct {
	EventContext context.Context
}

type DataSourceDndDropPerformedHandler interface {
	HandleDataSourceDndDropPerformed(DataSourceDndDropPerformedEvent)
}

func (p *DataSource) AddDndDropPerformedHandler(h DataSourceDndDropPerformedHandler) {
	if h != nil {
		p.mu.Lock()
		p.dndDropPerformedHandlers = append(p.dndDropPerformedHandlers, h)
		p.mu.Unlock()
	}
}

func (p *DataSource) RemoveDndDropPerformedHandler(h DataSourceDndDropPerformedHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.dndDropPerformedHandlers {
		if e == h {
			p.dndDropPerformedHandlers = append(p.dndDropPerformedHandlers[:i], p.dndDropPerformedHandlers[i+1:]...)
			break
		}
	}
}

type DataSourceDndFinishedEvent struct {
	EventContext context.Context
}

type DataSourceDndFinishedHandler interface {
	HandleDataSourceDndFinished(DataSourceDndFinishedEvent)
}

func (p *DataSource) AddDndFinishedHandler(h DataSourceDndFinishedHandler) {
	if h != nil {
		p.mu.Lock()
		p.dndFinishedHandlers = append(p.dndFinishedHandlers, h)
		p.mu.Unlock()
	}
}

func (p *DataSource) RemoveDndFinishedHandler(h DataSourceDndFinishedHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.dndFinishedHandlers {
		if e == h {
			p.dndFinishedHandlers = append(p.dndFinishedHandlers[:i], p.dndFinishedHandlers[i+1:]...)
			break
		}
	}
}

type DataSourceActionEvent struct {
	EventContext context.Context
	DndAction    uint32
}

type DataSourceActionHandler interface {
	HandleDataSourceAction(DataSourceActionEvent)
}

func (p *DataSource) AddActionHandler(h DataSourceActionHandler) {
	if h != nil {
		p.mu.Lock()
		p.actionHandlers = append(p.actionHandlers, h)
		p.mu.Unlock()
	}
}

func (p *DataSource) RemoveActionHandler(h DataSourceActionHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.actionHandlers {
		if e == h {
			p.actionHandlers = append(p.actionHandlers[:i], p.actionHandlers[i+1:]...)
			break
		}
	}
}

func (p *DataSource) Dispatch(ctx context.Context, event *Event) {
	switch event.Opcode {
	case 0:
		if len(p.targetHandlers) > 0 {
			ev := DataSourceTargetEvent{}
			ev.EventContext = ctx
			ev.MimeType = event.String()
			p.mu.RLock()
			for _, h := range p.targetHandlers {
				h.HandleDataSourceTarget(ev)
			}
			p.mu.RUnlock()
		}
	case 1:
		if len(p.sendHandlers) > 0 {
			ev := DataSourceSendEvent{}
			ev.EventContext = ctx
			ev.MimeType = event.String()
			ev.Fd = event.FD()
			p.mu.RLock()
			for _, h := range p.sendHandlers {
				h.HandleDataSourceSend(ev)
			}
			p.mu.RUnlock()
		}
	case 2:
		if len(p.cancelledHandlers) > 0 {
			ev := DataSourceCancelledEvent{}
			ev.EventContext = ctx
			p.mu.RLock()
			for _, h := range p.cancelledHandlers {
				h.HandleDataSourceCancelled(ev)
			}
			p.mu.RUnlock()
		}
	case 3:
		if len(p.dndDropPerformedHandlers) > 0 {
			ev := DataSourceDndDropPerformedEvent{}
			ev.EventContext = ctx
			p.mu.RLock()
			for _, h := range p.dndDropPerformedHandlers {
				h.HandleDataSourceDndDropPerformed(ev)
			}
			p.mu.RUnlock()
		}
	case 4:
		if len(p.dndFinishedHandlers) > 0 {
			ev := DataSourceDndFinishedEvent{}
			ev.EventContext = ctx
			p.mu.RLock()
			for _, h := range p.dndFinishedHandlers {
				h.HandleDataSourceDndFinished(ev)
			}
			p.mu.RUnlock()
		}
	case 5:
		if len(p.actionHandlers) > 0 {
			ev := DataSourceActionEvent{}
			ev.EventContext = ctx
			ev.DndAction = event.Uint32()
			p.mu.RLock()
			for _, h := range p.actionHandlers {
				h.HandleDataSourceAction(ev)
			}
			p.mu.RUnlock()
		}
	}
}

type DataSource struct {
	BaseProxy
	mu                       sync.RWMutex
	targetHandlers           []DataSourceTargetHandler
	sendHandlers             []DataSourceSendHandler
	cancelledHandlers        []DataSourceCancelledHandler
	dndDropPerformedHandlers []DataSourceDndDropPerformedHandler
	dndFinishedHandlers      []DataSourceDndFinishedHandler
	actionHandlers           []DataSourceActionHandler
}

func NewDataSource(ctx *Context) *DataSource {
	ret := new(DataSource)
	ctx.Register(ret)
	return ret
}

// Offer will add an offered mime type.
//
//
// This request adds a mime type to the set of mime types
// advertised to targets.  Can be called several times to offer
// multiple types.
//
func (p *DataSource) Offer(mime_type string) error {
	return p.Context().SendRequest(p, 0, mime_type)
}

// Destroy will destroy the data source.
//
//
// Destroy the data source.
//
func (p *DataSource) Destroy() error {
	return p.Context().SendRequest(p, 1)
}

// SetActions will set the available drag-and-drop actions.
//
//
// Sets the actions that the source side client supports for this
// operation. This request may trigger wl_data_source.action and
// wl_data_offer.action events if the compositor needs to change the
// selected action.
//
// The dnd_actions argument must contain only values expressed in the
// wl_data_device_manager.dnd_actions enum, otherwise it will result
// in a protocol error.
//
// This request must be made once only, and can only be made on sources
// used in drag-and-drop, so it must be performed before
// wl_data_device.start_drag. Attempting to use the source other than
// for drag-and-drop will raise a protocol error.
//
func (p *DataSource) SetActions(dnd_actions uint32) error {
	return p.Context().SendRequest(p, 2, dnd_actions)
}

const (
	DataSourceErrorInvalidActionMask = 0
	DataSourceErrorInvalidSource     = 1
)

type DataDeviceDataOfferEvent struct {
	EventContext context.Context
	Id           *DataOffer
}

type DataDeviceDataOfferHandler interface {
	HandleDataDeviceDataOffer(DataDeviceDataOfferEvent)
}

func (p *DataDevice) AddDataOfferHandler(h DataDeviceDataOfferHandler) {
	if h != nil {
		p.mu.Lock()
		p.dataOfferHandlers = append(p.dataOfferHandlers, h)
		p.mu.Unlock()
	}
}

func (p *DataDevice) RemoveDataOfferHandler(h DataDeviceDataOfferHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.dataOfferHandlers {
		if e == h {
			p.dataOfferHandlers = append(p.dataOfferHandlers[:i], p.dataOfferHandlers[i+1:]...)
			break
		}
	}
}

type DataDeviceEnterEvent struct {
	EventContext context.Context
	Serial       uint32
	Surface      *Surface
	X            float32
	Y            float32
	Id           *DataOffer
}

type DataDeviceEnterHandler interface {
	HandleDataDeviceEnter(DataDeviceEnterEvent)
}

func (p *DataDevice) AddEnterHandler(h DataDeviceEnterHandler) {
	if h != nil {
		p.mu.Lock()
		p.enterHandlers = append(p.enterHandlers, h)
		p.mu.Unlock()
	}
}

func (p *DataDevice) RemoveEnterHandler(h DataDeviceEnterHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.enterHandlers {
		if e == h {
			p.enterHandlers = append(p.enterHandlers[:i], p.enterHandlers[i+1:]...)
			break
		}
	}
}

type DataDeviceLeaveEvent struct {
	EventContext context.Context
}

type DataDeviceLeaveHandler interface {
	HandleDataDeviceLeave(DataDeviceLeaveEvent)
}

func (p *DataDevice) AddLeaveHandler(h DataDeviceLeaveHandler) {
	if h != nil {
		p.mu.Lock()
		p.leaveHandlers = append(p.leaveHandlers, h)
		p.mu.Unlock()
	}
}

func (p *DataDevice) RemoveLeaveHandler(h DataDeviceLeaveHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.leaveHandlers {
		if e == h {
			p.leaveHandlers = append(p.leaveHandlers[:i], p.leaveHandlers[i+1:]...)
			break
		}
	}
}

type DataDeviceMotionEvent struct {
	EventContext context.Context
	Time         uint32
	X            float32
	Y            float32
}

type DataDeviceMotionHandler interface {
	HandleDataDeviceMotion(DataDeviceMotionEvent)
}

func (p *DataDevice) AddMotionHandler(h DataDeviceMotionHandler) {
	if h != nil {
		p.mu.Lock()
		p.motionHandlers = append(p.motionHandlers, h)
		p.mu.Unlock()
	}
}

func (p *DataDevice) RemoveMotionHandler(h DataDeviceMotionHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.motionHandlers {
		if e == h {
			p.motionHandlers = append(p.motionHandlers[:i], p.motionHandlers[i+1:]...)
			break
		}
	}
}

type DataDeviceDropEvent struct {
	EventContext context.Context
}

type DataDeviceDropHandler interface {
	HandleDataDeviceDrop(DataDeviceDropEvent)
}

func (p *DataDevice) AddDropHandler(h DataDeviceDropHandler) {
	if h != nil {
		p.mu.Lock()
		p.dropHandlers = append(p.dropHandlers, h)
		p.mu.Unlock()
	}
}

func (p *DataDevice) RemoveDropHandler(h DataDeviceDropHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.dropHandlers {
		if e == h {
			p.dropHandlers = append(p.dropHandlers[:i], p.dropHandlers[i+1:]...)
			break
		}
	}
}

type DataDeviceSelectionEvent struct {
	EventContext context.Context
	Id           *DataOffer
}

type DataDeviceSelectionHandler interface {
	HandleDataDeviceSelection(DataDeviceSelectionEvent)
}

func (p *DataDevice) AddSelectionHandler(h DataDeviceSelectionHandler) {
	if h != nil {
		p.mu.Lock()
		p.selectionHandlers = append(p.selectionHandlers, h)
		p.mu.Unlock()
	}
}

func (p *DataDevice) RemoveSelectionHandler(h DataDeviceSelectionHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.selectionHandlers {
		if e == h {
			p.selectionHandlers = append(p.selectionHandlers[:i], p.selectionHandlers[i+1:]...)
			break
		}
	}
}

func (p *DataDevice) Dispatch(ctx context.Context, event *Event) {
	switch event.Opcode {
	case 0:
		if len(p.dataOfferHandlers) > 0 {
			ev := DataDeviceDataOfferEvent{}
			ev.EventContext = ctx
			ev.Id = event.Proxy(p.Context()).(*DataOffer)
			p.mu.RLock()
			for _, h := range p.dataOfferHandlers {
				h.HandleDataDeviceDataOffer(ev)
			}
			p.mu.RUnlock()
		}
	case 1:
		if len(p.enterHandlers) > 0 {
			ev := DataDeviceEnterEvent{}
			ev.EventContext = ctx
			ev.Serial = event.Uint32()
			ev.Surface = event.Proxy(p.Context()).(*Surface)
			ev.X = event.Float32()
			ev.Y = event.Float32()
			ev.Id = event.Proxy(p.Context()).(*DataOffer)
			p.mu.RLock()
			for _, h := range p.enterHandlers {
				h.HandleDataDeviceEnter(ev)
			}
			p.mu.RUnlock()
		}
	case 2:
		if len(p.leaveHandlers) > 0 {
			ev := DataDeviceLeaveEvent{}
			ev.EventContext = ctx
			p.mu.RLock()
			for _, h := range p.leaveHandlers {
				h.HandleDataDeviceLeave(ev)
			}
			p.mu.RUnlock()
		}
	case 3:
		if len(p.motionHandlers) > 0 {
			ev := DataDeviceMotionEvent{}
			ev.EventContext = ctx
			ev.Time = event.Uint32()
			ev.X = event.Float32()
			ev.Y = event.Float32()
			p.mu.RLock()
			for _, h := range p.motionHandlers {
				h.HandleDataDeviceMotion(ev)
			}
			p.mu.RUnlock()
		}
	case 4:
		if len(p.dropHandlers) > 0 {
			ev := DataDeviceDropEvent{}
			ev.EventContext = ctx
			p.mu.RLock()
			for _, h := range p.dropHandlers {
				h.HandleDataDeviceDrop(ev)
			}
			p.mu.RUnlock()
		}
	case 5:
		if len(p.selectionHandlers) > 0 {
			ev := DataDeviceSelectionEvent{}
			ev.EventContext = ctx
			ev.Id = event.Proxy(p.Context()).(*DataOffer)
			p.mu.RLock()
			for _, h := range p.selectionHandlers {
				h.HandleDataDeviceSelection(ev)
			}
			p.mu.RUnlock()
		}
	}
}

type DataDevice struct {
	BaseProxy
	mu                sync.RWMutex
	dataOfferHandlers []DataDeviceDataOfferHandler
	enterHandlers     []DataDeviceEnterHandler
	leaveHandlers     []DataDeviceLeaveHandler
	motionHandlers    []DataDeviceMotionHandler
	dropHandlers      []DataDeviceDropHandler
	selectionHandlers []DataDeviceSelectionHandler
}

func NewDataDevice(ctx *Context) *DataDevice {
	ret := new(DataDevice)
	ctx.Register(ret)
	return ret
}

// StartDrag will start drag-and-drop operation.
//
//
// This request asks the compositor to start a drag-and-drop
// operation on behalf of the client.
//
// The source argument is the data source that provides the data
// for the eventual data transfer. If source is NULL, enter, leave
// and motion events are sent only to the client that initiated the
// drag and the client is expected to handle the data passing
// internally.
//
// The origin surface is the surface where the drag originates and
// the client must have an active implicit grab that matches the
// serial.
//
// The icon surface is an optional (can be NULL) surface that
// provides an icon to be moved around with the cursor.  Initially,
// the top-left corner of the icon surface is placed at the cursor
// hotspot, but subsequent wl_surface.attach request can move the
// relative position. Attach requests must be confirmed with
// wl_surface.commit as usual. The icon surface is given the role of
// a drag-and-drop icon. If the icon surface already has another role,
// it raises a protocol error.
//
// The current and pending input regions of the icon wl_surface are
// cleared, and wl_surface.set_input_region is ignored until the
// wl_surface is no longer used as the icon surface. When the use
// as an icon ends, the current and pending input regions become
// undefined, and the wl_surface is unmapped.
//
func (p *DataDevice) StartDrag(source *DataSource, origin *Surface, icon *Surface, serial uint32) error {
	return p.Context().SendRequest(p, 0, source, origin, icon, serial)
}

// SetSelection will copy data to the selection.
//
//
// This request asks the compositor to set the selection
// to the data from the source on behalf of the client.
//
// To unset the selection, set the source to NULL.
//
func (p *DataDevice) SetSelection(source *DataSource, serial uint32) error {
	return p.Context().SendRequest(p, 1, source, serial)
}

// Release will destroy data device.
//
//
// This request destroys the data device.
//
func (p *DataDevice) Release() error {
	return p.Context().SendRequest(p, 2)
}

const (
	DataDeviceErrorRole = 0
)

type DataDeviceManager struct {
	BaseProxy
}

func NewDataDeviceManager(ctx *Context) *DataDeviceManager {
	ret := new(DataDeviceManager)
	ctx.Register(ret)
	return ret
}

// CreateDataSource will create a new data source.
//
//
// Create a new data source.
//
func (p *DataDeviceManager) CreateDataSource() (*DataSource, error) {
	ret := NewDataSource(p.Context())
	return ret, p.Context().SendRequest(p, 0, Proxy(ret))
}

// GetDataDevice will create a new data device.
//
//
// Create a new data device for a given seat.
//
func (p *DataDeviceManager) GetDataDevice(seat *Seat) (*DataDevice, error) {
	ret := NewDataDevice(p.Context())
	return ret, p.Context().SendRequest(p, 1, Proxy(ret), seat)
}

const (
	DataDeviceManagerDndActionNone = 0
	DataDeviceManagerDndActionCopy = 1
	DataDeviceManagerDndActionMove = 2
	DataDeviceManagerDndActionAsk  = 4
)

type Shell struct {
	BaseProxy
}

func NewShell(ctx *Context) *Shell {
	ret := new(Shell)
	ctx.Register(ret)
	return ret
}

// GetShellSurface will create a shell surface from a surface.
//
//
// Create a shell surface for an existing surface. This gives
// the wl_surface the role of a shell surface. If the wl_surface
// already has another role, it raises a protocol error.
//
// Only one shell surface can be associated with a given surface.
//
func (p *Shell) GetShellSurface(surface *Surface) (*ShellSurface, error) {
	ret := NewShellSurface(p.Context())
	return ret, p.Context().SendRequest(p, 0, Proxy(ret), surface)
}

const (
	ShellErrorRole = 0
)

type ShellSurfacePingEvent struct {
	EventContext context.Context
	Serial       uint32
}

type ShellSurfacePingHandler interface {
	HandleShellSurfacePing(ShellSurfacePingEvent)
}

func (p *ShellSurface) AddPingHandler(h ShellSurfacePingHandler) {
	if h != nil {
		p.mu.Lock()
		p.pingHandlers = append(p.pingHandlers, h)
		p.mu.Unlock()
	}
}

func (p *ShellSurface) RemovePingHandler(h ShellSurfacePingHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.pingHandlers {
		if e == h {
			p.pingHandlers = append(p.pingHandlers[:i], p.pingHandlers[i+1:]...)
			break
		}
	}
}

type ShellSurfaceConfigureEvent struct {
	EventContext context.Context
	Edges        uint32
	Width        int32
	Height       int32
}

type ShellSurfaceConfigureHandler interface {
	HandleShellSurfaceConfigure(ShellSurfaceConfigureEvent)
}

func (p *ShellSurface) AddConfigureHandler(h ShellSurfaceConfigureHandler) {
	if h != nil {
		p.mu.Lock()
		p.configureHandlers = append(p.configureHandlers, h)
		p.mu.Unlock()
	}
}

func (p *ShellSurface) RemoveConfigureHandler(h ShellSurfaceConfigureHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.configureHandlers {
		if e == h {
			p.configureHandlers = append(p.configureHandlers[:i], p.configureHandlers[i+1:]...)
			break
		}
	}
}

type ShellSurfacePopupDoneEvent struct {
	EventContext context.Context
}

type ShellSurfacePopupDoneHandler interface {
	HandleShellSurfacePopupDone(ShellSurfacePopupDoneEvent)
}

func (p *ShellSurface) AddPopupDoneHandler(h ShellSurfacePopupDoneHandler) {
	if h != nil {
		p.mu.Lock()
		p.popupDoneHandlers = append(p.popupDoneHandlers, h)
		p.mu.Unlock()
	}
}

func (p *ShellSurface) RemovePopupDoneHandler(h ShellSurfacePopupDoneHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.popupDoneHandlers {
		if e == h {
			p.popupDoneHandlers = append(p.popupDoneHandlers[:i], p.popupDoneHandlers[i+1:]...)
			break
		}
	}
}

func (p *ShellSurface) Dispatch(ctx context.Context, event *Event) {
	switch event.Opcode {
	case 0:
		if len(p.pingHandlers) > 0 {
			ev := ShellSurfacePingEvent{}
			ev.EventContext = ctx
			ev.Serial = event.Uint32()
			p.mu.RLock()
			for _, h := range p.pingHandlers {
				h.HandleShellSurfacePing(ev)
			}
			p.mu.RUnlock()
		}
	case 1:
		if len(p.configureHandlers) > 0 {
			ev := ShellSurfaceConfigureEvent{}
			ev.EventContext = ctx
			ev.Edges = event.Uint32()
			ev.Width = event.Int32()
			ev.Height = event.Int32()
			p.mu.RLock()
			for _, h := range p.configureHandlers {
				h.HandleShellSurfaceConfigure(ev)
			}
			p.mu.RUnlock()
		}
	case 2:
		if len(p.popupDoneHandlers) > 0 {
			ev := ShellSurfacePopupDoneEvent{}
			ev.EventContext = ctx
			p.mu.RLock()
			for _, h := range p.popupDoneHandlers {
				h.HandleShellSurfacePopupDone(ev)
			}
			p.mu.RUnlock()
		}
	}
}

type ShellSurface struct {
	BaseProxy
	mu                sync.RWMutex
	pingHandlers      []ShellSurfacePingHandler
	configureHandlers []ShellSurfaceConfigureHandler
	popupDoneHandlers []ShellSurfacePopupDoneHandler
}

func NewShellSurface(ctx *Context) *ShellSurface {
	ret := new(ShellSurface)
	ctx.Register(ret)
	return ret
}

// Pong will respond to a ping event.
//
//
// A client must respond to a ping event with a pong request or
// the client may be deemed unresponsive.
//
func (p *ShellSurface) Pong(serial uint32) error {
	return p.Context().SendRequest(p, 0, serial)
}

// Move will start an interactive move.
//
//
// Start a pointer-driven move of the surface.
//
// This request must be used in response to a button press event.
// The server may ignore move requests depending on the state of
// the surface (e.g. fullscreen or maximized).
//
func (p *ShellSurface) Move(seat *Seat, serial uint32) error {
	return p.Context().SendRequest(p, 1, seat, serial)
}

// Resize will start an interactive resize.
//
//
// Start a pointer-driven resizing of the surface.
//
// This request must be used in response to a button press event.
// The server may ignore resize requests depending on the state of
// the surface (e.g. fullscreen or maximized).
//
func (p *ShellSurface) Resize(seat *Seat, serial uint32, edges uint32) error {
	return p.Context().SendRequest(p, 2, seat, serial, edges)
}

// SetToplevel will make the surface a toplevel surface.
//
//
// Map the surface as a toplevel surface.
//
// A toplevel surface is not fullscreen, maximized or transient.
//
func (p *ShellSurface) SetToplevel() error {
	return p.Context().SendRequest(p, 3)
}

// SetTransient will make the surface a transient surface.
//
//
// Map the surface relative to an existing surface.
//
// The x and y arguments specify the location of the upper left
// corner of the surface relative to the upper left corner of the
// parent surface, in surface-local coordinates.
//
// The flags argument controls details of the transient behaviour.
//
func (p *ShellSurface) SetTransient(parent *Surface, x int32, y int32, flags uint32) error {
	return p.Context().SendRequest(p, 4, parent, x, y, flags)
}

// SetFullscreen will make the surface a fullscreen surface.
//
//
// Map the surface as a fullscreen surface.
//
// If an output parameter is given then the surface will be made
// fullscreen on that output. If the client does not specify the
// output then the compositor will apply its policy - usually
// choosing the output on which the surface has the biggest surface
// area.
//
// The client may specify a method to resolve a size conflict
// between the output size and the surface size - this is provided
// through the method parameter.
//
// The framerate parameter is used only when the method is set
// to "driver", to indicate the preferred framerate. A value of 0
// indicates that the client does not care about framerate.  The
// framerate is specified in mHz, that is framerate of 60000 is 60Hz.
//
// A method of "scale" or "driver" implies a scaling operation of
// the surface, either via a direct scaling operation or a change of
// the output mode. This will override any kind of output scaling, so
// that mapping a surface with a buffer size equal to the mode can
// fill the screen independent of buffer_scale.
//
// A method of "fill" means we don't scale up the buffer, however
// any output scale is applied. This means that you may run into
// an edge case where the application maps a buffer with the same
// size of the output mode but buffer_scale 1 (thus making a
// surface larger than the output). In this case it is allowed to
// downscale the results to fit the screen.
//
// The compositor must reply to this request with a configure event
// with the dimensions for the output on which the surface will
// be made fullscreen.
//
func (p *ShellSurface) SetFullscreen(method uint32, framerate uint32, output *Output) error {
	return p.Context().SendRequest(p, 5, method, framerate, output)
}

// SetPopup will make the surface a popup surface.
//
//
// Map the surface as a popup.
//
// A popup surface is a transient surface with an added pointer
// grab.
//
// An existing implicit grab will be changed to owner-events mode,
// and the popup grab will continue after the implicit grab ends
// (i.e. releasing the mouse button does not cause the popup to
// be unmapped).
//
// The popup grab continues until the window is destroyed or a
// mouse button is pressed in any other client's window. A click
// in any of the client's surfaces is reported as normal, however,
// clicks in other clients' surfaces will be discarded and trigger
// the callback.
//
// The x and y arguments specify the location of the upper left
// corner of the surface relative to the upper left corner of the
// parent surface, in surface-local coordinates.
//
func (p *ShellSurface) SetPopup(seat *Seat, serial uint32, parent *Surface, x int32, y int32, flags uint32) error {
	return p.Context().SendRequest(p, 6, seat, serial, parent, x, y, flags)
}

// SetMaximized will make the surface a maximized surface.
//
//
// Map the surface as a maximized surface.
//
// If an output parameter is given then the surface will be
// maximized on that output. If the client does not specify the
// output then the compositor will apply its policy - usually
// choosing the output on which the surface has the biggest surface
// area.
//
// The compositor will reply with a configure event telling
// the expected new surface size. The operation is completed
// on the next buffer attach to this surface.
//
// A maximized surface typically fills the entire output it is
// bound to, except for desktop elements such as panels. This is
// the main difference between a maximized shell surface and a
// fullscreen shell surface.
//
// The details depend on the compositor implementation.
//
func (p *ShellSurface) SetMaximized(output *Output) error {
	return p.Context().SendRequest(p, 7, output)
}

// SetTitle will set surface title.
//
//
// Set a short title for the surface.
//
// This string may be used to identify the surface in a task bar,
// window list, or other user interface elements provided by the
// compositor.
//
// The string must be encoded in UTF-8.
//
func (p *ShellSurface) SetTitle(title string) error {
	return p.Context().SendRequest(p, 8, title)
}

// SetClass will set surface class.
//
//
// Set a class for the surface.
//
// The surface class identifies the general class of applications
// to which the surface belongs. A common convention is to use the
// file name (or the full path if it is a non-standard location) of
// the application's .desktop file as the class.
//
func (p *ShellSurface) SetClass(class_ string) error {
	return p.Context().SendRequest(p, 9, class_)
}

const (
	ShellSurfaceResizeNone        = 0
	ShellSurfaceResizeTop         = 1
	ShellSurfaceResizeBottom      = 2
	ShellSurfaceResizeLeft        = 4
	ShellSurfaceResizeTopLeft     = 5
	ShellSurfaceResizeBottomLeft  = 6
	ShellSurfaceResizeRight       = 8
	ShellSurfaceResizeTopRight    = 9
	ShellSurfaceResizeBottomRight = 10
)

const (
	ShellSurfaceTransientInactive = 0x1
)

const (
	ShellSurfaceFullscreenMethodDefault = 0
	ShellSurfaceFullscreenMethodScale   = 1
	ShellSurfaceFullscreenMethodDriver  = 2
	ShellSurfaceFullscreenMethodFill    = 3
)

type SurfaceEnterEvent struct {
	EventContext context.Context
	Output       *Output
}

type SurfaceEnterHandler interface {
	HandleSurfaceEnter(SurfaceEnterEvent)
}

func (p *Surface) AddEnterHandler(h SurfaceEnterHandler) {
	if h != nil {
		p.mu.Lock()
		p.enterHandlers = append(p.enterHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Surface) RemoveEnterHandler(h SurfaceEnterHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.enterHandlers {
		if e == h {
			p.enterHandlers = append(p.enterHandlers[:i], p.enterHandlers[i+1:]...)
			break
		}
	}
}

type SurfaceLeaveEvent struct {
	EventContext context.Context
	Output       *Output
}

type SurfaceLeaveHandler interface {
	HandleSurfaceLeave(SurfaceLeaveEvent)
}

func (p *Surface) AddLeaveHandler(h SurfaceLeaveHandler) {
	if h != nil {
		p.mu.Lock()
		p.leaveHandlers = append(p.leaveHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Surface) RemoveLeaveHandler(h SurfaceLeaveHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.leaveHandlers {
		if e == h {
			p.leaveHandlers = append(p.leaveHandlers[:i], p.leaveHandlers[i+1:]...)
			break
		}
	}
}

func (p *Surface) Dispatch(ctx context.Context, event *Event) {
	switch event.Opcode {
	case 0:
		if len(p.enterHandlers) > 0 {
			ev := SurfaceEnterEvent{}
			ev.EventContext = ctx
			ev.Output = event.Proxy(p.Context()).(*Output)
			p.mu.RLock()
			for _, h := range p.enterHandlers {
				h.HandleSurfaceEnter(ev)
			}
			p.mu.RUnlock()
		}
	case 1:
		if len(p.leaveHandlers) > 0 {
			ev := SurfaceLeaveEvent{}
			ev.EventContext = ctx
			ev.Output = event.Proxy(p.Context()).(*Output)
			p.mu.RLock()
			for _, h := range p.leaveHandlers {
				h.HandleSurfaceLeave(ev)
			}
			p.mu.RUnlock()
		}
	}
}

type Surface struct {
	BaseProxy
	mu            sync.RWMutex
	enterHandlers []SurfaceEnterHandler
	leaveHandlers []SurfaceLeaveHandler
}

func NewSurface(ctx *Context) *Surface {
	ret := new(Surface)
	ctx.Register(ret)
	return ret
}

// Destroy will delete surface.
//
//
// Deletes the surface and invalidates its object ID.
//
func (p *Surface) Destroy() error {
	return p.Context().SendRequest(p, 0)
}

// Attach will set the surface contents.
//
//
// Set a buffer as the content of this surface.
//
// The new size of the surface is calculated based on the buffer
// size transformed by the inverse buffer_transform and the
// inverse buffer_scale. This means that the supplied buffer
// must be an integer multiple of the buffer_scale.
//
// The x and y arguments specify the location of the new pending
// buffer's upper left corner, relative to the current buffer's upper
// left corner, in surface-local coordinates. In other words, the
// x and y, combined with the new surface size define in which
// directions the surface's size changes.
//
// Surface contents are double-buffered state, see wl_surface.commit.
//
// The initial surface contents are void; there is no content.
// wl_surface.attach assigns the given wl_buffer as the pending
// wl_buffer. wl_surface.commit makes the pending wl_buffer the new
// surface contents, and the size of the surface becomes the size
// calculated from the wl_buffer, as described above. After commit,
// there is no pending buffer until the next attach.
//
// Committing a pending wl_buffer allows the compositor to read the
// pixels in the wl_buffer. The compositor may access the pixels at
// any time after the wl_surface.commit request. When the compositor
// will not access the pixels anymore, it will send the
// wl_buffer.release event. Only after receiving wl_buffer.release,
// the client may reuse the wl_buffer. A wl_buffer that has been
// attached and then replaced by another attach instead of committed
// will not receive a release event, and is not used by the
// compositor.
//
// Destroying the wl_buffer after wl_buffer.release does not change
// the surface contents. However, if the client destroys the
// wl_buffer before receiving the wl_buffer.release event, the surface
// contents become undefined immediately.
//
// If wl_surface.attach is sent with a NULL wl_buffer, the
// following wl_surface.commit will remove the surface content.
//
func (p *Surface) Attach(buffer *Buffer, x int32, y int32) error {
	return p.Context().SendRequest(p, 1, buffer, x, y)
}

// Damage will mark part of the surface damaged.
//
//
// This request is used to describe the regions where the pending
// buffer is different from the current surface contents, and where
// the surface therefore needs to be repainted. The compositor
// ignores the parts of the damage that fall outside of the surface.
//
// Damage is double-buffered state, see wl_surface.commit.
//
// The damage rectangle is specified in surface-local coordinates,
// where x and y specify the upper left corner of the damage rectangle.
//
// The initial value for pending damage is empty: no damage.
// wl_surface.damage adds pending damage: the new pending damage
// is the union of old pending damage and the given rectangle.
//
// wl_surface.commit assigns pending damage as the current damage,
// and clears pending damage. The server will clear the current
// damage as it repaints the surface.
//
// Alternatively, damage can be posted with wl_surface.damage_buffer
// which uses buffer coordinates instead of surface coordinates,
// and is probably the preferred and intuitive way of doing this.
//
func (p *Surface) Damage(x int32, y int32, width int32, height int32) error {
	return p.Context().SendRequest(p, 2, x, y, width, height)
}

// Frame will request a frame throttling hint.
//
//
// Request a notification when it is a good time to start drawing a new
// frame, by creating a frame callback. This is useful for throttling
// redrawing operations, and driving animations.
//
// When a client is animating on a wl_surface, it can use the 'frame'
// request to get notified when it is a good time to draw and commit the
// next frame of animation. If the client commits an update earlier than
// that, it is likely that some updates will not make it to the display,
// and the client is wasting resources by drawing too often.
//
// The frame request will take effect on the next wl_surface.commit.
// The notification will only be posted for one frame unless
// requested again. For a wl_surface, the notifications are posted in
// the order the frame requests were committed.
//
// The server must send the notifications so that a client
// will not send excessive updates, while still allowing
// the highest possible update rate for clients that wait for the reply
// before drawing again. The server should give some time for the client
// to draw and commit after sending the frame callback events to let it
// hit the next output refresh.
//
// A server should avoid signaling the frame callbacks if the
// surface is not visible in any way, e.g. the surface is off-screen,
// or completely obscured by other opaque surfaces.
//
// The object returned by this request will be destroyed by the
// compositor after the callback is fired and as such the client must not
// attempt to use it after that point.
//
// The callback_data passed in the callback is the current time, in
// milliseconds, with an undefined base.
//
func (p *Surface) Frame() (*Callback, error) {
	ret := NewCallback(p.Context())
	return ret, p.Context().SendRequest(p, 3, Proxy(ret))
}

// SetOpaqueRegion will set opaque region.
//
//
// This request sets the region of the surface that contains
// opaque content.
//
// The opaque region is an optimization hint for the compositor
// that lets it optimize the redrawing of content behind opaque
// regions.  Setting an opaque region is not required for correct
// behaviour, but marking transparent content as opaque will result
// in repaint artifacts.
//
// The opaque region is specified in surface-local coordinates.
//
// The compositor ignores the parts of the opaque region that fall
// outside of the surface.
//
// Opaque region is double-buffered state, see wl_surface.commit.
//
// wl_surface.set_opaque_region changes the pending opaque region.
// wl_surface.commit copies the pending region to the current region.
// Otherwise, the pending and current regions are never changed.
//
// The initial value for an opaque region is empty. Setting the pending
// opaque region has copy semantics, and the wl_region object can be
// destroyed immediately. A NULL wl_region causes the pending opaque
// region to be set to empty.
//
func (p *Surface) SetOpaqueRegion(region *Region) error {
	return p.Context().SendRequest(p, 4, region)
}

// SetInputRegion will set input region.
//
//
// This request sets the region of the surface that can receive
// pointer and touch events.
//
// Input events happening outside of this region will try the next
// surface in the server surface stack. The compositor ignores the
// parts of the input region that fall outside of the surface.
//
// The input region is specified in surface-local coordinates.
//
// Input region is double-buffered state, see wl_surface.commit.
//
// wl_surface.set_input_region changes the pending input region.
// wl_surface.commit copies the pending region to the current region.
// Otherwise the pending and current regions are never changed,
// except cursor and icon surfaces are special cases, see
// wl_pointer.set_cursor and wl_data_device.start_drag.
//
// The initial value for an input region is infinite. That means the
// whole surface will accept input. Setting the pending input region
// has copy semantics, and the wl_region object can be destroyed
// immediately. A NULL wl_region causes the input region to be set
// to infinite.
//
func (p *Surface) SetInputRegion(region *Region) error {
	return p.Context().SendRequest(p, 5, region)
}

// Commit will commit pending surface state.
//
//
// Surface state (input, opaque, and damage regions, attached buffers,
// etc.) is double-buffered. Protocol requests modify the pending state,
// as opposed to the current state in use by the compositor. A commit
// request atomically applies all pending state, replacing the current
// state. After commit, the new pending state is as documented for each
// related request.
//
// On commit, a pending wl_buffer is applied first, and all other state
// second. This means that all coordinates in double-buffered state are
// relative to the new wl_buffer coming into use, except for
// wl_surface.attach itself. If there is no pending wl_buffer, the
// coordinates are relative to the current surface contents.
//
// All requests that need a commit to become effective are documented
// to affect double-buffered state.
//
// Other interfaces may add further double-buffered surface state.
//
func (p *Surface) Commit() error {
	return p.Context().SendRequest(p, 6)
}

// SetBufferTransform will sets the buffer transformation.
//
//
// This request sets an optional transformation on how the compositor
// interprets the contents of the buffer attached to the surface. The
// accepted values for the transform parameter are the values for
// wl_output.transform.
//
// Buffer transform is double-buffered state, see wl_surface.commit.
//
// A newly created surface has its buffer transformation set to normal.
//
// wl_surface.set_buffer_transform changes the pending buffer
// transformation. wl_surface.commit copies the pending buffer
// transformation to the current one. Otherwise, the pending and current
// values are never changed.
//
// The purpose of this request is to allow clients to render content
// according to the output transform, thus permitting the compositor to
// use certain optimizations even if the display is rotated. Using
// hardware overlays and scanning out a client buffer for fullscreen
// surfaces are examples of such optimizations. Those optimizations are
// highly dependent on the compositor implementation, so the use of this
// request should be considered on a case-by-case basis.
//
// Note that if the transform value includes 90 or 270 degree rotation,
// the width of the buffer will become the surface height and the height
// of the buffer will become the surface width.
//
// If transform is not one of the values from the
// wl_output.transform enum the invalid_transform protocol error
// is raised.
//
func (p *Surface) SetBufferTransform(transform int32) error {
	return p.Context().SendRequest(p, 7, transform)
}

// SetBufferScale will sets the buffer scaling factor.
//
//
// This request sets an optional scaling factor on how the compositor
// interprets the contents of the buffer attached to the window.
//
// Buffer scale is double-buffered state, see wl_surface.commit.
//
// A newly created surface has its buffer scale set to 1.
//
// wl_surface.set_buffer_scale changes the pending buffer scale.
// wl_surface.commit copies the pending buffer scale to the current one.
// Otherwise, the pending and current values are never changed.
//
// The purpose of this request is to allow clients to supply higher
// resolution buffer data for use on high resolution outputs. It is
// intended that you pick the same buffer scale as the scale of the
// output that the surface is displayed on. This means the compositor
// can avoid scaling when rendering the surface on that output.
//
// Note that if the scale is larger than 1, then you have to attach
// a buffer that is larger (by a factor of scale in each dimension)
// than the desired surface size.
//
// If scale is not positive the invalid_scale protocol error is
// raised.
//
func (p *Surface) SetBufferScale(scale int32) error {
	return p.Context().SendRequest(p, 8, scale)
}

// DamageBuffer will mark part of the surface damaged using buffer coordinates.
//
//
// This request is used to describe the regions where the pending
// buffer is different from the current surface contents, and where
// the surface therefore needs to be repainted. The compositor
// ignores the parts of the damage that fall outside of the surface.
//
// Damage is double-buffered state, see wl_surface.commit.
//
// The damage rectangle is specified in buffer coordinates,
// where x and y specify the upper left corner of the damage rectangle.
//
// The initial value for pending damage is empty: no damage.
// wl_surface.damage_buffer adds pending damage: the new pending
// damage is the union of old pending damage and the given rectangle.
//
// wl_surface.commit assigns pending damage as the current damage,
// and clears pending damage. The server will clear the current
// damage as it repaints the surface.
//
// This request differs from wl_surface.damage in only one way - it
// takes damage in buffer coordinates instead of surface-local
// coordinates. While this generally is more intuitive than surface
// coordinates, it is especially desirable when using wp_viewport
// or when a drawing library (like EGL) is unaware of buffer scale
// and buffer transform.
//
// Note: Because buffer transformation changes and damage requests may
// be interleaved in the protocol stream, it is impossible to determine
// the actual mapping between surface and buffer damage until
// wl_surface.commit time. Therefore, compositors wishing to take both
// kinds of damage into account will have to accumulate damage from the
// two requests separately and only transform from one to the other
// after receiving the wl_surface.commit.
//
func (p *Surface) DamageBuffer(x int32, y int32, width int32, height int32) error {
	return p.Context().SendRequest(p, 9, x, y, width, height)
}

const (
	SurfaceErrorInvalidScale     = 0
	SurfaceErrorInvalidTransform = 1
)

type SeatCapabilitiesEvent struct {
	EventContext context.Context
	Capabilities uint32
}

type SeatCapabilitiesHandler interface {
	HandleSeatCapabilities(SeatCapabilitiesEvent)
}

func (p *Seat) AddCapabilitiesHandler(h SeatCapabilitiesHandler) {
	if h != nil {
		p.mu.Lock()
		p.capabilitiesHandlers = append(p.capabilitiesHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Seat) RemoveCapabilitiesHandler(h SeatCapabilitiesHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.capabilitiesHandlers {
		if e == h {
			p.capabilitiesHandlers = append(p.capabilitiesHandlers[:i], p.capabilitiesHandlers[i+1:]...)
			break
		}
	}
}

type SeatNameEvent struct {
	EventContext context.Context
	Name         string
}

type SeatNameHandler interface {
	HandleSeatName(SeatNameEvent)
}

func (p *Seat) AddNameHandler(h SeatNameHandler) {
	if h != nil {
		p.mu.Lock()
		p.nameHandlers = append(p.nameHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Seat) RemoveNameHandler(h SeatNameHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.nameHandlers {
		if e == h {
			p.nameHandlers = append(p.nameHandlers[:i], p.nameHandlers[i+1:]...)
			break
		}
	}
}

func (p *Seat) Dispatch(ctx context.Context, event *Event) {
	switch event.Opcode {
	case 0:
		if len(p.capabilitiesHandlers) > 0 {
			ev := SeatCapabilitiesEvent{}
			ev.EventContext = ctx
			ev.Capabilities = event.Uint32()
			p.mu.RLock()
			for _, h := range p.capabilitiesHandlers {
				h.HandleSeatCapabilities(ev)
			}
			p.mu.RUnlock()
		}
	case 1:
		if len(p.nameHandlers) > 0 {
			ev := SeatNameEvent{}
			ev.EventContext = ctx
			ev.Name = event.String()
			p.mu.RLock()
			for _, h := range p.nameHandlers {
				h.HandleSeatName(ev)
			}
			p.mu.RUnlock()
		}
	}
}

type Seat struct {
	BaseProxy
	mu                   sync.RWMutex
	capabilitiesHandlers []SeatCapabilitiesHandler
	nameHandlers         []SeatNameHandler
}

func NewSeat(ctx *Context) *Seat {
	ret := new(Seat)
	ctx.Register(ret)
	return ret
}

// GetPointer will return pointer object.
//
//
// The ID provided will be initialized to the wl_pointer interface
// for this seat.
//
// This request only takes effect if the seat has the pointer
// capability, or has had the pointer capability in the past.
// It is a protocol violation to issue this request on a seat that has
// never had the pointer capability.
//
func (p *Seat) GetPointer() (*Pointer, error) {
	ret := NewPointer(p.Context())
	return ret, p.Context().SendRequest(p, 0, Proxy(ret))
}

// GetKeyboard will return keyboard object.
//
//
// The ID provided will be initialized to the wl_keyboard interface
// for this seat.
//
// This request only takes effect if the seat has the keyboard
// capability, or has had the keyboard capability in the past.
// It is a protocol violation to issue this request on a seat that has
// never had the keyboard capability.
//
func (p *Seat) GetKeyboard() (*Keyboard, error) {
	ret := NewKeyboard(p.Context())
	return ret, p.Context().SendRequest(p, 1, Proxy(ret))
}

// GetTouch will return touch object.
//
//
// The ID provided will be initialized to the wl_touch interface
// for this seat.
//
// This request only takes effect if the seat has the touch
// capability, or has had the touch capability in the past.
// It is a protocol violation to issue this request on a seat that has
// never had the touch capability.
//
func (p *Seat) GetTouch() (*Touch, error) {
	ret := NewTouch(p.Context())
	return ret, p.Context().SendRequest(p, 2, Proxy(ret))
}

// Release will release the seat object.
//
//
// Using this request a client can tell the server that it is not going to
// use the seat object anymore.
//
func (p *Seat) Release() error {
	return p.Context().SendRequest(p, 3)
}

const (
	SeatCapabilityPointer  = 1
	SeatCapabilityKeyboard = 2
	SeatCapabilityTouch    = 4
)

type PointerEnterEvent struct {
	EventContext context.Context
	Serial       uint32
	Surface      *Surface
	SurfaceX     float32
	SurfaceY     float32
}

type PointerEnterHandler interface {
	HandlePointerEnter(PointerEnterEvent)
}

func (p *Pointer) AddEnterHandler(h PointerEnterHandler) {
	if h != nil {
		p.mu.Lock()
		p.enterHandlers = append(p.enterHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Pointer) RemoveEnterHandler(h PointerEnterHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.enterHandlers {
		if e == h {
			p.enterHandlers = append(p.enterHandlers[:i], p.enterHandlers[i+1:]...)
			break
		}
	}
}

type PointerLeaveEvent struct {
	EventContext context.Context
	Serial       uint32
	Surface      *Surface
}

type PointerLeaveHandler interface {
	HandlePointerLeave(PointerLeaveEvent)
}

func (p *Pointer) AddLeaveHandler(h PointerLeaveHandler) {
	if h != nil {
		p.mu.Lock()
		p.leaveHandlers = append(p.leaveHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Pointer) RemoveLeaveHandler(h PointerLeaveHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.leaveHandlers {
		if e == h {
			p.leaveHandlers = append(p.leaveHandlers[:i], p.leaveHandlers[i+1:]...)
			break
		}
	}
}

type PointerMotionEvent struct {
	EventContext context.Context
	Time         uint32
	SurfaceX     float32
	SurfaceY     float32
}

type PointerMotionHandler interface {
	HandlePointerMotion(PointerMotionEvent)
}

func (p *Pointer) AddMotionHandler(h PointerMotionHandler) {
	if h != nil {
		p.mu.Lock()
		p.motionHandlers = append(p.motionHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Pointer) RemoveMotionHandler(h PointerMotionHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.motionHandlers {
		if e == h {
			p.motionHandlers = append(p.motionHandlers[:i], p.motionHandlers[i+1:]...)
			break
		}
	}
}

type PointerButtonEvent struct {
	EventContext context.Context
	Serial       uint32
	Time         uint32
	Button       uint32
	State        uint32
}

type PointerButtonHandler interface {
	HandlePointerButton(PointerButtonEvent)
}

func (p *Pointer) AddButtonHandler(h PointerButtonHandler) {
	if h != nil {
		p.mu.Lock()
		p.buttonHandlers = append(p.buttonHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Pointer) RemoveButtonHandler(h PointerButtonHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.buttonHandlers {
		if e == h {
			p.buttonHandlers = append(p.buttonHandlers[:i], p.buttonHandlers[i+1:]...)
			break
		}
	}
}

type PointerAxisEvent struct {
	EventContext context.Context
	Time         uint32
	Axis         uint32
	Value        float32
}

type PointerAxisHandler interface {
	HandlePointerAxis(PointerAxisEvent)
}

func (p *Pointer) AddAxisHandler(h PointerAxisHandler) {
	if h != nil {
		p.mu.Lock()
		p.axisHandlers = append(p.axisHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Pointer) RemoveAxisHandler(h PointerAxisHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.axisHandlers {
		if e == h {
			p.axisHandlers = append(p.axisHandlers[:i], p.axisHandlers[i+1:]...)
			break
		}
	}
}

type PointerFrameEvent struct {
	EventContext context.Context
}

type PointerFrameHandler interface {
	HandlePointerFrame(PointerFrameEvent)
}

func (p *Pointer) AddFrameHandler(h PointerFrameHandler) {
	if h != nil {
		p.mu.Lock()
		p.frameHandlers = append(p.frameHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Pointer) RemoveFrameHandler(h PointerFrameHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.frameHandlers {
		if e == h {
			p.frameHandlers = append(p.frameHandlers[:i], p.frameHandlers[i+1:]...)
			break
		}
	}
}

type PointerAxisSourceEvent struct {
	EventContext context.Context
	AxisSource   uint32
}

type PointerAxisSourceHandler interface {
	HandlePointerAxisSource(PointerAxisSourceEvent)
}

func (p *Pointer) AddAxisSourceHandler(h PointerAxisSourceHandler) {
	if h != nil {
		p.mu.Lock()
		p.axisSourceHandlers = append(p.axisSourceHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Pointer) RemoveAxisSourceHandler(h PointerAxisSourceHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.axisSourceHandlers {
		if e == h {
			p.axisSourceHandlers = append(p.axisSourceHandlers[:i], p.axisSourceHandlers[i+1:]...)
			break
		}
	}
}

type PointerAxisStopEvent struct {
	EventContext context.Context
	Time         uint32
	Axis         uint32
}

type PointerAxisStopHandler interface {
	HandlePointerAxisStop(PointerAxisStopEvent)
}

func (p *Pointer) AddAxisStopHandler(h PointerAxisStopHandler) {
	if h != nil {
		p.mu.Lock()
		p.axisStopHandlers = append(p.axisStopHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Pointer) RemoveAxisStopHandler(h PointerAxisStopHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.axisStopHandlers {
		if e == h {
			p.axisStopHandlers = append(p.axisStopHandlers[:i], p.axisStopHandlers[i+1:]...)
			break
		}
	}
}

type PointerAxisDiscreteEvent struct {
	EventContext context.Context
	Axis         uint32
	Discrete     int32
}

type PointerAxisDiscreteHandler interface {
	HandlePointerAxisDiscrete(PointerAxisDiscreteEvent)
}

func (p *Pointer) AddAxisDiscreteHandler(h PointerAxisDiscreteHandler) {
	if h != nil {
		p.mu.Lock()
		p.axisDiscreteHandlers = append(p.axisDiscreteHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Pointer) RemoveAxisDiscreteHandler(h PointerAxisDiscreteHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.axisDiscreteHandlers {
		if e == h {
			p.axisDiscreteHandlers = append(p.axisDiscreteHandlers[:i], p.axisDiscreteHandlers[i+1:]...)
			break
		}
	}
}

func (p *Pointer) Dispatch(ctx context.Context, event *Event) {
	switch event.Opcode {
	case 0:
		if len(p.enterHandlers) > 0 {
			ev := PointerEnterEvent{}
			ev.EventContext = ctx
			ev.Serial = event.Uint32()
			ev.Surface = event.Proxy(p.Context()).(*Surface)
			ev.SurfaceX = event.Float32()
			ev.SurfaceY = event.Float32()
			p.mu.RLock()
			for _, h := range p.enterHandlers {
				h.HandlePointerEnter(ev)
			}
			p.mu.RUnlock()
		}
	case 1:
		if len(p.leaveHandlers) > 0 {
			ev := PointerLeaveEvent{}
			ev.EventContext = ctx
			ev.Serial = event.Uint32()
			ev.Surface = event.Proxy(p.Context()).(*Surface)
			p.mu.RLock()
			for _, h := range p.leaveHandlers {
				h.HandlePointerLeave(ev)
			}
			p.mu.RUnlock()
		}
	case 2:
		if len(p.motionHandlers) > 0 {
			ev := PointerMotionEvent{}
			ev.EventContext = ctx
			ev.Time = event.Uint32()
			ev.SurfaceX = event.Float32()
			ev.SurfaceY = event.Float32()
			p.mu.RLock()
			for _, h := range p.motionHandlers {
				h.HandlePointerMotion(ev)
			}
			p.mu.RUnlock()
		}
	case 3:
		if len(p.buttonHandlers) > 0 {
			ev := PointerButtonEvent{}
			ev.EventContext = ctx
			ev.Serial = event.Uint32()
			ev.Time = event.Uint32()
			ev.Button = event.Uint32()
			ev.State = event.Uint32()
			p.mu.RLock()
			for _, h := range p.buttonHandlers {
				h.HandlePointerButton(ev)
			}
			p.mu.RUnlock()
		}
	case 4:
		if len(p.axisHandlers) > 0 {
			ev := PointerAxisEvent{}
			ev.EventContext = ctx
			ev.Time = event.Uint32()
			ev.Axis = event.Uint32()
			ev.Value = event.Float32()
			p.mu.RLock()
			for _, h := range p.axisHandlers {
				h.HandlePointerAxis(ev)
			}
			p.mu.RUnlock()
		}
	case 5:
		if len(p.frameHandlers) > 0 {
			ev := PointerFrameEvent{}
			ev.EventContext = ctx
			p.mu.RLock()
			for _, h := range p.frameHandlers {
				h.HandlePointerFrame(ev)
			}
			p.mu.RUnlock()
		}
	case 6:
		if len(p.axisSourceHandlers) > 0 {
			ev := PointerAxisSourceEvent{}
			ev.EventContext = ctx
			ev.AxisSource = event.Uint32()
			p.mu.RLock()
			for _, h := range p.axisSourceHandlers {
				h.HandlePointerAxisSource(ev)
			}
			p.mu.RUnlock()
		}
	case 7:
		if len(p.axisStopHandlers) > 0 {
			ev := PointerAxisStopEvent{}
			ev.EventContext = ctx
			ev.Time = event.Uint32()
			ev.Axis = event.Uint32()
			p.mu.RLock()
			for _, h := range p.axisStopHandlers {
				h.HandlePointerAxisStop(ev)
			}
			p.mu.RUnlock()
		}
	case 8:
		if len(p.axisDiscreteHandlers) > 0 {
			ev := PointerAxisDiscreteEvent{}
			ev.EventContext = ctx
			ev.Axis = event.Uint32()
			ev.Discrete = event.Int32()
			p.mu.RLock()
			for _, h := range p.axisDiscreteHandlers {
				h.HandlePointerAxisDiscrete(ev)
			}
			p.mu.RUnlock()
		}
	}
}

type Pointer struct {
	BaseProxy
	mu                   sync.RWMutex
	enterHandlers        []PointerEnterHandler
	leaveHandlers        []PointerLeaveHandler
	motionHandlers       []PointerMotionHandler
	buttonHandlers       []PointerButtonHandler
	axisHandlers         []PointerAxisHandler
	frameHandlers        []PointerFrameHandler
	axisSourceHandlers   []PointerAxisSourceHandler
	axisStopHandlers     []PointerAxisStopHandler
	axisDiscreteHandlers []PointerAxisDiscreteHandler
}

func NewPointer(ctx *Context) *Pointer {
	ret := new(Pointer)
	ctx.Register(ret)
	return ret
}

// SetCursor will set the pointer surface.
//
//
// Set the pointer surface, i.e., the surface that contains the
// pointer image (cursor). This request gives the surface the role
// of a cursor. If the surface already has another role, it raises
// a protocol error.
//
// The cursor actually changes only if the pointer
// focus for this device is one of the requesting client's surfaces
// or the surface parameter is the current pointer surface. If
// there was a previous surface set with this request it is
// replaced. If surface is NULL, the pointer image is hidden.
//
// The parameters hotspot_x and hotspot_y define the position of
// the pointer surface relative to the pointer location. Its
// top-left corner is always at (x, y) - (hotspot_x, hotspot_y),
// where (x, y) are the coordinates of the pointer location, in
// surface-local coordinates.
//
// On surface.attach requests to the pointer surface, hotspot_x
// and hotspot_y are decremented by the x and y parameters
// passed to the request. Attach must be confirmed by
// wl_surface.commit as usual.
//
// The hotspot can also be updated by passing the currently set
// pointer surface to this request with new values for hotspot_x
// and hotspot_y.
//
// The current and pending input regions of the wl_surface are
// cleared, and wl_surface.set_input_region is ignored until the
// wl_surface is no longer used as the cursor. When the use as a
// cursor ends, the current and pending input regions become
// undefined, and the wl_surface is unmapped.
//
func (p *Pointer) SetCursor(serial uint32, surface *Surface, hotspot_x int32, hotspot_y int32) error {
	return p.Context().SendRequest(p, 0, serial, surface, hotspot_x, hotspot_y)
}

// Release will release the pointer object.
//
//
// Using this request a client can tell the server that it is not going to
// use the pointer object anymore.
//
// This request destroys the pointer proxy object, so clients must not call
// wl_pointer_destroy() after using this request.
//
func (p *Pointer) Release() error {
	return p.Context().SendRequest(p, 1)
}

const (
	PointerErrorRole = 0
)

const (
	PointerButtonStateReleased = 0
	PointerButtonStatePressed  = 1
)

const (
	PointerAxisVerticalScroll   = 0
	PointerAxisHorizontalScroll = 1
)

const (
	PointerAxisSourceWheel      = 0
	PointerAxisSourceFinger     = 1
	PointerAxisSourceContinuous = 2
	PointerAxisSourceWheelTilt  = 3
)

type KeyboardKeymapEvent struct {
	EventContext context.Context
	Format       uint32
	Fd           uintptr
	Size         uint32
}

type KeyboardKeymapHandler interface {
	HandleKeyboardKeymap(KeyboardKeymapEvent)
}

func (p *Keyboard) AddKeymapHandler(h KeyboardKeymapHandler) {
	if h != nil {
		p.mu.Lock()
		p.keymapHandlers = append(p.keymapHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Keyboard) RemoveKeymapHandler(h KeyboardKeymapHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.keymapHandlers {
		if e == h {
			p.keymapHandlers = append(p.keymapHandlers[:i], p.keymapHandlers[i+1:]...)
			break
		}
	}
}

type KeyboardEnterEvent struct {
	EventContext context.Context
	Serial       uint32
	Surface      *Surface
	Keys         []int32
}

type KeyboardEnterHandler interface {
	HandleKeyboardEnter(KeyboardEnterEvent)
}

func (p *Keyboard) AddEnterHandler(h KeyboardEnterHandler) {
	if h != nil {
		p.mu.Lock()
		p.enterHandlers = append(p.enterHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Keyboard) RemoveEnterHandler(h KeyboardEnterHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.enterHandlers {
		if e == h {
			p.enterHandlers = append(p.enterHandlers[:i], p.enterHandlers[i+1:]...)
			break
		}
	}
}

type KeyboardLeaveEvent struct {
	EventContext context.Context
	Serial       uint32
	Surface      *Surface
}

type KeyboardLeaveHandler interface {
	HandleKeyboardLeave(KeyboardLeaveEvent)
}

func (p *Keyboard) AddLeaveHandler(h KeyboardLeaveHandler) {
	if h != nil {
		p.mu.Lock()
		p.leaveHandlers = append(p.leaveHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Keyboard) RemoveLeaveHandler(h KeyboardLeaveHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.leaveHandlers {
		if e == h {
			p.leaveHandlers = append(p.leaveHandlers[:i], p.leaveHandlers[i+1:]...)
			break
		}
	}
}

type KeyboardKeyEvent struct {
	EventContext context.Context
	Serial       uint32
	Time         uint32
	Key          uint32
	State        uint32
}

type KeyboardKeyHandler interface {
	HandleKeyboardKey(KeyboardKeyEvent)
}

func (p *Keyboard) AddKeyHandler(h KeyboardKeyHandler) {
	if h != nil {
		p.mu.Lock()
		p.keyHandlers = append(p.keyHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Keyboard) RemoveKeyHandler(h KeyboardKeyHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.keyHandlers {
		if e == h {
			p.keyHandlers = append(p.keyHandlers[:i], p.keyHandlers[i+1:]...)
			break
		}
	}
}

type KeyboardModifiersEvent struct {
	EventContext  context.Context
	Serial        uint32
	ModsDepressed uint32
	ModsLatched   uint32
	ModsLocked    uint32
	Group         uint32
}

type KeyboardModifiersHandler interface {
	HandleKeyboardModifiers(KeyboardModifiersEvent)
}

func (p *Keyboard) AddModifiersHandler(h KeyboardModifiersHandler) {
	if h != nil {
		p.mu.Lock()
		p.modifiersHandlers = append(p.modifiersHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Keyboard) RemoveModifiersHandler(h KeyboardModifiersHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.modifiersHandlers {
		if e == h {
			p.modifiersHandlers = append(p.modifiersHandlers[:i], p.modifiersHandlers[i+1:]...)
			break
		}
	}
}

type KeyboardRepeatInfoEvent struct {
	EventContext context.Context
	Rate         int32
	Delay        int32
}

type KeyboardRepeatInfoHandler interface {
	HandleKeyboardRepeatInfo(KeyboardRepeatInfoEvent)
}

func (p *Keyboard) AddRepeatInfoHandler(h KeyboardRepeatInfoHandler) {
	if h != nil {
		p.mu.Lock()
		p.repeatInfoHandlers = append(p.repeatInfoHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Keyboard) RemoveRepeatInfoHandler(h KeyboardRepeatInfoHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.repeatInfoHandlers {
		if e == h {
			p.repeatInfoHandlers = append(p.repeatInfoHandlers[:i], p.repeatInfoHandlers[i+1:]...)
			break
		}
	}
}

func (p *Keyboard) Dispatch(ctx context.Context, event *Event) {
	switch event.Opcode {
	case 0:
		if len(p.keymapHandlers) > 0 {
			ev := KeyboardKeymapEvent{}
			ev.EventContext = ctx
			ev.Format = event.Uint32()
			ev.Fd = event.FD()
			ev.Size = event.Uint32()
			p.mu.RLock()
			for _, h := range p.keymapHandlers {
				h.HandleKeyboardKeymap(ev)
			}
			p.mu.RUnlock()
		}
	case 1:
		if len(p.enterHandlers) > 0 {
			ev := KeyboardEnterEvent{}
			ev.EventContext = ctx
			ev.Serial = event.Uint32()
			ev.Surface = event.Proxy(p.Context()).(*Surface)
			ev.Keys = event.Array()
			p.mu.RLock()
			for _, h := range p.enterHandlers {
				h.HandleKeyboardEnter(ev)
			}
			p.mu.RUnlock()
		}
	case 2:
		if len(p.leaveHandlers) > 0 {
			ev := KeyboardLeaveEvent{}
			ev.EventContext = ctx
			ev.Serial = event.Uint32()
			ev.Surface = event.Proxy(p.Context()).(*Surface)
			p.mu.RLock()
			for _, h := range p.leaveHandlers {
				h.HandleKeyboardLeave(ev)
			}
			p.mu.RUnlock()
		}
	case 3:
		if len(p.keyHandlers) > 0 {
			ev := KeyboardKeyEvent{}
			ev.EventContext = ctx
			ev.Serial = event.Uint32()
			ev.Time = event.Uint32()
			ev.Key = event.Uint32()
			ev.State = event.Uint32()
			p.mu.RLock()
			for _, h := range p.keyHandlers {
				h.HandleKeyboardKey(ev)
			}
			p.mu.RUnlock()
		}
	case 4:
		if len(p.modifiersHandlers) > 0 {
			ev := KeyboardModifiersEvent{}
			ev.EventContext = ctx
			ev.Serial = event.Uint32()
			ev.ModsDepressed = event.Uint32()
			ev.ModsLatched = event.Uint32()
			ev.ModsLocked = event.Uint32()
			ev.Group = event.Uint32()
			p.mu.RLock()
			for _, h := range p.modifiersHandlers {
				h.HandleKeyboardModifiers(ev)
			}
			p.mu.RUnlock()
		}
	case 5:
		if len(p.repeatInfoHandlers) > 0 {
			ev := KeyboardRepeatInfoEvent{}
			ev.EventContext = ctx
			ev.Rate = event.Int32()
			ev.Delay = event.Int32()
			p.mu.RLock()
			for _, h := range p.repeatInfoHandlers {
				h.HandleKeyboardRepeatInfo(ev)
			}
			p.mu.RUnlock()
		}
	}
}

type Keyboard struct {
	BaseProxy
	mu                 sync.RWMutex
	keymapHandlers     []KeyboardKeymapHandler
	enterHandlers      []KeyboardEnterHandler
	leaveHandlers      []KeyboardLeaveHandler
	keyHandlers        []KeyboardKeyHandler
	modifiersHandlers  []KeyboardModifiersHandler
	repeatInfoHandlers []KeyboardRepeatInfoHandler
}

func NewKeyboard(ctx *Context) *Keyboard {
	ret := new(Keyboard)
	ctx.Register(ret)
	return ret
}

// Release will release the keyboard object.
//
//
func (p *Keyboard) Release() error {
	return p.Context().SendRequest(p, 0)
}

const (
	KeyboardKeymapFormatNoKeymap = 0
	KeyboardKeymapFormatXkbV1    = 1
)

const (
	KeyboardKeyStateReleased = 0
	KeyboardKeyStatePressed  = 1
)

type TouchDownEvent struct {
	EventContext context.Context
	Serial       uint32
	Time         uint32
	Surface      *Surface
	Id           int32
	X            float32
	Y            float32
}

type TouchDownHandler interface {
	HandleTouchDown(TouchDownEvent)
}

func (p *Touch) AddDownHandler(h TouchDownHandler) {
	if h != nil {
		p.mu.Lock()
		p.downHandlers = append(p.downHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Touch) RemoveDownHandler(h TouchDownHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.downHandlers {
		if e == h {
			p.downHandlers = append(p.downHandlers[:i], p.downHandlers[i+1:]...)
			break
		}
	}
}

type TouchUpEvent struct {
	EventContext context.Context
	Serial       uint32
	Time         uint32
	Id           int32
}

type TouchUpHandler interface {
	HandleTouchUp(TouchUpEvent)
}

func (p *Touch) AddUpHandler(h TouchUpHandler) {
	if h != nil {
		p.mu.Lock()
		p.upHandlers = append(p.upHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Touch) RemoveUpHandler(h TouchUpHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.upHandlers {
		if e == h {
			p.upHandlers = append(p.upHandlers[:i], p.upHandlers[i+1:]...)
			break
		}
	}
}

type TouchMotionEvent struct {
	EventContext context.Context
	Time         uint32
	Id           int32
	X            float32
	Y            float32
}

type TouchMotionHandler interface {
	HandleTouchMotion(TouchMotionEvent)
}

func (p *Touch) AddMotionHandler(h TouchMotionHandler) {
	if h != nil {
		p.mu.Lock()
		p.motionHandlers = append(p.motionHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Touch) RemoveMotionHandler(h TouchMotionHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.motionHandlers {
		if e == h {
			p.motionHandlers = append(p.motionHandlers[:i], p.motionHandlers[i+1:]...)
			break
		}
	}
}

type TouchFrameEvent struct {
	EventContext context.Context
}

type TouchFrameHandler interface {
	HandleTouchFrame(TouchFrameEvent)
}

func (p *Touch) AddFrameHandler(h TouchFrameHandler) {
	if h != nil {
		p.mu.Lock()
		p.frameHandlers = append(p.frameHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Touch) RemoveFrameHandler(h TouchFrameHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.frameHandlers {
		if e == h {
			p.frameHandlers = append(p.frameHandlers[:i], p.frameHandlers[i+1:]...)
			break
		}
	}
}

type TouchCancelEvent struct {
	EventContext context.Context
}

type TouchCancelHandler interface {
	HandleTouchCancel(TouchCancelEvent)
}

func (p *Touch) AddCancelHandler(h TouchCancelHandler) {
	if h != nil {
		p.mu.Lock()
		p.cancelHandlers = append(p.cancelHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Touch) RemoveCancelHandler(h TouchCancelHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.cancelHandlers {
		if e == h {
			p.cancelHandlers = append(p.cancelHandlers[:i], p.cancelHandlers[i+1:]...)
			break
		}
	}
}

type TouchShapeEvent struct {
	EventContext context.Context
	Id           int32
	Major        float32
	Minor        float32
}

type TouchShapeHandler interface {
	HandleTouchShape(TouchShapeEvent)
}

func (p *Touch) AddShapeHandler(h TouchShapeHandler) {
	if h != nil {
		p.mu.Lock()
		p.shapeHandlers = append(p.shapeHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Touch) RemoveShapeHandler(h TouchShapeHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.shapeHandlers {
		if e == h {
			p.shapeHandlers = append(p.shapeHandlers[:i], p.shapeHandlers[i+1:]...)
			break
		}
	}
}

type TouchOrientationEvent struct {
	EventContext context.Context
	Id           int32
	Orientation  float32
}

type TouchOrientationHandler interface {
	HandleTouchOrientation(TouchOrientationEvent)
}

func (p *Touch) AddOrientationHandler(h TouchOrientationHandler) {
	if h != nil {
		p.mu.Lock()
		p.orientationHandlers = append(p.orientationHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Touch) RemoveOrientationHandler(h TouchOrientationHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.orientationHandlers {
		if e == h {
			p.orientationHandlers = append(p.orientationHandlers[:i], p.orientationHandlers[i+1:]...)
			break
		}
	}
}

func (p *Touch) Dispatch(ctx context.Context, event *Event) {
	switch event.Opcode {
	case 0:
		if len(p.downHandlers) > 0 {
			ev := TouchDownEvent{}
			ev.EventContext = ctx
			ev.Serial = event.Uint32()
			ev.Time = event.Uint32()
			ev.Surface = event.Proxy(p.Context()).(*Surface)
			ev.Id = event.Int32()
			ev.X = event.Float32()
			ev.Y = event.Float32()
			p.mu.RLock()
			for _, h := range p.downHandlers {
				h.HandleTouchDown(ev)
			}
			p.mu.RUnlock()
		}
	case 1:
		if len(p.upHandlers) > 0 {
			ev := TouchUpEvent{}
			ev.EventContext = ctx
			ev.Serial = event.Uint32()
			ev.Time = event.Uint32()
			ev.Id = event.Int32()
			p.mu.RLock()
			for _, h := range p.upHandlers {
				h.HandleTouchUp(ev)
			}
			p.mu.RUnlock()
		}
	case 2:
		if len(p.motionHandlers) > 0 {
			ev := TouchMotionEvent{}
			ev.EventContext = ctx
			ev.Time = event.Uint32()
			ev.Id = event.Int32()
			ev.X = event.Float32()
			ev.Y = event.Float32()
			p.mu.RLock()
			for _, h := range p.motionHandlers {
				h.HandleTouchMotion(ev)
			}
			p.mu.RUnlock()
		}
	case 3:
		if len(p.frameHandlers) > 0 {
			ev := TouchFrameEvent{}
			ev.EventContext = ctx
			p.mu.RLock()
			for _, h := range p.frameHandlers {
				h.HandleTouchFrame(ev)
			}
			p.mu.RUnlock()
		}
	case 4:
		if len(p.cancelHandlers) > 0 {
			ev := TouchCancelEvent{}
			ev.EventContext = ctx
			p.mu.RLock()
			for _, h := range p.cancelHandlers {
				h.HandleTouchCancel(ev)
			}
			p.mu.RUnlock()
		}
	case 5:
		if len(p.shapeHandlers) > 0 {
			ev := TouchShapeEvent{}
			ev.EventContext = ctx
			ev.Id = event.Int32()
			ev.Major = event.Float32()
			ev.Minor = event.Float32()
			p.mu.RLock()
			for _, h := range p.shapeHandlers {
				h.HandleTouchShape(ev)
			}
			p.mu.RUnlock()
		}
	case 6:
		if len(p.orientationHandlers) > 0 {
			ev := TouchOrientationEvent{}
			ev.EventContext = ctx
			ev.Id = event.Int32()
			ev.Orientation = event.Float32()
			p.mu.RLock()
			for _, h := range p.orientationHandlers {
				h.HandleTouchOrientation(ev)
			}
			p.mu.RUnlock()
		}
	}
}

type Touch struct {
	BaseProxy
	mu                  sync.RWMutex
	downHandlers        []TouchDownHandler
	upHandlers          []TouchUpHandler
	motionHandlers      []TouchMotionHandler
	frameHandlers       []TouchFrameHandler
	cancelHandlers      []TouchCancelHandler
	shapeHandlers       []TouchShapeHandler
	orientationHandlers []TouchOrientationHandler
}

func NewTouch(ctx *Context) *Touch {
	ret := new(Touch)
	ctx.Register(ret)
	return ret
}

// Release will release the touch object.
//
//
func (p *Touch) Release() error {
	return p.Context().SendRequest(p, 0)
}

type OutputGeometryEvent struct {
	EventContext   context.Context
	X              int32
	Y              int32
	PhysicalWidth  int32
	PhysicalHeight int32
	Subpixel       int32
	Make           string
	Model          string
	Transform      int32
}

type OutputGeometryHandler interface {
	HandleOutputGeometry(OutputGeometryEvent)
}

func (p *Output) AddGeometryHandler(h OutputGeometryHandler) {
	if h != nil {
		p.mu.Lock()
		p.geometryHandlers = append(p.geometryHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Output) RemoveGeometryHandler(h OutputGeometryHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.geometryHandlers {
		if e == h {
			p.geometryHandlers = append(p.geometryHandlers[:i], p.geometryHandlers[i+1:]...)
			break
		}
	}
}

type OutputModeEvent struct {
	EventContext context.Context
	Flags        uint32
	Width        int32
	Height       int32
	Refresh      int32
}

type OutputModeHandler interface {
	HandleOutputMode(OutputModeEvent)
}

func (p *Output) AddModeHandler(h OutputModeHandler) {
	if h != nil {
		p.mu.Lock()
		p.modeHandlers = append(p.modeHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Output) RemoveModeHandler(h OutputModeHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.modeHandlers {
		if e == h {
			p.modeHandlers = append(p.modeHandlers[:i], p.modeHandlers[i+1:]...)
			break
		}
	}
}

type OutputDoneEvent struct {
	EventContext context.Context
}

type OutputDoneHandler interface {
	HandleOutputDone(OutputDoneEvent)
}

func (p *Output) AddDoneHandler(h OutputDoneHandler) {
	if h != nil {
		p.mu.Lock()
		p.doneHandlers = append(p.doneHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Output) RemoveDoneHandler(h OutputDoneHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.doneHandlers {
		if e == h {
			p.doneHandlers = append(p.doneHandlers[:i], p.doneHandlers[i+1:]...)
			break
		}
	}
}

type OutputScaleEvent struct {
	EventContext context.Context
	Factor       int32
}

type OutputScaleHandler interface {
	HandleOutputScale(OutputScaleEvent)
}

func (p *Output) AddScaleHandler(h OutputScaleHandler) {
	if h != nil {
		p.mu.Lock()
		p.scaleHandlers = append(p.scaleHandlers, h)
		p.mu.Unlock()
	}
}

func (p *Output) RemoveScaleHandler(h OutputScaleHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	for i, e := range p.scaleHandlers {
		if e == h {
			p.scaleHandlers = append(p.scaleHandlers[:i], p.scaleHandlers[i+1:]...)
			break
		}
	}
}

func (p *Output) Dispatch(ctx context.Context, event *Event) {
	switch event.Opcode {
	case 0:
		if len(p.geometryHandlers) > 0 {
			ev := OutputGeometryEvent{}
			ev.EventContext = ctx
			ev.X = event.Int32()
			ev.Y = event.Int32()
			ev.PhysicalWidth = event.Int32()
			ev.PhysicalHeight = event.Int32()
			ev.Subpixel = event.Int32()
			ev.Make = event.String()
			ev.Model = event.String()
			ev.Transform = event.Int32()
			p.mu.RLock()
			for _, h := range p.geometryHandlers {
				h.HandleOutputGeometry(ev)
			}
			p.mu.RUnlock()
		}
	case 1:
		if len(p.modeHandlers) > 0 {
			ev := OutputModeEvent{}
			ev.EventContext = ctx
			ev.Flags = event.Uint32()
			ev.Width = event.Int32()
			ev.Height = event.Int32()
			ev.Refresh = event.Int32()
			p.mu.RLock()
			for _, h := range p.modeHandlers {
				h.HandleOutputMode(ev)
			}
			p.mu.RUnlock()
		}
	case 2:
		if len(p.doneHandlers) > 0 {
			ev := OutputDoneEvent{}
			ev.EventContext = ctx
			p.mu.RLock()
			for _, h := range p.doneHandlers {
				h.HandleOutputDone(ev)
			}
			p.mu.RUnlock()
		}
	case 3:
		if len(p.scaleHandlers) > 0 {
			ev := OutputScaleEvent{}
			ev.EventContext = ctx
			ev.Factor = event.Int32()
			p.mu.RLock()
			for _, h := range p.scaleHandlers {
				h.HandleOutputScale(ev)
			}
			p.mu.RUnlock()
		}
	}
}

type Output struct {
	BaseProxy
	mu               sync.RWMutex
	geometryHandlers []OutputGeometryHandler
	modeHandlers     []OutputModeHandler
	doneHandlers     []OutputDoneHandler
	scaleHandlers    []OutputScaleHandler
}

func NewOutput(ctx *Context) *Output {
	ret := new(Output)
	ctx.Register(ret)
	return ret
}

// Release will release the output object.
//
//
// Using this request a client can tell the server that it is not going to
// use the output object anymore.
//
func (p *Output) Release() error {
	return p.Context().SendRequest(p, 0)
}

const (
	OutputSubpixelUnknown       = 0
	OutputSubpixelNone          = 1
	OutputSubpixelHorizontalRgb = 2
	OutputSubpixelHorizontalBgr = 3
	OutputSubpixelVerticalRgb   = 4
	OutputSubpixelVerticalBgr   = 5
)

const (
	OutputTransformNormal     = 0
	OutputTransform90         = 1
	OutputTransform180        = 2
	OutputTransform270        = 3
	OutputTransformFlipped    = 4
	OutputTransformFlipped90  = 5
	OutputTransformFlipped180 = 6
	OutputTransformFlipped270 = 7
)

const (
	OutputModeCurrent   = 0x1
	OutputModePreferred = 0x2
)

type Region struct {
	BaseProxy
}

func NewRegion(ctx *Context) *Region {
	ret := new(Region)
	ctx.Register(ret)
	return ret
}

// Destroy will destroy region.
//
//
// Destroy the region.  This will invalidate the object ID.
//
func (p *Region) Destroy() error {
	return p.Context().SendRequest(p, 0)
}

// Add will add rectangle to region.
//
//
// Add the specified rectangle to the region.
//
func (p *Region) Add(x int32, y int32, width int32, height int32) error {
	return p.Context().SendRequest(p, 1, x, y, width, height)
}

// Subtract will subtract rectangle from region.
//
//
// Subtract the specified rectangle from the region.
//
func (p *Region) Subtract(x int32, y int32, width int32, height int32) error {
	return p.Context().SendRequest(p, 2, x, y, width, height)
}

type Subcompositor struct {
	BaseProxy
}

func NewSubcompositor(ctx *Context) *Subcompositor {
	ret := new(Subcompositor)
	ctx.Register(ret)
	return ret
}

// Destroy will unbind from the subcompositor interface.
//
//
// Informs the server that the client will not be using this
// protocol object anymore. This does not affect any other
// objects, wl_subsurface objects included.
//
func (p *Subcompositor) Destroy() error {
	return p.Context().SendRequest(p, 0)
}

// GetSubsurface will give a surface the role sub-surface.
//
//
// Create a sub-surface interface for the given surface, and
// associate it with the given parent surface. This turns a
// plain wl_surface into a sub-surface.
//
// The to-be sub-surface must not already have another role, and it
// must not have an existing wl_subsurface object. Otherwise a protocol
// error is raised.
//
// Adding sub-surfaces to a parent is a double-buffered operation on the
// parent (see wl_surface.commit). The effect of adding a sub-surface
// becomes visible on the next time the state of the parent surface is
// applied.
//
// This request modifies the behaviour of wl_surface.commit request on
// the sub-surface, see the documentation on wl_subsurface interface.
//
func (p *Subcompositor) GetSubsurface(surface *Surface, parent *Surface) (*Subsurface, error) {
	ret := NewSubsurface(p.Context())
	return ret, p.Context().SendRequest(p, 1, Proxy(ret), surface, parent)
}

const (
	SubcompositorErrorBadSurface = 0
)

type Subsurface struct {
	BaseProxy
}

func NewSubsurface(ctx *Context) *Subsurface {
	ret := new(Subsurface)
	ctx.Register(ret)
	return ret
}

// Destroy will remove sub-surface interface.
//
//
// The sub-surface interface is removed from the wl_surface object
// that was turned into a sub-surface with a
// wl_subcompositor.get_subsurface request. The wl_surface's association
// to the parent is deleted, and the wl_surface loses its role as
// a sub-surface. The wl_surface is unmapped immediately.
//
func (p *Subsurface) Destroy() error {
	return p.Context().SendRequest(p, 0)
}

// SetPosition will reposition the sub-surface.
//
//
// This schedules a sub-surface position change.
// The sub-surface will be moved so that its origin (top left
// corner pixel) will be at the location x, y of the parent surface
// coordinate system. The coordinates are not restricted to the parent
// surface area. Negative values are allowed.
//
// The scheduled coordinates will take effect whenever the state of the
// parent surface is applied. When this happens depends on whether the
// parent surface is in synchronized mode or not. See
// wl_subsurface.set_sync and wl_subsurface.set_desync for details.
//
// If more than one set_position request is invoked by the client before
// the commit of the parent surface, the position of a new request always
// replaces the scheduled position from any previous request.
//
// The initial position is 0, 0.
//
func (p *Subsurface) SetPosition(x int32, y int32) error {
	return p.Context().SendRequest(p, 1, x, y)
}

// PlaceAbove will restack the sub-surface.
//
//
// This sub-surface is taken from the stack, and put back just
// above the reference surface, changing the z-order of the sub-surfaces.
// The reference surface must be one of the sibling surfaces, or the
// parent surface. Using any other surface, including this sub-surface,
// will cause a protocol error.
//
// The z-order is double-buffered. Requests are handled in order and
// applied immediately to a pending state. The final pending state is
// copied to the active state the next time the state of the parent
// surface is applied. When this happens depends on whether the parent
// surface is in synchronized mode or not. See wl_subsurface.set_sync and
// wl_subsurface.set_desync for details.
//
// A new sub-surface is initially added as the top-most in the stack
// of its siblings and parent.
//
func (p *Subsurface) PlaceAbove(sibling *Surface) error {
	return p.Context().SendRequest(p, 2, sibling)
}

// PlaceBelow will restack the sub-surface.
//
//
// The sub-surface is placed just below the reference surface.
// See wl_subsurface.place_above.
//
func (p *Subsurface) PlaceBelow(sibling *Surface) error {
	return p.Context().SendRequest(p, 3, sibling)
}

// SetSync will set sub-surface to synchronized mode.
//
//
// Change the commit behaviour of the sub-surface to synchronized
// mode, also described as the parent dependent mode.
//
// In synchronized mode, wl_surface.commit on a sub-surface will
// accumulate the committed state in a cache, but the state will
// not be applied and hence will not change the compositor output.
// The cached state is applied to the sub-surface immediately after
// the parent surface's state is applied. This ensures atomic
// updates of the parent and all its synchronized sub-surfaces.
// Applying the cached state will invalidate the cache, so further
// parent surface commits do not (re-)apply old state.
//
// See wl_subsurface for the recursive effect of this mode.
//
func (p *Subsurface) SetSync() error {
	return p.Context().SendRequest(p, 4)
}

// SetDesync will set sub-surface to desynchronized mode.
//
//
// Change the commit behaviour of the sub-surface to desynchronized
// mode, also described as independent or freely running mode.
//
// In desynchronized mode, wl_surface.commit on a sub-surface will
// apply the pending state directly, without caching, as happens
// normally with a wl_surface. Calling wl_surface.commit on the
// parent surface has no effect on the sub-surface's wl_surface
// state. This mode allows a sub-surface to be updated on its own.
//
// If cached state exists when wl_surface.commit is called in
// desynchronized mode, the pending state is added to the cached
// state, and applied as a whole. This invalidates the cache.
//
// Note: even if a sub-surface is set to desynchronized, a parent
// sub-surface may override it to behave as synchronized. For details,
// see wl_subsurface.
//
// If a surface's parent surface behaves as desynchronized, then
// the cached state is applied on set_desync.
//
func (p *Subsurface) SetDesync() error {
	return p.Context().SendRequest(p, 5)
}

const (
	SubsurfaceErrorBadSurface = 0
)
