aboutsummaryrefslogtreecommitdiff
path: root/hpcu/main.go
diff options
context:
space:
mode:
Diffstat (limited to 'hpcu/main.go')
-rw-r--r--hpcu/main.go302
1 files changed, 158 insertions, 144 deletions
diff --git a/hpcu/main.go b/hpcu/main.go
index 6240ef1..3aebb62 100644
--- a/hpcu/main.go
+++ b/hpcu/main.go
@@ -133,180 +133,194 @@ func requestOwnership(origin *selectionState, time xproto.Timestamp) {
}
}
-func handleEvent(ev nexgb.Event) {
- switch e := ev.(type) {
- case xfixes.SelectionNotifyEvent:
- state, ok := selections[e.Selection]
- if !ok {
- break
- }
+func handleXfixesSelectionNotify(e xfixes.SelectionNotifyEvent) {
+ state, ok := selections[e.Selection]
+ if !ok {
+ return
+ }
- // Ownership request has been granted, don't ask ourselves for data.
- if e.Owner == wid {
- state.owning = e.SelectionTimestamp
- break
- }
+ // Ownership request has been granted, don't ask ourselves for data.
+ if e.Owner == wid {
+ state.owning = e.SelectionTimestamp
+ return
+ }
- // This should always be true.
- if state.owning < e.SelectionTimestamp {
- state.owning = 0
- }
+ // This should always be true.
+ if state.owning < e.SelectionTimestamp {
+ state.owning = 0
+ }
- // Not checking whether we should give up when our current retrieval
- // attempt is interrupted--the timeout mostly solves this.
- if e.Owner == xproto.WindowNone {
- break
- }
+ // Not checking whether we should give up when our current retrieval
+ // attempt is interrupted--the timeout mostly solves this.
+ if e.Owner == xproto.WindowNone {
+ return
+ }
- // 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
- // doesn't commence. Ideally we'd set up a separate queue for these
- // skipped requests and process them later.
- if state.inProgress != 0 && e.Timestamp-state.inProgress < 5000 {
- break
- }
+ // 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
+ // doesn't commence. Ideally we'd set up a separate queue for these
+ // skipped requests and process them later.
+ if state.inProgress != 0 && e.Timestamp-state.inProgress < 5000 {
+ return
+ }
- // ICCCM says we should ensure the named property doesn't exist.
- _ = xproto.DeleteProperty(X, e.Window, e.Selection)
+ // ICCCM says we should ensure the named property doesn't exist.
+ _ = xproto.DeleteProperty(X, e.Window, e.Selection)
- _ = xproto.ConvertSelection(X, e.Window, e.Selection,
- atomUTF8String, e.Selection, e.Timestamp)
+ _ = xproto.ConvertSelection(X, e.Window, e.Selection,
+ atomUTF8String, e.Selection, e.Timestamp)
- state.inProgress = e.Timestamp
- state.incr = false
+ state.inProgress = e.Timestamp
+ state.incr = false
+}
- case xproto.SelectionNotifyEvent:
- state, ok := selections[e.Selection]
- if e.Requestor != wid || !ok || e.Time != state.inProgress {
- break
- }
+func handleSelectionNotify(e xproto.SelectionNotifyEvent) {
+ state, ok := selections[e.Selection]
+ if e.Requestor != wid || !ok || e.Time != state.inProgress {
+ return
+ }
- state.inProgress = 0
- if e.Property == xproto.AtomNone {
- break
- }
+ state.inProgress = 0
+ if e.Property == xproto.AtomNone {
+ return
+ }
- state.buffer = nil
- reply, err := getProperty(e.Requestor, e.Property)
- if err != nil {
- break
- }
+ state.buffer = nil
+ reply, err := getProperty(e.Requestor, e.Property)
+ if err != nil {
+ return
+ }
- // When you select a lot of text in VIM, it starts the ICCCM
- // INCR mechanism, from which there is no opt-out.
- if reply.Type == atomINCR {
- state.inProgress = e.Time
- state.incr = true
- state.incrFailed = false
- } else if appendText(state, reply) {
- requestOwnership(state, e.Time)
- }
+ // When you select a lot of text in VIM, it starts the ICCCM
+ // INCR mechanism, from which there is no opt-out.
+ if reply.Type == atomINCR {
+ state.inProgress = e.Time
+ state.incr = true
+ state.incrFailed = false
+ } else if appendText(state, reply) {
+ requestOwnership(state, e.Time)
+ }
- _ = xproto.DeleteProperty(X, e.Requestor, e.Property)
+ _ = xproto.DeleteProperty(X, e.Requestor, e.Property)
+}
- case xproto.PropertyNotifyEvent:
- state, ok := selections[e.Atom]
- if e.Window != wid || e.State != xproto.PropertyNewValue ||
- !ok || !state.incr {
- break
- }
+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
- break
- }
+ 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 !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
+ if reply.ValueLen == 0 {
+ if !state.incrFailed {
+ requestOwnership(state, e.Time)
}
+ state.inProgress = 0
+ state.incr = false
+ }
- _ = xproto.DeleteProperty(X, e.Window, e.Atom)
+ _ = xproto.DeleteProperty(X, e.Window, e.Atom)
- case xproto.SelectionRequestEvent:
- property := e.Property
- if property == xproto.AtomNone {
- property = e.Target
- }
+}
- state, ok := selections[e.Selection]
- if e.Owner != wid || !ok {
- break
- }
+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
- )
+ 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}
+ // 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
+ 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))
- }
+ 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
+ case atomTIMESTAMP:
+ typ = xproto.AtomInteger
+ format = 32
- data = make([]byte, 4)
- nexgb.Put32(data, uint32(state.owning))
+ data = make([]byte, 4)
+ nexgb.Put32(data, uint32(state.owning))
- case atomUTF8String:
- typ = atomUTF8String
- format = 8
+ case atomUTF8String:
+ typ = atomUTF8String
+ format = 8
- data = []byte(contents)
- }
+ data = []byte(contents)
+ }
- response := xproto.SelectionNotifyEvent{
- Time: e.Time,
- Requestor: e.Requestor,
- Selection: e.Selection,
- Target: e.Target,
- Property: xproto.AtomNone,
- }
+ 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
- }
+ 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()))
+ _ = 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:
+ handlePropertyNotify(e)
+ case xproto.SelectionRequestEvent:
+ handleSelectionRequest(e)
}
}
@@ -345,7 +359,7 @@ func main() {
return
}
if ev != nil {
- handleEvent(ev)
+ handleXEvent(ev)
}
}
}