hpcu: the slightest cleanup

This commit is contained in:
Přemysl Eric Janouch 2018-11-01 11:38:17 +01:00
parent f99615c850
commit 056391eeca
Signed by: p
GPG Key ID: A0420B94F92B9493
1 changed files with 172 additions and 158 deletions

View File

@ -133,180 +133,194 @@ func requestOwnership(origin *selectionState, time xproto.Timestamp) {
} }
} }
func handleEvent(ev nexgb.Event) { func handleXfixesSelectionNotify(e xfixes.SelectionNotifyEvent) {
switch e := ev.(type) { state, ok := selections[e.Selection]
case xfixes.SelectionNotifyEvent: if !ok {
state, ok := selections[e.Selection] return
if !ok { }
break
}
// Ownership request has been granted, don't ask ourselves for data. // Ownership request has been granted, don't ask ourselves for data.
if e.Owner == wid { if e.Owner == wid {
state.owning = e.SelectionTimestamp state.owning = e.SelectionTimestamp
break return
} }
// This should always be true. // This should always be true.
if state.owning < e.SelectionTimestamp { if state.owning < e.SelectionTimestamp {
state.owning = 0 state.owning = 0
} }
// Not checking whether we should give up when our current retrieval // Not checking whether we should give up when our current retrieval
// attempt is interrupted--the timeout mostly solves this. // attempt is interrupted--the timeout mostly solves this.
if e.Owner == xproto.WindowNone { if e.Owner == xproto.WindowNone {
break return
} }
// Don't try to process two things at once. Each request gets a few // Don't try to process two things at once. Each request gets a few
// seconds to finish, then we move on, hoping that a property race // seconds to finish, then we move on, hoping that a property race
// doesn't commence. Ideally we'd set up a separate queue for these // doesn't commence. Ideally we'd set up a separate queue for these
// skipped requests and process them later. // skipped requests and process them later.
if state.inProgress != 0 && e.Timestamp-state.inProgress < 5000 { if state.inProgress != 0 && e.Timestamp-state.inProgress < 5000 {
break return
} }
// ICCCM says we should ensure the named property doesn't exist. // ICCCM says we should ensure the named property doesn't exist.
_ = xproto.DeleteProperty(X, e.Window, e.Selection) _ = xproto.DeleteProperty(X, e.Window, e.Selection)
_ = xproto.ConvertSelection(X, e.Window, e.Selection, _ = xproto.ConvertSelection(X, e.Window, e.Selection,
atomUTF8String, e.Selection, e.Timestamp) atomUTF8String, e.Selection, e.Timestamp)
state.inProgress = e.Timestamp state.inProgress = e.Timestamp
state.incr = false state.incr = false
}
case xproto.SelectionNotifyEvent: func handleSelectionNotify(e xproto.SelectionNotifyEvent) {
state, ok := selections[e.Selection] state, ok := selections[e.Selection]
if e.Requestor != wid || !ok || e.Time != state.inProgress { if e.Requestor != wid || !ok || e.Time != state.inProgress {
break return
} }
state.inProgress = 0 state.inProgress = 0
if e.Property == xproto.AtomNone { if e.Property == xproto.AtomNone {
break return
} }
state.buffer = nil state.buffer = nil
reply, err := getProperty(e.Requestor, e.Property) reply, err := getProperty(e.Requestor, e.Property)
if err != nil { if err != nil {
break return
} }
// When you select a lot of text in VIM, it starts the ICCCM // When you select a lot of text in VIM, it starts the ICCCM
// INCR mechanism, from which there is no opt-out. // INCR mechanism, from which there is no opt-out.
if reply.Type == atomINCR { if reply.Type == atomINCR {
state.inProgress = e.Time state.inProgress = e.Time
state.incr = true state.incr = true
state.incrFailed = false state.incrFailed = false
} else if appendText(state, reply) { } else if appendText(state, reply) {
requestOwnership(state, e.Time)
}
_ = xproto.DeleteProperty(X, e.Requestor, e.Property)
}
func handlePropertyNotify(e xproto.PropertyNotifyEvent) {
state, ok := selections[e.Atom]
if e.Window != wid || e.State != xproto.PropertyNewValue ||
!ok || !state.incr {
return
}
reply, err := getProperty(e.Window, e.Atom)
if err != nil {
state.incrFailed = true
return
}
if !appendText(state, reply) {
// We need to keep deleting the property.
state.incrFailed = true
}
if reply.ValueLen == 0 {
if !state.incrFailed {
requestOwnership(state, e.Time) requestOwnership(state, e.Time)
} }
state.inProgress = 0
state.incr = false
}
_ = xproto.DeleteProperty(X, e.Requestor, e.Property) _ = xproto.DeleteProperty(X, e.Window, e.Atom)
}
func handleSelectionRequest(e xproto.SelectionRequestEvent) {
property := e.Property
if property == xproto.AtomNone {
property = e.Target
}
state, ok := selections[e.Selection]
if e.Owner != wid || !ok {
return
}
var (
typ xproto.Atom
format byte
data []byte
)
// XXX: We should also support the MULTIPLE target but it seems to be
// unimportant and largely abandoned today.
targets := []xproto.Atom{atomTARGETS, atomTIMESTAMP, atomUTF8String}
switch e.Target {
case atomTARGETS:
typ = xproto.AtomAtom
format = 32
data = make([]byte, len(targets)*4)
for i, atom := range targets {
nexgb.Put32(data[i*4:], uint32(atom))
}
case atomTIMESTAMP:
typ = xproto.AtomInteger
format = 32
data = make([]byte, 4)
nexgb.Put32(data, uint32(state.owning))
case atomUTF8String:
typ = atomUTF8String
format = 8
data = []byte(contents)
}
response := xproto.SelectionNotifyEvent{
Time: e.Time,
Requestor: e.Requestor,
Selection: e.Selection,
Target: e.Target,
Property: xproto.AtomNone,
}
if typ == 0 || len(data) > int(setup.MaximumRequestLength)*4-64 ||
state.owning == 0 || e.Time < state.owning {
// TODO: Use the INCR mechanism for large data transfers instead
// of refusing the request, or at least use PropModeAppend.
//
// According to the ICCCM we need to set up a queue for concurrent
// (requestor, selection, target, timestamp) requests that differ
// only in the target property, and process them in order. The ICCCM
// has a nice rationale. It seems to only concern INCR. The queue
// might be a map[(who, what, how, when)][](where, data, offset).
//
// NOTE: Even with BigRequests support, it may technically be
// missing on the particular X server, and XGB copies buffers to yet
// another buffer, making very large transfers a very bad idea.
} else if xproto.ChangePropertyChecked(X, xproto.PropModeReplace,
e.Requestor, property, typ, format,
uint32(len(data)/int(format/8)), data).Check() == nil {
response.Property = property
}
_ = xproto.SendEvent(X, false /* propagate */, e.Requestor,
0 /* event mask */, string(response.Bytes()))
}
func handleXEvent(ev nexgb.Event) {
switch e := ev.(type) {
case xfixes.SelectionNotifyEvent:
handleXfixesSelectionNotify(e)
case xproto.SelectionNotifyEvent:
handleSelectionNotify(e)
case xproto.PropertyNotifyEvent: case xproto.PropertyNotifyEvent:
state, ok := selections[e.Atom] handlePropertyNotify(e)
if e.Window != wid || e.State != xproto.PropertyNewValue ||
!ok || !state.incr {
break
}
reply, err := getProperty(e.Window, e.Atom)
if err != nil {
state.incrFailed = true
break
}
if !appendText(state, reply) {
// We need to keep deleting the property.
state.incrFailed = true
}
if reply.ValueLen == 0 {
if !state.incrFailed {
requestOwnership(state, e.Time)
}
state.inProgress = 0
state.incr = false
}
_ = xproto.DeleteProperty(X, e.Window, e.Atom)
case xproto.SelectionRequestEvent: case xproto.SelectionRequestEvent:
property := e.Property handleSelectionRequest(e)
if property == xproto.AtomNone {
property = e.Target
}
state, ok := selections[e.Selection]
if e.Owner != wid || !ok {
break
}
var (
typ xproto.Atom
format byte
data []byte
)
// XXX: We should also support the MULTIPLE target but it seems to be
// unimportant and largely abandoned today.
targets := []xproto.Atom{atomTARGETS, atomTIMESTAMP, atomUTF8String}
switch e.Target {
case atomTARGETS:
typ = xproto.AtomAtom
format = 32
data = make([]byte, len(targets)*4)
for i, atom := range targets {
nexgb.Put32(data[i*4:], uint32(atom))
}
case atomTIMESTAMP:
typ = xproto.AtomInteger
format = 32
data = make([]byte, 4)
nexgb.Put32(data, uint32(state.owning))
case atomUTF8String:
typ = atomUTF8String
format = 8
data = []byte(contents)
}
response := xproto.SelectionNotifyEvent{
Time: e.Time,
Requestor: e.Requestor,
Selection: e.Selection,
Target: e.Target,
Property: xproto.AtomNone,
}
if typ == 0 || len(data) > int(setup.MaximumRequestLength)*4-64 ||
state.owning == 0 || e.Time < state.owning {
// TODO: Use the INCR mechanism for large data transfers instead
// of refusing the request, or at least use PropModeAppend.
//
// According to the ICCCM we need to set up a queue for concurrent
// (requestor, selection, target, timestamp) requests that differ
// only in the target property, and process them in order. The ICCCM
// has a nice rationale. It seems to only concern INCR. The queue
// might be a map[(who, what, how, when)][](where, data, offset).
//
// NOTE: Even with BigRequests support, it may technically be
// missing on the particular X server, and XGB copies buffers to yet
// another buffer, making very large transfers a very bad idea.
} else if xproto.ChangePropertyChecked(X, xproto.PropModeReplace,
e.Requestor, property, typ, format,
uint32(len(data)/int(format/8)), data).Check() == nil {
response.Property = property
}
_ = xproto.SendEvent(X, false /* propagate */, e.Requestor,
0 /* event mask */, string(response.Bytes()))
} }
} }
@ -345,7 +359,7 @@ func main() {
return return
} }
if ev != nil { if ev != nil {
handleEvent(ev) handleXEvent(ev)
} }
} }
} }