Add machinery for INCR

This commit is contained in:
Sasha Koshka 2024-07-11 03:56:25 -04:00
parent a376482293
commit 54ad3ebee6

View File

@ -9,6 +9,16 @@ import "github.com/jezek/xgbutil/xprop"
import "github.com/jezek/xgbutil/xevent"
import "github.com/jezek/xgbutil/xwindow"
const format8bit byte = 8
const format16bit byte = 16
const format32bit byte = 32
type claimRequest struct {
reader io.ReadSeekCloser
ty xproto.Atom // must be "INCR"
event xevent.SelectionRequestEvent
}
// Claim represents a claim that a window has on a particular selection.
type Claim struct {
window *xwindow.Window
@ -16,6 +26,8 @@ type Claim struct {
selection xproto.Atom
timestamp xproto.Timestamp
active bool
requests map[xproto.Atom] claimRequest
}
// NewClaim claims ownership of a specified selection, and allows using data
@ -57,6 +69,7 @@ func NewClaim (window *xwindow.Window, selection xproto.Atom, data Data, timesta
data: data,
selection: selection,
timestamp: timestamp,
requests: make(map[xproto.Atom] claimRequest),
}, nil
}
@ -165,7 +178,7 @@ func (claim *Claim) HandleSelectionRequest (
// send that list to the requestor
atomAtom, err := xprop.Atm(claim.window.X, "ATOM")
if err != nil { die(); return }
claim.fulfillSelectionRequest(data, 32, atomAtom, event)
claim.fulfillSelectionRequest(data, format32bit, atomAtom, event)
default:
// respond with data
@ -175,7 +188,7 @@ func (claim *Claim) HandleSelectionRequest (
data, err := io.ReadAll(reader)
reader.Close()
if err != nil { die() }
claim.fulfillSelectionRequest(data, 8, event.Target, event)
claim.fulfillSelectionRequest(data, format8bit, event.Target, event)
}
}
@ -186,7 +199,69 @@ func (claim *Claim) HandlePropertyNotify (
connection *xgbutil.XUtil,
event xevent.PropertyNotifyEvent,
) {
// TODO
// The selection owner then:
// ... Waits between each append for a PropertyNotify (state==Deleted)
// event that shows that the requestor has read the data. The reason for
// doing this is to limit the consumption of space in the server.
// FIXME check for state==Deleted
// if the request does not exist, the property was either modified in
// error or the request has already finished. either way, we simply
// exit.
request, ok := claim.requests[event.Atom]
if !ok { return }
done := func () {
request.reader.Close()
delete(claim.requests, request.event.Property)
}
die := func () {
done()
claim.refuseSelectionRequest(request.event)
}
// FIXME change the length of this if maximum-request-size is smaller
buffer := [1024]byte { }
size, err := request.reader.Read(buffer[:])
if err != nil { die(); return }
dataRead := buffer[:size]
if len(dataRead) > 0 {
// there is more data to send
// ... Appends the data in suitable-size chunks to the same property on
// the same window as the selection reply with a type corresponding to
// the actual type of the converted selection. The size should be less
// than the maximum-request-size in the connection handshake.
format := format8bit
err = xproto.ChangePropertyChecked (
claim.window.X.Conn(),
xproto.PropModeAppend, request.event.Requestor,
request.event.Property,
request.ty, format,
uint32(len(dataRead) / (int(format) / 8)), dataRead).Check()
if err != nil { die(); return }
} else {
// all data has been sent
// ... Waits (after the entire data has been transferred to the
// server) until a PropertyNotify (state==Deleted) event that
// shows that the data has been read by the requestor and then
// writes zero-length data to the property.
format := format8bit
err := xproto.ChangePropertyChecked (
claim.window.X.Conn(),
xproto.PropModeAppend, request.event.Requestor,
request.event.Property,
request.ty, format,
0, nil).Check()
if err != nil { die(); return }
done()
}
}
// While the selection claim is active, HandleSelectionClear should be called