diff --git a/eventsource.go b/eventsource.go new file mode 100644 index 0000000..cb434b1 --- /dev/null +++ b/eventsource.go @@ -0,0 +1,66 @@ +package wlr + +/* +#include +#include + +extern int _event_source_fd_callback(int fd, uint32_t mask, void *data); + +static inline struct wl_event_source *_event_loop_add_fd(struct wl_event_loop *loop, int fd, uint32_t mask, uintptr_t handle) { + return wl_event_loop_add_fd(loop, fd, mask, _event_source_fd_callback, (void *)handle); +} +*/ +import "C" + +import ( + "runtime/cgo" + "unsafe" +) + +type EventMask uint32 + +const ( + EventReadable EventMask = C.WL_EVENT_READABLE + EventWritable EventMask = C.WL_EVENT_WRITABLE + EventHangup EventMask = C.WL_EVENT_HANGUP + EventError EventMask = C.WL_EVENT_ERROR +) + +// EventSource is a source of events attached to an EventLoop. +// +// Note: It is the client's responsibility to call Remove when they are +// done with an EventSource in order to free resources. +type EventSource struct { + p *C.struct_wl_event_source + h cgo.Handle +} + +type eventSourceFdFunc func(fd uintptr, mask EventMask) + +// AddFd calls cb on the event loop whenever fd is ready for any of the +// events in mask. EventHangup and EventError are always reported. +func (evl EventLoop) AddFd(fd uintptr, mask EventMask, cb func(fd uintptr, mask EventMask)) EventSource { + h := cgo.NewHandle(eventSourceFdFunc(cb)) + p := C._event_loop_add_fd(evl.p, C.int(fd), C.uint32_t(mask), C.uintptr_t(h)) + if p == nil { + h.Delete() + return EventSource{} + } + return EventSource{p: p, h: h} +} + +func (s EventSource) Valid() bool { + return s.p != nil +} + +// Remove removes the source from its event loop and frees it. +func (s EventSource) Remove() { + C.wl_event_source_remove(s.p) + s.h.Delete() +} + +//export _event_source_fd_callback +func _event_source_fd_callback(fd C.int, mask C.uint32_t, data unsafe.Pointer) C.int { + cgo.Handle(uintptr(data)).Value().(eventSourceFdFunc)(uintptr(fd), EventMask(mask)) + return 0 +} diff --git a/presentation.go b/presentation.go new file mode 100644 index 0000000..ace2326 --- /dev/null +++ b/presentation.go @@ -0,0 +1,41 @@ +package wlr + +/* +#include +*/ +import "C" + +import "unsafe" + +type Presentation struct { + p *C.struct_wlr_presentation +} + +// CreatePresentation creates the wp_presentation global. Feedback for a +// surface is only sent once the compositor reports the output that the +// surface was shown on with PresentationSurfaceTexturedOnOutput or +// PresentationSurfaceScannedOutOnOutput. +func CreatePresentation(display Display, backend Backend, version uint32) Presentation { + p := C.wlr_presentation_create(display.p, backend.p, C.uint32_t(version)) + return Presentation{p: p} +} + +func (p Presentation) OnDestroy(cb func(Presentation)) Listener { + return newListener(&p.p.events.destroy, func(lis Listener, data unsafe.Pointer) { + cb(p) + }) +} + +// PresentationSurfaceTexturedOnOutput tells clients waiting on +// presentation feedback for surface that it was rendered on output as a +// texture. Call it before committing the output. +func PresentationSurfaceTexturedOnOutput(surface Surface, output Output) { + C.wlr_presentation_surface_textured_on_output(surface.p, output.p) +} + +// PresentationSurfaceScannedOutOnOutput is like +// PresentationSurfaceTexturedOnOutput, but for a surface whose buffer +// was scanned out directly. +func PresentationSurfaceScannedOutOnOutput(surface Surface, output Output) { + C.wlr_presentation_surface_scanned_out_on_output(surface.p, output.p) +} diff --git a/seat.go b/seat.go index a802f12..6bc0841 100644 --- a/seat.go +++ b/seat.go @@ -3,6 +3,8 @@ package wlr /* #include #include +#include +#include */ import "C" @@ -61,6 +63,44 @@ func (s Seat) OnRequestSetCursor(cb func(client SeatClient, surface Surface, ser }) } +// DataSource is the source of a clipboard selection or a drag. +type DataSource struct { + p *C.struct_wlr_data_source +} + +// PrimarySelectionSource is the source of a primary selection. +type PrimarySelectionSource struct { + p *C.struct_wlr_primary_selection_source +} + +// OnRequestSetSelection is called when a client, including Xwayland, +// wants to set the clipboard selection. The selection only changes if +// the compositor calls SetSelection. +func (s Seat) OnRequestSetSelection(cb func(source DataSource, serial uint32)) Listener { + return newListener(&s.p.events.request_set_selection, func(lis Listener, data unsafe.Pointer) { + event := (*C.struct_wlr_seat_request_set_selection_event)(data) + cb(DataSource{p: event.source}, uint32(event.serial)) + }) +} + +func (s Seat) SetSelection(source DataSource, serial uint32) { + C.wlr_seat_set_selection(s.p, source.p, C.uint32_t(serial)) +} + +// OnRequestSetPrimarySelection is called when a client, including +// Xwayland, wants to set the primary selection. The selection only +// changes if the compositor calls SetPrimarySelection. +func (s Seat) OnRequestSetPrimarySelection(cb func(source PrimarySelectionSource, serial uint32)) Listener { + return newListener(&s.p.events.request_set_primary_selection, func(lis Listener, data unsafe.Pointer) { + event := (*C.struct_wlr_seat_request_set_primary_selection_event)(data) + cb(PrimarySelectionSource{p: event.source}, uint32(event.serial)) + }) +} + +func (s Seat) SetPrimarySelection(source PrimarySelectionSource, serial uint32) { + C.wlr_seat_set_primary_selection(s.p, source.p, C.uint32_t(serial)) +} + func (s Seat) Capabilities() SeatCapability { return SeatCapability(s.p.capabilities) } diff --git a/xdg.go b/xdg.go index 91e29ae..961905b 100644 --- a/xdg.go +++ b/xdg.go @@ -228,6 +228,20 @@ func (p XDGPopup) Parent() Surface { return Surface{p: p.p.parent} } +// UnconstrainFromBox sets the popup's geometry so that it stays inside +// box, following its positioner's constraint adjustments, and +// schedules a configure. The box is in the coordinate system of the +// popup's root toplevel surface. +func (p XDGPopup) UnconstrainFromBox(box image.Rectangle) { + box = box.Canon() + C.wlr_xdg_popup_unconstrain_from_box(p.p, &C.struct_wlr_box{ + x: C.int(box.Min.X), + y: C.int(box.Min.Y), + width: C.int(box.Dx()), + height: C.int(box.Dy()), + }) +} + type XDGToplevel struct { p *C.struct_wlr_xdg_toplevel } diff --git a/xwayland.go b/xwayland.go index 094dd5f..216ce75 100644 --- a/xwayland.go +++ b/xwayland.go @@ -48,6 +48,12 @@ func (x Xwayland) SetCursor(img XCursorImage) { C.wlr_xwayland_set_cursor(x.p, buf, C.int32_t(img.p.hotspot_x), C.int32_t(img.p.hotspot_y)) } +// SetSeat sets the seat that Xwayland uses for selections such as +// the clipboard. It can be called before Xwayland is ready. +func (x Xwayland) SetSeat(seat Seat) { + C.wlr_xwayland_set_seat(x.p, seat.p) +} + func (x Xwayland) DisplayName() string { return C.GoString(x.p.display_name) }