Implemented INCR selection properties
This commit is contained in:
parent
ab61615018
commit
1ebf5e1103
@ -13,6 +13,7 @@ type selReqState int; const (
|
|||||||
selReqStateClosed selReqState = iota
|
selReqStateClosed selReqState = iota
|
||||||
selReqStateAwaitTargets
|
selReqStateAwaitTargets
|
||||||
selReqStateAwaitValue
|
selReqStateAwaitValue
|
||||||
|
selReqStateAwaitFirstChunk
|
||||||
selReqStateAwaitChunk
|
selReqStateAwaitChunk
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -22,6 +23,8 @@ type selectionRequest struct {
|
|||||||
source xproto.Atom
|
source xproto.Atom
|
||||||
destination xproto.Atom
|
destination xproto.Atom
|
||||||
accept []data.Mime
|
accept []data.Mime
|
||||||
|
incrBuffer []byte
|
||||||
|
incrMime data.Mime
|
||||||
callback func (data.Data, error)
|
callback func (data.Data, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,9 +141,11 @@ func (request *selectionRequest) handleSelectionNotify (
|
|||||||
event xevent.SelectionNotifyEvent,
|
event xevent.SelectionNotifyEvent,
|
||||||
) {
|
) {
|
||||||
// the only valid states that we can process a SelectionNotify event in
|
// the only valid states that we can process a SelectionNotify event in
|
||||||
if request.state != selReqStateAwaitValue && request.state != selReqStateAwaitTargets {
|
invalidState :=
|
||||||
return
|
request.state != selReqStateAwaitFirstChunk &&
|
||||||
}
|
request.state != selReqStateAwaitValue &&
|
||||||
|
request.state != selReqStateAwaitTargets
|
||||||
|
if invalidState { return }
|
||||||
|
|
||||||
// Follow:
|
// Follow:
|
||||||
// https://tronche.com/gui/x/icccm/sec-2.html#s-2.4
|
// https://tronche.com/gui/x/icccm/sec-2.html#s-2.4
|
||||||
@ -152,6 +157,13 @@ func (request *selectionRequest) handleSelectionNotify (
|
|||||||
// data.
|
// data.
|
||||||
if event.Property == 0 { request.die(nil); return }
|
if event.Property == 0 { request.die(nil); return }
|
||||||
|
|
||||||
|
// if we are waiting for the first INCR chunk, do the special stuff for
|
||||||
|
// that and not the other stuff.
|
||||||
|
if request.state == selReqStateAwaitFirstChunk {
|
||||||
|
request.handleINCRProperty(event.Property)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// When using GetProperty to retrieve the value of a selection, the
|
// When using GetProperty to retrieve the value of a selection, the
|
||||||
// property argument should be set to the corresponding value in the
|
// property argument should be set to the corresponding value in the
|
||||||
// SelectionNotify event. Because the requestor has no way of knowing
|
// SelectionNotify event. Because the requestor has no way of knowing
|
||||||
@ -172,7 +184,30 @@ func (request *selectionRequest) handleSelectionNotify (
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: handle INCR. do it here.
|
// https://tronche.com/gui/x/icccm/sec-2.html#s-2.7.2
|
||||||
|
// Requestors may receive a property of type INCR9 in response to any
|
||||||
|
// target that results in selection data. This indicates that the owner
|
||||||
|
// will send the actual data incrementally. The contents of the INCR
|
||||||
|
// property will be an integer, which represents a lower bound on the
|
||||||
|
// number of bytes of data in the selection. The requestor and the
|
||||||
|
// selection owner transfer the data in the selection in the following
|
||||||
|
// manner. The selection requestor starts the transfer process by
|
||||||
|
// deleting the (type==INCR) property forming the reply to the
|
||||||
|
// selection.
|
||||||
|
incr, err := xprop.Atm(request.window.backend.connection, "INCR")
|
||||||
|
if err != nil { request.die(err); return }
|
||||||
|
if reply.Type == incr {
|
||||||
|
// reply to the INCR selection
|
||||||
|
err = xproto.DeletePropertyChecked (
|
||||||
|
request.window.backend.connection.Conn(),
|
||||||
|
request.window.xWindow.Id,
|
||||||
|
request.destination).Check()
|
||||||
|
if err != nil { request.die(err); return }
|
||||||
|
|
||||||
|
// await the first chunk
|
||||||
|
request.state = selReqStateAwaitFirstChunk
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Once all the data in the selection has been retrieved (which may
|
// Once all the data in the selection has been retrieved (which may
|
||||||
// require getting the values of several properties &emdash; see section
|
// require getting the values of several properties &emdash; see section
|
||||||
@ -188,6 +223,8 @@ func (request *selectionRequest) handleSelectionNotify (
|
|||||||
request.destination).Check()
|
request.destination).Check()
|
||||||
if err != nil { request.die(err); return }
|
if err != nil { request.die(err); return }
|
||||||
|
|
||||||
|
// depending on which state the selection request is in, do something
|
||||||
|
// different with the property's value
|
||||||
switch request.state {
|
switch request.state {
|
||||||
case selReqStateAwaitValue:
|
case selReqStateAwaitValue:
|
||||||
// get the type from the property and convert that to the mime
|
// get the type from the property and convert that to the mime
|
||||||
@ -264,3 +301,40 @@ func (request *selectionRequest) handleSelectionNotify (
|
|||||||
request.convertSelection(chosenTarget, selReqStateAwaitValue)
|
request.convertSelection(chosenTarget, selReqStateAwaitValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (request *selectionRequest) handlePropertyNotify (
|
||||||
|
connection *xgbutil.XUtil,
|
||||||
|
event xevent.PropertyNotifyEvent,
|
||||||
|
) {
|
||||||
|
// the only valid state that we can process a PropertyNotify event in
|
||||||
|
if request.state != selReqStateAwaitChunk { return }
|
||||||
|
if event.State != xproto.PropertyNewValue { return }
|
||||||
|
|
||||||
|
request.handleINCRProperty(event.Atom)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (request *selectionRequest) handleINCRProperty (property xproto.Atom) {
|
||||||
|
// Retrieving data using GetProperty with the delete argument True.
|
||||||
|
reply, err := xproto.GetProperty (
|
||||||
|
request.window.backend.connection.Conn(), true,
|
||||||
|
request.window.xWindow.Id, property, xproto.GetPropertyTypeAny,
|
||||||
|
0, (1 << 32) - 1).Reply()
|
||||||
|
if err != nil { request.die(err); return }
|
||||||
|
|
||||||
|
if len(reply.Value) == 0 {
|
||||||
|
// a zero length property means the transfer has finished. we
|
||||||
|
// finalize the request with the data we have, and don't wait
|
||||||
|
// for more.
|
||||||
|
request.finalize(data.Bytes(request.incrMime, request.incrBuffer))
|
||||||
|
} else {
|
||||||
|
// a property with content means the transfer is still ongoing.
|
||||||
|
// we append the data we got and wait for more.
|
||||||
|
request.state = selReqStateAwaitChunk
|
||||||
|
request.incrBuffer = append(request.incrBuffer, reply.Value...)
|
||||||
|
|
||||||
|
targetName, err := xprop.AtomName (
|
||||||
|
request.window.backend.connection, reply.Type)
|
||||||
|
if err != nil { request.die(err); return }
|
||||||
|
request.incrMime, _ = targetToMime(targetName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user