feat(xwm): add map flow, property decoding, serial pairing and reparent handling
MapRequest batches ten GetProperty, GetGeometry and MapWindow; Ready fires once every reply (and the XRes pid fallback, propClientIDs) is in. Titles, class, transient-for and fullscreen changes reach the host only when they differ. WL_SURFACE_SERIAL pairs with set_serial in either order. ReparentNotify drops or adopts root children. Adds recorded-stream allocation tests.
- commit
- ce78abc602422d152d0ca8f64f1a568cd8e7c991
- author
- brice · · 2026-10-22 12:43 UTC
- committer
- brice · · 2026-10-22 17:54 UTC
- parent
- 50a2e95
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
11 files · +4896 -33
M Makefile +1 -1
| @@ -69,7 +69,7 @@ adapter-imports: | |||
| 69 | 69 | [ -z "$$bad" ] || { echo "$$bad"; echo 'adapter imports another adapter: use ports or a shared library (Makefile ADAPTER_LIBS)' >&2; exit 1; } | |
| 70 | 70 | # Fast, mandatory guards for tiled content publications and SHM copies. | |
| 71 | 71 | perf-check: | |
| 72 | - | CGO_ENABLED=0 go test ./internal/core ./internal/app ./internal/adapters/drm ./internal/adapters/headless ./internal/adapters/vulkan ./internal/adapters/wayland ./internal/adapters/outputkit/capture ./internal/adapters/screencast ./internal/adapters/wayland/xwm -run '^(TestAnimateAllocations|TestPublishAllocations|TestPublishSubscribersAllocations|TestPublishStashSlideAllocations|TestPublishOverviewAllocations|TestPublishLeavingAllocations|TestOutputRoutingAllocations|TestReportSeenAllocations|TestFrameLifecycleTransitionsAllocations|TestFullscreenShownAllocations|TestFrameDecisionAllocations|TestCommitFrameAllocations|TestColorPipelineAllocations|TestShownBySnapshotAllocations|TestFlipShowsAllocations|TestMRUNoteFocusDoesNotAllocateWhenSettled|TestDueFramesAllocations|TestRenderSteadyStateAllocations|TestRenderSteadyStateDMABufAllocations|TestSceneOpaqueRegionAllocations|TestSceneDeltaAllocations|TestAccountFlipAllocations|TestFlipDoneAllocations|TestSceneWalkUnchangedTiledSHM|TestTiledCommitPublishAllocations|TestCapturedCommitApplyAllocations|TestCapturedViewportApplyAllocations|TestEffectiveInputEmptyTreeAllocations|TestHeadlessTiledSHMCallbackAndCopyBudget|TestReleaseHeldAllocations|TestCommitDamageAllocations|TestEmitContentAllocations|TestPresentationPushAllocations|TestAnimatingFrameSendAllocations|TestContentBatchCycleAllocations|TestWriteMappedAllocations|TestCapturedForwardAllocations|TestCommandForwardAllocations|TestOutboxQueuedDeliveryAllocations|TestCastFrameAllocations|TestCastProducerAllocations|TestCaptureCycleAllocations|TestLogScenesAllocations|TestOverviewNamedRowsAllocations|TestBufferContentAllocations|TestDueFramesFireScratch|TestRetireSemaphoreAllocatesNothing|TestTableLookupAllocations|TestTableInsertRemoveAllocations)$$' -count=1 | |
| 72 | + | CGO_ENABLED=0 go test ./internal/core ./internal/app ./internal/adapters/drm ./internal/adapters/headless ./internal/adapters/vulkan ./internal/adapters/wayland ./internal/adapters/outputkit/capture ./internal/adapters/screencast ./internal/adapters/wayland/xwm -run '^(TestAnimateAllocations|TestPublishAllocations|TestPublishSubscribersAllocations|TestPublishStashSlideAllocations|TestPublishOverviewAllocations|TestPublishLeavingAllocations|TestOutputRoutingAllocations|TestReportSeenAllocations|TestFrameLifecycleTransitionsAllocations|TestFullscreenShownAllocations|TestFrameDecisionAllocations|TestCommitFrameAllocations|TestColorPipelineAllocations|TestShownBySnapshotAllocations|TestFlipShowsAllocations|TestMRUNoteFocusDoesNotAllocateWhenSettled|TestDueFramesAllocations|TestRenderSteadyStateAllocations|TestRenderSteadyStateDMABufAllocations|TestSceneOpaqueRegionAllocations|TestSceneDeltaAllocations|TestAccountFlipAllocations|TestFlipDoneAllocations|TestSceneWalkUnchangedTiledSHM|TestTiledCommitPublishAllocations|TestCapturedCommitApplyAllocations|TestCapturedViewportApplyAllocations|TestEffectiveInputEmptyTreeAllocations|TestHeadlessTiledSHMCallbackAndCopyBudget|TestReleaseHeldAllocations|TestCommitDamageAllocations|TestEmitContentAllocations|TestPresentationPushAllocations|TestAnimatingFrameSendAllocations|TestContentBatchCycleAllocations|TestWriteMappedAllocations|TestCapturedForwardAllocations|TestCommandForwardAllocations|TestOutboxQueuedDeliveryAllocations|TestCastFrameAllocations|TestCastProducerAllocations|TestCaptureCycleAllocations|TestLogScenesAllocations|TestOverviewNamedRowsAllocations|TestBufferContentAllocations|TestDueFramesFireScratch|TestRetireSemaphoreAllocatesNothing|TestTableLookupAllocations|TestTableInsertRemoveAllocations|TestPropertyUnchangedAllocations|TestDispatchAllocations)$$' -count=1 | |
| 73 | 73 | CGO_ENABLED=0 go test -tags xturbo_poison ./internal/adapters/wayland/xwm -count=1 | |
| 74 | 74 | check: vet test arch fakes-check log-check perf-check | |
| 75 | 75 | ||
| @@ -69,7 +69,7 @@ adapter-imports: | |||||
| 69 | [ -z "$$bad" ] || { echo "$$bad"; echo 'adapter imports another adapter: use ports or a shared library (Makefile ADAPTER_LIBS)' >&2; exit 1; } | 69 | [ -z "$$bad" ] || { echo "$$bad"; echo 'adapter imports another adapter: use ports or a shared library (Makefile ADAPTER_LIBS)' >&2; exit 1; } | ||
| 70 | # Fast, mandatory guards for tiled content publications and SHM copies. | 70 | # Fast, mandatory guards for tiled content publications and SHM copies. | ||
| 71 | perf-check: | 71 | perf-check: | ||
| 72 | - | CGO_ENABLED=0 go test ./internal/core ./internal/app ./internal/adapters/drm ./internal/adapters/headless ./internal/adapters/vulkan ./internal/adapters/wayland ./internal/adapters/outputkit/capture ./internal/adapters/screencast ./internal/adapters/wayland/xwm -run '^(TestAnimateAllocations|TestPublishAllocations|TestPublishSubscribersAllocations|TestPublishStashSlideAllocations|TestPublishOverviewAllocations|TestPublishLeavingAllocations|TestOutputRoutingAllocations|TestReportSeenAllocations|TestFrameLifecycleTransitionsAllocations|TestFullscreenShownAllocations|TestFrameDecisionAllocations|TestCommitFrameAllocations|TestColorPipelineAllocations|TestShownBySnapshotAllocations|TestFlipShowsAllocations|TestMRUNoteFocusDoesNotAllocateWhenSettled|TestDueFramesAllocations|TestRenderSteadyStateAllocations|TestRenderSteadyStateDMABufAllocations|TestSceneOpaqueRegionAllocations|TestSceneDeltaAllocations|TestAccountFlipAllocations|TestFlipDoneAllocations|TestSceneWalkUnchangedTiledSHM|TestTiledCommitPublishAllocations|TestCapturedCommitApplyAllocations|TestCapturedViewportApplyAllocations|TestEffectiveInputEmptyTreeAllocations|TestHeadlessTiledSHMCallbackAndCopyBudget|TestReleaseHeldAllocations|TestCommitDamageAllocations|TestEmitContentAllocations|TestPresentationPushAllocations|TestAnimatingFrameSendAllocations|TestContentBatchCycleAllocations|TestWriteMappedAllocations|TestCapturedForwardAllocations|TestCommandForwardAllocations|TestOutboxQueuedDeliveryAllocations|TestCastFrameAllocations|TestCastProducerAllocations|TestCaptureCycleAllocations|TestLogScenesAllocations|TestOverviewNamedRowsAllocations|TestBufferContentAllocations|TestDueFramesFireScratch|TestRetireSemaphoreAllocatesNothing|TestTableLookupAllocations|TestTableInsertRemoveAllocations)$$' -count=1 | 72 | + | CGO_ENABLED=0 go test ./internal/core ./internal/app ./internal/adapters/drm ./internal/adapters/headless ./internal/adapters/vulkan ./internal/adapters/wayland ./internal/adapters/outputkit/capture ./internal/adapters/screencast ./internal/adapters/wayland/xwm -run '^(TestAnimateAllocations|TestPublishAllocations|TestPublishSubscribersAllocations|TestPublishStashSlideAllocations|TestPublishOverviewAllocations|TestPublishLeavingAllocations|TestOutputRoutingAllocations|TestReportSeenAllocations|TestFrameLifecycleTransitionsAllocations|TestFullscreenShownAllocations|TestFrameDecisionAllocations|TestCommitFrameAllocations|TestColorPipelineAllocations|TestShownBySnapshotAllocations|TestFlipShowsAllocations|TestMRUNoteFocusDoesNotAllocateWhenSettled|TestDueFramesAllocations|TestRenderSteadyStateAllocations|TestRenderSteadyStateDMABufAllocations|TestSceneOpaqueRegionAllocations|TestSceneDeltaAllocations|TestAccountFlipAllocations|TestFlipDoneAllocations|TestSceneWalkUnchangedTiledSHM|TestTiledCommitPublishAllocations|TestCapturedCommitApplyAllocations|TestCapturedViewportApplyAllocations|TestEffectiveInputEmptyTreeAllocations|TestHeadlessTiledSHMCallbackAndCopyBudget|TestReleaseHeldAllocations|TestCommitDamageAllocations|TestEmitContentAllocations|TestPresentationPushAllocations|TestAnimatingFrameSendAllocations|TestContentBatchCycleAllocations|TestWriteMappedAllocations|TestCapturedForwardAllocations|TestCommandForwardAllocations|TestOutboxQueuedDeliveryAllocations|TestCastFrameAllocations|TestCastProducerAllocations|TestCaptureCycleAllocations|TestLogScenesAllocations|TestOverviewNamedRowsAllocations|TestBufferContentAllocations|TestDueFramesFireScratch|TestRetireSemaphoreAllocatesNothing|TestTableLookupAllocations|TestTableInsertRemoveAllocations|TestPropertyUnchangedAllocations|TestDispatchAllocations)$$' -count=1 |
| 73 | CGO_ENABLED=0 go test -tags xturbo_poison ./internal/adapters/wayland/xwm -count=1 | 73 | CGO_ENABLED=0 go test -tags xturbo_poison ./internal/adapters/wayland/xwm -count=1 | ||
| 74 | check: vet test arch fakes-check log-check perf-check | 74 | check: vet test arch fakes-check log-check perf-check | ||
| 75 | 75 | ||||
M internal/adapters/wayland/xwm/events.go +14 -6
| @@ -34,6 +34,8 @@ func (x *XWM) onEvent(ev *xturbo.Event) { | |||
| 34 | 34 | x.onCreateNotify(ev) | |
| 35 | 35 | case xproto.KindDestroyNotify: | |
| 36 | 36 | x.onDestroyNotify(ev) | |
| 37 | + | case xproto.KindReparentNotify: | |
| 38 | + | x.onReparentNotify(ev) | |
| 37 | 39 | } | |
| 38 | 40 | if x.host == nil { | |
| 39 | 41 | if ev.Kind == xproto.KindMapRequest { | |
| @@ -108,12 +110,11 @@ func (x *XWM) onError(e *xturbo.XError) { | |||
| 108 | 110 | if e.Code == xproto.BadAccess { | |
| 109 | 111 | x.bootErr = ErrWMExists | |
| 110 | 112 | } | |
| 111 | - | case kindProp, kindGeom, kindConfigure, kindFocus: | |
| 112 | - | if e.Code != xproto.BadWindow { | |
| 113 | - | return | |
| 114 | - | } | |
| 115 | - | // The window died between request and reply; DestroyNotify follows. | |
| 116 | - | _, rec := x.tab.live(e.Args[0]) | |
| 113 | + | case kindProp, kindGeom, kindClientIds, kindConfigure, kindFocus: | |
| 114 | + | // Usually BadWindow: the window died between request and reply and | |
| 115 | + | // DestroyNotify follows. Whatever the code, the awaited reply will | |
| 116 | + | // never come, so the map must not wait for it. | |
| 117 | + | s, rec := x.tab.live(e.Args[0]) | |
| 117 | 118 | if rec == nil { | |
| 118 | 119 | x.stats.Stale++ | |
| 119 | 120 | return | |
| @@ -123,6 +124,13 @@ func (x *XWM) onError(e *xturbo.XError) { | |||
| 123 | 124 | rec.pending &^= 1 << e.Args[1] | |
| 124 | 125 | case kindGeom: | |
| 125 | 126 | rec.pending &^= propGeom | |
| 127 | + | case kindClientIds: | |
| 128 | + | rec.pending &^= propClientIDs | |
| 129 | + | default: | |
| 130 | + | return | |
| 131 | + | } | |
| 132 | + | if e.Code != xproto.BadWindow { // a dead window is never announced | |
| 133 | + | x.checkReady(s) | |
| 126 | 134 | } | |
| 127 | 135 | } | |
| 128 | 136 | } | |
| @@ -34,6 +34,8 @@ func (x *XWM) onEvent(ev *xturbo.Event) { | |||||
| 34 | x.onCreateNotify(ev) | 34 | x.onCreateNotify(ev) | ||
| 35 | case xproto.KindDestroyNotify: | 35 | case xproto.KindDestroyNotify: | ||
| 36 | x.onDestroyNotify(ev) | 36 | x.onDestroyNotify(ev) | ||
| 37 | + | case xproto.KindReparentNotify: | |||
| 38 | + | x.onReparentNotify(ev) | |||
| 37 | } | 39 | } | ||
| 38 | if x.host == nil { | 40 | if x.host == nil { | ||
| 39 | if ev.Kind == xproto.KindMapRequest { | 41 | if ev.Kind == xproto.KindMapRequest { | ||
| @@ -108,12 +110,11 @@ func (x *XWM) onError(e *xturbo.XError) { | |||||
| 108 | if e.Code == xproto.BadAccess { | 110 | if e.Code == xproto.BadAccess { | ||
| 109 | x.bootErr = ErrWMExists | 111 | x.bootErr = ErrWMExists | ||
| 110 | } | 112 | } | ||
| 111 | - | case kindProp, kindGeom, kindConfigure, kindFocus: | 113 | + | case kindProp, kindGeom, kindClientIds, kindConfigure, kindFocus: |
| 112 | - | if e.Code != xproto.BadWindow { | 114 | + | // Usually BadWindow: the window died between request and reply and |
| 113 | - | return | 115 | + | // DestroyNotify follows. Whatever the code, the awaited reply will |
| 114 | - | } | 116 | + | // never come, so the map must not wait for it. |
| 115 | - | // The window died between request and reply; DestroyNotify follows. | 117 | + | s, rec := x.tab.live(e.Args[0]) |
| 116 | - | _, rec := x.tab.live(e.Args[0]) | |||
| 117 | if rec == nil { | 118 | if rec == nil { | ||
| 118 | x.stats.Stale++ | 119 | x.stats.Stale++ | ||
| 119 | return | 120 | return | ||
| @@ -123,6 +124,13 @@ func (x *XWM) onError(e *xturbo.XError) { | |||||
| 123 | rec.pending &^= 1 << e.Args[1] | 124 | rec.pending &^= 1 << e.Args[1] | ||
| 124 | case kindGeom: | 125 | case kindGeom: | ||
| 125 | rec.pending &^= propGeom | 126 | rec.pending &^= propGeom | ||
| 127 | + | case kindClientIds: | |||
| 128 | + | rec.pending &^= propClientIDs | |||
| 129 | + | default: | |||
| 130 | + | return | |||
| 131 | + | } | |||
| 132 | + | if e.Code != xproto.BadWindow { // a dead window is never announced | |||
| 133 | + | x.checkReady(s) | |||
| 126 | } | 134 | } | ||
| 127 | } | 135 | } | ||
| 128 | } | 136 | } | ||
M internal/adapters/wayland/xwm/mapflow.go +368 -13
| @@ -1,21 +1,376 @@ | |||
| 1 | 1 | package xwm | |
| 2 | 2 | ||
| 3 | - | import "bnema.dev/xturbo" | |
| 3 | + | import ( | |
| 4 | + | "bnema.dev/xturbo" | |
| 5 | + | "bnema.dev/xturbo/xproto" | |
| 6 | + | ) | |
| 4 | 7 | ||
| 5 | - | // beginMap starts the map flow of a managed window: properties, geometry, | |
| 6 | - | // MapWindow. Also called by Attach for windows mapped before it. | |
| 7 | - | func (x *XWM) beginMap(s Slot) { _ = s } | |
| 8 | + | // ICCCM WM_STATE values. | |
| 9 | + | const ( | |
| 10 | + | wmStateWithdrawn uint32 = 0 | |
| 11 | + | wmStateNormal uint32 = 1 | |
| 12 | + | ) | |
| 8 | 13 | ||
| 9 | - | func (x *XWM) onMapRequest(ev *xturbo.Event) { _ = ev } | |
| 10 | - | func (x *XWM) onMapNotify(ev *xturbo.Event) { _ = ev } | |
| 11 | - | func (x *XWM) onUnmapNotify(ev *xturbo.Event) { _ = ev } | |
| 12 | - | func (x *XWM) onClientMessage(ev *xturbo.Event) { _ = ev } | |
| 14 | + | // _NET_WM_STATE client message actions. | |
| 15 | + | const ( | |
| 16 | + | netStateRemove = 0 | |
| 17 | + | netStateAdd = 1 | |
| 18 | + | netStateToggle = 2 | |
| 19 | + | ) | |
| 13 | 20 | ||
| 14 | - | func (x *XWM) onGeomReply(s Slot, rec *record, r *xturbo.Reply) { _, _, _ = s, rec, r } | |
| 15 | - | func (x *XWM) onClientIdsReply(s Slot, rec *record, r *xturbo.Reply) { _, _, _ = s, rec, r } | |
| 21 | + | // beginMap starts the map flow of a managed window: every property, the | |
| 22 | + | // geometry and MapWindow go out in one batch (wlroots order). Also called by | |
| 23 | + | // Attach for windows mapped before it. | |
| 24 | + | func (x *XWM) beginMap(s Slot) { | |
| 25 | + | rec := x.tab.rec(s) | |
| 26 | + | if rec.kind != kindManaged || rec.mapping { | |
| 27 | + | return | |
| 28 | + | } | |
| 29 | + | rec.mapping, rec.ready = true, false | |
| 30 | + | rec.hasNetName = false | |
| 31 | + | rec.pending = propGeom | |
| 32 | + | xid := rec.xid | |
| 33 | + | for idx := 0; idx < propCount; idx++ { | |
| 34 | + | x.requestProp(s, idx) | |
| 35 | + | } | |
| 36 | + | b := x.conn.Buf() | |
| 37 | + | x.expect(xproto.GetGeometry(b, xproto.Drawable(xid)), kindGeom, x.tab.tag(s), 0) | |
| 38 | + | xproto.MapWindow(b, xproto.Window(xid)) | |
| 39 | + | } | |
| 16 | 40 | ||
| 17 | - | // SetSerial records the serial of a wl_surface (xwayland_surface_v1.set_serial). | |
| 18 | - | func (x *XWM) SetSerial(surfaceID uint64, serial uint64) { _, _ = surfaceID, serial } | |
| 41 | + | func (x *XWM) onMapRequest(ev *xturbo.Event) { | |
| 42 | + | if s := x.tab.lookup(uint32(xproto.MapRequestOf(ev).Window())); s != 0 { | |
| 43 | + | x.beginMap(s) | |
| 44 | + | } | |
| 45 | + | } | |
| 46 | + | ||
| 47 | + | func (x *XWM) onMapNotify(ev *xturbo.Event) { | |
| 48 | + | if s := x.tab.lookup(uint32(xproto.MapNotifyOf(ev).Window())); s != 0 { | |
| 49 | + | x.tab.rec(s).mapped = true | |
| 50 | + | } | |
| 51 | + | } | |
| 52 | + | ||
| 53 | + | // onUnmapNotify ends the mapped life of a managed window; a later MapRequest | |
| 54 | + | // starts over and re-reads the properties. Synthetic events (ICCCM unmap | |
| 55 | + | // requests) are not an unmap. | |
| 56 | + | func (x *XWM) onUnmapNotify(ev *xturbo.Event) { | |
| 57 | + | if ev.SendEvent { | |
| 58 | + | return | |
| 59 | + | } | |
| 60 | + | s := x.tab.lookup(uint32(xproto.UnmapNotifyOf(ev).Window())) | |
| 61 | + | if s == 0 { | |
| 62 | + | return | |
| 63 | + | } | |
| 64 | + | rec := x.tab.rec(s) | |
| 65 | + | rec.mapped = false | |
| 66 | + | if rec.kind != kindManaged { | |
| 67 | + | return | |
| 68 | + | } | |
| 69 | + | wasMapping := rec.mapping | |
| 70 | + | rec.ready, rec.mapping, rec.pending = false, false, 0 | |
| 71 | + | rec.serial, rec.surface = 0, 0 | |
| 72 | + | if wasMapping { | |
| 73 | + | xid := rec.xid | |
| 74 | + | x.setProp32Typed(xid, atomWMState, x.atoms[atomWMState], []uint32{wmStateWithdrawn, 0}) | |
| 75 | + | xproto.DeleteProperty(x.conn.Buf(), xproto.Window(xid), xproto.Atom(x.atoms[atomNetWMState])) | |
| 76 | + | x.unlist(xid) | |
| 77 | + | } | |
| 78 | + | if rec.id != 0 { | |
| 79 | + | x.host.Dissociate(s, false) | |
| 80 | + | } | |
| 81 | + | } | |
| 82 | + | ||
| 83 | + | // setProp32Typed is setProp32 with an explicit property type atom. | |
| 84 | + | func (x *XWM) setProp32Typed(win uint32, prop int, typ uint32, vals []uint32) { | |
| 85 | + | x.setProp32(win, prop, xproto.Atom(typ), vals) | |
| 86 | + | } | |
| 87 | + | ||
| 88 | + | // checkReady fires Ready once every awaited reply is in. | |
| 89 | + | func (x *XWM) checkReady(s Slot) { | |
| 90 | + | rec := x.tab.rec(s) | |
| 91 | + | if rec == nil || rec.pending != 0 || rec.ready || !rec.mapping || rec.kind != kindManaged || x.host == nil { | |
| 92 | + | return | |
| 93 | + | } | |
| 94 | + | rec.ready = true | |
| 95 | + | info := x.info(s) | |
| 96 | + | xid := rec.xid | |
| 97 | + | ||
| 98 | + | var state [2]uint32 | |
| 99 | + | n := 0 | |
| 100 | + | if rec.modal { | |
| 101 | + | state[n] = x.atoms[atomNetWMStateModal] | |
| 102 | + | n++ | |
| 103 | + | } | |
| 104 | + | if rec.fullscreen { | |
| 105 | + | state[n] = x.atoms[atomNetWMStateFullscreen] | |
| 106 | + | n++ | |
| 107 | + | } | |
| 108 | + | x.setProp32(xid, atomNetWMState, xproto.AtomAtom, state[:n]) | |
| 109 | + | x.setProp32Typed(xid, atomWMState, x.atoms[atomWMState], []uint32{wmStateNormal, 0}) | |
| 110 | + | x.clients = append(x.clients, xid) | |
| 111 | + | x.stacking = append(x.stacking, xid) | |
| 112 | + | x.publishLists() | |
| 113 | + | ||
| 114 | + | x.host.Ready(s, info) | |
| 115 | + | x.tryPair(s) | |
| 116 | + | } | |
| 117 | + | ||
| 118 | + | // info is what the host learns when a window is ready. | |
| 119 | + | func (x *XWM) info(s Slot) WindowInfo { | |
| 120 | + | rec := x.tab.rec(s) | |
| 121 | + | parent := x.managedSlot(rec.transient) | |
| 122 | + | fixed := rec.minW > 0 && rec.minH > 0 && rec.minW == rec.maxW && rec.minH == rec.maxH | |
| 123 | + | info := WindowInfo{ | |
| 124 | + | PID: int(rec.pid), | |
| 125 | + | Floating: floatingType(rec.wtype) || parent != 0 || fixed, | |
| 126 | + | Parent: parent, | |
| 127 | + | Modal: rec.modal, | |
| 128 | + | Fullscreen: rec.fullscreen, | |
| 129 | + | Title: rec.title, | |
| 130 | + | AppID: rec.class, | |
| 131 | + | } | |
| 132 | + | if info.Floating { | |
| 133 | + | info.Width, info.Height = int(rec.w), int(rec.h) | |
| 134 | + | } | |
| 135 | + | return info | |
| 136 | + | } | |
| 137 | + | ||
| 138 | + | func (x *XWM) onGeomReply(s Slot, rec *record, r *xturbo.Reply) { | |
| 139 | + | if g, ok := xproto.ParseGetGeometryReply(r.Raw); ok { | |
| 140 | + | rec.x, rec.y, rec.w, rec.h = int32(g.X()), int32(g.Y()), uint32(g.Width()), uint32(g.Height()) | |
| 141 | + | } | |
| 142 | + | rec.pending &^= propGeom | |
| 143 | + | x.checkReady(s) | |
| 144 | + | } | |
| 145 | + | ||
| 146 | + | // publishLists rewrites _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING. | |
| 147 | + | func (x *XWM) publishLists() { | |
| 148 | + | x.setProp32(x.root, atomNetClientList, xproto.AtomWindow, x.clients) | |
| 149 | + | x.setProp32(x.root, atomNetClientListStacking, xproto.AtomWindow, x.stacking) | |
| 150 | + | } | |
| 151 | + | ||
| 152 | + | // unlist drops xid from both client lists and republishes them if it was in. | |
| 153 | + | func (x *XWM) unlist(xid uint32) { | |
| 154 | + | was := len(x.clients) | |
| 155 | + | x.clients = removeID(x.clients, xid) | |
| 156 | + | x.stacking = removeID(x.stacking, xid) | |
| 157 | + | if len(x.clients) != was { | |
| 158 | + | x.publishLists() | |
| 159 | + | } | |
| 160 | + | } | |
| 161 | + | ||
| 162 | + | func removeID(l []uint32, xid uint32) []uint32 { | |
| 163 | + | for i, v := range l { | |
| 164 | + | if v == xid { | |
| 165 | + | return append(l[:i], l[i+1:]...) | |
| 166 | + | } | |
| 167 | + | } | |
| 168 | + | return l | |
| 169 | + | } | |
| 170 | + | ||
| 171 | + | // onClientMessage handles WL_SURFACE_SERIAL (pairing), the legacy | |
| 172 | + | // WL_SURFACE_ID (counted, ignored) and _NET_WM_STATE requests. | |
| 173 | + | func (x *XWM) onClientMessage(ev *xturbo.Event) { | |
| 174 | + | e := xproto.ClientMessageOf(ev) | |
| 175 | + | if e.Format() != 32 { | |
| 176 | + | return | |
| 177 | + | } | |
| 178 | + | typ := uint32(e.Type()) | |
| 179 | + | switch typ { | |
| 180 | + | case x.atoms[atomWLSurfaceSerial]: | |
| 181 | + | s := x.tab.lookup(uint32(e.Window())) | |
| 182 | + | if s == 0 { | |
| 183 | + | return | |
| 184 | + | } | |
| 185 | + | rec := x.tab.rec(s) | |
| 186 | + | if rec.serial != 0 { | |
| 187 | + | x.log.Debug().Uint32("xid", rec.xid).Msg("duplicate WL_SURFACE_SERIAL ignored") | |
| 188 | + | return | |
| 189 | + | } | |
| 190 | + | d := e.Data().Data32() | |
| 191 | + | rec.serial = uint64(d[1])<<32 | uint64(d[0]) | |
| 192 | + | x.tryPair(s) | |
| 193 | + | case x.atoms[atomWLSurfaceID]: | |
| 194 | + | x.stats.LegacyID++ | |
| 195 | + | if x.stats.LegacyID == 1 { | |
| 196 | + | x.log.Warn().Msg("WL_SURFACE_ID received: Xwayland did not bind xwayland_shell_v1, window ignored") | |
| 197 | + | } | |
| 198 | + | case x.atoms[atomNetWMState]: | |
| 199 | + | x.onNetWMState(e) | |
| 200 | + | } | |
| 201 | + | } | |
| 202 | + | ||
| 203 | + | // onNetWMState forwards fullscreen requests to the host and records them; the | |
| 204 | + | // property itself is written when core answers with a configure. | |
| 205 | + | func (x *XWM) onNetWMState(e xproto.ClientMessageEvent) { | |
| 206 | + | s := x.tab.lookup(uint32(e.Window())) | |
| 207 | + | if s == 0 { | |
| 208 | + | return | |
| 209 | + | } | |
| 210 | + | rec := x.tab.rec(s) | |
| 211 | + | if rec.kind != kindManaged { | |
| 212 | + | return | |
| 213 | + | } | |
| 214 | + | d := e.Data().Data32() | |
| 215 | + | apply := func(cur bool) bool { | |
| 216 | + | switch d[0] { | |
| 217 | + | case netStateRemove: | |
| 218 | + | return false | |
| 219 | + | case netStateAdd: | |
| 220 | + | return true | |
| 221 | + | case netStateToggle: | |
| 222 | + | return !cur | |
| 223 | + | } | |
| 224 | + | return cur | |
| 225 | + | } | |
| 226 | + | for _, a := range d[1:3] { | |
| 227 | + | switch { | |
| 228 | + | case a == 0: | |
| 229 | + | case a == x.atoms[atomNetWMStateModal]: | |
| 230 | + | rec.modal = apply(rec.modal) | |
| 231 | + | case a == x.atoms[atomNetWMStateFullscreen]: | |
| 232 | + | on := apply(rec.fullscreen) | |
| 233 | + | if on == rec.fullscreen { | |
| 234 | + | continue | |
| 235 | + | } | |
| 236 | + | rec.fullscreen = on | |
| 237 | + | if rec.ready { | |
| 238 | + | x.host.Fullscreen(s, on) | |
| 239 | + | rec = x.tab.rec(s) | |
| 240 | + | } | |
| 241 | + | } | |
| 242 | + | } | |
| 243 | + | } | |
| 244 | + | ||
| 245 | + | // onReparentNotify keeps the table to root's direct children: a window moved | |
| 246 | + | // away is forgotten, one moved into root is treated as newly created. | |
| 247 | + | func (x *XWM) onReparentNotify(ev *xturbo.Event) { | |
| 248 | + | e := xproto.ReparentNotifyOf(ev) | |
| 249 | + | xid := uint32(e.Window()) | |
| 250 | + | if xid == x.wmWin { | |
| 251 | + | return | |
| 252 | + | } | |
| 253 | + | s := x.tab.lookup(xid) | |
| 254 | + | if uint32(e.Parent()) != x.root { | |
| 255 | + | if s != 0 { | |
| 256 | + | x.dropWindow(s) | |
| 257 | + | } | |
| 258 | + | return | |
| 259 | + | } | |
| 260 | + | if s != 0 { | |
| 261 | + | return | |
| 262 | + | } | |
| 263 | + | s = x.insert(xid) | |
| 264 | + | if s == 0 { | |
| 265 | + | return | |
| 266 | + | } | |
| 267 | + | rec := x.tab.rec(s) | |
| 268 | + | rec.override = e.OverrideRedirect() | |
| 269 | + | rec.x, rec.y = int32(e.X()), int32(e.Y()) | |
| 270 | + | if rec.override { | |
| 271 | + | rec.kind = kindUnmanaged | |
| 272 | + | x.stats.UnmanagedSeen++ | |
| 273 | + | return | |
| 274 | + | } | |
| 275 | + | if x.host != nil { | |
| 276 | + | x.adopt(s) | |
| 277 | + | } | |
| 278 | + | } | |
| 279 | + | ||
| 280 | + | // dropWindow forgets s: the host is told if it knew the window. | |
| 281 | + | func (x *XWM) dropWindow(s Slot) { | |
| 282 | + | rec := x.tab.rec(s) | |
| 283 | + | xid := rec.xid | |
| 284 | + | if rec.kind == kindManaged { | |
| 285 | + | x.unlist(xid) | |
| 286 | + | if x.active == s { | |
| 287 | + | x.active = 0 | |
| 288 | + | } | |
| 289 | + | if rec.id != 0 && x.host != nil { | |
| 290 | + | rec.id = 0 | |
| 291 | + | x.host.Dissociate(s, true) | |
| 292 | + | } | |
| 293 | + | } | |
| 294 | + | x.tab.remove(s) | |
| 295 | + | } | |
| 296 | + | ||
| 297 | + | // tryPair links the window to the wl_surface carrying its serial, once both | |
| 298 | + | // are known and the window is ready (the host maps on the surface's first | |
| 299 | + | // buffer, so it must know the window's info by then). Unmanaged windows keep | |
| 300 | + | // the surface but are never associated. | |
| 301 | + | func (x *XWM) tryPair(s Slot) { | |
| 302 | + | rec := x.tab.rec(s) | |
| 303 | + | if rec.serial == 0 || rec.surface != 0 { | |
| 304 | + | return | |
| 305 | + | } | |
| 306 | + | if rec.kind == kindManaged && !rec.ready { | |
| 307 | + | return | |
| 308 | + | } | |
| 309 | + | for i := 0; i < x.unpairedN; i++ { | |
| 310 | + | if x.unpaired[i].serial != rec.serial { | |
| 311 | + | continue | |
| 312 | + | } | |
| 313 | + | rec.surface = x.unpaired[i].surface | |
| 314 | + | x.unpairedN-- | |
| 315 | + | x.unpaired[i] = x.unpaired[x.unpairedN] | |
| 316 | + | if rec.kind == kindManaged { | |
| 317 | + | x.log.Debug().Uint32("xid", rec.xid).Uint64("surface", rec.surface).Msg("x11 window paired") | |
| 318 | + | x.host.Associate(s, rec.surface) | |
| 319 | + | } | |
| 320 | + | return | |
| 321 | + | } | |
| 322 | + | } | |
| 323 | + | ||
| 324 | + | // SetSerial records the serial of a wl_surface (xwayland_surface_v1.set_serial) | |
| 325 | + | // and pairs it with the window announcing the same serial. | |
| 326 | + | func (x *XWM) SetSerial(surfaceID uint64, serial uint64) { | |
| 327 | + | if serial == 0 || x.closed { | |
| 328 | + | return | |
| 329 | + | } | |
| 330 | + | for i := 0; i < x.unpairedN; i++ { | |
| 331 | + | if x.unpaired[i].serial == serial { | |
| 332 | + | x.unpaired[i].surface = surfaceID | |
| 333 | + | x.pairSerial(serial) | |
| 334 | + | return | |
| 335 | + | } | |
| 336 | + | } | |
| 337 | + | if x.unpairedN == unpairedCap { | |
| 338 | + | copy(x.unpaired[:], x.unpaired[1:]) | |
| 339 | + | x.unpairedN-- | |
| 340 | + | if !x.warnedUnpaired { | |
| 341 | + | x.warnedUnpaired = true | |
| 342 | + | x.log.Warn().Msg("too many unpaired surfaces, dropping the oldest") | |
| 343 | + | } | |
| 344 | + | } | |
| 345 | + | x.unpaired[x.unpairedN] = struct{ serial, surface uint64 }{serial, surfaceID} | |
| 346 | + | x.unpairedN++ | |
| 347 | + | x.pairSerial(serial) | |
| 348 | + | } | |
| 349 | + | ||
| 350 | + | // pairSerial offers a newly known surface serial to the windows. | |
| 351 | + | func (x *XWM) pairSerial(serial uint64) { | |
| 352 | + | for i := range x.tab.recs { | |
| 353 | + | if r := &x.tab.recs[i]; r.kind != kindFree && r.serial == serial && r.surface == 0 { | |
| 354 | + | x.tryPair(Slot(i + 1)) | |
| 355 | + | break | |
| 356 | + | } | |
| 357 | + | } | |
| 358 | + | x.wake() | |
| 359 | + | } | |
| 19 | 360 | ||
| 20 | 361 | // SurfaceGone forgets a destroyed wl_surface. | |
| 21 | - | func (x *XWM) SurfaceGone(surfaceID uint64) { _ = surfaceID } | |
| 362 | + | func (x *XWM) SurfaceGone(surfaceID uint64) { | |
| 363 | + | for i := 0; i < x.unpairedN; i++ { | |
| 364 | + | if x.unpaired[i].surface == surfaceID { | |
| 365 | + | x.unpairedN-- | |
| 366 | + | x.unpaired[i] = x.unpaired[x.unpairedN] | |
| 367 | + | break | |
| 368 | + | } | |
| 369 | + | } | |
| 370 | + | for i := range x.tab.recs { | |
| 371 | + | if r := &x.tab.recs[i]; r.kind != kindFree && r.surface == surfaceID { | |
| 372 | + | r.surface = 0 | |
| 373 | + | } | |
| 374 | + | } | |
| 375 | + | x.wake() | |
| 376 | + | } | |
| @@ -1,21 +1,376 @@ | |||||
| 1 | package xwm | 1 | package xwm | ||
| 2 | 2 | ||||
| 3 | - | import "bnema.dev/xturbo" | 3 | + | import ( |
| 4 | + | "bnema.dev/xturbo" | |||
| 5 | + | "bnema.dev/xturbo/xproto" | |||
| 6 | + | ) | |||
| 4 | 7 | ||||
| 5 | - | // beginMap starts the map flow of a managed window: properties, geometry, | 8 | + | // ICCCM WM_STATE values. |
| 6 | - | // MapWindow. Also called by Attach for windows mapped before it. | 9 | + | const ( |
| 7 | - | func (x *XWM) beginMap(s Slot) { _ = s } | 10 | + | wmStateWithdrawn uint32 = 0 |
| 11 | + | wmStateNormal uint32 = 1 | |||
| 12 | + | ) | |||
| 8 | 13 | ||||
| 9 | - | func (x *XWM) onMapRequest(ev *xturbo.Event) { _ = ev } | 14 | + | // _NET_WM_STATE client message actions. |
| 10 | - | func (x *XWM) onMapNotify(ev *xturbo.Event) { _ = ev } | 15 | + | const ( |
| 11 | - | func (x *XWM) onUnmapNotify(ev *xturbo.Event) { _ = ev } | 16 | + | netStateRemove = 0 |
| 12 | - | func (x *XWM) onClientMessage(ev *xturbo.Event) { _ = ev } | 17 | + | netStateAdd = 1 |
| 18 | + | netStateToggle = 2 | |||
| 19 | + | ) | |||
| 13 | 20 | ||||
| 14 | - | func (x *XWM) onGeomReply(s Slot, rec *record, r *xturbo.Reply) { _, _, _ = s, rec, r } | 21 | + | // beginMap starts the map flow of a managed window: every property, the |
| 15 | - | func (x *XWM) onClientIdsReply(s Slot, rec *record, r *xturbo.Reply) { _, _, _ = s, rec, r } | 22 | + | // geometry and MapWindow go out in one batch (wlroots order). Also called by |
| 23 | + | // Attach for windows mapped before it. | |||
| 24 | + | func (x *XWM) beginMap(s Slot) { | |||
| 25 | + | rec := x.tab.rec(s) | |||
| 26 | + | if rec.kind != kindManaged || rec.mapping { | |||
| 27 | + | return | |||
| 28 | + | } | |||
| 29 | + | rec.mapping, rec.ready = true, false | |||
| 30 | + | rec.hasNetName = false | |||
| 31 | + | rec.pending = propGeom | |||
| 32 | + | xid := rec.xid | |||
| 33 | + | for idx := 0; idx < propCount; idx++ { | |||
| 34 | + | x.requestProp(s, idx) | |||
| 35 | + | } | |||
| 36 | + | b := x.conn.Buf() | |||
| 37 | + | x.expect(xproto.GetGeometry(b, xproto.Drawable(xid)), kindGeom, x.tab.tag(s), 0) | |||
| 38 | + | xproto.MapWindow(b, xproto.Window(xid)) | |||
| 39 | + | } | |||
| 16 | 40 | ||||
| 17 | - | // SetSerial records the serial of a wl_surface (xwayland_surface_v1.set_serial). | 41 | + | func (x *XWM) onMapRequest(ev *xturbo.Event) { |
| 18 | - | func (x *XWM) SetSerial(surfaceID uint64, serial uint64) { _, _ = surfaceID, serial } | 42 | + | if s := x.tab.lookup(uint32(xproto.MapRequestOf(ev).Window())); s != 0 { |
| 43 | + | x.beginMap(s) | |||
| 44 | + | } | |||
| 45 | + | } | |||
| 46 | + | ||||
| 47 | + | func (x *XWM) onMapNotify(ev *xturbo.Event) { | |||
| 48 | + | if s := x.tab.lookup(uint32(xproto.MapNotifyOf(ev).Window())); s != 0 { | |||
| 49 | + | x.tab.rec(s).mapped = true | |||
| 50 | + | } | |||
| 51 | + | } | |||
| 52 | + | ||||
| 53 | + | // onUnmapNotify ends the mapped life of a managed window; a later MapRequest | |||
| 54 | + | // starts over and re-reads the properties. Synthetic events (ICCCM unmap | |||
| 55 | + | // requests) are not an unmap. | |||
| 56 | + | func (x *XWM) onUnmapNotify(ev *xturbo.Event) { | |||
| 57 | + | if ev.SendEvent { | |||
| 58 | + | return | |||
| 59 | + | } | |||
| 60 | + | s := x.tab.lookup(uint32(xproto.UnmapNotifyOf(ev).Window())) | |||
| 61 | + | if s == 0 { | |||
| 62 | + | return | |||
| 63 | + | } | |||
| 64 | + | rec := x.tab.rec(s) | |||
| 65 | + | rec.mapped = false | |||
| 66 | + | if rec.kind != kindManaged { | |||
| 67 | + | return | |||
| 68 | + | } | |||
| 69 | + | wasMapping := rec.mapping | |||
| 70 | + | rec.ready, rec.mapping, rec.pending = false, false, 0 | |||
| 71 | + | rec.serial, rec.surface = 0, 0 | |||
| 72 | + | if wasMapping { | |||
| 73 | + | xid := rec.xid | |||
| 74 | + | x.setProp32Typed(xid, atomWMState, x.atoms[atomWMState], []uint32{wmStateWithdrawn, 0}) | |||
| 75 | + | xproto.DeleteProperty(x.conn.Buf(), xproto.Window(xid), xproto.Atom(x.atoms[atomNetWMState])) | |||
| 76 | + | x.unlist(xid) | |||
| 77 | + | } | |||
| 78 | + | if rec.id != 0 { | |||
| 79 | + | x.host.Dissociate(s, false) | |||
| 80 | + | } | |||
| 81 | + | } | |||
| 82 | + | ||||
| 83 | + | // setProp32Typed is setProp32 with an explicit property type atom. | |||
| 84 | + | func (x *XWM) setProp32Typed(win uint32, prop int, typ uint32, vals []uint32) { | |||
| 85 | + | x.setProp32(win, prop, xproto.Atom(typ), vals) | |||
| 86 | + | } | |||
| 87 | + | ||||
| 88 | + | // checkReady fires Ready once every awaited reply is in. | |||
| 89 | + | func (x *XWM) checkReady(s Slot) { | |||
| 90 | + | rec := x.tab.rec(s) | |||
| 91 | + | if rec == nil || rec.pending != 0 || rec.ready || !rec.mapping || rec.kind != kindManaged || x.host == nil { | |||
| 92 | + | return | |||
| 93 | + | } | |||
| 94 | + | rec.ready = true | |||
| 95 | + | info := x.info(s) | |||
| 96 | + | xid := rec.xid | |||
| 97 | + | ||||
| 98 | + | var state [2]uint32 | |||
| 99 | + | n := 0 | |||
| 100 | + | if rec.modal { | |||
| 101 | + | state[n] = x.atoms[atomNetWMStateModal] | |||
| 102 | + | n++ | |||
| 103 | + | } | |||
| 104 | + | if rec.fullscreen { | |||
| 105 | + | state[n] = x.atoms[atomNetWMStateFullscreen] | |||
| 106 | + | n++ | |||
| 107 | + | } | |||
| 108 | + | x.setProp32(xid, atomNetWMState, xproto.AtomAtom, state[:n]) | |||
| 109 | + | x.setProp32Typed(xid, atomWMState, x.atoms[atomWMState], []uint32{wmStateNormal, 0}) | |||
| 110 | + | x.clients = append(x.clients, xid) | |||
| 111 | + | x.stacking = append(x.stacking, xid) | |||
| 112 | + | x.publishLists() | |||
| 113 | + | ||||
| 114 | + | x.host.Ready(s, info) | |||
| 115 | + | x.tryPair(s) | |||
| 116 | + | } | |||
| 117 | + | ||||
| 118 | + | // info is what the host learns when a window is ready. | |||
| 119 | + | func (x *XWM) info(s Slot) WindowInfo { | |||
| 120 | + | rec := x.tab.rec(s) | |||
| 121 | + | parent := x.managedSlot(rec.transient) | |||
| 122 | + | fixed := rec.minW > 0 && rec.minH > 0 && rec.minW == rec.maxW && rec.minH == rec.maxH | |||
| 123 | + | info := WindowInfo{ | |||
| 124 | + | PID: int(rec.pid), | |||
| 125 | + | Floating: floatingType(rec.wtype) || parent != 0 || fixed, | |||
| 126 | + | Parent: parent, | |||
| 127 | + | Modal: rec.modal, | |||
| 128 | + | Fullscreen: rec.fullscreen, | |||
| 129 | + | Title: rec.title, | |||
| 130 | + | AppID: rec.class, | |||
| 131 | + | } | |||
| 132 | + | if info.Floating { | |||
| 133 | + | info.Width, info.Height = int(rec.w), int(rec.h) | |||
| 134 | + | } | |||
| 135 | + | return info | |||
| 136 | + | } | |||
| 137 | + | ||||
| 138 | + | func (x *XWM) onGeomReply(s Slot, rec *record, r *xturbo.Reply) { | |||
| 139 | + | if g, ok := xproto.ParseGetGeometryReply(r.Raw); ok { | |||
| 140 | + | rec.x, rec.y, rec.w, rec.h = int32(g.X()), int32(g.Y()), uint32(g.Width()), uint32(g.Height()) | |||
| 141 | + | } | |||
| 142 | + | rec.pending &^= propGeom | |||
| 143 | + | x.checkReady(s) | |||
| 144 | + | } | |||
| 145 | + | ||||
| 146 | + | // publishLists rewrites _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING. | |||
| 147 | + | func (x *XWM) publishLists() { | |||
| 148 | + | x.setProp32(x.root, atomNetClientList, xproto.AtomWindow, x.clients) | |||
| 149 | + | x.setProp32(x.root, atomNetClientListStacking, xproto.AtomWindow, x.stacking) | |||
| 150 | + | } | |||
| 151 | + | ||||
| 152 | + | // unlist drops xid from both client lists and republishes them if it was in. | |||
| 153 | + | func (x *XWM) unlist(xid uint32) { | |||
| 154 | + | was := len(x.clients) | |||
| 155 | + | x.clients = removeID(x.clients, xid) | |||
| 156 | + | x.stacking = removeID(x.stacking, xid) | |||
| 157 | + | if len(x.clients) != was { | |||
| 158 | + | x.publishLists() | |||
| 159 | + | } | |||
| 160 | + | } | |||
| 161 | + | ||||
| 162 | + | func removeID(l []uint32, xid uint32) []uint32 { | |||
| 163 | + | for i, v := range l { | |||
| 164 | + | if v == xid { | |||
| 165 | + | return append(l[:i], l[i+1:]...) | |||
| 166 | + | } | |||
| 167 | + | } | |||
| 168 | + | return l | |||
| 169 | + | } | |||
| 170 | + | ||||
| 171 | + | // onClientMessage handles WL_SURFACE_SERIAL (pairing), the legacy | |||
| 172 | + | // WL_SURFACE_ID (counted, ignored) and _NET_WM_STATE requests. | |||
| 173 | + | func (x *XWM) onClientMessage(ev *xturbo.Event) { | |||
| 174 | + | e := xproto.ClientMessageOf(ev) | |||
| 175 | + | if e.Format() != 32 { | |||
| 176 | + | return | |||
| 177 | + | } | |||
| 178 | + | typ := uint32(e.Type()) | |||
| 179 | + | switch typ { | |||
| 180 | + | case x.atoms[atomWLSurfaceSerial]: | |||
| 181 | + | s := x.tab.lookup(uint32(e.Window())) | |||
| 182 | + | if s == 0 { | |||
| 183 | + | return | |||
| 184 | + | } | |||
| 185 | + | rec := x.tab.rec(s) | |||
| 186 | + | if rec.serial != 0 { | |||
| 187 | + | x.log.Debug().Uint32("xid", rec.xid).Msg("duplicate WL_SURFACE_SERIAL ignored") | |||
| 188 | + | return | |||
| 189 | + | } | |||
| 190 | + | d := e.Data().Data32() | |||
| 191 | + | rec.serial = uint64(d[1])<<32 | uint64(d[0]) | |||
| 192 | + | x.tryPair(s) | |||
| 193 | + | case x.atoms[atomWLSurfaceID]: | |||
| 194 | + | x.stats.LegacyID++ | |||
| 195 | + | if x.stats.LegacyID == 1 { | |||
| 196 | + | x.log.Warn().Msg("WL_SURFACE_ID received: Xwayland did not bind xwayland_shell_v1, window ignored") | |||
| 197 | + | } | |||
| 198 | + | case x.atoms[atomNetWMState]: | |||
| 199 | + | x.onNetWMState(e) | |||
| 200 | + | } | |||
| 201 | + | } | |||
| 202 | + | ||||
| 203 | + | // onNetWMState forwards fullscreen requests to the host and records them; the | |||
| 204 | + | // property itself is written when core answers with a configure. | |||
| 205 | + | func (x *XWM) onNetWMState(e xproto.ClientMessageEvent) { | |||
| 206 | + | s := x.tab.lookup(uint32(e.Window())) | |||
| 207 | + | if s == 0 { | |||
| 208 | + | return | |||
| 209 | + | } | |||
| 210 | + | rec := x.tab.rec(s) | |||
| 211 | + | if rec.kind != kindManaged { | |||
| 212 | + | return | |||
| 213 | + | } | |||
| 214 | + | d := e.Data().Data32() | |||
| 215 | + | apply := func(cur bool) bool { | |||
| 216 | + | switch d[0] { | |||
| 217 | + | case netStateRemove: | |||
| 218 | + | return false | |||
| 219 | + | case netStateAdd: | |||
| 220 | + | return true | |||
| 221 | + | case netStateToggle: | |||
| 222 | + | return !cur | |||
| 223 | + | } | |||
| 224 | + | return cur | |||
| 225 | + | } | |||
| 226 | + | for _, a := range d[1:3] { | |||
| 227 | + | switch { | |||
| 228 | + | case a == 0: | |||
| 229 | + | case a == x.atoms[atomNetWMStateModal]: | |||
| 230 | + | rec.modal = apply(rec.modal) | |||
| 231 | + | case a == x.atoms[atomNetWMStateFullscreen]: | |||
| 232 | + | on := apply(rec.fullscreen) | |||
| 233 | + | if on == rec.fullscreen { | |||
| 234 | + | continue | |||
| 235 | + | } | |||
| 236 | + | rec.fullscreen = on | |||
| 237 | + | if rec.ready { | |||
| 238 | + | x.host.Fullscreen(s, on) | |||
| 239 | + | rec = x.tab.rec(s) | |||
| 240 | + | } | |||
| 241 | + | } | |||
| 242 | + | } | |||
| 243 | + | } | |||
| 244 | + | ||||
| 245 | + | // onReparentNotify keeps the table to root's direct children: a window moved | |||
| 246 | + | // away is forgotten, one moved into root is treated as newly created. | |||
| 247 | + | func (x *XWM) onReparentNotify(ev *xturbo.Event) { | |||
| 248 | + | e := xproto.ReparentNotifyOf(ev) | |||
| 249 | + | xid := uint32(e.Window()) | |||
| 250 | + | if xid == x.wmWin { | |||
| 251 | + | return | |||
| 252 | + | } | |||
| 253 | + | s := x.tab.lookup(xid) | |||
| 254 | + | if uint32(e.Parent()) != x.root { | |||
| 255 | + | if s != 0 { | |||
| 256 | + | x.dropWindow(s) | |||
| 257 | + | } | |||
| 258 | + | return | |||
| 259 | + | } | |||
| 260 | + | if s != 0 { | |||
| 261 | + | return | |||
| 262 | + | } | |||
| 263 | + | s = x.insert(xid) | |||
| 264 | + | if s == 0 { | |||
| 265 | + | return | |||
| 266 | + | } | |||
| 267 | + | rec := x.tab.rec(s) | |||
| 268 | + | rec.override = e.OverrideRedirect() | |||
| 269 | + | rec.x, rec.y = int32(e.X()), int32(e.Y()) | |||
| 270 | + | if rec.override { | |||
| 271 | + | rec.kind = kindUnmanaged | |||
| 272 | + | x.stats.UnmanagedSeen++ | |||
| 273 | + | return | |||
| 274 | + | } | |||
| 275 | + | if x.host != nil { | |||
| 276 | + | x.adopt(s) | |||
| 277 | + | } | |||
| 278 | + | } | |||
| 279 | + | ||||
| 280 | + | // dropWindow forgets s: the host is told if it knew the window. | |||
| 281 | + | func (x *XWM) dropWindow(s Slot) { | |||
| 282 | + | rec := x.tab.rec(s) | |||
| 283 | + | xid := rec.xid | |||
| 284 | + | if rec.kind == kindManaged { | |||
| 285 | + | x.unlist(xid) | |||
| 286 | + | if x.active == s { | |||
| 287 | + | x.active = 0 | |||
| 288 | + | } | |||
| 289 | + | if rec.id != 0 && x.host != nil { | |||
| 290 | + | rec.id = 0 | |||
| 291 | + | x.host.Dissociate(s, true) | |||
| 292 | + | } | |||
| 293 | + | } | |||
| 294 | + | x.tab.remove(s) | |||
| 295 | + | } | |||
| 296 | + | ||||
| 297 | + | // tryPair links the window to the wl_surface carrying its serial, once both | |||
| 298 | + | // are known and the window is ready (the host maps on the surface's first | |||
| 299 | + | // buffer, so it must know the window's info by then). Unmanaged windows keep | |||
| 300 | + | // the surface but are never associated. | |||
| 301 | + | func (x *XWM) tryPair(s Slot) { | |||
| 302 | + | rec := x.tab.rec(s) | |||
| 303 | + | if rec.serial == 0 || rec.surface != 0 { | |||
| 304 | + | return | |||
| 305 | + | } | |||
| 306 | + | if rec.kind == kindManaged && !rec.ready { | |||
| 307 | + | return | |||
| 308 | + | } | |||
| 309 | + | for i := 0; i < x.unpairedN; i++ { | |||
| 310 | + | if x.unpaired[i].serial != rec.serial { | |||
| 311 | + | continue | |||
| 312 | + | } | |||
| 313 | + | rec.surface = x.unpaired[i].surface | |||
| 314 | + | x.unpairedN-- | |||
| 315 | + | x.unpaired[i] = x.unpaired[x.unpairedN] | |||
| 316 | + | if rec.kind == kindManaged { | |||
| 317 | + | x.log.Debug().Uint32("xid", rec.xid).Uint64("surface", rec.surface).Msg("x11 window paired") | |||
| 318 | + | x.host.Associate(s, rec.surface) | |||
| 319 | + | } | |||
| 320 | + | return | |||
| 321 | + | } | |||
| 322 | + | } | |||
| 323 | + | ||||
| 324 | + | // SetSerial records the serial of a wl_surface (xwayland_surface_v1.set_serial) | |||
| 325 | + | // and pairs it with the window announcing the same serial. | |||
| 326 | + | func (x *XWM) SetSerial(surfaceID uint64, serial uint64) { | |||
| 327 | + | if serial == 0 || x.closed { | |||
| 328 | + | return | |||
| 329 | + | } | |||
| 330 | + | for i := 0; i < x.unpairedN; i++ { | |||
| 331 | + | if x.unpaired[i].serial == serial { | |||
| 332 | + | x.unpaired[i].surface = surfaceID | |||
| 333 | + | x.pairSerial(serial) | |||
| 334 | + | return | |||
| 335 | + | } | |||
| 336 | + | } | |||
| 337 | + | if x.unpairedN == unpairedCap { | |||
| 338 | + | copy(x.unpaired[:], x.unpaired[1:]) | |||
| 339 | + | x.unpairedN-- | |||
| 340 | + | if !x.warnedUnpaired { | |||
| 341 | + | x.warnedUnpaired = true | |||
| 342 | + | x.log.Warn().Msg("too many unpaired surfaces, dropping the oldest") | |||
| 343 | + | } | |||
| 344 | + | } | |||
| 345 | + | x.unpaired[x.unpairedN] = struct{ serial, surface uint64 }{serial, surfaceID} | |||
| 346 | + | x.unpairedN++ | |||
| 347 | + | x.pairSerial(serial) | |||
| 348 | + | } | |||
| 349 | + | ||||
| 350 | + | // pairSerial offers a newly known surface serial to the windows. | |||
| 351 | + | func (x *XWM) pairSerial(serial uint64) { | |||
| 352 | + | for i := range x.tab.recs { | |||
| 353 | + | if r := &x.tab.recs[i]; r.kind != kindFree && r.serial == serial && r.surface == 0 { | |||
| 354 | + | x.tryPair(Slot(i + 1)) | |||
| 355 | + | break | |||
| 356 | + | } | |||
| 357 | + | } | |||
| 358 | + | x.wake() | |||
| 359 | + | } | |||
| 19 | 360 | ||||
| 20 | // SurfaceGone forgets a destroyed wl_surface. | 361 | // SurfaceGone forgets a destroyed wl_surface. | ||
| 21 | - | func (x *XWM) SurfaceGone(surfaceID uint64) { _ = surfaceID } | 362 | + | func (x *XWM) SurfaceGone(surfaceID uint64) { |
| 363 | + | for i := 0; i < x.unpairedN; i++ { | |||
| 364 | + | if x.unpaired[i].surface == surfaceID { | |||
| 365 | + | x.unpairedN-- | |||
| 366 | + | x.unpaired[i] = x.unpaired[x.unpairedN] | |||
| 367 | + | break | |||
| 368 | + | } | |||
| 369 | + | } | |||
| 370 | + | for i := range x.tab.recs { | |||
| 371 | + | if r := &x.tab.recs[i]; r.kind != kindFree && r.surface == surfaceID { | |||
| 372 | + | r.surface = 0 | |||
| 373 | + | } | |||
| 374 | + | } | |||
| 375 | + | x.wake() | |||
| 376 | + | } | |||
A internal/adapters/wayland/xwm/mapflow_test.go +789 -0
| @@ -0,0 +1,789 @@ | |||
| 1 | + | package xwm | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "encoding/binary" | |
| 5 | + | "testing" | |
| 6 | + | ||
| 7 | + | "bnema.dev/xturbo" | |
| 8 | + | "bnema.dev/xturbo/xproto" | |
| 9 | + | "github.com/bnema/neferwl/internal/ports" | |
| 10 | + | "github.com/stretchr/testify/mock" | |
| 11 | + | "github.com/stretchr/testify/require" | |
| 12 | + | ) | |
| 13 | + | ||
| 14 | + | // harness bundles an attached XWM, its peer and the host mock. | |
| 15 | + | type harness struct { | |
| 16 | + | t *testing.T | |
| 17 | + | x *XWM | |
| 18 | + | p *xpeer | |
| 19 | + | h *mockhost | |
| 20 | + | ||
| 21 | + | ready map[uint32]WindowInfo // by xid, filled by Ready | |
| 22 | + | next ports.WindowID | |
| 23 | + | } | |
| 24 | + | ||
| 25 | + | func newHarness(t *testing.T, mutate func(p *xpeer)) *harness { | |
| 26 | + | t.Helper() | |
| 27 | + | x, p := bootPeer(t, mutate) | |
| 28 | + | hs := &harness{t: t, x: x, p: p, h: newMockhost(t), ready: map[uint32]WindowInfo{}} | |
| 29 | + | src := newMockfdSource(t) | |
| 30 | + | src.EXPECT().Remove().Maybe() | |
| 31 | + | src.EXPECT().SetWritable(mock.Anything).Return(nil).Maybe() | |
| 32 | + | post, _ := newPost() | |
| 33 | + | x.attach(src, hs.h, post) | |
| 34 | + | return hs | |
| 35 | + | } | |
| 36 | + | ||
| 37 | + | func (hs *harness) expectCreated(win uint32) { | |
| 38 | + | hs.next++ | |
| 39 | + | hs.h.EXPECT().Created(mock.Anything, win).Return(hs.next).Once() | |
| 40 | + | } | |
| 41 | + | ||
| 42 | + | func (hs *harness) expectReady(win uint32) { | |
| 43 | + | hs.h.EXPECT().Ready(mock.Anything, mock.Anything).Run(func(_ Slot, info WindowInfo) { | |
| 44 | + | hs.ready[win] = info | |
| 45 | + | }).Once() | |
| 46 | + | } | |
| 47 | + | ||
| 48 | + | func (hs *harness) create(win uint32) Slot { | |
| 49 | + | hs.t.Helper() | |
| 50 | + | hs.expectCreated(win) | |
| 51 | + | hs.p.createNotify(win, false) | |
| 52 | + | readUntil(hs.t, hs.x, func() bool { return hs.x.Slot(win) != 0 }) | |
| 53 | + | return hs.x.Slot(win) | |
| 54 | + | } | |
| 55 | + | ||
| 56 | + | // mapAndWait creates and maps win and waits for Ready. | |
| 57 | + | func (hs *harness) mapAndWait(win uint32) Slot { | |
| 58 | + | hs.t.Helper() | |
| 59 | + | s := hs.create(win) | |
| 60 | + | hs.expectReady(win) | |
| 61 | + | hs.p.mapRequest(win) | |
| 62 | + | readUntil(hs.t, hs.x, func() bool { _, ok := hs.ready[win]; return ok }) | |
| 63 | + | return s | |
| 64 | + | } | |
| 65 | + | ||
| 66 | + | func (hs *harness) str(win uint32, atom string, typ uint32, s string) { | |
| 67 | + | hs.p.setProp(win, hs.p.atom(atom), typ, 8, []byte(s)) | |
| 68 | + | } | |
| 69 | + | ||
| 70 | + | func (hs *harness) words(win uint32, atom string, typ uint32, w ...uint32) { | |
| 71 | + | hs.p.setProp(win, hs.p.atom(atom), typ, 32, le32(w...)) | |
| 72 | + | } | |
| 73 | + | ||
| 74 | + | func (hs *harness) atoms(win uint32, atom string, names ...string) { | |
| 75 | + | var w []uint32 | |
| 76 | + | for _, n := range names { | |
| 77 | + | w = append(w, hs.p.atom(n)) | |
| 78 | + | } | |
| 79 | + | hs.words(win, atom, uint32(xproto.AtomAtom), w...) | |
| 80 | + | } | |
| 81 | + | ||
| 82 | + | func (hs *harness) classic(win uint32) { | |
| 83 | + | hs.p.setProp(win, uint32(xproto.AtomWmClass), uint32(xproto.AtomString), 8, []byte("inst\x00Class\x00")) | |
| 84 | + | hs.str(win, "_NET_WM_NAME", hs.p.atom("UTF8_STRING"), "net title") | |
| 85 | + | hs.p.setProp(win, uint32(xproto.AtomWmName), uint32(xproto.AtomString), 8, []byte("old title")) | |
| 86 | + | hs.words(win, "_NET_WM_PID", uint32(xproto.AtomCardinal), 4242) | |
| 87 | + | hs.p.set(func(p *xpeer) { p.geoms[win] = xpeerGeom{w: 300, h: 200} }) | |
| 88 | + | } | |
| 89 | + | ||
| 90 | + | func (hs *harness) count(match func(r xpeerReq) bool) int { | |
| 91 | + | n := 0 | |
| 92 | + | for _, r := range hs.p.requests() { | |
| 93 | + | if match(r) { | |
| 94 | + | n++ | |
| 95 | + | } | |
| 96 | + | } | |
| 97 | + | return n | |
| 98 | + | } | |
| 99 | + | ||
| 100 | + | func (hs *harness) waitMap(win uint32) { | |
| 101 | + | hs.t.Helper() | |
| 102 | + | readUntil(hs.t, hs.x, func() bool { | |
| 103 | + | return hs.count(func(r xpeerReq) bool { return r.major == opMapWindow && r.u32(4) == win }) > 0 | |
| 104 | + | }) | |
| 105 | + | } | |
| 106 | + | ||
| 107 | + | func TestMapFlowBatchesRequestsAndReadyFiresOnce(t *testing.T) { | |
| 108 | + | hs := newHarness(t, nil) | |
| 109 | + | const win = 0x500001 | |
| 110 | + | hs.classic(win) | |
| 111 | + | hs.create(win) | |
| 112 | + | base := len(hs.p.requests()) | |
| 113 | + | ||
| 114 | + | hs.p.holdReplies() | |
| 115 | + | hs.p.mapRequest(win) | |
| 116 | + | hs.expectReady(win) | |
| 117 | + | hs.waitMap(win) | |
| 118 | + | ||
| 119 | + | reqs := hs.p.requests()[base:] | |
| 120 | + | want := []uint32{ | |
| 121 | + | uint32(xproto.AtomWmClass), uint32(xproto.AtomWmName), hs.p.atom("_NET_WM_NAME"), uint32(xproto.AtomWmHints), | |
| 122 | + | uint32(xproto.AtomWmNormalHints), hs.p.atom("WM_PROTOCOLS"), uint32(xproto.AtomWmTransientFor), | |
| 123 | + | hs.p.atom("_NET_WM_WINDOW_TYPE"), hs.p.atom("_NET_WM_STATE"), hs.p.atom("_NET_WM_PID"), | |
| 124 | + | } | |
| 125 | + | require.GreaterOrEqual(t, len(reqs), len(want)+2) | |
| 126 | + | for i, a := range want { | |
| 127 | + | require.EqualValues(t, opGetProperty, reqs[i].major, i) | |
| 128 | + | require.Equal(t, uint32(win), reqs[i].u32(4)) | |
| 129 | + | require.Equal(t, a, reqs[i].u32(8), i) | |
| 130 | + | require.EqualValues(t, 1024, reqs[i].u32(20), "long length: one 4 KiB read") | |
| 131 | + | } | |
| 132 | + | require.EqualValues(t, opGetGeometry, reqs[len(want)].major) | |
| 133 | + | require.EqualValues(t, opMapWindow, reqs[len(want)+1].major, "MapWindow in the same batch") | |
| 134 | + | ||
| 135 | + | hs.p.release() // every reply arrives after MapWindow went out | |
| 136 | + | readUntil(t, hs.x, func() bool { _, ok := hs.ready[win]; return ok }) | |
| 137 | + | info := hs.ready[win] | |
| 138 | + | require.Equal(t, WindowInfo{PID: 4242, Title: "net title", AppID: "Class"}, info, "_NET_WM_NAME wins, class is the second string") | |
| 139 | + | ||
| 140 | + | state, ok := hs.p.prop(win, "WM_STATE") | |
| 141 | + | require.True(t, ok) | |
| 142 | + | require.Equal(t, []uint32{1, 0}, atomsOf(state)) | |
| 143 | + | list, ok := hs.p.prop(peerRoot, "_NET_CLIENT_LIST") | |
| 144 | + | require.True(t, ok) | |
| 145 | + | require.Equal(t, []uint32{win}, atomsOf(list)) | |
| 146 | + | } | |
| 147 | + | ||
| 148 | + | func TestMapFlowFloatingAndModal(t *testing.T) { | |
| 149 | + | hint := func(minw, minh, maxw, maxh uint32) []byte { | |
| 150 | + | return le32(hintMinSize|hintMaxSize, 0, 0, 0, 0, minw, minh, maxw, maxh, 0, 0, 0, 0, 0, 0, 0, 0, 0) | |
| 151 | + | } | |
| 152 | + | cases := []struct { | |
| 153 | + | name string | |
| 154 | + | setup func(hs *harness, win uint32) | |
| 155 | + | want func(info WindowInfo) | |
| 156 | + | }{ | |
| 157 | + | {"dialog type", func(hs *harness, w uint32) { | |
| 158 | + | hs.atoms(w, "_NET_WM_WINDOW_TYPE", "_NET_WM_WINDOW_TYPE_DIALOG") | |
| 159 | + | }, func(i WindowInfo) { | |
| 160 | + | require.True(t, i.Floating) | |
| 161 | + | require.Equal(t, 300, i.Width) | |
| 162 | + | require.Equal(t, 200, i.Height) | |
| 163 | + | }}, | |
| 164 | + | {"utility type", func(hs *harness, w uint32) { | |
| 165 | + | hs.atoms(w, "_NET_WM_WINDOW_TYPE", "_NET_WM_WINDOW_TYPE_UTILITY") | |
| 166 | + | }, func(i WindowInfo) { require.True(t, i.Floating) }}, | |
| 167 | + | {"splash type", func(hs *harness, w uint32) { | |
| 168 | + | hs.atoms(w, "_NET_WM_WINDOW_TYPE", "_NET_WM_WINDOW_TYPE_SPLASH") | |
| 169 | + | }, func(i WindowInfo) { require.True(t, i.Floating) }}, | |
| 170 | + | {"normal type", func(hs *harness, w uint32) { | |
| 171 | + | hs.atoms(w, "_NET_WM_WINDOW_TYPE", "_NET_WM_WINDOW_TYPE_NORMAL") | |
| 172 | + | }, func(i WindowInfo) { require.False(t, i.Floating); require.Zero(t, i.Width) }}, | |
| 173 | + | {"fixed size", func(hs *harness, w uint32) { | |
| 174 | + | hs.p.setProp(w, uint32(xproto.AtomWmNormalHints), uint32(xproto.AtomWmSizeHints), 32, hint(200, 100, 200, 100)) | |
| 175 | + | }, func(i WindowInfo) { require.True(t, i.Floating) }}, | |
| 176 | + | {"resizable", func(hs *harness, w uint32) { | |
| 177 | + | hs.p.setProp(w, uint32(xproto.AtomWmNormalHints), uint32(xproto.AtomWmSizeHints), 32, hint(100, 100, 800, 600)) | |
| 178 | + | }, func(i WindowInfo) { require.False(t, i.Floating) }}, | |
| 179 | + | {"modal", func(hs *harness, w uint32) { | |
| 180 | + | hs.atoms(w, "_NET_WM_STATE", "_NET_WM_STATE_MODAL") | |
| 181 | + | }, func(i WindowInfo) { require.True(t, i.Modal); require.False(t, i.Fullscreen) }}, | |
| 182 | + | {"fullscreen at map", func(hs *harness, w uint32) { | |
| 183 | + | hs.atoms(w, "_NET_WM_STATE", "_NET_WM_STATE_FULLSCREEN") | |
| 184 | + | }, func(i WindowInfo) { require.True(t, i.Fullscreen) }}, | |
| 185 | + | } | |
| 186 | + | for _, c := range cases { | |
| 187 | + | t.Run(c.name, func(t *testing.T) { | |
| 188 | + | hs := newHarness(t, nil) | |
| 189 | + | const win = 0x500001 | |
| 190 | + | hs.classic(win) | |
| 191 | + | c.setup(hs, win) | |
| 192 | + | hs.mapAndWait(win) | |
| 193 | + | c.want(hs.ready[win]) | |
| 194 | + | }) | |
| 195 | + | } | |
| 196 | + | } | |
| 197 | + | ||
| 198 | + | func TestMapFlowTransientForManagedWindowFloats(t *testing.T) { | |
| 199 | + | hs := newHarness(t, nil) | |
| 200 | + | const parent, child = 0x500001, 0x500002 | |
| 201 | + | hs.classic(parent) | |
| 202 | + | ps := hs.mapAndWait(parent) | |
| 203 | + | hs.classic(child) | |
| 204 | + | hs.p.setProp(child, uint32(xproto.AtomWmTransientFor), uint32(xproto.AtomWindow), 32, le32(parent)) | |
| 205 | + | hs.mapAndWait(child) | |
| 206 | + | require.True(t, hs.ready[child].Floating) | |
| 207 | + | require.Equal(t, ps, hs.ready[child].Parent) | |
| 208 | + | } | |
| 209 | + | ||
| 210 | + | func TestMapFlowTransientForUnknownWindowIsNotAParent(t *testing.T) { | |
| 211 | + | hs := newHarness(t, nil) | |
| 212 | + | const win = 0x500001 | |
| 213 | + | hs.classic(win) | |
| 214 | + | hs.p.setProp(win, uint32(xproto.AtomWmTransientFor), uint32(xproto.AtomWindow), 32, le32(0x777777)) | |
| 215 | + | hs.mapAndWait(win) | |
| 216 | + | require.Zero(t, hs.ready[win].Parent) | |
| 217 | + | require.False(t, hs.ready[win].Floating) | |
| 218 | + | } | |
| 219 | + | ||
| 220 | + | func TestMapFlowClassFallsBackToInstance(t *testing.T) { | |
| 221 | + | hs := newHarness(t, nil) | |
| 222 | + | const win = 0x500001 | |
| 223 | + | hs.classic(win) | |
| 224 | + | hs.p.setProp(win, uint32(xproto.AtomWmClass), uint32(xproto.AtomString), 8, []byte("onlyinstance\x00")) | |
| 225 | + | hs.mapAndWait(win) | |
| 226 | + | require.Equal(t, "onlyinstance", hs.ready[win].AppID) | |
| 227 | + | } | |
| 228 | + | ||
| 229 | + | func TestMapFlowTitleFallsBackToWMName(t *testing.T) { | |
| 230 | + | hs := newHarness(t, nil) | |
| 231 | + | const win = 0x500001 | |
| 232 | + | hs.classic(win) | |
| 233 | + | hs.p.set(func(p *xpeer) { delete(p.props[win], p.atoms["_NET_WM_NAME"]) }) | |
| 234 | + | hs.mapAndWait(win) | |
| 235 | + | require.Equal(t, "old title", hs.ready[win].Title) | |
| 236 | + | } | |
| 237 | + | ||
| 238 | + | func TestMapFlowPIDFromXRes(t *testing.T) { | |
| 239 | + | hs := newHarness(t, func(p *xpeer) { p.pids = map[uint32]uint32{0x500001: 777} }) | |
| 240 | + | const win = 0x500001 | |
| 241 | + | hs.classic(win) | |
| 242 | + | hs.p.set(func(p *xpeer) { delete(p.props[win], p.atoms["_NET_WM_PID"]) }) | |
| 243 | + | hs.create(win) | |
| 244 | + | hs.expectReady(win) | |
| 245 | + | hs.p.mapRequest(win) | |
| 246 | + | readUntil(t, hs.x, func() bool { _, ok := hs.ready[win]; return ok }) | |
| 247 | + | require.Equal(t, 777, hs.ready[win].PID, "Ready waited for the QueryClientIds reply") | |
| 248 | + | require.Equal(t, 1, hs.count(func(r xpeerReq) bool { return r.major == 144 && r.minor == 4 })) | |
| 249 | + | require.Zero(t, hs.x.tab.rec(hs.x.Slot(win)).pending) | |
| 250 | + | } | |
| 251 | + | ||
| 252 | + | func TestMapFlowPIDUnknownStillReady(t *testing.T) { | |
| 253 | + | hs := newHarness(t, nil) | |
| 254 | + | const win = 0x500001 | |
| 255 | + | hs.classic(win) | |
| 256 | + | hs.p.set(func(p *xpeer) { delete(p.props[win], p.atoms["_NET_WM_PID"]) }) | |
| 257 | + | hs.mapAndWait(win) | |
| 258 | + | require.Zero(t, hs.ready[win].PID) | |
| 259 | + | } | |
| 260 | + | ||
| 261 | + | func TestMapFlowNoXResAsksNothing(t *testing.T) { | |
| 262 | + | exts := fullPeerExts() | |
| 263 | + | delete(exts, "X-Resource") | |
| 264 | + | fd, p := startXPeer(t, exts) | |
| 265 | + | x, err := Boot(fd, testLog()) | |
| 266 | + | require.NoError(t, err) | |
| 267 | + | t.Cleanup(x.CloseConn) | |
| 268 | + | h := newMockhost(t) | |
| 269 | + | src := newMockfdSource(t) | |
| 270 | + | src.EXPECT().Remove().Maybe() | |
| 271 | + | post, _ := newPost() | |
| 272 | + | x.attach(src, h, post) | |
| 273 | + | hs := &harness{t: t, x: x, p: p, h: h, ready: map[uint32]WindowInfo{}} | |
| 274 | + | const win = 0x500001 | |
| 275 | + | hs.classic(win) | |
| 276 | + | p.set(func(p *xpeer) { delete(p.props[win], p.atoms["_NET_WM_PID"]) }) | |
| 277 | + | hs.mapAndWait(win) | |
| 278 | + | require.Zero(t, hs.count(func(r xpeerReq) bool { return r.major == 144 })) | |
| 279 | + | } | |
| 280 | + | ||
| 281 | + | func TestMapFlowBadWindowOnPropertiesNeverReady(t *testing.T) { | |
| 282 | + | hs := newHarness(t, nil) | |
| 283 | + | const win = 0x500001 | |
| 284 | + | hs.classic(win) | |
| 285 | + | hs.p.set(func(p *xpeer) { p.bad[win] = true }) | |
| 286 | + | s := hs.create(win) | |
| 287 | + | hs.p.mapRequest(win) | |
| 288 | + | readUntil(t, hs.x, func() bool { return hs.x.Stats().Errors >= uint64(propCount)+1 }) | |
| 289 | + | require.Zero(t, hs.x.tab.rec(s).pending, "failed replies are no longer awaited") | |
| 290 | + | require.False(t, hs.x.tab.rec(s).ready) | |
| 291 | + | require.Zero(t, hs.x.Stats().Unattributed) | |
| 292 | + | ||
| 293 | + | hs.h.EXPECT().Dissociate(s, true).Once() | |
| 294 | + | hs.p.destroyNotify(win) | |
| 295 | + | readUntil(t, hs.x, func() bool { return hs.x.Slot(win) == 0 }) | |
| 296 | + | } | |
| 297 | + | ||
| 298 | + | func TestMapRequestTwiceBeforeReadyAsksOnce(t *testing.T) { | |
| 299 | + | hs := newHarness(t, nil) | |
| 300 | + | const win = 0x500001 | |
| 301 | + | hs.classic(win) | |
| 302 | + | hs.create(win) | |
| 303 | + | hs.p.holdReplies() | |
| 304 | + | hs.p.mapRequest(win) | |
| 305 | + | hs.p.mapRequest(win) | |
| 306 | + | hs.expectReady(win) | |
| 307 | + | hs.waitMap(win) | |
| 308 | + | hs.p.release() | |
| 309 | + | readUntil(t, hs.x, func() bool { _, ok := hs.ready[win]; return ok }) | |
| 310 | + | require.Equal(t, 1, hs.count(func(r xpeerReq) bool { return r.major == opMapWindow && r.u32(4) == win })) | |
| 311 | + | } | |
| 312 | + | ||
| 313 | + | func TestMapNotifyMarksMapped(t *testing.T) { | |
| 314 | + | hs := newHarness(t, nil) | |
| 315 | + | const win = 0x500001 | |
| 316 | + | hs.classic(win) | |
| 317 | + | s := hs.mapAndWait(win) | |
| 318 | + | hs.p.mapNotify(win) | |
| 319 | + | readUntil(t, hs.x, func() bool { return hs.x.tab.rec(s).mapped }) | |
| 320 | + | } | |
| 321 | + | ||
| 322 | + | // Property changes after Ready. | |
| 323 | + | ||
| 324 | + | func (hs *harness) notify(win uint32, atom string, deleted bool) { | |
| 325 | + | hs.t.Helper() | |
| 326 | + | before := hs.x.Stats().Replies | |
| 327 | + | hs.p.propertyNotify(win, hs.p.atom(atom), deleted) | |
| 328 | + | if deleted { | |
| 329 | + | hs.p.propertyNotify(win, hs.p.atom("WM_PROTOCOLS"), false) // sentinel: one reply follows | |
| 330 | + | readUntil(hs.t, hs.x, func() bool { return hs.x.Stats().Replies > before }) | |
| 331 | + | return | |
| 332 | + | } | |
| 333 | + | readUntil(hs.t, hs.x, func() bool { return hs.x.Stats().Replies > before }) | |
| 334 | + | } | |
| 335 | + | ||
| 336 | + | func TestPropertyChangedTitleReachesHostOnce(t *testing.T) { | |
| 337 | + | hs := newHarness(t, nil) | |
| 338 | + | const win = 0x500001 | |
| 339 | + | hs.classic(win) | |
| 340 | + | s := hs.mapAndWait(win) | |
| 341 | + | ||
| 342 | + | hs.h.EXPECT().Title(s, "renamed").Once() | |
| 343 | + | hs.str(win, "_NET_WM_NAME", hs.p.atom("UTF8_STRING"), "renamed") | |
| 344 | + | hs.notify(win, "_NET_WM_NAME", false) | |
| 345 | + | require.Equal(t, "renamed", hs.x.tab.rec(s).title) | |
| 346 | + | ||
| 347 | + | // Same value again: no host call (the mock fails on an unexpected one). | |
| 348 | + | hs.notify(win, "_NET_WM_NAME", false) | |
| 349 | + | ||
| 350 | + | // WM_NAME is ignored while _NET_WM_NAME is set. | |
| 351 | + | hs.p.setProp(win, uint32(xproto.AtomWmName), uint32(xproto.AtomString), 8, []byte("legacy")) | |
| 352 | + | before := hs.x.Stats().Events | |
| 353 | + | hs.p.propertyNotify(win, uint32(xproto.AtomWmName), false) | |
| 354 | + | readUntil(t, hs.x, func() bool { return hs.x.Stats().Events > before }) | |
| 355 | + | require.Equal(t, "renamed", hs.x.tab.rec(s).title) | |
| 356 | + | } | |
| 357 | + | ||
| 358 | + | func TestPropertyNetNameDeletedFallsBackToWMName(t *testing.T) { | |
| 359 | + | hs := newHarness(t, nil) | |
| 360 | + | const win = 0x500001 | |
| 361 | + | hs.classic(win) | |
| 362 | + | s := hs.mapAndWait(win) | |
| 363 | + | hs.p.set(func(p *xpeer) { delete(p.props[win], p.atoms["_NET_WM_NAME"]) }) | |
| 364 | + | hs.h.EXPECT().Title(s, "old title").Once() | |
| 365 | + | hs.p.propertyNotify(win, hs.p.atom("_NET_WM_NAME"), true) | |
| 366 | + | readUntil(t, hs.x, func() bool { return hs.x.tab.rec(s).title == "old title" }) | |
| 367 | + | } | |
| 368 | + | ||
| 369 | + | func TestPropertyClassChangeReachesHost(t *testing.T) { | |
| 370 | + | hs := newHarness(t, nil) | |
| 371 | + | const win = 0x500001 | |
| 372 | + | hs.classic(win) | |
| 373 | + | s := hs.mapAndWait(win) | |
| 374 | + | hs.h.EXPECT().AppID(s, "Other").Once() | |
| 375 | + | hs.p.setProp(win, uint32(xproto.AtomWmClass), uint32(xproto.AtomString), 8, []byte("i\x00Other\x00")) | |
| 376 | + | hs.p.propertyNotify(win, uint32(xproto.AtomWmClass), false) | |
| 377 | + | readUntil(t, hs.x, func() bool { return hs.x.tab.rec(s).class == "Other" }) | |
| 378 | + | } | |
| 379 | + | ||
| 380 | + | func TestPropertyTransientChangeReachesHost(t *testing.T) { | |
| 381 | + | hs := newHarness(t, nil) | |
| 382 | + | const a, b = 0x500001, 0x500002 | |
| 383 | + | hs.classic(a) | |
| 384 | + | as := hs.mapAndWait(a) | |
| 385 | + | hs.classic(b) | |
| 386 | + | bs := hs.mapAndWait(b) | |
| 387 | + | hs.h.EXPECT().Parent(bs, as).Once() | |
| 388 | + | hs.p.setProp(b, uint32(xproto.AtomWmTransientFor), uint32(xproto.AtomWindow), 32, le32(a)) | |
| 389 | + | hs.p.propertyNotify(b, uint32(xproto.AtomWmTransientFor), false) | |
| 390 | + | readUntil(t, hs.x, func() bool { return hs.x.tab.rec(bs).transient == a }) | |
| 391 | + | } | |
| 392 | + | ||
| 393 | + | func TestPropertyFullscreenStateChangeReachesHost(t *testing.T) { | |
| 394 | + | hs := newHarness(t, nil) | |
| 395 | + | const win = 0x500001 | |
| 396 | + | hs.classic(win) | |
| 397 | + | s := hs.mapAndWait(win) | |
| 398 | + | hs.h.EXPECT().Fullscreen(s, true).Once() | |
| 399 | + | hs.atoms(win, "_NET_WM_STATE", "_NET_WM_STATE_FULLSCREEN") | |
| 400 | + | hs.p.propertyNotify(win, hs.p.atom("_NET_WM_STATE"), false) | |
| 401 | + | readUntil(t, hs.x, func() bool { return hs.x.tab.rec(s).fullscreen }) | |
| 402 | + | } | |
| 403 | + | ||
| 404 | + | func TestPropertyInputProtocolsAndHints(t *testing.T) { | |
| 405 | + | hs := newHarness(t, nil) | |
| 406 | + | const win = 0x500001 | |
| 407 | + | hs.classic(win) | |
| 408 | + | hs.atoms(win, "WM_PROTOCOLS", "WM_DELETE_WINDOW", "WM_TAKE_FOCUS") | |
| 409 | + | hs.p.setProp(win, uint32(xproto.AtomWmHints), uint32(xproto.AtomWmHints), 32, le32(hintInput, 0, 0, 0, 0, 0, 0, 0, 0)) | |
| 410 | + | s := hs.mapAndWait(win) | |
| 411 | + | r := hs.x.tab.rec(s) | |
| 412 | + | require.True(t, r.deleteWindow) | |
| 413 | + | require.True(t, r.takeFocus) | |
| 414 | + | require.False(t, r.input, "WM_HINTS input = false") | |
| 415 | + | ||
| 416 | + | // No WM_HINTS: input defaults to true. | |
| 417 | + | const other = 0x500002 | |
| 418 | + | hs.classic(other) | |
| 419 | + | o := hs.mapAndWait(other) | |
| 420 | + | require.True(t, hs.x.tab.rec(o).input) | |
| 421 | + | require.False(t, hs.x.tab.rec(o).deleteWindow) | |
| 422 | + | } | |
| 423 | + | ||
| 424 | + | func TestPropertyUnwatchedAtomAsksNothing(t *testing.T) { | |
| 425 | + | hs := newHarness(t, nil) | |
| 426 | + | const win = 0x500001 | |
| 427 | + | hs.classic(win) | |
| 428 | + | hs.mapAndWait(win) | |
| 429 | + | n := len(hs.p.requests()) | |
| 430 | + | hs.p.propertyNotify(win, hs.p.atom("_MOTIF_WM_HINTS"), false) | |
| 431 | + | hs.p.propertyNotify(0x999999, hs.p.atom("_NET_WM_NAME"), false) // unknown window | |
| 432 | + | readUntil(t, hs.x, func() bool { return hs.x.Stats().Events >= 2 }) | |
| 433 | + | require.Len(t, hs.p.requests(), n) | |
| 434 | + | } | |
| 435 | + | ||
| 436 | + | // Pairing. | |
| 437 | + | ||
| 438 | + | func (hs *harness) serialMsg(win uint32, serial uint64) { | |
| 439 | + | hs.p.clientMessage(win, hs.p.atom("WL_SURFACE_SERIAL"), uint32(serial), uint32(serial>>32)) | |
| 440 | + | hs.t.Helper() | |
| 441 | + | before := hs.x.Stats().Events | |
| 442 | + | readUntil(hs.t, hs.x, func() bool { return hs.x.Stats().Events > before }) | |
| 443 | + | } | |
| 444 | + | ||
| 445 | + | func TestPairingSerialBeforeSetSerial(t *testing.T) { | |
| 446 | + | hs := newHarness(t, nil) | |
| 447 | + | const win = 0x500001 | |
| 448 | + | hs.classic(win) | |
| 449 | + | s := hs.mapAndWait(win) | |
| 450 | + | hs.serialMsg(win, 0x1_0000_0002) | |
| 451 | + | require.EqualValues(t, 0x1_0000_0002, hs.x.tab.rec(s).serial, "high word in data32[1]") | |
| 452 | + | hs.h.EXPECT().Associate(s, uint64(99)).Once() | |
| 453 | + | hs.x.SetSerial(99, 0x1_0000_0002) | |
| 454 | + | require.EqualValues(t, 99, hs.x.tab.rec(s).surface) | |
| 455 | + | require.Zero(t, hs.x.unpairedN) | |
| 456 | + | } | |
| 457 | + | ||
| 458 | + | func TestPairingSetSerialBeforeSerial(t *testing.T) { | |
| 459 | + | hs := newHarness(t, nil) | |
| 460 | + | const win = 0x500001 | |
| 461 | + | hs.classic(win) | |
| 462 | + | s := hs.mapAndWait(win) | |
| 463 | + | hs.x.SetSerial(99, 7) | |
| 464 | + | require.Equal(t, 1, hs.x.unpairedN) | |
| 465 | + | hs.h.EXPECT().Associate(s, uint64(99)).Once() | |
| 466 | + | hs.serialMsg(win, 7) | |
| 467 | + | require.Zero(t, hs.x.unpairedN) | |
| 468 | + | } | |
| 469 | + | ||
| 470 | + | func TestPairingWaitsForReady(t *testing.T) { | |
| 471 | + | hs := newHarness(t, nil) | |
| 472 | + | const win = 0x500001 | |
| 473 | + | hs.classic(win) | |
| 474 | + | s := hs.create(win) | |
| 475 | + | hs.x.SetSerial(5, 3) | |
| 476 | + | hs.serialMsg(win, 3) // not mapped yet: no Associate (the mock fails on one) | |
| 477 | + | require.Zero(t, hs.x.tab.rec(s).surface) | |
| 478 | + | ||
| 479 | + | hs.h.EXPECT().Associate(s, uint64(5)).Once() | |
| 480 | + | hs.expectReady(win) | |
| 481 | + | hs.p.mapRequest(win) | |
| 482 | + | readUntil(t, hs.x, func() bool { return hs.x.tab.rec(s).surface != 0 }) | |
| 483 | + | } | |
| 484 | + | ||
| 485 | + | func TestPairingSerialForUnknownWindowIgnored(t *testing.T) { | |
| 486 | + | hs := newHarness(t, nil) | |
| 487 | + | hs.x.SetSerial(5, 3) | |
| 488 | + | hs.serialMsg(0x888888, 3) | |
| 489 | + | require.Equal(t, 1, hs.x.unpairedN, "stays unpaired") | |
| 490 | + | } | |
| 491 | + | ||
| 492 | + | func TestPairingSurfaceGoneBeforePair(t *testing.T) { | |
| 493 | + | hs := newHarness(t, nil) | |
| 494 | + | const win = 0x500001 | |
| 495 | + | hs.classic(win) | |
| 496 | + | s := hs.mapAndWait(win) | |
| 497 | + | hs.x.SetSerial(5, 3) | |
| 498 | + | hs.x.SurfaceGone(5) | |
| 499 | + | require.Zero(t, hs.x.unpairedN) | |
| 500 | + | hs.serialMsg(win, 3) // the surface is gone: nothing to pair with | |
| 501 | + | require.Zero(t, hs.x.tab.rec(s).surface) | |
| 502 | + | } | |
| 503 | + | ||
| 504 | + | func TestPairingSurfaceGoneAfterPairClearsLink(t *testing.T) { | |
| 505 | + | hs := newHarness(t, nil) | |
| 506 | + | const win = 0x500001 | |
| 507 | + | hs.classic(win) | |
| 508 | + | s := hs.mapAndWait(win) | |
| 509 | + | hs.serialMsg(win, 3) | |
| 510 | + | hs.h.EXPECT().Associate(s, uint64(5)).Once() | |
| 511 | + | hs.x.SetSerial(5, 3) | |
| 512 | + | hs.x.SurfaceGone(5) | |
| 513 | + | require.Zero(t, hs.x.tab.rec(s).surface) | |
| 514 | + | } | |
| 515 | + | ||
| 516 | + | func TestPairingDuplicateSerialIgnored(t *testing.T) { | |
| 517 | + | hs := newHarness(t, nil) | |
| 518 | + | const win = 0x500001 | |
| 519 | + | hs.classic(win) | |
| 520 | + | s := hs.mapAndWait(win) | |
| 521 | + | hs.serialMsg(win, 3) | |
| 522 | + | hs.serialMsg(win, 4) | |
| 523 | + | require.EqualValues(t, 3, hs.x.tab.rec(s).serial) | |
| 524 | + | hs.x.SetSerial(8, 4) // nobody announces 4: stays unpaired | |
| 525 | + | require.Equal(t, 1, hs.x.unpairedN) | |
| 526 | + | } | |
| 527 | + | ||
| 528 | + | func TestPairingUnmanagedKeepsSurfaceWithoutAssociate(t *testing.T) { | |
| 529 | + | hs := newHarness(t, nil) | |
| 530 | + | hs.p.createNotify(0x500009, true) | |
| 531 | + | readUntil(t, hs.x, func() bool { return hs.x.Slot(0x500009) != 0 }) | |
| 532 | + | hs.serialMsg(0x500009, 3) | |
| 533 | + | hs.x.SetSerial(5, 3) // the mock fails on an Associate | |
| 534 | + | require.EqualValues(t, 5, hs.x.tab.rec(hs.x.Slot(0x500009)).surface) | |
| 535 | + | } | |
| 536 | + | ||
| 537 | + | func TestPairingTableOverflowDropsOldest(t *testing.T) { | |
| 538 | + | hs := newHarness(t, nil) | |
| 539 | + | for i := uint64(1); i <= unpairedCap+1; i++ { | |
| 540 | + | hs.x.SetSerial(100+i, i) | |
| 541 | + | } | |
| 542 | + | require.Equal(t, unpairedCap, hs.x.unpairedN) | |
| 543 | + | for i := 0; i < hs.x.unpairedN; i++ { | |
| 544 | + | require.NotEqual(t, uint64(1), hs.x.unpaired[i].serial, "oldest dropped") | |
| 545 | + | } | |
| 546 | + | } | |
| 547 | + | ||
| 548 | + | func TestPairingZeroSerialIgnored(t *testing.T) { | |
| 549 | + | hs := newHarness(t, nil) | |
| 550 | + | hs.x.SetSerial(5, 0) | |
| 551 | + | require.Zero(t, hs.x.unpairedN) | |
| 552 | + | } | |
| 553 | + | ||
| 554 | + | func TestLegacySurfaceIDCountedAndIgnored(t *testing.T) { | |
| 555 | + | hs := newHarness(t, nil) | |
| 556 | + | const win = 0x500001 | |
| 557 | + | hs.classic(win) | |
| 558 | + | s := hs.mapAndWait(win) | |
| 559 | + | hs.p.clientMessage(win, hs.p.atom("WL_SURFACE_ID"), 12) | |
| 560 | + | readUntil(t, hs.x, func() bool { return hs.x.Stats().LegacyID == 1 }) | |
| 561 | + | require.Zero(t, hs.x.tab.rec(s).serial) | |
| 562 | + | } | |
| 563 | + | ||
| 564 | + | func TestNetWMStateClientMessageForwardsFullscreen(t *testing.T) { | |
| 565 | + | hs := newHarness(t, nil) | |
| 566 | + | const win = 0x500001 | |
| 567 | + | hs.classic(win) | |
| 568 | + | s := hs.mapAndWait(win) | |
| 569 | + | hs.h.EXPECT().Fullscreen(s, true).Once() | |
| 570 | + | hs.p.clientMessage(win, hs.p.atom("_NET_WM_STATE"), 1, hs.p.atom("_NET_WM_STATE_FULLSCREEN")) | |
| 571 | + | readUntil(t, hs.x, func() bool { return hs.x.tab.rec(s).fullscreen }) | |
| 572 | + | hs.h.EXPECT().Fullscreen(s, false).Once() // toggle | |
| 573 | + | hs.p.clientMessage(win, hs.p.atom("_NET_WM_STATE"), 2, hs.p.atom("_NET_WM_STATE_FULLSCREEN")) | |
| 574 | + | readUntil(t, hs.x, func() bool { return !hs.x.tab.rec(s).fullscreen }) | |
| 575 | + | // Not written back by the message itself. | |
| 576 | + | st, ok := hs.p.prop(win, "_NET_WM_STATE") | |
| 577 | + | require.True(t, ok) | |
| 578 | + | require.Empty(t, st.data) | |
| 579 | + | } | |
| 580 | + | ||
| 581 | + | // Unmap, destroy, remap. | |
| 582 | + | ||
| 583 | + | func TestUnmapDissociatesAndRemapRereadsProperties(t *testing.T) { | |
| 584 | + | hs := newHarness(t, nil) | |
| 585 | + | const win = 0x500001 | |
| 586 | + | hs.classic(win) | |
| 587 | + | s := hs.mapAndWait(win) | |
| 588 | + | ||
| 589 | + | // A synthetic UnmapNotify (ICCCM withdraw request) is not an unmap. | |
| 590 | + | hs.p.unmapNotify(win, true) | |
| 591 | + | readUntil(t, hs.x, func() bool { return hs.x.Stats().Events >= 2 }) | |
| 592 | + | require.True(t, hs.x.tab.rec(s).ready) | |
| 593 | + | ||
| 594 | + | hs.h.EXPECT().Dissociate(s, false).Once() | |
| 595 | + | hs.p.unmapNotify(win, false) | |
| 596 | + | readUntil(t, hs.x, func() bool { return !hs.x.tab.rec(s).ready }) | |
| 597 | + | r := hs.x.tab.rec(s) | |
| 598 | + | require.False(t, r.mapping) | |
| 599 | + | require.Zero(t, r.serial) | |
| 600 | + | hs.p.waitReq(0, func(q xpeerReq) bool { | |
| 601 | + | return q.major == opSetInputFocus || q.major == opChangeProperty && q.u32(4) == win | |
| 602 | + | }) | |
| 603 | + | readUntil(t, hs.x, func() bool { | |
| 604 | + | v, ok := hs.p.prop(win, "WM_STATE") | |
| 605 | + | return ok && len(v.data) == 8 && binary.LittleEndian.Uint32(v.data) == 0 | |
| 606 | + | }) | |
| 607 | + | _, ok := hs.p.prop(win, "_NET_WM_STATE") | |
| 608 | + | require.False(t, ok, "_NET_WM_STATE deleted") | |
| 609 | + | list, _ := hs.p.prop(peerRoot, "_NET_CLIENT_LIST") | |
| 610 | + | require.Empty(t, list.data) | |
| 611 | + | ||
| 612 | + | // Remap starts over. | |
| 613 | + | delete(hs.ready, win) | |
| 614 | + | hs.expectReady(win) | |
| 615 | + | n := hs.count(func(q xpeerReq) bool { return q.major == opGetProperty && q.u32(4) == win }) | |
| 616 | + | hs.p.mapRequest(win) | |
| 617 | + | readUntil(t, hs.x, func() bool { _, ok := hs.ready[win]; return ok }) | |
| 618 | + | require.Equal(t, n+propCount, hs.count(func(q xpeerReq) bool { return q.major == opGetProperty && q.u32(4) == win })) | |
| 619 | + | list, _ = hs.p.prop(peerRoot, "_NET_CLIENT_LIST") | |
| 620 | + | require.Equal(t, []uint32{win}, atomsOf(list)) | |
| 621 | + | } | |
| 622 | + | ||
| 623 | + | func TestDestroyWhileMappingNeverReady(t *testing.T) { | |
| 624 | + | hs := newHarness(t, nil) | |
| 625 | + | const win = 0x500001 | |
| 626 | + | hs.classic(win) | |
| 627 | + | s := hs.create(win) | |
| 628 | + | hs.p.holdReplies() | |
| 629 | + | hs.p.mapRequest(win) | |
| 630 | + | hs.waitMap(win) | |
| 631 | + | hs.h.EXPECT().Dissociate(s, true).Once() | |
| 632 | + | hs.p.destroyNotify(win) | |
| 633 | + | readUntil(t, hs.x, func() bool { return hs.x.Slot(win) == 0 }) | |
| 634 | + | replies := hs.x.Stats().Replies | |
| 635 | + | hs.p.release() // replies for a window that is gone: xturbo retired their slots | |
| 636 | + | readUntil(t, hs.x, func() bool { return hs.x.conn.Stats().DroppedReplies >= uint64(propCount) }) | |
| 637 | + | require.Equal(t, replies, hs.x.Stats().Replies, "none reaches the XWM") | |
| 638 | + | } | |
| 639 | + | ||
| 640 | + | func TestStaleRepliesAfterSlotReuseAreIgnored(t *testing.T) { | |
| 641 | + | hs := newHarness(t, nil) | |
| 642 | + | const old, fresh = 0x500001, 0x500002 | |
| 643 | + | hs.classic(old) | |
| 644 | + | hs.classic(fresh) | |
| 645 | + | s := hs.create(old) | |
| 646 | + | hs.p.holdReplies() | |
| 647 | + | hs.p.mapRequest(old) | |
| 648 | + | hs.waitMap(old) | |
| 649 | + | hs.h.EXPECT().Dissociate(s, true).Once() | |
| 650 | + | hs.p.destroyNotify(old) | |
| 651 | + | readUntil(t, hs.x, func() bool { return hs.x.Slot(old) == 0 }) | |
| 652 | + | ||
| 653 | + | hs.expectCreated(fresh) | |
| 654 | + | hs.p.createNotify(fresh, false) | |
| 655 | + | readUntil(t, hs.x, func() bool { return hs.x.Slot(fresh) != 0 }) | |
| 656 | + | require.Equal(t, s, hs.x.Slot(fresh), "the freed slot is reused") | |
| 657 | + | ||
| 658 | + | hs.p.release() | |
| 659 | + | readUntil(t, hs.x, func() bool { return hs.x.conn.Stats().DroppedReplies >= uint64(propCount) }) | |
| 660 | + | ||
| 661 | + | // A reply that does get through with the old tag (slot reused, generation | |
| 662 | + | // bumped) is ignored. | |
| 663 | + | oldTag := s | Slot(hs.x.tab.rec(s).gen-1)<<16 | |
| 664 | + | rep := make([]byte, 32) | |
| 665 | + | rep[0] = 1 | |
| 666 | + | hs.x.onReply(&xturbo.Reply{Kind: kindProp, Args: [4]uint32{uint32(oldTag), propClass}, Raw: rep}) | |
| 667 | + | hs.x.onReply(&xturbo.Reply{Kind: kindGeom, Args: [4]uint32{uint32(oldTag)}, Raw: rep}) | |
| 668 | + | require.EqualValues(t, 2, hs.x.Stats().Stale) | |
| 669 | + | require.False(t, hs.x.tab.rec(s).ready, "stale replies must not complete the new window") | |
| 670 | + | require.Zero(t, hs.x.tab.rec(s).pending) | |
| 671 | + | } | |
| 672 | + | ||
| 673 | + | // Reparenting. | |
| 674 | + | ||
| 675 | + | func TestReparentAwayFromRootRemovesManagedWindow(t *testing.T) { | |
| 676 | + | hs := newHarness(t, nil) | |
| 677 | + | const win = 0x500001 | |
| 678 | + | hs.classic(win) | |
| 679 | + | s := hs.mapAndWait(win) | |
| 680 | + | hs.h.EXPECT().Dissociate(s, true).Once() | |
| 681 | + | hs.p.reparentNotify(win, 0x600000) | |
| 682 | + | readUntil(t, hs.x, func() bool { return hs.x.Slot(win) == 0 }) | |
| 683 | + | list, _ := hs.p.prop(peerRoot, "_NET_CLIENT_LIST") | |
| 684 | + | require.Empty(t, list.data) | |
| 685 | + | require.Zero(t, hs.x.tab.n) | |
| 686 | + | } | |
| 687 | + | ||
| 688 | + | func TestReparentAwayOfUnmanagedWindowRemovesIt(t *testing.T) { | |
| 689 | + | hs := newHarness(t, nil) | |
| 690 | + | hs.p.createNotify(0x500009, true) | |
| 691 | + | readUntil(t, hs.x, func() bool { return hs.x.Slot(0x500009) != 0 }) | |
| 692 | + | hs.p.reparentNotify(0x500009, 0x600000) | |
| 693 | + | readUntil(t, hs.x, func() bool { return hs.x.Slot(0x500009) == 0 }) | |
| 694 | + | } | |
| 695 | + | ||
| 696 | + | func TestReparentIntoRootAdoptsWindow(t *testing.T) { | |
| 697 | + | hs := newHarness(t, nil) | |
| 698 | + | const win = 0x500001 | |
| 699 | + | hs.expectCreated(win) | |
| 700 | + | hs.p.reparentNotify(win, peerRoot) | |
| 701 | + | readUntil(t, hs.x, func() bool { return hs.x.Slot(win) != 0 }) | |
| 702 | + | require.Equal(t, kindManaged, hs.x.tab.rec(hs.x.Slot(win)).kind) | |
| 703 | + | ||
| 704 | + | // Already known: no second Created. | |
| 705 | + | hs.p.reparentNotify(win, peerRoot) | |
| 706 | + | readUntil(t, hs.x, func() bool { return hs.x.Stats().Events >= 2 }) | |
| 707 | + | } | |
| 708 | + | ||
| 709 | + | func TestReparentIntoRootOfOverrideRedirectWindowStaysUnmanaged(t *testing.T) { | |
| 710 | + | hs := newHarness(t, nil) | |
| 711 | + | hs.p.event(21, func(b *[32]byte) { | |
| 712 | + | binary.LittleEndian.PutUint32(b[4:], peerRoot) | |
| 713 | + | binary.LittleEndian.PutUint32(b[8:], 0x500009) | |
| 714 | + | binary.LittleEndian.PutUint32(b[12:], peerRoot) | |
| 715 | + | b[20] = 1 | |
| 716 | + | }) | |
| 717 | + | readUntil(t, hs.x, func() bool { return hs.x.Slot(0x500009) != 0 }) | |
| 718 | + | require.Equal(t, kindUnmanaged, hs.x.tab.rec(hs.x.Slot(0x500009)).kind) | |
| 719 | + | } | |
| 720 | + | ||
| 721 | + | func TestReparentOfWMWindowIgnored(t *testing.T) { | |
| 722 | + | hs := newHarness(t, nil) | |
| 723 | + | hs.p.reparentNotify(hs.x.wmWin, peerRoot) | |
| 724 | + | readUntil(t, hs.x, func() bool { return hs.x.Stats().Events >= 1 }) | |
| 725 | + | require.Zero(t, hs.x.Slot(hs.x.wmWin)) | |
| 726 | + | } | |
| 727 | + | ||
| 728 | + | // Window known only before Attach: Attach replays the map flow. | |
| 729 | + | func TestAttachMapsWindowsRequestedBeforeAttach(t *testing.T) { | |
| 730 | + | x, p := bootPeer(t, nil) | |
| 731 | + | const win = 0x500001 | |
| 732 | + | p.setProp(win, uint32(xproto.AtomWmClass), uint32(xproto.AtomString), 8, []byte("a\x00B\x00")) | |
| 733 | + | p.createNotify(win, false) | |
| 734 | + | p.mapRequest(win) | |
| 735 | + | readUntil(t, x, func() bool { return x.Stats().Events >= 2 }) | |
| 736 | + | h := newMockhost(t) | |
| 737 | + | src := newMockfdSource(t) | |
| 738 | + | src.EXPECT().Remove().Maybe() | |
| 739 | + | post, _ := newPost() | |
| 740 | + | var got WindowInfo | |
| 741 | + | done := false | |
| 742 | + | h.EXPECT().Created(mock.Anything, uint32(win)).Return(ports.WindowID(1)).Once() | |
| 743 | + | h.EXPECT().Ready(mock.Anything, mock.Anything).Run(func(_ Slot, i WindowInfo) { got, done = i, true }).Once() | |
| 744 | + | x.attach(src, h, post) | |
| 745 | + | readUntil(t, x, func() bool { return done }) | |
| 746 | + | require.Equal(t, "B", got.AppID) | |
| 747 | + | } | |
| 748 | + | ||
| 749 | + | // Replies complete a map in any order (a server may answer the geometry | |
| 750 | + | // before the properties it was asked for first): Ready fires on the last one. | |
| 751 | + | func TestMapFlowReadyFiresOnLastReplyInAnyOrder(t *testing.T) { | |
| 752 | + | hs := newHarness(t, nil) | |
| 753 | + | const win = 0x500001 | |
| 754 | + | hs.classic(win) | |
| 755 | + | s := hs.create(win) | |
| 756 | + | r := hs.x.tab.rec(s) | |
| 757 | + | r.mapping, r.pending = true, propMaskAll&^propClientIDs | |
| 758 | + | hs.expectReady(win) | |
| 759 | + | order := []int{propCount, propPID, propClass, propNetName, propName, propHints, propNormalHints, propProtocols, propTransientFor, propWindowType, propState} | |
| 760 | + | for i, bit := range order { | |
| 761 | + | require.False(t, hs.x.tab.rec(s).ready, i) | |
| 762 | + | if bit == propCount { // the geometry | |
| 763 | + | hs.x.tab.rec(s).w, hs.x.tab.rec(s).h = 300, 200 | |
| 764 | + | hs.x.tab.rec(s).pending &^= propGeom | |
| 765 | + | hs.x.checkReady(s) | |
| 766 | + | continue | |
| 767 | + | } | |
| 768 | + | var val []byte | |
| 769 | + | var format uint8 = 8 | |
| 770 | + | switch bit { | |
| 771 | + | case propClass: | |
| 772 | + | val = []byte("a\x00B\x00") | |
| 773 | + | case propNetName: | |
| 774 | + | val = []byte("t") | |
| 775 | + | case propPID: | |
| 776 | + | val, format = le32(5), 32 | |
| 777 | + | default: | |
| 778 | + | format = 32 | |
| 779 | + | } | |
| 780 | + | x := hs.x | |
| 781 | + | x.applyProp(s, bit, format, val) | |
| 782 | + | x.tab.rec(s).pending &^= 1 << bit | |
| 783 | + | x.checkReady(s) | |
| 784 | + | } | |
| 785 | + | require.True(t, hs.x.tab.rec(s).ready) | |
| 786 | + | require.Equal(t, "B", hs.ready[win].AppID) | |
| 787 | + | require.Equal(t, "t", hs.ready[win].Title) | |
| 788 | + | require.Equal(t, 5, hs.ready[win].PID) | |
| 789 | + | } | |
| @@ -0,0 +1,789 @@ | |||||
| 1 | + | package xwm | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "encoding/binary" | |||
| 5 | + | "testing" | |||
| 6 | + | ||||
| 7 | + | "bnema.dev/xturbo" | |||
| 8 | + | "bnema.dev/xturbo/xproto" | |||
| 9 | + | "github.com/bnema/neferwl/internal/ports" | |||
| 10 | + | "github.com/stretchr/testify/mock" | |||
| 11 | + | "github.com/stretchr/testify/require" | |||
| 12 | + | ) | |||
| 13 | + | ||||
| 14 | + | // harness bundles an attached XWM, its peer and the host mock. | |||
| 15 | + | type harness struct { | |||
| 16 | + | t *testing.T | |||
| 17 | + | x *XWM | |||
| 18 | + | p *xpeer | |||
| 19 | + | h *mockhost | |||
| 20 | + | ||||
| 21 | + | ready map[uint32]WindowInfo // by xid, filled by Ready | |||
| 22 | + | next ports.WindowID | |||
| 23 | + | } | |||
| 24 | + | ||||
| 25 | + | func newHarness(t *testing.T, mutate func(p *xpeer)) *harness { | |||
| 26 | + | t.Helper() | |||
| 27 | + | x, p := bootPeer(t, mutate) | |||
| 28 | + | hs := &harness{t: t, x: x, p: p, h: newMockhost(t), ready: map[uint32]WindowInfo{}} | |||
| 29 | + | src := newMockfdSource(t) | |||
| 30 | + | src.EXPECT().Remove().Maybe() | |||
| 31 | + | src.EXPECT().SetWritable(mock.Anything).Return(nil).Maybe() | |||
| 32 | + | post, _ := newPost() | |||
| 33 | + | x.attach(src, hs.h, post) | |||
| 34 | + | return hs | |||
| 35 | + | } | |||
| 36 | + | ||||
| 37 | + | func (hs *harness) expectCreated(win uint32) { | |||
| 38 | + | hs.next++ | |||
| 39 | + | hs.h.EXPECT().Created(mock.Anything, win).Return(hs.next).Once() | |||
| 40 | + | } | |||
| 41 | + | ||||
| 42 | + | func (hs *harness) expectReady(win uint32) { | |||
| 43 | + | hs.h.EXPECT().Ready(mock.Anything, mock.Anything).Run(func(_ Slot, info WindowInfo) { | |||
| 44 | + | hs.ready[win] = info | |||
| 45 | + | }).Once() | |||
| 46 | + | } | |||
| 47 | + | ||||
| 48 | + | func (hs *harness) create(win uint32) Slot { | |||
| 49 | + | hs.t.Helper() | |||
| 50 | + | hs.expectCreated(win) | |||
| 51 | + | hs.p.createNotify(win, false) | |||
| 52 | + | readUntil(hs.t, hs.x, func() bool { return hs.x.Slot(win) != 0 }) | |||
| 53 | + | return hs.x.Slot(win) | |||
| 54 | + | } | |||
| 55 | + | ||||
| 56 | + | // mapAndWait creates and maps win and waits for Ready. | |||
| 57 | + | func (hs *harness) mapAndWait(win uint32) Slot { | |||
| 58 | + | hs.t.Helper() | |||
| 59 | + | s := hs.create(win) | |||
| 60 | + | hs.expectReady(win) | |||
| 61 | + | hs.p.mapRequest(win) | |||
| 62 | + | readUntil(hs.t, hs.x, func() bool { _, ok := hs.ready[win]; return ok }) | |||
| 63 | + | return s | |||
| 64 | + | } | |||
| 65 | + | ||||
| 66 | + | func (hs *harness) str(win uint32, atom string, typ uint32, s string) { | |||
| 67 | + | hs.p.setProp(win, hs.p.atom(atom), typ, 8, []byte(s)) | |||
| 68 | + | } | |||
| 69 | + | ||||
| 70 | + | func (hs *harness) words(win uint32, atom string, typ uint32, w ...uint32) { | |||
| 71 | + | hs.p.setProp(win, hs.p.atom(atom), typ, 32, le32(w...)) | |||
| 72 | + | } | |||
| 73 | + | ||||
| 74 | + | func (hs *harness) atoms(win uint32, atom string, names ...string) { | |||
| 75 | + | var w []uint32 | |||
| 76 | + | for _, n := range names { | |||
| 77 | + | w = append(w, hs.p.atom(n)) | |||
| 78 | + | } | |||
| 79 | + | hs.words(win, atom, uint32(xproto.AtomAtom), w...) | |||
| 80 | + | } | |||
| 81 | + | ||||
| 82 | + | func (hs *harness) classic(win uint32) { | |||
| 83 | + | hs.p.setProp(win, uint32(xproto.AtomWmClass), uint32(xproto.AtomString), 8, []byte("inst\x00Class\x00")) | |||
| 84 | + | hs.str(win, "_NET_WM_NAME", hs.p.atom("UTF8_STRING"), "net title") | |||
| 85 | + | hs.p.setProp(win, uint32(xproto.AtomWmName), uint32(xproto.AtomString), 8, []byte("old title")) | |||
| 86 | + | hs.words(win, "_NET_WM_PID", uint32(xproto.AtomCardinal), 4242) | |||
| 87 | + | hs.p.set(func(p *xpeer) { p.geoms[win] = xpeerGeom{w: 300, h: 200} }) | |||
| 88 | + | } | |||
| 89 | + | ||||
| 90 | + | func (hs *harness) count(match func(r xpeerReq) bool) int { | |||
| 91 | + | n := 0 | |||
| 92 | + | for _, r := range hs.p.requests() { | |||
| 93 | + | if match(r) { | |||
| 94 | + | n++ | |||
| 95 | + | } | |||
| 96 | + | } | |||
| 97 | + | return n | |||
| 98 | + | } | |||
| 99 | + | ||||
| 100 | + | func (hs *harness) waitMap(win uint32) { | |||
| 101 | + | hs.t.Helper() | |||
| 102 | + | readUntil(hs.t, hs.x, func() bool { | |||
| 103 | + | return hs.count(func(r xpeerReq) bool { return r.major == opMapWindow && r.u32(4) == win }) > 0 | |||
| 104 | + | }) | |||
| 105 | + | } | |||
| 106 | + | ||||
| 107 | + | func TestMapFlowBatchesRequestsAndReadyFiresOnce(t *testing.T) { | |||
| 108 | + | hs := newHarness(t, nil) | |||
| 109 | + | const win = 0x500001 | |||
| 110 | + | hs.classic(win) | |||
| 111 | + | hs.create(win) | |||
| 112 | + | base := len(hs.p.requests()) | |||
| 113 | + | ||||
| 114 | + | hs.p.holdReplies() | |||
| 115 | + | hs.p.mapRequest(win) | |||
| 116 | + | hs.expectReady(win) | |||
| 117 | + | hs.waitMap(win) | |||
| 118 | + | ||||
| 119 | + | reqs := hs.p.requests()[base:] | |||
| 120 | + | want := []uint32{ | |||
| 121 | + | uint32(xproto.AtomWmClass), uint32(xproto.AtomWmName), hs.p.atom("_NET_WM_NAME"), uint32(xproto.AtomWmHints), | |||
| 122 | + | uint32(xproto.AtomWmNormalHints), hs.p.atom("WM_PROTOCOLS"), uint32(xproto.AtomWmTransientFor), | |||
| 123 | + | hs.p.atom("_NET_WM_WINDOW_TYPE"), hs.p.atom("_NET_WM_STATE"), hs.p.atom("_NET_WM_PID"), | |||
| 124 | + | } | |||
| 125 | + | require.GreaterOrEqual(t, len(reqs), len(want)+2) | |||
| 126 | + | for i, a := range want { | |||
| 127 | + | require.EqualValues(t, opGetProperty, reqs[i].major, i) | |||
| 128 | + | require.Equal(t, uint32(win), reqs[i].u32(4)) | |||
| 129 | + | require.Equal(t, a, reqs[i].u32(8), i) | |||
| 130 | + | require.EqualValues(t, 1024, reqs[i].u32(20), "long length: one 4 KiB read") | |||
| 131 | + | } | |||
| 132 | + | require.EqualValues(t, opGetGeometry, reqs[len(want)].major) | |||
| 133 | + | require.EqualValues(t, opMapWindow, reqs[len(want)+1].major, "MapWindow in the same batch") | |||
| 134 | + | ||||
| 135 | + | hs.p.release() // every reply arrives after MapWindow went out | |||
| 136 | + | readUntil(t, hs.x, func() bool { _, ok := hs.ready[win]; return ok }) | |||
| 137 | + | info := hs.ready[win] | |||
| 138 | + | require.Equal(t, WindowInfo{PID: 4242, Title: "net title", AppID: "Class"}, info, "_NET_WM_NAME wins, class is the second string") | |||
| 139 | + | ||||
| 140 | + | state, ok := hs.p.prop(win, "WM_STATE") | |||
| 141 | + | require.True(t, ok) | |||
| 142 | + | require.Equal(t, []uint32{1, 0}, atomsOf(state)) | |||
| 143 | + | list, ok := hs.p.prop(peerRoot, "_NET_CLIENT_LIST") | |||
| 144 | + | require.True(t, ok) | |||
| 145 | + | require.Equal(t, []uint32{win}, atomsOf(list)) | |||
| 146 | + | } | |||
| 147 | + | ||||
| 148 | + | func TestMapFlowFloatingAndModal(t *testing.T) { | |||
| 149 | + | hint := func(minw, minh, maxw, maxh uint32) []byte { | |||
| 150 | + | return le32(hintMinSize|hintMaxSize, 0, 0, 0, 0, minw, minh, maxw, maxh, 0, 0, 0, 0, 0, 0, 0, 0, 0) | |||
| 151 | + | } | |||
| 152 | + | cases := []struct { | |||
| 153 | + | name string | |||
| 154 | + | setup func(hs *harness, win uint32) | |||
| 155 | + | want func(info WindowInfo) | |||
| 156 | + | }{ | |||
| 157 | + | {"dialog type", func(hs *harness, w uint32) { | |||
| 158 | + | hs.atoms(w, "_NET_WM_WINDOW_TYPE", "_NET_WM_WINDOW_TYPE_DIALOG") | |||
| 159 | + | }, func(i WindowInfo) { | |||
| 160 | + | require.True(t, i.Floating) | |||
| 161 | + | require.Equal(t, 300, i.Width) | |||
| 162 | + | require.Equal(t, 200, i.Height) | |||
| 163 | + | }}, | |||
| 164 | + | {"utility type", func(hs *harness, w uint32) { | |||
| 165 | + | hs.atoms(w, "_NET_WM_WINDOW_TYPE", "_NET_WM_WINDOW_TYPE_UTILITY") | |||
| 166 | + | }, func(i WindowInfo) { require.True(t, i.Floating) }}, | |||
| 167 | + | {"splash type", func(hs *harness, w uint32) { | |||
| 168 | + | hs.atoms(w, "_NET_WM_WINDOW_TYPE", "_NET_WM_WINDOW_TYPE_SPLASH") | |||
| 169 | + | }, func(i WindowInfo) { require.True(t, i.Floating) }}, | |||
| 170 | + | {"normal type", func(hs *harness, w uint32) { | |||
| 171 | + | hs.atoms(w, "_NET_WM_WINDOW_TYPE", "_NET_WM_WINDOW_TYPE_NORMAL") | |||
| 172 | + | }, func(i WindowInfo) { require.False(t, i.Floating); require.Zero(t, i.Width) }}, | |||
| 173 | + | {"fixed size", func(hs *harness, w uint32) { | |||
| 174 | + | hs.p.setProp(w, uint32(xproto.AtomWmNormalHints), uint32(xproto.AtomWmSizeHints), 32, hint(200, 100, 200, 100)) | |||
| 175 | + | }, func(i WindowInfo) { require.True(t, i.Floating) }}, | |||
| 176 | + | {"resizable", func(hs *harness, w uint32) { | |||
| 177 | + | hs.p.setProp(w, uint32(xproto.AtomWmNormalHints), uint32(xproto.AtomWmSizeHints), 32, hint(100, 100, 800, 600)) | |||
| 178 | + | }, func(i WindowInfo) { require.False(t, i.Floating) }}, | |||
| 179 | + | {"modal", func(hs *harness, w uint32) { | |||
| 180 | + | hs.atoms(w, "_NET_WM_STATE", "_NET_WM_STATE_MODAL") | |||
| 181 | + | }, func(i WindowInfo) { require.True(t, i.Modal); require.False(t, i.Fullscreen) }}, | |||
| 182 | + | {"fullscreen at map", func(hs *harness, w uint32) { | |||
| 183 | + | hs.atoms(w, "_NET_WM_STATE", "_NET_WM_STATE_FULLSCREEN") | |||
| 184 | + | }, func(i WindowInfo) { require.True(t, i.Fullscreen) }}, | |||
| 185 | + | } | |||
| 186 | + | for _, c := range cases { | |||
| 187 | + | t.Run(c.name, func(t *testing.T) { | |||
| 188 | + | hs := newHarness(t, nil) | |||
| 189 | + | const win = 0x500001 | |||
| 190 | + | hs.classic(win) | |||
| 191 | + | c.setup(hs, win) | |||
| 192 | + | hs.mapAndWait(win) | |||
| 193 | + | c.want(hs.ready[win]) | |||
| 194 | + | }) | |||
| 195 | + | } | |||
| 196 | + | } | |||
| 197 | + | ||||
| 198 | + | func TestMapFlowTransientForManagedWindowFloats(t *testing.T) { | |||
| 199 | + | hs := newHarness(t, nil) | |||
| 200 | + | const parent, child = 0x500001, 0x500002 | |||
| 201 | + | hs.classic(parent) | |||
| 202 | + | ps := hs.mapAndWait(parent) | |||
| 203 | + | hs.classic(child) | |||
| 204 | + | hs.p.setProp(child, uint32(xproto.AtomWmTransientFor), uint32(xproto.AtomWindow), 32, le32(parent)) | |||
| 205 | + | hs.mapAndWait(child) | |||
| 206 | + | require.True(t, hs.ready[child].Floating) | |||
| 207 | + | require.Equal(t, ps, hs.ready[child].Parent) | |||
| 208 | + | } | |||
| 209 | + | ||||
| 210 | + | func TestMapFlowTransientForUnknownWindowIsNotAParent(t *testing.T) { | |||
| 211 | + | hs := newHarness(t, nil) | |||
| 212 | + | const win = 0x500001 | |||
| 213 | + | hs.classic(win) | |||
| 214 | + | hs.p.setProp(win, uint32(xproto.AtomWmTransientFor), uint32(xproto.AtomWindow), 32, le32(0x777777)) | |||
| 215 | + | hs.mapAndWait(win) | |||
| 216 | + | require.Zero(t, hs.ready[win].Parent) | |||
| 217 | + | require.False(t, hs.ready[win].Floating) | |||
| 218 | + | } | |||
| 219 | + | ||||
| 220 | + | func TestMapFlowClassFallsBackToInstance(t *testing.T) { | |||
| 221 | + | hs := newHarness(t, nil) | |||
| 222 | + | const win = 0x500001 | |||
| 223 | + | hs.classic(win) | |||
| 224 | + | hs.p.setProp(win, uint32(xproto.AtomWmClass), uint32(xproto.AtomString), 8, []byte("onlyinstance\x00")) | |||
| 225 | + | hs.mapAndWait(win) | |||
| 226 | + | require.Equal(t, "onlyinstance", hs.ready[win].AppID) | |||
| 227 | + | } | |||
| 228 | + | ||||
| 229 | + | func TestMapFlowTitleFallsBackToWMName(t *testing.T) { | |||
| 230 | + | hs := newHarness(t, nil) | |||
| 231 | + | const win = 0x500001 | |||
| 232 | + | hs.classic(win) | |||
| 233 | + | hs.p.set(func(p *xpeer) { delete(p.props[win], p.atoms["_NET_WM_NAME"]) }) | |||
| 234 | + | hs.mapAndWait(win) | |||
| 235 | + | require.Equal(t, "old title", hs.ready[win].Title) | |||
| 236 | + | } | |||
| 237 | + | ||||
| 238 | + | func TestMapFlowPIDFromXRes(t *testing.T) { | |||
| 239 | + | hs := newHarness(t, func(p *xpeer) { p.pids = map[uint32]uint32{0x500001: 777} }) | |||
| 240 | + | const win = 0x500001 | |||
| 241 | + | hs.classic(win) | |||
| 242 | + | hs.p.set(func(p *xpeer) { delete(p.props[win], p.atoms["_NET_WM_PID"]) }) | |||
| 243 | + | hs.create(win) | |||
| 244 | + | hs.expectReady(win) | |||
| 245 | + | hs.p.mapRequest(win) | |||
| 246 | + | readUntil(t, hs.x, func() bool { _, ok := hs.ready[win]; return ok }) | |||
| 247 | + | require.Equal(t, 777, hs.ready[win].PID, "Ready waited for the QueryClientIds reply") | |||
| 248 | + | require.Equal(t, 1, hs.count(func(r xpeerReq) bool { return r.major == 144 && r.minor == 4 })) | |||
| 249 | + | require.Zero(t, hs.x.tab.rec(hs.x.Slot(win)).pending) | |||
| 250 | + | } | |||
| 251 | + | ||||
| 252 | + | func TestMapFlowPIDUnknownStillReady(t *testing.T) { | |||
| 253 | + | hs := newHarness(t, nil) | |||
| 254 | + | const win = 0x500001 | |||
| 255 | + | hs.classic(win) | |||
| 256 | + | hs.p.set(func(p *xpeer) { delete(p.props[win], p.atoms["_NET_WM_PID"]) }) | |||
| 257 | + | hs.mapAndWait(win) | |||
| 258 | + | require.Zero(t, hs.ready[win].PID) | |||
| 259 | + | } | |||
| 260 | + | ||||
| 261 | + | func TestMapFlowNoXResAsksNothing(t *testing.T) { | |||
| 262 | + | exts := fullPeerExts() | |||
| 263 | + | delete(exts, "X-Resource") | |||
| 264 | + | fd, p := startXPeer(t, exts) | |||
| 265 | + | x, err := Boot(fd, testLog()) | |||
| 266 | + | require.NoError(t, err) | |||
| 267 | + | t.Cleanup(x.CloseConn) | |||
| 268 | + | h := newMockhost(t) | |||
| 269 | + | src := newMockfdSource(t) | |||
| 270 | + | src.EXPECT().Remove().Maybe() | |||
| 271 | + | post, _ := newPost() | |||
| 272 | + | x.attach(src, h, post) | |||
| 273 | + | hs := &harness{t: t, x: x, p: p, h: h, ready: map[uint32]WindowInfo{}} | |||
| 274 | + | const win = 0x500001 | |||
| 275 | + | hs.classic(win) | |||
| 276 | + | p.set(func(p *xpeer) { delete(p.props[win], p.atoms["_NET_WM_PID"]) }) | |||
| 277 | + | hs.mapAndWait(win) | |||
| 278 | + | require.Zero(t, hs.count(func(r xpeerReq) bool { return r.major == 144 })) | |||
| 279 | + | } | |||
| 280 | + | ||||
| 281 | + | func TestMapFlowBadWindowOnPropertiesNeverReady(t *testing.T) { | |||
| 282 | + | hs := newHarness(t, nil) | |||
| 283 | + | const win = 0x500001 | |||
| 284 | + | hs.classic(win) | |||
| 285 | + | hs.p.set(func(p *xpeer) { p.bad[win] = true }) | |||
| 286 | + | s := hs.create(win) | |||
| 287 | + | hs.p.mapRequest(win) | |||
| 288 | + | readUntil(t, hs.x, func() bool { return hs.x.Stats().Errors >= uint64(propCount)+1 }) | |||
| 289 | + | require.Zero(t, hs.x.tab.rec(s).pending, "failed replies are no longer awaited") | |||
| 290 | + | require.False(t, hs.x.tab.rec(s).ready) | |||
| 291 | + | require.Zero(t, hs.x.Stats().Unattributed) | |||
| 292 | + | ||||
| 293 | + | hs.h.EXPECT().Dissociate(s, true).Once() | |||
| 294 | + | hs.p.destroyNotify(win) | |||
| 295 | + | readUntil(t, hs.x, func() bool { return hs.x.Slot(win) == 0 }) | |||
| 296 | + | } | |||
| 297 | + | ||||
| 298 | + | func TestMapRequestTwiceBeforeReadyAsksOnce(t *testing.T) { | |||
| 299 | + | hs := newHarness(t, nil) | |||
| 300 | + | const win = 0x500001 | |||
| 301 | + | hs.classic(win) | |||
| 302 | + | hs.create(win) | |||
| 303 | + | hs.p.holdReplies() | |||
| 304 | + | hs.p.mapRequest(win) | |||
| 305 | + | hs.p.mapRequest(win) | |||
| 306 | + | hs.expectReady(win) | |||
| 307 | + | hs.waitMap(win) | |||
| 308 | + | hs.p.release() | |||
| 309 | + | readUntil(t, hs.x, func() bool { _, ok := hs.ready[win]; return ok }) | |||
| 310 | + | require.Equal(t, 1, hs.count(func(r xpeerReq) bool { return r.major == opMapWindow && r.u32(4) == win })) | |||
| 311 | + | } | |||
| 312 | + | ||||
| 313 | + | func TestMapNotifyMarksMapped(t *testing.T) { | |||
| 314 | + | hs := newHarness(t, nil) | |||
| 315 | + | const win = 0x500001 | |||
| 316 | + | hs.classic(win) | |||
| 317 | + | s := hs.mapAndWait(win) | |||
| 318 | + | hs.p.mapNotify(win) | |||
| 319 | + | readUntil(t, hs.x, func() bool { return hs.x.tab.rec(s).mapped }) | |||
| 320 | + | } | |||
| 321 | + | ||||
| 322 | + | // Property changes after Ready. | |||
| 323 | + | ||||
| 324 | + | func (hs *harness) notify(win uint32, atom string, deleted bool) { | |||
| 325 | + | hs.t.Helper() | |||
| 326 | + | before := hs.x.Stats().Replies | |||
| 327 | + | hs.p.propertyNotify(win, hs.p.atom(atom), deleted) | |||
| 328 | + | if deleted { | |||
| 329 | + | hs.p.propertyNotify(win, hs.p.atom("WM_PROTOCOLS"), false) // sentinel: one reply follows | |||
| 330 | + | readUntil(hs.t, hs.x, func() bool { return hs.x.Stats().Replies > before }) | |||
| 331 | + | return | |||
| 332 | + | } | |||
| 333 | + | readUntil(hs.t, hs.x, func() bool { return hs.x.Stats().Replies > before }) | |||
| 334 | + | } | |||
| 335 | + | ||||
| 336 | + | func TestPropertyChangedTitleReachesHostOnce(t *testing.T) { | |||
| 337 | + | hs := newHarness(t, nil) | |||
| 338 | + | const win = 0x500001 | |||
| 339 | + | hs.classic(win) | |||
| 340 | + | s := hs.mapAndWait(win) | |||
| 341 | + | ||||
| 342 | + | hs.h.EXPECT().Title(s, "renamed").Once() | |||
| 343 | + | hs.str(win, "_NET_WM_NAME", hs.p.atom("UTF8_STRING"), "renamed") | |||
| 344 | + | hs.notify(win, "_NET_WM_NAME", false) | |||
| 345 | + | require.Equal(t, "renamed", hs.x.tab.rec(s).title) | |||
| 346 | + | ||||
| 347 | + | // Same value again: no host call (the mock fails on an unexpected one). | |||
| 348 | + | hs.notify(win, "_NET_WM_NAME", false) | |||
| 349 | + | ||||
| 350 | + | // WM_NAME is ignored while _NET_WM_NAME is set. | |||
| 351 | + | hs.p.setProp(win, uint32(xproto.AtomWmName), uint32(xproto.AtomString), 8, []byte("legacy")) | |||
| 352 | + | before := hs.x.Stats().Events | |||
| 353 | + | hs.p.propertyNotify(win, uint32(xproto.AtomWmName), false) | |||
| 354 | + | readUntil(t, hs.x, func() bool { return hs.x.Stats().Events > before }) | |||
| 355 | + | require.Equal(t, "renamed", hs.x.tab.rec(s).title) | |||
| 356 | + | } | |||
| 357 | + | ||||
| 358 | + | func TestPropertyNetNameDeletedFallsBackToWMName(t *testing.T) { | |||
| 359 | + | hs := newHarness(t, nil) | |||
| 360 | + | const win = 0x500001 | |||
| 361 | + | hs.classic(win) | |||
| 362 | + | s := hs.mapAndWait(win) | |||
| 363 | + | hs.p.set(func(p *xpeer) { delete(p.props[win], p.atoms["_NET_WM_NAME"]) }) | |||
| 364 | + | hs.h.EXPECT().Title(s, "old title").Once() | |||
| 365 | + | hs.p.propertyNotify(win, hs.p.atom("_NET_WM_NAME"), true) | |||
| 366 | + | readUntil(t, hs.x, func() bool { return hs.x.tab.rec(s).title == "old title" }) | |||
| 367 | + | } | |||
| 368 | + | ||||
| 369 | + | func TestPropertyClassChangeReachesHost(t *testing.T) { | |||
| 370 | + | hs := newHarness(t, nil) | |||
| 371 | + | const win = 0x500001 | |||
| 372 | + | hs.classic(win) | |||
| 373 | + | s := hs.mapAndWait(win) | |||
| 374 | + | hs.h.EXPECT().AppID(s, "Other").Once() | |||
| 375 | + | hs.p.setProp(win, uint32(xproto.AtomWmClass), uint32(xproto.AtomString), 8, []byte("i\x00Other\x00")) | |||
| 376 | + | hs.p.propertyNotify(win, uint32(xproto.AtomWmClass), false) | |||
| 377 | + | readUntil(t, hs.x, func() bool { return hs.x.tab.rec(s).class == "Other" }) | |||
| 378 | + | } | |||
| 379 | + | ||||
| 380 | + | func TestPropertyTransientChangeReachesHost(t *testing.T) { | |||
| 381 | + | hs := newHarness(t, nil) | |||
| 382 | + | const a, b = 0x500001, 0x500002 | |||
| 383 | + | hs.classic(a) | |||
| 384 | + | as := hs.mapAndWait(a) | |||
| 385 | + | hs.classic(b) | |||
| 386 | + | bs := hs.mapAndWait(b) | |||
| 387 | + | hs.h.EXPECT().Parent(bs, as).Once() | |||
| 388 | + | hs.p.setProp(b, uint32(xproto.AtomWmTransientFor), uint32(xproto.AtomWindow), 32, le32(a)) | |||
| 389 | + | hs.p.propertyNotify(b, uint32(xproto.AtomWmTransientFor), false) | |||
| 390 | + | readUntil(t, hs.x, func() bool { return hs.x.tab.rec(bs).transient == a }) | |||
| 391 | + | } | |||
| 392 | + | ||||
| 393 | + | func TestPropertyFullscreenStateChangeReachesHost(t *testing.T) { | |||
| 394 | + | hs := newHarness(t, nil) | |||
| 395 | + | const win = 0x500001 | |||
| 396 | + | hs.classic(win) | |||
| 397 | + | s := hs.mapAndWait(win) | |||
| 398 | + | hs.h.EXPECT().Fullscreen(s, true).Once() | |||
| 399 | + | hs.atoms(win, "_NET_WM_STATE", "_NET_WM_STATE_FULLSCREEN") | |||
| 400 | + | hs.p.propertyNotify(win, hs.p.atom("_NET_WM_STATE"), false) | |||
| 401 | + | readUntil(t, hs.x, func() bool { return hs.x.tab.rec(s).fullscreen }) | |||
| 402 | + | } | |||
| 403 | + | ||||
| 404 | + | func TestPropertyInputProtocolsAndHints(t *testing.T) { | |||
| 405 | + | hs := newHarness(t, nil) | |||
| 406 | + | const win = 0x500001 | |||
| 407 | + | hs.classic(win) | |||
| 408 | + | hs.atoms(win, "WM_PROTOCOLS", "WM_DELETE_WINDOW", "WM_TAKE_FOCUS") | |||
| 409 | + | hs.p.setProp(win, uint32(xproto.AtomWmHints), uint32(xproto.AtomWmHints), 32, le32(hintInput, 0, 0, 0, 0, 0, 0, 0, 0)) | |||
| 410 | + | s := hs.mapAndWait(win) | |||
| 411 | + | r := hs.x.tab.rec(s) | |||
| 412 | + | require.True(t, r.deleteWindow) | |||
| 413 | + | require.True(t, r.takeFocus) | |||
| 414 | + | require.False(t, r.input, "WM_HINTS input = false") | |||
| 415 | + | ||||
| 416 | + | // No WM_HINTS: input defaults to true. | |||
| 417 | + | const other = 0x500002 | |||
| 418 | + | hs.classic(other) | |||
| 419 | + | o := hs.mapAndWait(other) | |||
| 420 | + | require.True(t, hs.x.tab.rec(o).input) | |||
| 421 | + | require.False(t, hs.x.tab.rec(o).deleteWindow) | |||
| 422 | + | } | |||
| 423 | + | ||||
| 424 | + | func TestPropertyUnwatchedAtomAsksNothing(t *testing.T) { | |||
| 425 | + | hs := newHarness(t, nil) | |||
| 426 | + | const win = 0x500001 | |||
| 427 | + | hs.classic(win) | |||
| 428 | + | hs.mapAndWait(win) | |||
| 429 | + | n := len(hs.p.requests()) | |||
| 430 | + | hs.p.propertyNotify(win, hs.p.atom("_MOTIF_WM_HINTS"), false) | |||
| 431 | + | hs.p.propertyNotify(0x999999, hs.p.atom("_NET_WM_NAME"), false) // unknown window | |||
| 432 | + | readUntil(t, hs.x, func() bool { return hs.x.Stats().Events >= 2 }) | |||
| 433 | + | require.Len(t, hs.p.requests(), n) | |||
| 434 | + | } | |||
| 435 | + | ||||
| 436 | + | // Pairing. | |||
| 437 | + | ||||
| 438 | + | func (hs *harness) serialMsg(win uint32, serial uint64) { | |||
| 439 | + | hs.p.clientMessage(win, hs.p.atom("WL_SURFACE_SERIAL"), uint32(serial), uint32(serial>>32)) | |||
| 440 | + | hs.t.Helper() | |||
| 441 | + | before := hs.x.Stats().Events | |||
| 442 | + | readUntil(hs.t, hs.x, func() bool { return hs.x.Stats().Events > before }) | |||
| 443 | + | } | |||
| 444 | + | ||||
| 445 | + | func TestPairingSerialBeforeSetSerial(t *testing.T) { | |||
| 446 | + | hs := newHarness(t, nil) | |||
| 447 | + | const win = 0x500001 | |||
| 448 | + | hs.classic(win) | |||
| 449 | + | s := hs.mapAndWait(win) | |||
| 450 | + | hs.serialMsg(win, 0x1_0000_0002) | |||
| 451 | + | require.EqualValues(t, 0x1_0000_0002, hs.x.tab.rec(s).serial, "high word in data32[1]") | |||
| 452 | + | hs.h.EXPECT().Associate(s, uint64(99)).Once() | |||
| 453 | + | hs.x.SetSerial(99, 0x1_0000_0002) | |||
| 454 | + | require.EqualValues(t, 99, hs.x.tab.rec(s).surface) | |||
| 455 | + | require.Zero(t, hs.x.unpairedN) | |||
| 456 | + | } | |||
| 457 | + | ||||
| 458 | + | func TestPairingSetSerialBeforeSerial(t *testing.T) { | |||
| 459 | + | hs := newHarness(t, nil) | |||
| 460 | + | const win = 0x500001 | |||
| 461 | + | hs.classic(win) | |||
| 462 | + | s := hs.mapAndWait(win) | |||
| 463 | + | hs.x.SetSerial(99, 7) | |||
| 464 | + | require.Equal(t, 1, hs.x.unpairedN) | |||
| 465 | + | hs.h.EXPECT().Associate(s, uint64(99)).Once() | |||
| 466 | + | hs.serialMsg(win, 7) | |||
| 467 | + | require.Zero(t, hs.x.unpairedN) | |||
| 468 | + | } | |||
| 469 | + | ||||
| 470 | + | func TestPairingWaitsForReady(t *testing.T) { | |||
| 471 | + | hs := newHarness(t, nil) | |||
| 472 | + | const win = 0x500001 | |||
| 473 | + | hs.classic(win) | |||
| 474 | + | s := hs.create(win) | |||
| 475 | + | hs.x.SetSerial(5, 3) | |||
| 476 | + | hs.serialMsg(win, 3) // not mapped yet: no Associate (the mock fails on one) | |||
| 477 | + | require.Zero(t, hs.x.tab.rec(s).surface) | |||
| 478 | + | ||||
| 479 | + | hs.h.EXPECT().Associate(s, uint64(5)).Once() | |||
| 480 | + | hs.expectReady(win) | |||
| 481 | + | hs.p.mapRequest(win) | |||
| 482 | + | readUntil(t, hs.x, func() bool { return hs.x.tab.rec(s).surface != 0 }) | |||
| 483 | + | } | |||
| 484 | + | ||||
| 485 | + | func TestPairingSerialForUnknownWindowIgnored(t *testing.T) { | |||
| 486 | + | hs := newHarness(t, nil) | |||
| 487 | + | hs.x.SetSerial(5, 3) | |||
| 488 | + | hs.serialMsg(0x888888, 3) | |||
| 489 | + | require.Equal(t, 1, hs.x.unpairedN, "stays unpaired") | |||
| 490 | + | } | |||
| 491 | + | ||||
| 492 | + | func TestPairingSurfaceGoneBeforePair(t *testing.T) { | |||
| 493 | + | hs := newHarness(t, nil) | |||
| 494 | + | const win = 0x500001 | |||
| 495 | + | hs.classic(win) | |||
| 496 | + | s := hs.mapAndWait(win) | |||
| 497 | + | hs.x.SetSerial(5, 3) | |||
| 498 | + | hs.x.SurfaceGone(5) | |||
| 499 | + | require.Zero(t, hs.x.unpairedN) | |||
| 500 | + | hs.serialMsg(win, 3) // the surface is gone: nothing to pair with | |||
| 501 | + | require.Zero(t, hs.x.tab.rec(s).surface) | |||
| 502 | + | } | |||
| 503 | + | ||||
| 504 | + | func TestPairingSurfaceGoneAfterPairClearsLink(t *testing.T) { | |||
| 505 | + | hs := newHarness(t, nil) | |||
| 506 | + | const win = 0x500001 | |||
| 507 | + | hs.classic(win) | |||
| 508 | + | s := hs.mapAndWait(win) | |||
| 509 | + | hs.serialMsg(win, 3) | |||
| 510 | + | hs.h.EXPECT().Associate(s, uint64(5)).Once() | |||
| 511 | + | hs.x.SetSerial(5, 3) | |||
| 512 | + | hs.x.SurfaceGone(5) | |||
| 513 | + | require.Zero(t, hs.x.tab.rec(s).surface) | |||
| 514 | + | } | |||
| 515 | + | ||||
| 516 | + | func TestPairingDuplicateSerialIgnored(t *testing.T) { | |||
| 517 | + | hs := newHarness(t, nil) | |||
| 518 | + | const win = 0x500001 | |||
| 519 | + | hs.classic(win) | |||
| 520 | + | s := hs.mapAndWait(win) | |||
| 521 | + | hs.serialMsg(win, 3) | |||
| 522 | + | hs.serialMsg(win, 4) | |||
| 523 | + | require.EqualValues(t, 3, hs.x.tab.rec(s).serial) | |||
| 524 | + | hs.x.SetSerial(8, 4) // nobody announces 4: stays unpaired | |||
| 525 | + | require.Equal(t, 1, hs.x.unpairedN) | |||
| 526 | + | } | |||
| 527 | + | ||||
| 528 | + | func TestPairingUnmanagedKeepsSurfaceWithoutAssociate(t *testing.T) { | |||
| 529 | + | hs := newHarness(t, nil) | |||
| 530 | + | hs.p.createNotify(0x500009, true) | |||
| 531 | + | readUntil(t, hs.x, func() bool { return hs.x.Slot(0x500009) != 0 }) | |||
| 532 | + | hs.serialMsg(0x500009, 3) | |||
| 533 | + | hs.x.SetSerial(5, 3) // the mock fails on an Associate | |||
| 534 | + | require.EqualValues(t, 5, hs.x.tab.rec(hs.x.Slot(0x500009)).surface) | |||
| 535 | + | } | |||
| 536 | + | ||||
| 537 | + | func TestPairingTableOverflowDropsOldest(t *testing.T) { | |||
| 538 | + | hs := newHarness(t, nil) | |||
| 539 | + | for i := uint64(1); i <= unpairedCap+1; i++ { | |||
| 540 | + | hs.x.SetSerial(100+i, i) | |||
| 541 | + | } | |||
| 542 | + | require.Equal(t, unpairedCap, hs.x.unpairedN) | |||
| 543 | + | for i := 0; i < hs.x.unpairedN; i++ { | |||
| 544 | + | require.NotEqual(t, uint64(1), hs.x.unpaired[i].serial, "oldest dropped") | |||
| 545 | + | } | |||
| 546 | + | } | |||
| 547 | + | ||||
| 548 | + | func TestPairingZeroSerialIgnored(t *testing.T) { | |||
| 549 | + | hs := newHarness(t, nil) | |||
| 550 | + | hs.x.SetSerial(5, 0) | |||
| 551 | + | require.Zero(t, hs.x.unpairedN) | |||
| 552 | + | } | |||
| 553 | + | ||||
| 554 | + | func TestLegacySurfaceIDCountedAndIgnored(t *testing.T) { | |||
| 555 | + | hs := newHarness(t, nil) | |||
| 556 | + | const win = 0x500001 | |||
| 557 | + | hs.classic(win) | |||
| 558 | + | s := hs.mapAndWait(win) | |||
| 559 | + | hs.p.clientMessage(win, hs.p.atom("WL_SURFACE_ID"), 12) | |||
| 560 | + | readUntil(t, hs.x, func() bool { return hs.x.Stats().LegacyID == 1 }) | |||
| 561 | + | require.Zero(t, hs.x.tab.rec(s).serial) | |||
| 562 | + | } | |||
| 563 | + | ||||
| 564 | + | func TestNetWMStateClientMessageForwardsFullscreen(t *testing.T) { | |||
| 565 | + | hs := newHarness(t, nil) | |||
| 566 | + | const win = 0x500001 | |||
| 567 | + | hs.classic(win) | |||
| 568 | + | s := hs.mapAndWait(win) | |||
| 569 | + | hs.h.EXPECT().Fullscreen(s, true).Once() | |||
| 570 | + | hs.p.clientMessage(win, hs.p.atom("_NET_WM_STATE"), 1, hs.p.atom("_NET_WM_STATE_FULLSCREEN")) | |||
| 571 | + | readUntil(t, hs.x, func() bool { return hs.x.tab.rec(s).fullscreen }) | |||
| 572 | + | hs.h.EXPECT().Fullscreen(s, false).Once() // toggle | |||
| 573 | + | hs.p.clientMessage(win, hs.p.atom("_NET_WM_STATE"), 2, hs.p.atom("_NET_WM_STATE_FULLSCREEN")) | |||
| 574 | + | readUntil(t, hs.x, func() bool { return !hs.x.tab.rec(s).fullscreen }) | |||
| 575 | + | // Not written back by the message itself. | |||
| 576 | + | st, ok := hs.p.prop(win, "_NET_WM_STATE") | |||
| 577 | + | require.True(t, ok) | |||
| 578 | + | require.Empty(t, st.data) | |||
| 579 | + | } | |||
| 580 | + | ||||
| 581 | + | // Unmap, destroy, remap. | |||
| 582 | + | ||||
| 583 | + | func TestUnmapDissociatesAndRemapRereadsProperties(t *testing.T) { | |||
| 584 | + | hs := newHarness(t, nil) | |||
| 585 | + | const win = 0x500001 | |||
| 586 | + | hs.classic(win) | |||
| 587 | + | s := hs.mapAndWait(win) | |||
| 588 | + | ||||
| 589 | + | // A synthetic UnmapNotify (ICCCM withdraw request) is not an unmap. | |||
| 590 | + | hs.p.unmapNotify(win, true) | |||
| 591 | + | readUntil(t, hs.x, func() bool { return hs.x.Stats().Events >= 2 }) | |||
| 592 | + | require.True(t, hs.x.tab.rec(s).ready) | |||
| 593 | + | ||||
| 594 | + | hs.h.EXPECT().Dissociate(s, false).Once() | |||
| 595 | + | hs.p.unmapNotify(win, false) | |||
| 596 | + | readUntil(t, hs.x, func() bool { return !hs.x.tab.rec(s).ready }) | |||
| 597 | + | r := hs.x.tab.rec(s) | |||
| 598 | + | require.False(t, r.mapping) | |||
| 599 | + | require.Zero(t, r.serial) | |||
| 600 | + | hs.p.waitReq(0, func(q xpeerReq) bool { | |||
| 601 | + | return q.major == opSetInputFocus || q.major == opChangeProperty && q.u32(4) == win | |||
| 602 | + | }) | |||
| 603 | + | readUntil(t, hs.x, func() bool { | |||
| 604 | + | v, ok := hs.p.prop(win, "WM_STATE") | |||
| 605 | + | return ok && len(v.data) == 8 && binary.LittleEndian.Uint32(v.data) == 0 | |||
| 606 | + | }) | |||
| 607 | + | _, ok := hs.p.prop(win, "_NET_WM_STATE") | |||
| 608 | + | require.False(t, ok, "_NET_WM_STATE deleted") | |||
| 609 | + | list, _ := hs.p.prop(peerRoot, "_NET_CLIENT_LIST") | |||
| 610 | + | require.Empty(t, list.data) | |||
| 611 | + | ||||
| 612 | + | // Remap starts over. | |||
| 613 | + | delete(hs.ready, win) | |||
| 614 | + | hs.expectReady(win) | |||
| 615 | + | n := hs.count(func(q xpeerReq) bool { return q.major == opGetProperty && q.u32(4) == win }) | |||
| 616 | + | hs.p.mapRequest(win) | |||
| 617 | + | readUntil(t, hs.x, func() bool { _, ok := hs.ready[win]; return ok }) | |||
| 618 | + | require.Equal(t, n+propCount, hs.count(func(q xpeerReq) bool { return q.major == opGetProperty && q.u32(4) == win })) | |||
| 619 | + | list, _ = hs.p.prop(peerRoot, "_NET_CLIENT_LIST") | |||
| 620 | + | require.Equal(t, []uint32{win}, atomsOf(list)) | |||
| 621 | + | } | |||
| 622 | + | ||||
| 623 | + | func TestDestroyWhileMappingNeverReady(t *testing.T) { | |||
| 624 | + | hs := newHarness(t, nil) | |||
| 625 | + | const win = 0x500001 | |||
| 626 | + | hs.classic(win) | |||
| 627 | + | s := hs.create(win) | |||
| 628 | + | hs.p.holdReplies() | |||
| 629 | + | hs.p.mapRequest(win) | |||
| 630 | + | hs.waitMap(win) | |||
| 631 | + | hs.h.EXPECT().Dissociate(s, true).Once() | |||
| 632 | + | hs.p.destroyNotify(win) | |||
| 633 | + | readUntil(t, hs.x, func() bool { return hs.x.Slot(win) == 0 }) | |||
| 634 | + | replies := hs.x.Stats().Replies | |||
| 635 | + | hs.p.release() // replies for a window that is gone: xturbo retired their slots | |||
| 636 | + | readUntil(t, hs.x, func() bool { return hs.x.conn.Stats().DroppedReplies >= uint64(propCount) }) | |||
| 637 | + | require.Equal(t, replies, hs.x.Stats().Replies, "none reaches the XWM") | |||
| 638 | + | } | |||
| 639 | + | ||||
| 640 | + | func TestStaleRepliesAfterSlotReuseAreIgnored(t *testing.T) { | |||
| 641 | + | hs := newHarness(t, nil) | |||
| 642 | + | const old, fresh = 0x500001, 0x500002 | |||
| 643 | + | hs.classic(old) | |||
| 644 | + | hs.classic(fresh) | |||
| 645 | + | s := hs.create(old) | |||
| 646 | + | hs.p.holdReplies() | |||
| 647 | + | hs.p.mapRequest(old) | |||
| 648 | + | hs.waitMap(old) | |||
| 649 | + | hs.h.EXPECT().Dissociate(s, true).Once() | |||
| 650 | + | hs.p.destroyNotify(old) | |||
| 651 | + | readUntil(t, hs.x, func() bool { return hs.x.Slot(old) == 0 }) | |||
| 652 | + | ||||
| 653 | + | hs.expectCreated(fresh) | |||
| 654 | + | hs.p.createNotify(fresh, false) | |||
| 655 | + | readUntil(t, hs.x, func() bool { return hs.x.Slot(fresh) != 0 }) | |||
| 656 | + | require.Equal(t, s, hs.x.Slot(fresh), "the freed slot is reused") | |||
| 657 | + | ||||
| 658 | + | hs.p.release() | |||
| 659 | + | readUntil(t, hs.x, func() bool { return hs.x.conn.Stats().DroppedReplies >= uint64(propCount) }) | |||
| 660 | + | ||||
| 661 | + | // A reply that does get through with the old tag (slot reused, generation | |||
| 662 | + | // bumped) is ignored. | |||
| 663 | + | oldTag := s | Slot(hs.x.tab.rec(s).gen-1)<<16 | |||
| 664 | + | rep := make([]byte, 32) | |||
| 665 | + | rep[0] = 1 | |||
| 666 | + | hs.x.onReply(&xturbo.Reply{Kind: kindProp, Args: [4]uint32{uint32(oldTag), propClass}, Raw: rep}) | |||
| 667 | + | hs.x.onReply(&xturbo.Reply{Kind: kindGeom, Args: [4]uint32{uint32(oldTag)}, Raw: rep}) | |||
| 668 | + | require.EqualValues(t, 2, hs.x.Stats().Stale) | |||
| 669 | + | require.False(t, hs.x.tab.rec(s).ready, "stale replies must not complete the new window") | |||
| 670 | + | require.Zero(t, hs.x.tab.rec(s).pending) | |||
| 671 | + | } | |||
| 672 | + | ||||
| 673 | + | // Reparenting. | |||
| 674 | + | ||||
| 675 | + | func TestReparentAwayFromRootRemovesManagedWindow(t *testing.T) { | |||
| 676 | + | hs := newHarness(t, nil) | |||
| 677 | + | const win = 0x500001 | |||
| 678 | + | hs.classic(win) | |||
| 679 | + | s := hs.mapAndWait(win) | |||
| 680 | + | hs.h.EXPECT().Dissociate(s, true).Once() | |||
| 681 | + | hs.p.reparentNotify(win, 0x600000) | |||
| 682 | + | readUntil(t, hs.x, func() bool { return hs.x.Slot(win) == 0 }) | |||
| 683 | + | list, _ := hs.p.prop(peerRoot, "_NET_CLIENT_LIST") | |||
| 684 | + | require.Empty(t, list.data) | |||
| 685 | + | require.Zero(t, hs.x.tab.n) | |||
| 686 | + | } | |||
| 687 | + | ||||
| 688 | + | func TestReparentAwayOfUnmanagedWindowRemovesIt(t *testing.T) { | |||
| 689 | + | hs := newHarness(t, nil) | |||
| 690 | + | hs.p.createNotify(0x500009, true) | |||
| 691 | + | readUntil(t, hs.x, func() bool { return hs.x.Slot(0x500009) != 0 }) | |||
| 692 | + | hs.p.reparentNotify(0x500009, 0x600000) | |||
| 693 | + | readUntil(t, hs.x, func() bool { return hs.x.Slot(0x500009) == 0 }) | |||
| 694 | + | } | |||
| 695 | + | ||||
| 696 | + | func TestReparentIntoRootAdoptsWindow(t *testing.T) { | |||
| 697 | + | hs := newHarness(t, nil) | |||
| 698 | + | const win = 0x500001 | |||
| 699 | + | hs.expectCreated(win) | |||
| 700 | + | hs.p.reparentNotify(win, peerRoot) | |||
| 701 | + | readUntil(t, hs.x, func() bool { return hs.x.Slot(win) != 0 }) | |||
| 702 | + | require.Equal(t, kindManaged, hs.x.tab.rec(hs.x.Slot(win)).kind) | |||
| 703 | + | ||||
| 704 | + | // Already known: no second Created. | |||
| 705 | + | hs.p.reparentNotify(win, peerRoot) | |||
| 706 | + | readUntil(t, hs.x, func() bool { return hs.x.Stats().Events >= 2 }) | |||
| 707 | + | } | |||
| 708 | + | ||||
| 709 | + | func TestReparentIntoRootOfOverrideRedirectWindowStaysUnmanaged(t *testing.T) { | |||
| 710 | + | hs := newHarness(t, nil) | |||
| 711 | + | hs.p.event(21, func(b *[32]byte) { | |||
| 712 | + | binary.LittleEndian.PutUint32(b[4:], peerRoot) | |||
| 713 | + | binary.LittleEndian.PutUint32(b[8:], 0x500009) | |||
| 714 | + | binary.LittleEndian.PutUint32(b[12:], peerRoot) | |||
| 715 | + | b[20] = 1 | |||
| 716 | + | }) | |||
| 717 | + | readUntil(t, hs.x, func() bool { return hs.x.Slot(0x500009) != 0 }) | |||
| 718 | + | require.Equal(t, kindUnmanaged, hs.x.tab.rec(hs.x.Slot(0x500009)).kind) | |||
| 719 | + | } | |||
| 720 | + | ||||
| 721 | + | func TestReparentOfWMWindowIgnored(t *testing.T) { | |||
| 722 | + | hs := newHarness(t, nil) | |||
| 723 | + | hs.p.reparentNotify(hs.x.wmWin, peerRoot) | |||
| 724 | + | readUntil(t, hs.x, func() bool { return hs.x.Stats().Events >= 1 }) | |||
| 725 | + | require.Zero(t, hs.x.Slot(hs.x.wmWin)) | |||
| 726 | + | } | |||
| 727 | + | ||||
| 728 | + | // Window known only before Attach: Attach replays the map flow. | |||
| 729 | + | func TestAttachMapsWindowsRequestedBeforeAttach(t *testing.T) { | |||
| 730 | + | x, p := bootPeer(t, nil) | |||
| 731 | + | const win = 0x500001 | |||
| 732 | + | p.setProp(win, uint32(xproto.AtomWmClass), uint32(xproto.AtomString), 8, []byte("a\x00B\x00")) | |||
| 733 | + | p.createNotify(win, false) | |||
| 734 | + | p.mapRequest(win) | |||
| 735 | + | readUntil(t, x, func() bool { return x.Stats().Events >= 2 }) | |||
| 736 | + | h := newMockhost(t) | |||
| 737 | + | src := newMockfdSource(t) | |||
| 738 | + | src.EXPECT().Remove().Maybe() | |||
| 739 | + | post, _ := newPost() | |||
| 740 | + | var got WindowInfo | |||
| 741 | + | done := false | |||
| 742 | + | h.EXPECT().Created(mock.Anything, uint32(win)).Return(ports.WindowID(1)).Once() | |||
| 743 | + | h.EXPECT().Ready(mock.Anything, mock.Anything).Run(func(_ Slot, i WindowInfo) { got, done = i, true }).Once() | |||
| 744 | + | x.attach(src, h, post) | |||
| 745 | + | readUntil(t, x, func() bool { return done }) | |||
| 746 | + | require.Equal(t, "B", got.AppID) | |||
| 747 | + | } | |||
| 748 | + | ||||
| 749 | + | // Replies complete a map in any order (a server may answer the geometry | |||
| 750 | + | // before the properties it was asked for first): Ready fires on the last one. | |||
| 751 | + | func TestMapFlowReadyFiresOnLastReplyInAnyOrder(t *testing.T) { | |||
| 752 | + | hs := newHarness(t, nil) | |||
| 753 | + | const win = 0x500001 | |||
| 754 | + | hs.classic(win) | |||
| 755 | + | s := hs.create(win) | |||
| 756 | + | r := hs.x.tab.rec(s) | |||
| 757 | + | r.mapping, r.pending = true, propMaskAll&^propClientIDs | |||
| 758 | + | hs.expectReady(win) | |||
| 759 | + | order := []int{propCount, propPID, propClass, propNetName, propName, propHints, propNormalHints, propProtocols, propTransientFor, propWindowType, propState} | |||
| 760 | + | for i, bit := range order { | |||
| 761 | + | require.False(t, hs.x.tab.rec(s).ready, i) | |||
| 762 | + | if bit == propCount { // the geometry | |||
| 763 | + | hs.x.tab.rec(s).w, hs.x.tab.rec(s).h = 300, 200 | |||
| 764 | + | hs.x.tab.rec(s).pending &^= propGeom | |||
| 765 | + | hs.x.checkReady(s) | |||
| 766 | + | continue | |||
| 767 | + | } | |||
| 768 | + | var val []byte | |||
| 769 | + | var format uint8 = 8 | |||
| 770 | + | switch bit { | |||
| 771 | + | case propClass: | |||
| 772 | + | val = []byte("a\x00B\x00") | |||
| 773 | + | case propNetName: | |||
| 774 | + | val = []byte("t") | |||
| 775 | + | case propPID: | |||
| 776 | + | val, format = le32(5), 32 | |||
| 777 | + | default: | |||
| 778 | + | format = 32 | |||
| 779 | + | } | |||
| 780 | + | x := hs.x | |||
| 781 | + | x.applyProp(s, bit, format, val) | |||
| 782 | + | x.tab.rec(s).pending &^= 1 << bit | |||
| 783 | + | x.checkReady(s) | |||
| 784 | + | } | |||
| 785 | + | require.True(t, hs.x.tab.rec(s).ready) | |||
| 786 | + | require.Equal(t, "B", hs.ready[win].AppID) | |||
| 787 | + | require.Equal(t, "t", hs.ready[win].Title) | |||
| 788 | + | require.Equal(t, 5, hs.ready[win].PID) | |||
| 789 | + | } | |||
M internal/adapters/wayland/xwm/props.go +305 -7
| @@ -1,12 +1,17 @@ | |||
| 1 | 1 | package xwm | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | + | "bytes" | |
| 5 | + | "encoding/binary" | |
| 6 | + | ||
| 4 | 7 | "bnema.dev/xturbo" | |
| 8 | + | "bnema.dev/xturbo/res" | |
| 5 | 9 | "bnema.dev/xturbo/xproto" | |
| 6 | 10 | ) | |
| 7 | 11 | ||
| 8 | 12 | // Property indices (second Expect argument of kindProp) and their bits in | |
| 9 | - | // record.pending. propGeom is the GetGeometry bit. | |
| 13 | + | // record.pending. propGeom is the GetGeometry bit; propClientIDs is raised | |
| 14 | + | // while a QueryClientIds reply stands in for a missing _NET_WM_PID. | |
| 10 | 15 | const ( | |
| 11 | 16 | propClass = iota | |
| 12 | 17 | propName | |
| @@ -22,14 +27,307 @@ const ( | |||
| 22 | 27 | ) | |
| 23 | 28 | ||
| 24 | 29 | const ( | |
| 25 | - | propGeom uint16 = 1 << propCount | |
| 30 | + | propGeom uint16 = 1 << propCount | |
| 31 | + | propClientIDs uint16 = propGeom << 1 | |
| 32 | + | // propMaskAll is what a map waits for: every property and the geometry. | |
| 26 | 33 | propMaskAll uint16 = propGeom<<1 - 1 | |
| 27 | 34 | ) | |
| 28 | 35 | ||
| 29 | - | // onPropertyNotify handles a changed property of a managed window. | |
| 30 | - | func (x *XWM) onPropertyNotify(ev *xturbo.Event) { _ = ev } | |
| 36 | + | // WM_NORMAL_HINTS flags and WM_HINTS flags. | |
| 37 | + | const ( | |
| 38 | + | hintInput = 1 << 0 | |
| 39 | + | hintMinSize = 1 << 4 | |
| 40 | + | hintMaxSize = 1 << 5 | |
| 41 | + | ) | |
| 42 | + | ||
| 43 | + | // maxPropWords bounds one GetProperty (4 KiB), so titles are truncated there. | |
| 44 | + | const maxPropWords = 1024 | |
| 45 | + | ||
| 46 | + | // propIndex maps a property atom to its index, or -1 when it is not watched. | |
| 47 | + | func (x *XWM) propIndex(a uint32) int { | |
| 48 | + | switch a { | |
| 49 | + | case uint32(xproto.AtomWmClass): | |
| 50 | + | return propClass | |
| 51 | + | case uint32(xproto.AtomWmName): | |
| 52 | + | return propName | |
| 53 | + | case uint32(xproto.AtomWmHints): | |
| 54 | + | return propHints | |
| 55 | + | case uint32(xproto.AtomWmNormalHints): | |
| 56 | + | return propNormalHints | |
| 57 | + | case uint32(xproto.AtomWmTransientFor): | |
| 58 | + | return propTransientFor | |
| 59 | + | case x.atoms[atomNetWMName]: | |
| 60 | + | return propNetName | |
| 61 | + | case x.atoms[atomWMProtocols]: | |
| 62 | + | return propProtocols | |
| 63 | + | case x.atoms[atomNetWMWindowType]: | |
| 64 | + | return propWindowType | |
| 65 | + | case x.atoms[atomNetWMState]: | |
| 66 | + | return propState | |
| 67 | + | case x.atoms[atomNetWMPID]: | |
| 68 | + | return propPID | |
| 69 | + | } | |
| 70 | + | return -1 | |
| 71 | + | } | |
| 72 | + | ||
| 73 | + | func (x *XWM) propAtom(idx int) xproto.Atom { | |
| 74 | + | switch idx { | |
| 75 | + | case propClass: | |
| 76 | + | return xproto.AtomWmClass | |
| 77 | + | case propName: | |
| 78 | + | return xproto.AtomWmName | |
| 79 | + | case propHints: | |
| 80 | + | return xproto.AtomWmHints | |
| 81 | + | case propNormalHints: | |
| 82 | + | return xproto.AtomWmNormalHints | |
| 83 | + | case propTransientFor: | |
| 84 | + | return xproto.AtomWmTransientFor | |
| 85 | + | case propNetName: | |
| 86 | + | return xproto.Atom(x.atoms[atomNetWMName]) | |
| 87 | + | case propProtocols: | |
| 88 | + | return xproto.Atom(x.atoms[atomWMProtocols]) | |
| 89 | + | case propWindowType: | |
| 90 | + | return xproto.Atom(x.atoms[atomNetWMWindowType]) | |
| 91 | + | case propState: | |
| 92 | + | return xproto.Atom(x.atoms[atomNetWMState]) | |
| 93 | + | default: | |
| 94 | + | return xproto.Atom(x.atoms[atomNetWMPID]) | |
| 95 | + | } | |
| 96 | + | } | |
| 97 | + | ||
| 98 | + | // requestProp queues a GetProperty for property idx of s. | |
| 99 | + | func (x *XWM) requestProp(s Slot, idx int) { | |
| 100 | + | rec := x.tab.rec(s) | |
| 101 | + | seq := xproto.GetProperty(x.conn.Buf(), false, xproto.Window(rec.xid), x.propAtom(idx), xproto.AtomAny, 0, maxPropWords) | |
| 102 | + | rec.pending |= 1 << idx | |
| 103 | + | x.expect(seq, kindProp, x.tab.tag(s), uint32(idx)) | |
| 104 | + | } | |
| 105 | + | ||
| 106 | + | // onPropertyNotify handles a changed property of a managed window that is | |
| 107 | + | // being mapped or is mapped; unwatched atoms cost nothing. | |
| 108 | + | func (x *XWM) onPropertyNotify(ev *xturbo.Event) { | |
| 109 | + | e := xproto.PropertyNotifyOf(ev) | |
| 110 | + | s := x.tab.lookup(uint32(e.Window())) | |
| 111 | + | if s == 0 { | |
| 112 | + | return | |
| 113 | + | } | |
| 114 | + | if rec := x.tab.rec(s); rec.kind != kindManaged || !rec.mapping { | |
| 115 | + | return | |
| 116 | + | } | |
| 117 | + | idx := x.propIndex(uint32(e.Atom())) | |
| 118 | + | if idx < 0 { | |
| 119 | + | return | |
| 120 | + | } | |
| 121 | + | if e.State() == xproto.PropertyDelete { | |
| 122 | + | x.applyProp(s, idx, 0, nil) | |
| 123 | + | return | |
| 124 | + | } | |
| 125 | + | x.requestProp(s, idx) | |
| 126 | + | } | |
| 127 | + | ||
| 128 | + | // onPropReply decodes one GetProperty reply into the record. An absent | |
| 129 | + | // property (format 0) clears its fields. | |
| 130 | + | func (x *XWM) onPropReply(s Slot, _ *record, r *xturbo.Reply) { | |
| 131 | + | idx := int(r.Args[1]) | |
| 132 | + | if idx < 0 || idx >= propCount { | |
| 133 | + | return | |
| 134 | + | } | |
| 135 | + | var format uint8 | |
| 136 | + | var val []byte | |
| 137 | + | if rep, ok := xproto.ParseGetPropertyReply(r.Raw); ok { | |
| 138 | + | format, val = rep.Format(), rep.Value() | |
| 139 | + | } | |
| 140 | + | x.applyProp(s, idx, format, val) | |
| 141 | + | x.tab.rec(s).pending &^= 1 << idx | |
| 142 | + | x.checkReady(s) | |
| 143 | + | } | |
| 144 | + | ||
| 145 | + | func word(b []byte, i int) uint32 { return binary.LittleEndian.Uint32(b[4*i:]) } | |
| 146 | + | ||
| 147 | + | // applyProp stores one decoded property. It does not allocate unless a string | |
| 148 | + | // changed. Host calls come last: the record is not touched after them. | |
| 149 | + | func (x *XWM) applyProp(s Slot, idx int, format uint8, val []byte) { | |
| 150 | + | rec := x.tab.rec(s) | |
| 151 | + | if idx == propClass || idx == propName || idx == propNetName { | |
| 152 | + | if format != 8 { | |
| 153 | + | val = nil | |
| 154 | + | } | |
| 155 | + | } else if format != 32 { | |
| 156 | + | val = nil | |
| 157 | + | } | |
| 158 | + | switch idx { | |
| 159 | + | case propClass: | |
| 160 | + | inst, class := val, []byte(nil) | |
| 161 | + | if i := bytes.IndexByte(val, 0); i >= 0 { | |
| 162 | + | inst, class = val[:i], val[i+1:] | |
| 163 | + | if j := bytes.IndexByte(class, 0); j >= 0 { | |
| 164 | + | class = class[:j] | |
| 165 | + | } | |
| 166 | + | } | |
| 167 | + | app := class | |
| 168 | + | if len(app) == 0 { | |
| 169 | + | app = inst | |
| 170 | + | } | |
| 171 | + | if rec.class == string(app) { | |
| 172 | + | return | |
| 173 | + | } | |
| 174 | + | rec.class = string(app) | |
| 175 | + | if rec.ready { | |
| 176 | + | x.host.AppID(s, rec.class) | |
| 177 | + | } | |
| 178 | + | case propName: | |
| 179 | + | if !rec.hasNetName { | |
| 180 | + | x.setTitle(s, val) | |
| 181 | + | } | |
| 182 | + | case propNetName: | |
| 183 | + | had := rec.hasNetName | |
| 184 | + | rec.hasNetName = len(val) > 0 | |
| 185 | + | if rec.hasNetName { | |
| 186 | + | x.setTitle(s, val) | |
| 187 | + | } else if had && rec.mapping { | |
| 188 | + | x.requestProp(s, propName) | |
| 189 | + | } | |
| 190 | + | case propHints: | |
| 191 | + | rec.input = true | |
| 192 | + | if len(val) >= 8 && word(val, 0)&hintInput != 0 { | |
| 193 | + | rec.input = word(val, 1) != 0 | |
| 194 | + | } | |
| 195 | + | case propNormalHints: | |
| 196 | + | rec.minW, rec.minH, rec.maxW, rec.maxH = 0, 0, 0, 0 | |
| 197 | + | if len(val) >= 36 { | |
| 198 | + | fl := word(val, 0) | |
| 199 | + | if fl&hintMinSize != 0 { | |
| 200 | + | rec.minW, rec.minH = int32(word(val, 5)), int32(word(val, 6)) | |
| 201 | + | } | |
| 202 | + | if fl&hintMaxSize != 0 { | |
| 203 | + | rec.maxW, rec.maxH = int32(word(val, 7)), int32(word(val, 8)) | |
| 204 | + | } | |
| 205 | + | } | |
| 206 | + | case propProtocols: | |
| 207 | + | rec.deleteWindow, rec.takeFocus = false, false | |
| 208 | + | for i := 0; i+4 <= len(val); i += 4 { | |
| 209 | + | switch binary.LittleEndian.Uint32(val[i:]) { | |
| 210 | + | case x.atoms[atomWMDeleteWindow]: | |
| 211 | + | rec.deleteWindow = true | |
| 212 | + | case x.atoms[atomWMTakeFocus]: | |
| 213 | + | rec.takeFocus = true | |
| 214 | + | } | |
| 215 | + | } | |
| 216 | + | case propTransientFor: | |
| 217 | + | var t uint32 | |
| 218 | + | if len(val) >= 4 { | |
| 219 | + | t = word(val, 0) | |
| 220 | + | } | |
| 221 | + | if t == rec.transient { | |
| 222 | + | return | |
| 223 | + | } | |
| 224 | + | rec.transient = t | |
| 225 | + | if rec.ready { | |
| 226 | + | x.host.Parent(s, x.managedSlot(t)) | |
| 227 | + | } | |
| 228 | + | case propWindowType: | |
| 229 | + | rec.wtype = 0 | |
| 230 | + | for i := 0; i+4 <= len(val); i += 4 { | |
| 231 | + | if t := x.windowType(binary.LittleEndian.Uint32(val[i:])); t != 0 { | |
| 232 | + | rec.wtype = t | |
| 233 | + | break | |
| 234 | + | } | |
| 235 | + | } | |
| 236 | + | case propState: | |
| 237 | + | var modal, fs bool | |
| 238 | + | for i := 0; i+4 <= len(val); i += 4 { | |
| 239 | + | switch binary.LittleEndian.Uint32(val[i:]) { | |
| 240 | + | case x.atoms[atomNetWMStateModal]: | |
| 241 | + | modal = true | |
| 242 | + | case x.atoms[atomNetWMStateFullscreen]: | |
| 243 | + | fs = true | |
| 244 | + | } | |
| 245 | + | } | |
| 246 | + | changed := fs != rec.fullscreen | |
| 247 | + | rec.modal, rec.fullscreen = modal, fs | |
| 248 | + | if changed && rec.ready { | |
| 249 | + | x.host.Fullscreen(s, fs) | |
| 250 | + | } | |
| 251 | + | case propPID: | |
| 252 | + | if len(val) >= 4 { | |
| 253 | + | rec.pid = int32(word(val, 0)) | |
| 254 | + | return | |
| 255 | + | } | |
| 256 | + | rec.pid = 0 | |
| 257 | + | if !rec.ready && rec.pending&propClientIDs == 0 && x.conn.Ext().Info(xturbo.ExtRes).Present { | |
| 258 | + | x.queryClientIDs(s) | |
| 259 | + | } | |
| 260 | + | } | |
| 261 | + | } | |
| 262 | + | ||
| 263 | + | // setTitle stores a title when it differs; only a change allocates. | |
| 264 | + | func (x *XWM) setTitle(s Slot, val []byte) { | |
| 265 | + | rec := x.tab.rec(s) | |
| 266 | + | if rec.title == string(val) { | |
| 267 | + | return | |
| 268 | + | } | |
| 269 | + | rec.title = string(val) | |
| 270 | + | if rec.ready { | |
| 271 | + | x.host.Title(s, rec.title) | |
| 272 | + | } | |
| 273 | + | } | |
| 274 | + | ||
| 275 | + | // windowType returns the atom enum of a recognised _NET_WM_WINDOW_TYPE atom, | |
| 276 | + | // or 0. | |
| 277 | + | func (x *XWM) windowType(a uint32) uint8 { | |
| 278 | + | for t := atomNetWMWindowTypeNormal; t <= atomNetWMWindowTypeDND; t++ { | |
| 279 | + | if x.atoms[t] == a { | |
| 280 | + | return uint8(t) | |
| 281 | + | } | |
| 282 | + | } | |
| 283 | + | return 0 | |
| 284 | + | } | |
| 285 | + | ||
| 286 | + | // floatingType reports whether a window type floats by itself. | |
| 287 | + | func floatingType(t uint8) bool { | |
| 288 | + | switch int(t) { | |
| 289 | + | case atomNetWMWindowTypeDialog, atomNetWMWindowTypeUtility, atomNetWMWindowTypeSplash, atomNetWMWindowTypeToolbar: | |
| 290 | + | return true | |
| 291 | + | } | |
| 292 | + | return false | |
| 293 | + | } | |
| 294 | + | ||
| 295 | + | // managedSlot returns the slot of the managed window xid, or 0. | |
| 296 | + | func (x *XWM) managedSlot(xid uint32) Slot { | |
| 297 | + | if xid == 0 { | |
| 298 | + | return 0 | |
| 299 | + | } | |
| 300 | + | if s := x.tab.lookup(xid); s != 0 && x.tab.rec(s).kind == kindManaged { | |
| 301 | + | return s | |
| 302 | + | } | |
| 303 | + | return 0 | |
| 304 | + | } | |
| 31 | 305 | ||
| 32 | - | // onPropReply decodes one GetProperty reply into the record. | |
| 33 | - | func (x *XWM) onPropReply(s Slot, rec *record, r *xturbo.Reply) { _, _, _ = s, rec, r } | |
| 306 | + | // queryClientIDs asks XRes for the PID of the client owning s, which stands | |
| 307 | + | // in for a missing _NET_WM_PID: Ready waits for it (propClientIDs). | |
| 308 | + | func (x *XWM) queryClientIDs(s Slot) { | |
| 309 | + | rec := x.tab.rec(s) | |
| 310 | + | specs := [1]res.ClientIdSpec{{Client: rec.xid, Mask: res.ClientIdMaskLocalClientPID}} | |
| 311 | + | seq := res.QueryClientIds(x.conn.Buf(), specs[:]) | |
| 312 | + | if seq == 0 { | |
| 313 | + | return | |
| 314 | + | } | |
| 315 | + | rec.pending |= propClientIDs | |
| 316 | + | x.expect(seq, kindClientIds, x.tab.tag(s), 0) | |
| 317 | + | } | |
| 34 | 318 | ||
| 35 | - | var _ = xproto.AtomWmClass | |
| 319 | + | // onClientIdsReply stores the PID XRes found and releases the map. | |
| 320 | + | func (x *XWM) onClientIdsReply(s Slot, rec *record, r *xturbo.Reply) { | |
| 321 | + | if q, ok := res.ParseQueryClientIdsReply(r.Raw); ok { | |
| 322 | + | it := q.Ids() | |
| 323 | + | for it.Next() { | |
| 324 | + | v := it.Value() | |
| 325 | + | if v.Spec().Mask == res.ClientIdMaskLocalClientPID && v.Value().Len() > 0 { | |
| 326 | + | rec.pid = int32(v.Value().At(0)) | |
| 327 | + | break | |
| 328 | + | } | |
| 329 | + | } | |
| 330 | + | } | |
| 331 | + | rec.pending &^= propClientIDs | |
| 332 | + | x.checkReady(s) | |
| 333 | + | } | |
| @@ -1,12 +1,17 @@ | |||||
| 1 | package xwm | 1 | package xwm | ||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | + | "bytes" | |||
| 5 | + | "encoding/binary" | |||
| 6 | + | ||||
| 4 | "bnema.dev/xturbo" | 7 | "bnema.dev/xturbo" | ||
| 8 | + | "bnema.dev/xturbo/res" | |||
| 5 | "bnema.dev/xturbo/xproto" | 9 | "bnema.dev/xturbo/xproto" | ||
| 6 | ) | 10 | ) | ||
| 7 | 11 | ||||
| 8 | // Property indices (second Expect argument of kindProp) and their bits in | 12 | // Property indices (second Expect argument of kindProp) and their bits in | ||
| 9 | - | // record.pending. propGeom is the GetGeometry bit. | 13 | + | // record.pending. propGeom is the GetGeometry bit; propClientIDs is raised |
| 14 | + | // while a QueryClientIds reply stands in for a missing _NET_WM_PID. | |||
| 10 | const ( | 15 | const ( | ||
| 11 | propClass = iota | 16 | propClass = iota | ||
| 12 | propName | 17 | propName | ||
| @@ -22,14 +27,307 @@ const ( | |||||
| 22 | ) | 27 | ) | ||
| 23 | 28 | ||||
| 24 | const ( | 29 | const ( | ||
| 25 | - | propGeom uint16 = 1 << propCount | 30 | + | propGeom uint16 = 1 << propCount |
| 31 | + | propClientIDs uint16 = propGeom << 1 | |||
| 32 | + | // propMaskAll is what a map waits for: every property and the geometry. | |||
| 26 | propMaskAll uint16 = propGeom<<1 - 1 | 33 | propMaskAll uint16 = propGeom<<1 - 1 | ||
| 27 | ) | 34 | ) | ||
| 28 | 35 | ||||
| 29 | - | // onPropertyNotify handles a changed property of a managed window. | 36 | + | // WM_NORMAL_HINTS flags and WM_HINTS flags. |
| 30 | - | func (x *XWM) onPropertyNotify(ev *xturbo.Event) { _ = ev } | 37 | + | const ( |
| 38 | + | hintInput = 1 << 0 | |||
| 39 | + | hintMinSize = 1 << 4 | |||
| 40 | + | hintMaxSize = 1 << 5 | |||
| 41 | + | ) | |||
| 42 | + | ||||
| 43 | + | // maxPropWords bounds one GetProperty (4 KiB), so titles are truncated there. | |||
| 44 | + | const maxPropWords = 1024 | |||
| 45 | + | ||||
| 46 | + | // propIndex maps a property atom to its index, or -1 when it is not watched. | |||
| 47 | + | func (x *XWM) propIndex(a uint32) int { | |||
| 48 | + | switch a { | |||
| 49 | + | case uint32(xproto.AtomWmClass): | |||
| 50 | + | return propClass | |||
| 51 | + | case uint32(xproto.AtomWmName): | |||
| 52 | + | return propName | |||
| 53 | + | case uint32(xproto.AtomWmHints): | |||
| 54 | + | return propHints | |||
| 55 | + | case uint32(xproto.AtomWmNormalHints): | |||
| 56 | + | return propNormalHints | |||
| 57 | + | case uint32(xproto.AtomWmTransientFor): | |||
| 58 | + | return propTransientFor | |||
| 59 | + | case x.atoms[atomNetWMName]: | |||
| 60 | + | return propNetName | |||
| 61 | + | case x.atoms[atomWMProtocols]: | |||
| 62 | + | return propProtocols | |||
| 63 | + | case x.atoms[atomNetWMWindowType]: | |||
| 64 | + | return propWindowType | |||
| 65 | + | case x.atoms[atomNetWMState]: | |||
| 66 | + | return propState | |||
| 67 | + | case x.atoms[atomNetWMPID]: | |||
| 68 | + | return propPID | |||
| 69 | + | } | |||
| 70 | + | return -1 | |||
| 71 | + | } | |||
| 72 | + | ||||
| 73 | + | func (x *XWM) propAtom(idx int) xproto.Atom { | |||
| 74 | + | switch idx { | |||
| 75 | + | case propClass: | |||
| 76 | + | return xproto.AtomWmClass | |||
| 77 | + | case propName: | |||
| 78 | + | return xproto.AtomWmName | |||
| 79 | + | case propHints: | |||
| 80 | + | return xproto.AtomWmHints | |||
| 81 | + | case propNormalHints: | |||
| 82 | + | return xproto.AtomWmNormalHints | |||
| 83 | + | case propTransientFor: | |||
| 84 | + | return xproto.AtomWmTransientFor | |||
| 85 | + | case propNetName: | |||
| 86 | + | return xproto.Atom(x.atoms[atomNetWMName]) | |||
| 87 | + | case propProtocols: | |||
| 88 | + | return xproto.Atom(x.atoms[atomWMProtocols]) | |||
| 89 | + | case propWindowType: | |||
| 90 | + | return xproto.Atom(x.atoms[atomNetWMWindowType]) | |||
| 91 | + | case propState: | |||
| 92 | + | return xproto.Atom(x.atoms[atomNetWMState]) | |||
| 93 | + | default: | |||
| 94 | + | return xproto.Atom(x.atoms[atomNetWMPID]) | |||
| 95 | + | } | |||
| 96 | + | } | |||
| 97 | + | ||||
| 98 | + | // requestProp queues a GetProperty for property idx of s. | |||
| 99 | + | func (x *XWM) requestProp(s Slot, idx int) { | |||
| 100 | + | rec := x.tab.rec(s) | |||
| 101 | + | seq := xproto.GetProperty(x.conn.Buf(), false, xproto.Window(rec.xid), x.propAtom(idx), xproto.AtomAny, 0, maxPropWords) | |||
| 102 | + | rec.pending |= 1 << idx | |||
| 103 | + | x.expect(seq, kindProp, x.tab.tag(s), uint32(idx)) | |||
| 104 | + | } | |||
| 105 | + | ||||
| 106 | + | // onPropertyNotify handles a changed property of a managed window that is | |||
| 107 | + | // being mapped or is mapped; unwatched atoms cost nothing. | |||
| 108 | + | func (x *XWM) onPropertyNotify(ev *xturbo.Event) { | |||
| 109 | + | e := xproto.PropertyNotifyOf(ev) | |||
| 110 | + | s := x.tab.lookup(uint32(e.Window())) | |||
| 111 | + | if s == 0 { | |||
| 112 | + | return | |||
| 113 | + | } | |||
| 114 | + | if rec := x.tab.rec(s); rec.kind != kindManaged || !rec.mapping { | |||
| 115 | + | return | |||
| 116 | + | } | |||
| 117 | + | idx := x.propIndex(uint32(e.Atom())) | |||
| 118 | + | if idx < 0 { | |||
| 119 | + | return | |||
| 120 | + | } | |||
| 121 | + | if e.State() == xproto.PropertyDelete { | |||
| 122 | + | x.applyProp(s, idx, 0, nil) | |||
| 123 | + | return | |||
| 124 | + | } | |||
| 125 | + | x.requestProp(s, idx) | |||
| 126 | + | } | |||
| 127 | + | ||||
| 128 | + | // onPropReply decodes one GetProperty reply into the record. An absent | |||
| 129 | + | // property (format 0) clears its fields. | |||
| 130 | + | func (x *XWM) onPropReply(s Slot, _ *record, r *xturbo.Reply) { | |||
| 131 | + | idx := int(r.Args[1]) | |||
| 132 | + | if idx < 0 || idx >= propCount { | |||
| 133 | + | return | |||
| 134 | + | } | |||
| 135 | + | var format uint8 | |||
| 136 | + | var val []byte | |||
| 137 | + | if rep, ok := xproto.ParseGetPropertyReply(r.Raw); ok { | |||
| 138 | + | format, val = rep.Format(), rep.Value() | |||
| 139 | + | } | |||
| 140 | + | x.applyProp(s, idx, format, val) | |||
| 141 | + | x.tab.rec(s).pending &^= 1 << idx | |||
| 142 | + | x.checkReady(s) | |||
| 143 | + | } | |||
| 144 | + | ||||
| 145 | + | func word(b []byte, i int) uint32 { return binary.LittleEndian.Uint32(b[4*i:]) } | |||
| 146 | + | ||||
| 147 | + | // applyProp stores one decoded property. It does not allocate unless a string | |||
| 148 | + | // changed. Host calls come last: the record is not touched after them. | |||
| 149 | + | func (x *XWM) applyProp(s Slot, idx int, format uint8, val []byte) { | |||
| 150 | + | rec := x.tab.rec(s) | |||
| 151 | + | if idx == propClass || idx == propName || idx == propNetName { | |||
| 152 | + | if format != 8 { | |||
| 153 | + | val = nil | |||
| 154 | + | } | |||
| 155 | + | } else if format != 32 { | |||
| 156 | + | val = nil | |||
| 157 | + | } | |||
| 158 | + | switch idx { | |||
| 159 | + | case propClass: | |||
| 160 | + | inst, class := val, []byte(nil) | |||
| 161 | + | if i := bytes.IndexByte(val, 0); i >= 0 { | |||
| 162 | + | inst, class = val[:i], val[i+1:] | |||
| 163 | + | if j := bytes.IndexByte(class, 0); j >= 0 { | |||
| 164 | + | class = class[:j] | |||
| 165 | + | } | |||
| 166 | + | } | |||
| 167 | + | app := class | |||
| 168 | + | if len(app) == 0 { | |||
| 169 | + | app = inst | |||
| 170 | + | } | |||
| 171 | + | if rec.class == string(app) { | |||
| 172 | + | return | |||
| 173 | + | } | |||
| 174 | + | rec.class = string(app) | |||
| 175 | + | if rec.ready { | |||
| 176 | + | x.host.AppID(s, rec.class) | |||
| 177 | + | } | |||
| 178 | + | case propName: | |||
| 179 | + | if !rec.hasNetName { | |||
| 180 | + | x.setTitle(s, val) | |||
| 181 | + | } | |||
| 182 | + | case propNetName: | |||
| 183 | + | had := rec.hasNetName | |||
| 184 | + | rec.hasNetName = len(val) > 0 | |||
| 185 | + | if rec.hasNetName { | |||
| 186 | + | x.setTitle(s, val) | |||
| 187 | + | } else if had && rec.mapping { | |||
| 188 | + | x.requestProp(s, propName) | |||
| 189 | + | } | |||
| 190 | + | case propHints: | |||
| 191 | + | rec.input = true | |||
| 192 | + | if len(val) >= 8 && word(val, 0)&hintInput != 0 { | |||
| 193 | + | rec.input = word(val, 1) != 0 | |||
| 194 | + | } | |||
| 195 | + | case propNormalHints: | |||
| 196 | + | rec.minW, rec.minH, rec.maxW, rec.maxH = 0, 0, 0, 0 | |||
| 197 | + | if len(val) >= 36 { | |||
| 198 | + | fl := word(val, 0) | |||
| 199 | + | if fl&hintMinSize != 0 { | |||
| 200 | + | rec.minW, rec.minH = int32(word(val, 5)), int32(word(val, 6)) | |||
| 201 | + | } | |||
| 202 | + | if fl&hintMaxSize != 0 { | |||
| 203 | + | rec.maxW, rec.maxH = int32(word(val, 7)), int32(word(val, 8)) | |||
| 204 | + | } | |||
| 205 | + | } | |||
| 206 | + | case propProtocols: | |||
| 207 | + | rec.deleteWindow, rec.takeFocus = false, false | |||
| 208 | + | for i := 0; i+4 <= len(val); i += 4 { | |||
| 209 | + | switch binary.LittleEndian.Uint32(val[i:]) { | |||
| 210 | + | case x.atoms[atomWMDeleteWindow]: | |||
| 211 | + | rec.deleteWindow = true | |||
| 212 | + | case x.atoms[atomWMTakeFocus]: | |||
| 213 | + | rec.takeFocus = true | |||
| 214 | + | } | |||
| 215 | + | } | |||
| 216 | + | case propTransientFor: | |||
| 217 | + | var t uint32 | |||
| 218 | + | if len(val) >= 4 { | |||
| 219 | + | t = word(val, 0) | |||
| 220 | + | } | |||
| 221 | + | if t == rec.transient { | |||
| 222 | + | return | |||
| 223 | + | } | |||
| 224 | + | rec.transient = t | |||
| 225 | + | if rec.ready { | |||
| 226 | + | x.host.Parent(s, x.managedSlot(t)) | |||
| 227 | + | } | |||
| 228 | + | case propWindowType: | |||
| 229 | + | rec.wtype = 0 | |||
| 230 | + | for i := 0; i+4 <= len(val); i += 4 { | |||
| 231 | + | if t := x.windowType(binary.LittleEndian.Uint32(val[i:])); t != 0 { | |||
| 232 | + | rec.wtype = t | |||
| 233 | + | break | |||
| 234 | + | } | |||
| 235 | + | } | |||
| 236 | + | case propState: | |||
| 237 | + | var modal, fs bool | |||
| 238 | + | for i := 0; i+4 <= len(val); i += 4 { | |||
| 239 | + | switch binary.LittleEndian.Uint32(val[i:]) { | |||
| 240 | + | case x.atoms[atomNetWMStateModal]: | |||
| 241 | + | modal = true | |||
| 242 | + | case x.atoms[atomNetWMStateFullscreen]: | |||
| 243 | + | fs = true | |||
| 244 | + | } | |||
| 245 | + | } | |||
| 246 | + | changed := fs != rec.fullscreen | |||
| 247 | + | rec.modal, rec.fullscreen = modal, fs | |||
| 248 | + | if changed && rec.ready { | |||
| 249 | + | x.host.Fullscreen(s, fs) | |||
| 250 | + | } | |||
| 251 | + | case propPID: | |||
| 252 | + | if len(val) >= 4 { | |||
| 253 | + | rec.pid = int32(word(val, 0)) | |||
| 254 | + | return | |||
| 255 | + | } | |||
| 256 | + | rec.pid = 0 | |||
| 257 | + | if !rec.ready && rec.pending&propClientIDs == 0 && x.conn.Ext().Info(xturbo.ExtRes).Present { | |||
| 258 | + | x.queryClientIDs(s) | |||
| 259 | + | } | |||
| 260 | + | } | |||
| 261 | + | } | |||
| 262 | + | ||||
| 263 | + | // setTitle stores a title when it differs; only a change allocates. | |||
| 264 | + | func (x *XWM) setTitle(s Slot, val []byte) { | |||
| 265 | + | rec := x.tab.rec(s) | |||
| 266 | + | if rec.title == string(val) { | |||
| 267 | + | return | |||
| 268 | + | } | |||
| 269 | + | rec.title = string(val) | |||
| 270 | + | if rec.ready { | |||
| 271 | + | x.host.Title(s, rec.title) | |||
| 272 | + | } | |||
| 273 | + | } | |||
| 274 | + | ||||
| 275 | + | // windowType returns the atom enum of a recognised _NET_WM_WINDOW_TYPE atom, | |||
| 276 | + | // or 0. | |||
| 277 | + | func (x *XWM) windowType(a uint32) uint8 { | |||
| 278 | + | for t := atomNetWMWindowTypeNormal; t <= atomNetWMWindowTypeDND; t++ { | |||
| 279 | + | if x.atoms[t] == a { | |||
| 280 | + | return uint8(t) | |||
| 281 | + | } | |||
| 282 | + | } | |||
| 283 | + | return 0 | |||
| 284 | + | } | |||
| 285 | + | ||||
| 286 | + | // floatingType reports whether a window type floats by itself. | |||
| 287 | + | func floatingType(t uint8) bool { | |||
| 288 | + | switch int(t) { | |||
| 289 | + | case atomNetWMWindowTypeDialog, atomNetWMWindowTypeUtility, atomNetWMWindowTypeSplash, atomNetWMWindowTypeToolbar: | |||
| 290 | + | return true | |||
| 291 | + | } | |||
| 292 | + | return false | |||
| 293 | + | } | |||
| 294 | + | ||||
| 295 | + | // managedSlot returns the slot of the managed window xid, or 0. | |||
| 296 | + | func (x *XWM) managedSlot(xid uint32) Slot { | |||
| 297 | + | if xid == 0 { | |||
| 298 | + | return 0 | |||
| 299 | + | } | |||
| 300 | + | if s := x.tab.lookup(xid); s != 0 && x.tab.rec(s).kind == kindManaged { | |||
| 301 | + | return s | |||
| 302 | + | } | |||
| 303 | + | return 0 | |||
| 304 | + | } | |||
| 31 | 305 | ||||
| 32 | - | // onPropReply decodes one GetProperty reply into the record. | 306 | + | // queryClientIDs asks XRes for the PID of the client owning s, which stands |
| 33 | - | func (x *XWM) onPropReply(s Slot, rec *record, r *xturbo.Reply) { _, _, _ = s, rec, r } | 307 | + | // in for a missing _NET_WM_PID: Ready waits for it (propClientIDs). |
| 308 | + | func (x *XWM) queryClientIDs(s Slot) { | |||
| 309 | + | rec := x.tab.rec(s) | |||
| 310 | + | specs := [1]res.ClientIdSpec{{Client: rec.xid, Mask: res.ClientIdMaskLocalClientPID}} | |||
| 311 | + | seq := res.QueryClientIds(x.conn.Buf(), specs[:]) | |||
| 312 | + | if seq == 0 { | |||
| 313 | + | return | |||
| 314 | + | } | |||
| 315 | + | rec.pending |= propClientIDs | |||
| 316 | + | x.expect(seq, kindClientIds, x.tab.tag(s), 0) | |||
| 317 | + | } | |||
| 34 | 318 | ||||
| 35 | - | var _ = xproto.AtomWmClass | 319 | + | // onClientIdsReply stores the PID XRes found and releases the map. |
| 320 | + | func (x *XWM) onClientIdsReply(s Slot, rec *record, r *xturbo.Reply) { | |||
| 321 | + | if q, ok := res.ParseQueryClientIdsReply(r.Raw); ok { | |||
| 322 | + | it := q.Ids() | |||
| 323 | + | for it.Next() { | |||
| 324 | + | v := it.Value() | |||
| 325 | + | if v.Spec().Mask == res.ClientIdMaskLocalClientPID && v.Value().Len() > 0 { | |||
| 326 | + | rec.pid = int32(v.Value().At(0)) | |||
| 327 | + | break | |||
| 328 | + | } | |||
| 329 | + | } | |||
| 330 | + | } | |||
| 331 | + | rec.pending &^= propClientIDs | |||
| 332 | + | x.checkReady(s) | |||
| 333 | + | } | |||
A internal/adapters/wayland/xwm/streams_test.go +178 -0
| @@ -0,0 +1,178 @@ | |||
| 1 | + | package xwm | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "encoding/hex" | |
| 5 | + | "os" | |
| 6 | + | "path/filepath" | |
| 7 | + | "runtime" | |
| 8 | + | "strings" | |
| 9 | + | "testing" | |
| 10 | + | "time" | |
| 11 | + | ||
| 12 | + | "bnema.dev/xturbo/xproto" | |
| 13 | + | "github.com/stretchr/testify/require" | |
| 14 | + | ) | |
| 15 | + | ||
| 16 | + | // The recorded streams are the bytes an X server wrote to the XWM during a | |
| 17 | + | // steady-state session of one mapped window, captured from the scripted xpeer | |
| 18 | + | // (real encoded X packets: events, GetProperty replies). The scenario is | |
| 19 | + | // deterministic, so a replay meets the request sequence numbers it recorded. | |
| 20 | + | // They are not xtrace captures of a real Xwayland: xpeer speaks the same wire | |
| 21 | + | // protocol and keeps the fixture reproducible. Regenerate with | |
| 22 | + | // | |
| 23 | + | // XWM_UPDATE_STREAMS=1 go test ./internal/adapters/wayland/xwm -run TestRecordedStreams | |
| 24 | + | const ( | |
| 25 | + | streamCycles = 400 | |
| 26 | + | streamWarm = 20 // cycles replayed before measuring | |
| 27 | + | ) | |
| 28 | + | ||
| 29 | + | const streamWin = 0x500001 | |
| 30 | + | ||
| 31 | + | type streamKind struct { | |
| 32 | + | name string | |
| 33 | + | // perCycle is Events+Replies the XWM sees per cycle. | |
| 34 | + | perCycle int | |
| 35 | + | cycle func(hs *harness) | |
| 36 | + | } | |
| 37 | + | ||
| 38 | + | var streamKinds = []streamKind{ | |
| 39 | + | // A title notification the XWM answers with one GetProperty whose reply | |
| 40 | + | // equals the stored title. | |
| 41 | + | {"property_unchanged", 2, func(hs *harness) { | |
| 42 | + | before := hs.x.Stats().Replies | |
| 43 | + | hs.p.propertyNotify(streamWin, hs.p.atom("_NET_WM_NAME"), false) | |
| 44 | + | readUntil(hs.t, hs.x, func() bool { return hs.x.Stats().Replies > before }) | |
| 45 | + | }}, | |
| 46 | + | // The same plus ConfigureNotify, FocusIn and MapNotify. | |
| 47 | + | {"steady", 5, func(hs *harness) { | |
| 48 | + | before := hs.x.Stats().Replies | |
| 49 | + | hs.p.propertyNotify(streamWin, hs.p.atom("_NET_WM_NAME"), false) | |
| 50 | + | readUntil(hs.t, hs.x, func() bool { return hs.x.Stats().Replies > before }) | |
| 51 | + | events := hs.x.Stats().Events | |
| 52 | + | hs.p.configureNotify(streamWin) | |
| 53 | + | hs.p.focusIn(streamWin) | |
| 54 | + | hs.p.mapNotify(streamWin) | |
| 55 | + | readUntil(hs.t, hs.x, func() bool { return hs.x.Stats().Events >= events+3 }) | |
| 56 | + | }}, | |
| 57 | + | } | |
| 58 | + | ||
| 59 | + | // streamScenario boots, maps one window and parks the peer behind a poke so | |
| 60 | + | // nothing but the test writes to the XWM afterwards (an allocation count is | |
| 61 | + | // process-wide). The poke is part of the scenario, recorded or replayed. | |
| 62 | + | func streamScenario(t *testing.T) *harness { | |
| 63 | + | t.Helper() | |
| 64 | + | hs := newHarness(t, nil) | |
| 65 | + | hs.classic(streamWin) | |
| 66 | + | hs.mapAndWait(streamWin) | |
| 67 | + | return hs | |
| 68 | + | } | |
| 69 | + | ||
| 70 | + | func poke(hs *harness) { | |
| 71 | + | hs.t.Helper() | |
| 72 | + | n := len(hs.p.requests()) | |
| 73 | + | xproto.GetInputFocus(hs.x.conn.Buf()) | |
| 74 | + | hs.x.flush() | |
| 75 | + | hs.p.waitReq(n, func(r xpeerReq) bool { return r.major == opGetInputFocus }) | |
| 76 | + | } | |
| 77 | + | ||
| 78 | + | func recordStream(t *testing.T, k streamKind) []byte { | |
| 79 | + | hs := streamScenario(t) | |
| 80 | + | poke(hs) | |
| 81 | + | hs.p.mu.Lock() | |
| 82 | + | hs.p.record = true | |
| 83 | + | hs.p.mu.Unlock() | |
| 84 | + | for i := 0; i < streamCycles; i++ { | |
| 85 | + | k.cycle(hs) | |
| 86 | + | } | |
| 87 | + | hs.p.mu.Lock() | |
| 88 | + | defer hs.p.mu.Unlock() | |
| 89 | + | hs.p.record = false | |
| 90 | + | return append([]byte(nil), hs.p.tap...) | |
| 91 | + | } | |
| 92 | + | ||
| 93 | + | func streamPath(k streamKind) string { | |
| 94 | + | return filepath.Join("testdata", "streams", k.name+".hex") | |
| 95 | + | } | |
| 96 | + | ||
| 97 | + | func loadStream(t *testing.T, k streamKind) []byte { | |
| 98 | + | t.Helper() | |
| 99 | + | text, err := os.ReadFile(streamPath(k)) | |
| 100 | + | require.NoError(t, err) | |
| 101 | + | b, err := hex.DecodeString(strings.Join(strings.Fields(string(text)), "")) | |
| 102 | + | require.NoError(t, err) | |
| 103 | + | return b | |
| 104 | + | } | |
| 105 | + | ||
| 106 | + | func encodeHex(b []byte) string { | |
| 107 | + | var sb strings.Builder | |
| 108 | + | for len(b) > 0 { | |
| 109 | + | n := min(32, len(b)) | |
| 110 | + | sb.WriteString(hex.EncodeToString(b[:n])) | |
| 111 | + | sb.WriteByte('\n') | |
| 112 | + | b = b[n:] | |
| 113 | + | } | |
| 114 | + | return sb.String() | |
| 115 | + | } | |
| 116 | + | ||
| 117 | + | func TestRecordedStreams(t *testing.T) { | |
| 118 | + | for _, k := range streamKinds { | |
| 119 | + | t.Run(k.name, func(t *testing.T) { | |
| 120 | + | got := recordStream(t, k) | |
| 121 | + | if os.Getenv("XWM_UPDATE_STREAMS") != "" { | |
| 122 | + | require.NoError(t, os.MkdirAll(filepath.Dir(streamPath(k)), 0o755)) | |
| 123 | + | require.NoError(t, os.WriteFile(streamPath(k), []byte(encodeHex(got)), 0o644)) | |
| 124 | + | } | |
| 125 | + | require.Equal(t, loadStream(t, k), got, "the committed stream no longer matches the protocol the XWM speaks") | |
| 126 | + | }) | |
| 127 | + | } | |
| 128 | + | } | |
| 129 | + | ||
| 130 | + | // replay feeds the recorded stream and reports the mallocs of the part after | |
| 131 | + | // the warm-up cycles. | |
| 132 | + | func replay(t *testing.T, k streamKind) (mallocs uint64, hs *harness) { | |
| 133 | + | t.Helper() | |
| 134 | + | stream := loadStream(t, k) | |
| 135 | + | hs = streamScenario(t) | |
| 136 | + | hs.p.pause() | |
| 137 | + | poke(hs) | |
| 138 | + | _, err := hs.p.f.Write(stream) | |
| 139 | + | require.NoError(t, err) | |
| 140 | + | ||
| 141 | + | x := hs.x | |
| 142 | + | base := x.Stats().Events + x.Stats().Replies | |
| 143 | + | drive := func(until uint64) { | |
| 144 | + | deadline := time.Now().Add(10 * time.Second) | |
| 145 | + | for x.Stats().Events+x.Stats().Replies < until { | |
| 146 | + | if time.Now().After(deadline) { // no formatting arguments: boxing them would count as mallocs | |
| 147 | + | t.Fatal("stream stalled") | |
| 148 | + | } | |
| 149 | + | before := x.Stats().Events + x.Stats().Replies | |
| 150 | + | x.onReadable() | |
| 151 | + | if x.Stats().Events+x.Stats().Replies == before { | |
| 152 | + | runtime.Gosched() | |
| 153 | + | } | |
| 154 | + | } | |
| 155 | + | } | |
| 156 | + | drive(base + uint64(streamWarm*k.perCycle)) | |
| 157 | + | target := base + uint64(streamCycles*k.perCycle) | |
| 158 | + | ||
| 159 | + | var m0, m1 runtime.MemStats | |
| 160 | + | runtime.GC() | |
| 161 | + | runtime.ReadMemStats(&m0) | |
| 162 | + | drive(target) | |
| 163 | + | runtime.ReadMemStats(&m1) | |
| 164 | + | require.Equal(t, target, x.Stats().Events+x.Stats().Replies) | |
| 165 | + | return m1.Mallocs - m0.Mallocs, hs | |
| 166 | + | } | |
| 167 | + | ||
| 168 | + | func TestPropertyUnchangedAllocations(t *testing.T) { | |
| 169 | + | m, hs := replay(t, streamKinds[0]) | |
| 170 | + | require.Zero(t, m, "unchanged property cycles must not allocate") | |
| 171 | + | require.Equal(t, "net title", hs.x.tab.rec(hs.x.Slot(streamWin)).title) | |
| 172 | + | } | |
| 173 | + | ||
| 174 | + | func TestDispatchAllocations(t *testing.T) { | |
| 175 | + | m, hs := replay(t, streamKinds[1]) | |
| 176 | + | require.Zero(t, m, "steady-state event dispatch must not allocate") | |
| 177 | + | require.True(t, hs.x.tab.rec(hs.x.Slot(streamWin)).mapped) | |
| 178 | + | } | |
| @@ -0,0 +1,178 @@ | |||||
| 1 | + | package xwm | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "encoding/hex" | |||
| 5 | + | "os" | |||
| 6 | + | "path/filepath" | |||
| 7 | + | "runtime" | |||
| 8 | + | "strings" | |||
| 9 | + | "testing" | |||
| 10 | + | "time" | |||
| 11 | + | ||||
| 12 | + | "bnema.dev/xturbo/xproto" | |||
| 13 | + | "github.com/stretchr/testify/require" | |||
| 14 | + | ) | |||
| 15 | + | ||||
| 16 | + | // The recorded streams are the bytes an X server wrote to the XWM during a | |||
| 17 | + | // steady-state session of one mapped window, captured from the scripted xpeer | |||
| 18 | + | // (real encoded X packets: events, GetProperty replies). The scenario is | |||
| 19 | + | // deterministic, so a replay meets the request sequence numbers it recorded. | |||
| 20 | + | // They are not xtrace captures of a real Xwayland: xpeer speaks the same wire | |||
| 21 | + | // protocol and keeps the fixture reproducible. Regenerate with | |||
| 22 | + | // | |||
| 23 | + | // XWM_UPDATE_STREAMS=1 go test ./internal/adapters/wayland/xwm -run TestRecordedStreams | |||
| 24 | + | const ( | |||
| 25 | + | streamCycles = 400 | |||
| 26 | + | streamWarm = 20 // cycles replayed before measuring | |||
| 27 | + | ) | |||
| 28 | + | ||||
| 29 | + | const streamWin = 0x500001 | |||
| 30 | + | ||||
| 31 | + | type streamKind struct { | |||
| 32 | + | name string | |||
| 33 | + | // perCycle is Events+Replies the XWM sees per cycle. | |||
| 34 | + | perCycle int | |||
| 35 | + | cycle func(hs *harness) | |||
| 36 | + | } | |||
| 37 | + | ||||
| 38 | + | var streamKinds = []streamKind{ | |||
| 39 | + | // A title notification the XWM answers with one GetProperty whose reply | |||
| 40 | + | // equals the stored title. | |||
| 41 | + | {"property_unchanged", 2, func(hs *harness) { | |||
| 42 | + | before := hs.x.Stats().Replies | |||
| 43 | + | hs.p.propertyNotify(streamWin, hs.p.atom("_NET_WM_NAME"), false) | |||
| 44 | + | readUntil(hs.t, hs.x, func() bool { return hs.x.Stats().Replies > before }) | |||
| 45 | + | }}, | |||
| 46 | + | // The same plus ConfigureNotify, FocusIn and MapNotify. | |||
| 47 | + | {"steady", 5, func(hs *harness) { | |||
| 48 | + | before := hs.x.Stats().Replies | |||
| 49 | + | hs.p.propertyNotify(streamWin, hs.p.atom("_NET_WM_NAME"), false) | |||
| 50 | + | readUntil(hs.t, hs.x, func() bool { return hs.x.Stats().Replies > before }) | |||
| 51 | + | events := hs.x.Stats().Events | |||
| 52 | + | hs.p.configureNotify(streamWin) | |||
| 53 | + | hs.p.focusIn(streamWin) | |||
| 54 | + | hs.p.mapNotify(streamWin) | |||
| 55 | + | readUntil(hs.t, hs.x, func() bool { return hs.x.Stats().Events >= events+3 }) | |||
| 56 | + | }}, | |||
| 57 | + | } | |||
| 58 | + | ||||
| 59 | + | // streamScenario boots, maps one window and parks the peer behind a poke so | |||
| 60 | + | // nothing but the test writes to the XWM afterwards (an allocation count is | |||
| 61 | + | // process-wide). The poke is part of the scenario, recorded or replayed. | |||
| 62 | + | func streamScenario(t *testing.T) *harness { | |||
| 63 | + | t.Helper() | |||
| 64 | + | hs := newHarness(t, nil) | |||
| 65 | + | hs.classic(streamWin) | |||
| 66 | + | hs.mapAndWait(streamWin) | |||
| 67 | + | return hs | |||
| 68 | + | } | |||
| 69 | + | ||||
| 70 | + | func poke(hs *harness) { | |||
| 71 | + | hs.t.Helper() | |||
| 72 | + | n := len(hs.p.requests()) | |||
| 73 | + | xproto.GetInputFocus(hs.x.conn.Buf()) | |||
| 74 | + | hs.x.flush() | |||
| 75 | + | hs.p.waitReq(n, func(r xpeerReq) bool { return r.major == opGetInputFocus }) | |||
| 76 | + | } | |||
| 77 | + | ||||
| 78 | + | func recordStream(t *testing.T, k streamKind) []byte { | |||
| 79 | + | hs := streamScenario(t) | |||
| 80 | + | poke(hs) | |||
| 81 | + | hs.p.mu.Lock() | |||
| 82 | + | hs.p.record = true | |||
| 83 | + | hs.p.mu.Unlock() | |||
| 84 | + | for i := 0; i < streamCycles; i++ { | |||
| 85 | + | k.cycle(hs) | |||
| 86 | + | } | |||
| 87 | + | hs.p.mu.Lock() | |||
| 88 | + | defer hs.p.mu.Unlock() | |||
| 89 | + | hs.p.record = false | |||
| 90 | + | return append([]byte(nil), hs.p.tap...) | |||
| 91 | + | } | |||
| 92 | + | ||||
| 93 | + | func streamPath(k streamKind) string { | |||
| 94 | + | return filepath.Join("testdata", "streams", k.name+".hex") | |||
| 95 | + | } | |||
| 96 | + | ||||
| 97 | + | func loadStream(t *testing.T, k streamKind) []byte { | |||
| 98 | + | t.Helper() | |||
| 99 | + | text, err := os.ReadFile(streamPath(k)) | |||
| 100 | + | require.NoError(t, err) | |||
| 101 | + | b, err := hex.DecodeString(strings.Join(strings.Fields(string(text)), "")) | |||
| 102 | + | require.NoError(t, err) | |||
| 103 | + | return b | |||
| 104 | + | } | |||
| 105 | + | ||||
| 106 | + | func encodeHex(b []byte) string { | |||
| 107 | + | var sb strings.Builder | |||
| 108 | + | for len(b) > 0 { | |||
| 109 | + | n := min(32, len(b)) | |||
| 110 | + | sb.WriteString(hex.EncodeToString(b[:n])) | |||
| 111 | + | sb.WriteByte('\n') | |||
| 112 | + | b = b[n:] | |||
| 113 | + | } | |||
| 114 | + | return sb.String() | |||
| 115 | + | } | |||
| 116 | + | ||||
| 117 | + | func TestRecordedStreams(t *testing.T) { | |||
| 118 | + | for _, k := range streamKinds { | |||
| 119 | + | t.Run(k.name, func(t *testing.T) { | |||
| 120 | + | got := recordStream(t, k) | |||
| 121 | + | if os.Getenv("XWM_UPDATE_STREAMS") != "" { | |||
| 122 | + | require.NoError(t, os.MkdirAll(filepath.Dir(streamPath(k)), 0o755)) | |||
| 123 | + | require.NoError(t, os.WriteFile(streamPath(k), []byte(encodeHex(got)), 0o644)) | |||
| 124 | + | } | |||
| 125 | + | require.Equal(t, loadStream(t, k), got, "the committed stream no longer matches the protocol the XWM speaks") | |||
| 126 | + | }) | |||
| 127 | + | } | |||
| 128 | + | } | |||
| 129 | + | ||||
| 130 | + | // replay feeds the recorded stream and reports the mallocs of the part after | |||
| 131 | + | // the warm-up cycles. | |||
| 132 | + | func replay(t *testing.T, k streamKind) (mallocs uint64, hs *harness) { | |||
| 133 | + | t.Helper() | |||
| 134 | + | stream := loadStream(t, k) | |||
| 135 | + | hs = streamScenario(t) | |||
| 136 | + | hs.p.pause() | |||
| 137 | + | poke(hs) | |||
| 138 | + | _, err := hs.p.f.Write(stream) | |||
| 139 | + | require.NoError(t, err) | |||
| 140 | + | ||||
| 141 | + | x := hs.x | |||
| 142 | + | base := x.Stats().Events + x.Stats().Replies | |||
| 143 | + | drive := func(until uint64) { | |||
| 144 | + | deadline := time.Now().Add(10 * time.Second) | |||
| 145 | + | for x.Stats().Events+x.Stats().Replies < until { | |||
| 146 | + | if time.Now().After(deadline) { // no formatting arguments: boxing them would count as mallocs | |||
| 147 | + | t.Fatal("stream stalled") | |||
| 148 | + | } | |||
| 149 | + | before := x.Stats().Events + x.Stats().Replies | |||
| 150 | + | x.onReadable() | |||
| 151 | + | if x.Stats().Events+x.Stats().Replies == before { | |||
| 152 | + | runtime.Gosched() | |||
| 153 | + | } | |||
| 154 | + | } | |||
| 155 | + | } | |||
| 156 | + | drive(base + uint64(streamWarm*k.perCycle)) | |||
| 157 | + | target := base + uint64(streamCycles*k.perCycle) | |||
| 158 | + | ||||
| 159 | + | var m0, m1 runtime.MemStats | |||
| 160 | + | runtime.GC() | |||
| 161 | + | runtime.ReadMemStats(&m0) | |||
| 162 | + | drive(target) | |||
| 163 | + | runtime.ReadMemStats(&m1) | |||
| 164 | + | require.Equal(t, target, x.Stats().Events+x.Stats().Replies) | |||
| 165 | + | return m1.Mallocs - m0.Mallocs, hs | |||
| 166 | + | } | |||
| 167 | + | ||||
| 168 | + | func TestPropertyUnchangedAllocations(t *testing.T) { | |||
| 169 | + | m, hs := replay(t, streamKinds[0]) | |||
| 170 | + | require.Zero(t, m, "unchanged property cycles must not allocate") | |||
| 171 | + | require.Equal(t, "net title", hs.x.tab.rec(hs.x.Slot(streamWin)).title) | |||
| 172 | + | } | |||
| 173 | + | ||||
| 174 | + | func TestDispatchAllocations(t *testing.T) { | |||
| 175 | + | m, hs := replay(t, streamKinds[1]) | |||
| 176 | + | require.Zero(t, m, "steady-state event dispatch must not allocate") | |||
| 177 | + | require.True(t, hs.x.tab.rec(hs.x.Slot(streamWin)).mapped) | |||
| 178 | + | } | |||
M internal/adapters/wayland/xwm/table.go +4 -2
| @@ -1,4 +1,4 @@ | |||
| 1 | - | //lint:file-ignore U1000 the record fields below are filled by the map, property, configure and focus flows that build on this skeleton | |
| 1 | + | //lint:file-ignore U1000 pend, sent and stateSent are used by the configure flow | |
| 2 | 2 | ||
| 3 | 3 | package xwm | |
| 4 | 4 | ||
| @@ -202,7 +202,9 @@ func (t *table) lookup(xid uint32) Slot { | |||
| 202 | 202 | } | |
| 203 | 203 | } | |
| 204 | 204 | ||
| 205 | - | // rec returns the record of s, or nil when s is out of range. | |
| 205 | + | // rec returns the record of s, or nil when s is out of range. The pointer is | |
| 206 | + | // valid only until the next insert, host call or anything else that can grow | |
| 207 | + | // the table or free s: never hold it across those, fetch it again with rec(s). | |
| 206 | 208 | func (t *table) rec(s Slot) *record { | |
| 207 | 209 | if s == 0 || int(s) > len(t.recs) { | |
| 208 | 210 | return nil | |
| @@ -1,4 +1,4 @@ | |||||
| 1 | - | //lint:file-ignore U1000 the record fields below are filled by the map, property, configure and focus flows that build on this skeleton | 1 | + | //lint:file-ignore U1000 pend, sent and stateSent are used by the configure flow |
| 2 | 2 | ||||
| 3 | package xwm | 3 | package xwm | ||
| 4 | 4 | ||||
| @@ -202,7 +202,9 @@ func (t *table) lookup(xid uint32) Slot { | |||||
| 202 | } | 202 | } | ||
| 203 | } | 203 | } | ||
| 204 | 204 | ||||
| 205 | - | // rec returns the record of s, or nil when s is out of range. | 205 | + | // rec returns the record of s, or nil when s is out of range. The pointer is |
| 206 | + | // valid only until the next insert, host call or anything else that can grow | |||
| 207 | + | // the table or free s: never hold it across those, fetch it again with rec(s). | |||
| 206 | func (t *table) rec(s Slot) *record { | 208 | func (t *table) rec(s Slot) *record { | ||
| 207 | if s == 0 || int(s) > len(t.recs) { | 209 | if s == 0 || int(s) > len(t.recs) { | ||
| 208 | return nil | 210 | return nil | ||
A internal/adapters/wayland/xwm/testdata/streams/property_unchanged.hex +950 -0
| @@ -0,0 +1,950 @@ | |||
| 1 | + | 1c005f0001005000f30300000000000000000000000000000000000000000000 | |
| 2 | + | 0108600003000000ef0300000000000009000000000000000000000000000000 | |
| 3 | + | 6e6574207469746c650000001c00600001005000f30300000000000000000000 | |
| 4 | + | 0000000000000000000000000108610003000000ef0300000000000009000000 | |
| 5 | + | 0000000000000000000000006e6574207469746c650000001c00610001005000 | |
| 6 | + | f303000000000000000000000000000000000000000000000108620003000000 | |
| 7 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 8 | + | 650000001c00620001005000f303000000000000000000000000000000000000 | |
| 9 | + | 000000000108630003000000ef03000000000000090000000000000000000000 | |
| 10 | + | 000000006e6574207469746c650000001c00630001005000f303000000000000 | |
| 11 | + | 000000000000000000000000000000000108640003000000ef03000000000000 | |
| 12 | + | 090000000000000000000000000000006e6574207469746c650000001c006400 | |
| 13 | + | 01005000f3030000000000000000000000000000000000000000000001086500 | |
| 14 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 15 | + | 7469746c650000001c00650001005000f3030000000000000000000000000000 | |
| 16 | + | 00000000000000000108660003000000ef030000000000000900000000000000 | |
| 17 | + | 00000000000000006e6574207469746c650000001c00660001005000f3030000 | |
| 18 | + | 00000000000000000000000000000000000000000108670003000000ef030000 | |
| 19 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 20 | + | 1c00670001005000f30300000000000000000000000000000000000000000000 | |
| 21 | + | 0108680003000000ef0300000000000009000000000000000000000000000000 | |
| 22 | + | 6e6574207469746c650000001c00680001005000f30300000000000000000000 | |
| 23 | + | 0000000000000000000000000108690003000000ef0300000000000009000000 | |
| 24 | + | 0000000000000000000000006e6574207469746c650000001c00690001005000 | |
| 25 | + | f3030000000000000000000000000000000000000000000001086a0003000000 | |
| 26 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 27 | + | 650000001c006a0001005000f303000000000000000000000000000000000000 | |
| 28 | + | 0000000001086b0003000000ef03000000000000090000000000000000000000 | |
| 29 | + | 000000006e6574207469746c650000001c006b0001005000f303000000000000 | |
| 30 | + | 0000000000000000000000000000000001086c0003000000ef03000000000000 | |
| 31 | + | 090000000000000000000000000000006e6574207469746c650000001c006c00 | |
| 32 | + | 01005000f3030000000000000000000000000000000000000000000001086d00 | |
| 33 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 34 | + | 7469746c650000001c006d0001005000f3030000000000000000000000000000 | |
| 35 | + | 000000000000000001086e0003000000ef030000000000000900000000000000 | |
| 36 | + | 00000000000000006e6574207469746c650000001c006e0001005000f3030000 | |
| 37 | + | 000000000000000000000000000000000000000001086f0003000000ef030000 | |
| 38 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 39 | + | 1c006f0001005000f30300000000000000000000000000000000000000000000 | |
| 40 | + | 0108700003000000ef0300000000000009000000000000000000000000000000 | |
| 41 | + | 6e6574207469746c650000001c00700001005000f30300000000000000000000 | |
| 42 | + | 0000000000000000000000000108710003000000ef0300000000000009000000 | |
| 43 | + | 0000000000000000000000006e6574207469746c650000001c00710001005000 | |
| 44 | + | f303000000000000000000000000000000000000000000000108720003000000 | |
| 45 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 46 | + | 650000001c00720001005000f303000000000000000000000000000000000000 | |
| 47 | + | 000000000108730003000000ef03000000000000090000000000000000000000 | |
| 48 | + | 000000006e6574207469746c650000001c00730001005000f303000000000000 | |
| 49 | + | 000000000000000000000000000000000108740003000000ef03000000000000 | |
| 50 | + | 090000000000000000000000000000006e6574207469746c650000001c007400 | |
| 51 | + | 01005000f3030000000000000000000000000000000000000000000001087500 | |
| 52 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 53 | + | 7469746c650000001c00750001005000f3030000000000000000000000000000 | |
| 54 | + | 00000000000000000108760003000000ef030000000000000900000000000000 | |
| 55 | + | 00000000000000006e6574207469746c650000001c00760001005000f3030000 | |
| 56 | + | 00000000000000000000000000000000000000000108770003000000ef030000 | |
| 57 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 58 | + | 1c00770001005000f30300000000000000000000000000000000000000000000 | |
| 59 | + | 0108780003000000ef0300000000000009000000000000000000000000000000 | |
| 60 | + | 6e6574207469746c650000001c00780001005000f30300000000000000000000 | |
| 61 | + | 0000000000000000000000000108790003000000ef0300000000000009000000 | |
| 62 | + | 0000000000000000000000006e6574207469746c650000001c00790001005000 | |
| 63 | + | f3030000000000000000000000000000000000000000000001087a0003000000 | |
| 64 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 65 | + | 650000001c007a0001005000f303000000000000000000000000000000000000 | |
| 66 | + | 0000000001087b0003000000ef03000000000000090000000000000000000000 | |
| 67 | + | 000000006e6574207469746c650000001c007b0001005000f303000000000000 | |
| 68 | + | 0000000000000000000000000000000001087c0003000000ef03000000000000 | |
| 69 | + | 090000000000000000000000000000006e6574207469746c650000001c007c00 | |
| 70 | + | 01005000f3030000000000000000000000000000000000000000000001087d00 | |
| 71 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 72 | + | 7469746c650000001c007d0001005000f3030000000000000000000000000000 | |
| 73 | + | 000000000000000001087e0003000000ef030000000000000900000000000000 | |
| 74 | + | 00000000000000006e6574207469746c650000001c007e0001005000f3030000 | |
| 75 | + | 000000000000000000000000000000000000000001087f0003000000ef030000 | |
| 76 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 77 | + | 1c007f0001005000f30300000000000000000000000000000000000000000000 | |
| 78 | + | 0108800003000000ef0300000000000009000000000000000000000000000000 | |
| 79 | + | 6e6574207469746c650000001c00800001005000f30300000000000000000000 | |
| 80 | + | 0000000000000000000000000108810003000000ef0300000000000009000000 | |
| 81 | + | 0000000000000000000000006e6574207469746c650000001c00810001005000 | |
| 82 | + | f303000000000000000000000000000000000000000000000108820003000000 | |
| 83 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 84 | + | 650000001c00820001005000f303000000000000000000000000000000000000 | |
| 85 | + | 000000000108830003000000ef03000000000000090000000000000000000000 | |
| 86 | + | 000000006e6574207469746c650000001c00830001005000f303000000000000 | |
| 87 | + | 000000000000000000000000000000000108840003000000ef03000000000000 | |
| 88 | + | 090000000000000000000000000000006e6574207469746c650000001c008400 | |
| 89 | + | 01005000f3030000000000000000000000000000000000000000000001088500 | |
| 90 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 91 | + | 7469746c650000001c00850001005000f3030000000000000000000000000000 | |
| 92 | + | 00000000000000000108860003000000ef030000000000000900000000000000 | |
| 93 | + | 00000000000000006e6574207469746c650000001c00860001005000f3030000 | |
| 94 | + | 00000000000000000000000000000000000000000108870003000000ef030000 | |
| 95 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 96 | + | 1c00870001005000f30300000000000000000000000000000000000000000000 | |
| 97 | + | 0108880003000000ef0300000000000009000000000000000000000000000000 | |
| 98 | + | 6e6574207469746c650000001c00880001005000f30300000000000000000000 | |
| 99 | + | 0000000000000000000000000108890003000000ef0300000000000009000000 | |
| 100 | + | 0000000000000000000000006e6574207469746c650000001c00890001005000 | |
| 101 | + | f3030000000000000000000000000000000000000000000001088a0003000000 | |
| 102 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 103 | + | 650000001c008a0001005000f303000000000000000000000000000000000000 | |
| 104 | + | 0000000001088b0003000000ef03000000000000090000000000000000000000 | |
| 105 | + | 000000006e6574207469746c650000001c008b0001005000f303000000000000 | |
| 106 | + | 0000000000000000000000000000000001088c0003000000ef03000000000000 | |
| 107 | + | 090000000000000000000000000000006e6574207469746c650000001c008c00 | |
| 108 | + | 01005000f3030000000000000000000000000000000000000000000001088d00 | |
| 109 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 110 | + | 7469746c650000001c008d0001005000f3030000000000000000000000000000 | |
| 111 | + | 000000000000000001088e0003000000ef030000000000000900000000000000 | |
| 112 | + | 00000000000000006e6574207469746c650000001c008e0001005000f3030000 | |
| 113 | + | 000000000000000000000000000000000000000001088f0003000000ef030000 | |
| 114 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 115 | + | 1c008f0001005000f30300000000000000000000000000000000000000000000 | |
| 116 | + | 0108900003000000ef0300000000000009000000000000000000000000000000 | |
| 117 | + | 6e6574207469746c650000001c00900001005000f30300000000000000000000 | |
| 118 | + | 0000000000000000000000000108910003000000ef0300000000000009000000 | |
| 119 | + | 0000000000000000000000006e6574207469746c650000001c00910001005000 | |
| 120 | + | f303000000000000000000000000000000000000000000000108920003000000 | |
| 121 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 122 | + | 650000001c00920001005000f303000000000000000000000000000000000000 | |
| 123 | + | 000000000108930003000000ef03000000000000090000000000000000000000 | |
| 124 | + | 000000006e6574207469746c650000001c00930001005000f303000000000000 | |
| 125 | + | 000000000000000000000000000000000108940003000000ef03000000000000 | |
| 126 | + | 090000000000000000000000000000006e6574207469746c650000001c009400 | |
| 127 | + | 01005000f3030000000000000000000000000000000000000000000001089500 | |
| 128 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 129 | + | 7469746c650000001c00950001005000f3030000000000000000000000000000 | |
| 130 | + | 00000000000000000108960003000000ef030000000000000900000000000000 | |
| 131 | + | 00000000000000006e6574207469746c650000001c00960001005000f3030000 | |
| 132 | + | 00000000000000000000000000000000000000000108970003000000ef030000 | |
| 133 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 134 | + | 1c00970001005000f30300000000000000000000000000000000000000000000 | |
| 135 | + | 0108980003000000ef0300000000000009000000000000000000000000000000 | |
| 136 | + | 6e6574207469746c650000001c00980001005000f30300000000000000000000 | |
| 137 | + | 0000000000000000000000000108990003000000ef0300000000000009000000 | |
| 138 | + | 0000000000000000000000006e6574207469746c650000001c00990001005000 | |
| 139 | + | f3030000000000000000000000000000000000000000000001089a0003000000 | |
| 140 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 141 | + | 650000001c009a0001005000f303000000000000000000000000000000000000 | |
| 142 | + | 0000000001089b0003000000ef03000000000000090000000000000000000000 | |
| 143 | + | 000000006e6574207469746c650000001c009b0001005000f303000000000000 | |
| 144 | + | 0000000000000000000000000000000001089c0003000000ef03000000000000 | |
| 145 | + | 090000000000000000000000000000006e6574207469746c650000001c009c00 | |
| 146 | + | 01005000f3030000000000000000000000000000000000000000000001089d00 | |
| 147 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 148 | + | 7469746c650000001c009d0001005000f3030000000000000000000000000000 | |
| 149 | + | 000000000000000001089e0003000000ef030000000000000900000000000000 | |
| 150 | + | 00000000000000006e6574207469746c650000001c009e0001005000f3030000 | |
| 151 | + | 000000000000000000000000000000000000000001089f0003000000ef030000 | |
| 152 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 153 | + | 1c009f0001005000f30300000000000000000000000000000000000000000000 | |
| 154 | + | 0108a00003000000ef0300000000000009000000000000000000000000000000 | |
| 155 | + | 6e6574207469746c650000001c00a00001005000f30300000000000000000000 | |
| 156 | + | 0000000000000000000000000108a10003000000ef0300000000000009000000 | |
| 157 | + | 0000000000000000000000006e6574207469746c650000001c00a10001005000 | |
| 158 | + | f303000000000000000000000000000000000000000000000108a20003000000 | |
| 159 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 160 | + | 650000001c00a20001005000f303000000000000000000000000000000000000 | |
| 161 | + | 000000000108a30003000000ef03000000000000090000000000000000000000 | |
| 162 | + | 000000006e6574207469746c650000001c00a30001005000f303000000000000 | |
| 163 | + | 000000000000000000000000000000000108a40003000000ef03000000000000 | |
| 164 | + | 090000000000000000000000000000006e6574207469746c650000001c00a400 | |
| 165 | + | 01005000f303000000000000000000000000000000000000000000000108a500 | |
| 166 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 167 | + | 7469746c650000001c00a50001005000f3030000000000000000000000000000 | |
| 168 | + | 00000000000000000108a60003000000ef030000000000000900000000000000 | |
| 169 | + | 00000000000000006e6574207469746c650000001c00a60001005000f3030000 | |
| 170 | + | 00000000000000000000000000000000000000000108a70003000000ef030000 | |
| 171 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 172 | + | 1c00a70001005000f30300000000000000000000000000000000000000000000 | |
| 173 | + | 0108a80003000000ef0300000000000009000000000000000000000000000000 | |
| 174 | + | 6e6574207469746c650000001c00a80001005000f30300000000000000000000 | |
| 175 | + | 0000000000000000000000000108a90003000000ef0300000000000009000000 | |
| 176 | + | 0000000000000000000000006e6574207469746c650000001c00a90001005000 | |
| 177 | + | f303000000000000000000000000000000000000000000000108aa0003000000 | |
| 178 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 179 | + | 650000001c00aa0001005000f303000000000000000000000000000000000000 | |
| 180 | + | 000000000108ab0003000000ef03000000000000090000000000000000000000 | |
| 181 | + | 000000006e6574207469746c650000001c00ab0001005000f303000000000000 | |
| 182 | + | 000000000000000000000000000000000108ac0003000000ef03000000000000 | |
| 183 | + | 090000000000000000000000000000006e6574207469746c650000001c00ac00 | |
| 184 | + | 01005000f303000000000000000000000000000000000000000000000108ad00 | |
| 185 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 186 | + | 7469746c650000001c00ad0001005000f3030000000000000000000000000000 | |
| 187 | + | 00000000000000000108ae0003000000ef030000000000000900000000000000 | |
| 188 | + | 00000000000000006e6574207469746c650000001c00ae0001005000f3030000 | |
| 189 | + | 00000000000000000000000000000000000000000108af0003000000ef030000 | |
| 190 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 191 | + | 1c00af0001005000f30300000000000000000000000000000000000000000000 | |
| 192 | + | 0108b00003000000ef0300000000000009000000000000000000000000000000 | |
| 193 | + | 6e6574207469746c650000001c00b00001005000f30300000000000000000000 | |
| 194 | + | 0000000000000000000000000108b10003000000ef0300000000000009000000 | |
| 195 | + | 0000000000000000000000006e6574207469746c650000001c00b10001005000 | |
| 196 | + | f303000000000000000000000000000000000000000000000108b20003000000 | |
| 197 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 198 | + | 650000001c00b20001005000f303000000000000000000000000000000000000 | |
| 199 | + | 000000000108b30003000000ef03000000000000090000000000000000000000 | |
| 200 | + | 000000006e6574207469746c650000001c00b30001005000f303000000000000 | |
| 201 | + | 000000000000000000000000000000000108b40003000000ef03000000000000 | |
| 202 | + | 090000000000000000000000000000006e6574207469746c650000001c00b400 | |
| 203 | + | 01005000f303000000000000000000000000000000000000000000000108b500 | |
| 204 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 205 | + | 7469746c650000001c00b50001005000f3030000000000000000000000000000 | |
| 206 | + | 00000000000000000108b60003000000ef030000000000000900000000000000 | |
| 207 | + | 00000000000000006e6574207469746c650000001c00b60001005000f3030000 | |
| 208 | + | 00000000000000000000000000000000000000000108b70003000000ef030000 | |
| 209 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 210 | + | 1c00b70001005000f30300000000000000000000000000000000000000000000 | |
| 211 | + | 0108b80003000000ef0300000000000009000000000000000000000000000000 | |
| 212 | + | 6e6574207469746c650000001c00b80001005000f30300000000000000000000 | |
| 213 | + | 0000000000000000000000000108b90003000000ef0300000000000009000000 | |
| 214 | + | 0000000000000000000000006e6574207469746c650000001c00b90001005000 | |
| 215 | + | f303000000000000000000000000000000000000000000000108ba0003000000 | |
| 216 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 217 | + | 650000001c00ba0001005000f303000000000000000000000000000000000000 | |
| 218 | + | 000000000108bb0003000000ef03000000000000090000000000000000000000 | |
| 219 | + | 000000006e6574207469746c650000001c00bb0001005000f303000000000000 | |
| 220 | + | 000000000000000000000000000000000108bc0003000000ef03000000000000 | |
| 221 | + | 090000000000000000000000000000006e6574207469746c650000001c00bc00 | |
| 222 | + | 01005000f303000000000000000000000000000000000000000000000108bd00 | |
| 223 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 224 | + | 7469746c650000001c00bd0001005000f3030000000000000000000000000000 | |
| 225 | + | 00000000000000000108be0003000000ef030000000000000900000000000000 | |
| 226 | + | 00000000000000006e6574207469746c650000001c00be0001005000f3030000 | |
| 227 | + | 00000000000000000000000000000000000000000108bf0003000000ef030000 | |
| 228 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 229 | + | 1c00bf0001005000f30300000000000000000000000000000000000000000000 | |
| 230 | + | 0108c00003000000ef0300000000000009000000000000000000000000000000 | |
| 231 | + | 6e6574207469746c650000001c00c00001005000f30300000000000000000000 | |
| 232 | + | 0000000000000000000000000108c10003000000ef0300000000000009000000 | |
| 233 | + | 0000000000000000000000006e6574207469746c650000001c00c10001005000 | |
| 234 | + | f303000000000000000000000000000000000000000000000108c20003000000 | |
| 235 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 236 | + | 650000001c00c20001005000f303000000000000000000000000000000000000 | |
| 237 | + | 000000000108c30003000000ef03000000000000090000000000000000000000 | |
| 238 | + | 000000006e6574207469746c650000001c00c30001005000f303000000000000 | |
| 239 | + | 000000000000000000000000000000000108c40003000000ef03000000000000 | |
| 240 | + | 090000000000000000000000000000006e6574207469746c650000001c00c400 | |
| 241 | + | 01005000f303000000000000000000000000000000000000000000000108c500 | |
| 242 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 243 | + | 7469746c650000001c00c50001005000f3030000000000000000000000000000 | |
| 244 | + | 00000000000000000108c60003000000ef030000000000000900000000000000 | |
| 245 | + | 00000000000000006e6574207469746c650000001c00c60001005000f3030000 | |
| 246 | + | 00000000000000000000000000000000000000000108c70003000000ef030000 | |
| 247 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 248 | + | 1c00c70001005000f30300000000000000000000000000000000000000000000 | |
| 249 | + | 0108c80003000000ef0300000000000009000000000000000000000000000000 | |
| 250 | + | 6e6574207469746c650000001c00c80001005000f30300000000000000000000 | |
| 251 | + | 0000000000000000000000000108c90003000000ef0300000000000009000000 | |
| 252 | + | 0000000000000000000000006e6574207469746c650000001c00c90001005000 | |
| 253 | + | f303000000000000000000000000000000000000000000000108ca0003000000 | |
| 254 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 255 | + | 650000001c00ca0001005000f303000000000000000000000000000000000000 | |
| 256 | + | 000000000108cb0003000000ef03000000000000090000000000000000000000 | |
| 257 | + | 000000006e6574207469746c650000001c00cb0001005000f303000000000000 | |
| 258 | + | 000000000000000000000000000000000108cc0003000000ef03000000000000 | |
| 259 | + | 090000000000000000000000000000006e6574207469746c650000001c00cc00 | |
| 260 | + | 01005000f303000000000000000000000000000000000000000000000108cd00 | |
| 261 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 262 | + | 7469746c650000001c00cd0001005000f3030000000000000000000000000000 | |
| 263 | + | 00000000000000000108ce0003000000ef030000000000000900000000000000 | |
| 264 | + | 00000000000000006e6574207469746c650000001c00ce0001005000f3030000 | |
| 265 | + | 00000000000000000000000000000000000000000108cf0003000000ef030000 | |
| 266 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 267 | + | 1c00cf0001005000f30300000000000000000000000000000000000000000000 | |
| 268 | + | 0108d00003000000ef0300000000000009000000000000000000000000000000 | |
| 269 | + | 6e6574207469746c650000001c00d00001005000f30300000000000000000000 | |
| 270 | + | 0000000000000000000000000108d10003000000ef0300000000000009000000 | |
| 271 | + | 0000000000000000000000006e6574207469746c650000001c00d10001005000 | |
| 272 | + | f303000000000000000000000000000000000000000000000108d20003000000 | |
| 273 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 274 | + | 650000001c00d20001005000f303000000000000000000000000000000000000 | |
| 275 | + | 000000000108d30003000000ef03000000000000090000000000000000000000 | |
| 276 | + | 000000006e6574207469746c650000001c00d30001005000f303000000000000 | |
| 277 | + | 000000000000000000000000000000000108d40003000000ef03000000000000 | |
| 278 | + | 090000000000000000000000000000006e6574207469746c650000001c00d400 | |
| 279 | + | 01005000f303000000000000000000000000000000000000000000000108d500 | |
| 280 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 281 | + | 7469746c650000001c00d50001005000f3030000000000000000000000000000 | |
| 282 | + | 00000000000000000108d60003000000ef030000000000000900000000000000 | |
| 283 | + | 00000000000000006e6574207469746c650000001c00d60001005000f3030000 | |
| 284 | + | 00000000000000000000000000000000000000000108d70003000000ef030000 | |
| 285 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 286 | + | 1c00d70001005000f30300000000000000000000000000000000000000000000 | |
| 287 | + | 0108d80003000000ef0300000000000009000000000000000000000000000000 | |
| 288 | + | 6e6574207469746c650000001c00d80001005000f30300000000000000000000 | |
| 289 | + | 0000000000000000000000000108d90003000000ef0300000000000009000000 | |
| 290 | + | 0000000000000000000000006e6574207469746c650000001c00d90001005000 | |
| 291 | + | f303000000000000000000000000000000000000000000000108da0003000000 | |
| 292 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 293 | + | 650000001c00da0001005000f303000000000000000000000000000000000000 | |
| 294 | + | 000000000108db0003000000ef03000000000000090000000000000000000000 | |
| 295 | + | 000000006e6574207469746c650000001c00db0001005000f303000000000000 | |
| 296 | + | 000000000000000000000000000000000108dc0003000000ef03000000000000 | |
| 297 | + | 090000000000000000000000000000006e6574207469746c650000001c00dc00 | |
| 298 | + | 01005000f303000000000000000000000000000000000000000000000108dd00 | |
| 299 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 300 | + | 7469746c650000001c00dd0001005000f3030000000000000000000000000000 | |
| 301 | + | 00000000000000000108de0003000000ef030000000000000900000000000000 | |
| 302 | + | 00000000000000006e6574207469746c650000001c00de0001005000f3030000 | |
| 303 | + | 00000000000000000000000000000000000000000108df0003000000ef030000 | |
| 304 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 305 | + | 1c00df0001005000f30300000000000000000000000000000000000000000000 | |
| 306 | + | 0108e00003000000ef0300000000000009000000000000000000000000000000 | |
| 307 | + | 6e6574207469746c650000001c00e00001005000f30300000000000000000000 | |
| 308 | + | 0000000000000000000000000108e10003000000ef0300000000000009000000 | |
| 309 | + | 0000000000000000000000006e6574207469746c650000001c00e10001005000 | |
| 310 | + | f303000000000000000000000000000000000000000000000108e20003000000 | |
| 311 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 312 | + | 650000001c00e20001005000f303000000000000000000000000000000000000 | |
| 313 | + | 000000000108e30003000000ef03000000000000090000000000000000000000 | |
| 314 | + | 000000006e6574207469746c650000001c00e30001005000f303000000000000 | |
| 315 | + | 000000000000000000000000000000000108e40003000000ef03000000000000 | |
| 316 | + | 090000000000000000000000000000006e6574207469746c650000001c00e400 | |
| 317 | + | 01005000f303000000000000000000000000000000000000000000000108e500 | |
| 318 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 319 | + | 7469746c650000001c00e50001005000f3030000000000000000000000000000 | |
| 320 | + | 00000000000000000108e60003000000ef030000000000000900000000000000 | |
| 321 | + | 00000000000000006e6574207469746c650000001c00e60001005000f3030000 | |
| 322 | + | 00000000000000000000000000000000000000000108e70003000000ef030000 | |
| 323 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 324 | + | 1c00e70001005000f30300000000000000000000000000000000000000000000 | |
| 325 | + | 0108e80003000000ef0300000000000009000000000000000000000000000000 | |
| 326 | + | 6e6574207469746c650000001c00e80001005000f30300000000000000000000 | |
| 327 | + | 0000000000000000000000000108e90003000000ef0300000000000009000000 | |
| 328 | + | 0000000000000000000000006e6574207469746c650000001c00e90001005000 | |
| 329 | + | f303000000000000000000000000000000000000000000000108ea0003000000 | |
| 330 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 331 | + | 650000001c00ea0001005000f303000000000000000000000000000000000000 | |
| 332 | + | 000000000108eb0003000000ef03000000000000090000000000000000000000 | |
| 333 | + | 000000006e6574207469746c650000001c00eb0001005000f303000000000000 | |
| 334 | + | 000000000000000000000000000000000108ec0003000000ef03000000000000 | |
| 335 | + | 090000000000000000000000000000006e6574207469746c650000001c00ec00 | |
| 336 | + | 01005000f303000000000000000000000000000000000000000000000108ed00 | |
| 337 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 338 | + | 7469746c650000001c00ed0001005000f3030000000000000000000000000000 | |
| 339 | + | 00000000000000000108ee0003000000ef030000000000000900000000000000 | |
| 340 | + | 00000000000000006e6574207469746c650000001c00ee0001005000f3030000 | |
| 341 | + | 00000000000000000000000000000000000000000108ef0003000000ef030000 | |
| 342 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 343 | + | 1c00ef0001005000f30300000000000000000000000000000000000000000000 | |
| 344 | + | 0108f00003000000ef0300000000000009000000000000000000000000000000 | |
| 345 | + | 6e6574207469746c650000001c00f00001005000f30300000000000000000000 | |
| 346 | + | 0000000000000000000000000108f10003000000ef0300000000000009000000 | |
| 347 | + | 0000000000000000000000006e6574207469746c650000001c00f10001005000 | |
| 348 | + | f303000000000000000000000000000000000000000000000108f20003000000 | |
| 349 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 350 | + | 650000001c00f20001005000f303000000000000000000000000000000000000 | |
| 351 | + | 000000000108f30003000000ef03000000000000090000000000000000000000 | |
| 352 | + | 000000006e6574207469746c650000001c00f30001005000f303000000000000 | |
| 353 | + | 000000000000000000000000000000000108f40003000000ef03000000000000 | |
| 354 | + | 090000000000000000000000000000006e6574207469746c650000001c00f400 | |
| 355 | + | 01005000f303000000000000000000000000000000000000000000000108f500 | |
| 356 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 357 | + | 7469746c650000001c00f50001005000f3030000000000000000000000000000 | |
| 358 | + | 00000000000000000108f60003000000ef030000000000000900000000000000 | |
| 359 | + | 00000000000000006e6574207469746c650000001c00f60001005000f3030000 | |
| 360 | + | 00000000000000000000000000000000000000000108f70003000000ef030000 | |
| 361 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 362 | + | 1c00f70001005000f30300000000000000000000000000000000000000000000 | |
| 363 | + | 0108f80003000000ef0300000000000009000000000000000000000000000000 | |
| 364 | + | 6e6574207469746c650000001c00f80001005000f30300000000000000000000 | |
| 365 | + | 0000000000000000000000000108f90003000000ef0300000000000009000000 | |
| 366 | + | 0000000000000000000000006e6574207469746c650000001c00f90001005000 | |
| 367 | + | f303000000000000000000000000000000000000000000000108fa0003000000 | |
| 368 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 369 | + | 650000001c00fa0001005000f303000000000000000000000000000000000000 | |
| 370 | + | 000000000108fb0003000000ef03000000000000090000000000000000000000 | |
| 371 | + | 000000006e6574207469746c650000001c00fb0001005000f303000000000000 | |
| 372 | + | 000000000000000000000000000000000108fc0003000000ef03000000000000 | |
| 373 | + | 090000000000000000000000000000006e6574207469746c650000001c00fc00 | |
| 374 | + | 01005000f303000000000000000000000000000000000000000000000108fd00 | |
| 375 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 376 | + | 7469746c650000001c00fd0001005000f3030000000000000000000000000000 | |
| 377 | + | 00000000000000000108fe0003000000ef030000000000000900000000000000 | |
| 378 | + | 00000000000000006e6574207469746c650000001c00fe0001005000f3030000 | |
| 379 | + | 00000000000000000000000000000000000000000108ff0003000000ef030000 | |
| 380 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 381 | + | 1c00ff0001005000f30300000000000000000000000000000000000000000000 | |
| 382 | + | 0108000103000000ef0300000000000009000000000000000000000000000000 | |
| 383 | + | 6e6574207469746c650000001c00000101005000f30300000000000000000000 | |
| 384 | + | 0000000000000000000000000108010103000000ef0300000000000009000000 | |
| 385 | + | 0000000000000000000000006e6574207469746c650000001c00010101005000 | |
| 386 | + | f303000000000000000000000000000000000000000000000108020103000000 | |
| 387 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 388 | + | 650000001c00020101005000f303000000000000000000000000000000000000 | |
| 389 | + | 000000000108030103000000ef03000000000000090000000000000000000000 | |
| 390 | + | 000000006e6574207469746c650000001c00030101005000f303000000000000 | |
| 391 | + | 000000000000000000000000000000000108040103000000ef03000000000000 | |
| 392 | + | 090000000000000000000000000000006e6574207469746c650000001c000401 | |
| 393 | + | 01005000f3030000000000000000000000000000000000000000000001080501 | |
| 394 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 395 | + | 7469746c650000001c00050101005000f3030000000000000000000000000000 | |
| 396 | + | 00000000000000000108060103000000ef030000000000000900000000000000 | |
| 397 | + | 00000000000000006e6574207469746c650000001c00060101005000f3030000 | |
| 398 | + | 00000000000000000000000000000000000000000108070103000000ef030000 | |
| 399 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 400 | + | 1c00070101005000f30300000000000000000000000000000000000000000000 | |
| 401 | + | 0108080103000000ef0300000000000009000000000000000000000000000000 | |
| 402 | + | 6e6574207469746c650000001c00080101005000f30300000000000000000000 | |
| 403 | + | 0000000000000000000000000108090103000000ef0300000000000009000000 | |
| 404 | + | 0000000000000000000000006e6574207469746c650000001c00090101005000 | |
| 405 | + | f3030000000000000000000000000000000000000000000001080a0103000000 | |
| 406 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 407 | + | 650000001c000a0101005000f303000000000000000000000000000000000000 | |
| 408 | + | 0000000001080b0103000000ef03000000000000090000000000000000000000 | |
| 409 | + | 000000006e6574207469746c650000001c000b0101005000f303000000000000 | |
| 410 | + | 0000000000000000000000000000000001080c0103000000ef03000000000000 | |
| 411 | + | 090000000000000000000000000000006e6574207469746c650000001c000c01 | |
| 412 | + | 01005000f3030000000000000000000000000000000000000000000001080d01 | |
| 413 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 414 | + | 7469746c650000001c000d0101005000f3030000000000000000000000000000 | |
| 415 | + | 000000000000000001080e0103000000ef030000000000000900000000000000 | |
| 416 | + | 00000000000000006e6574207469746c650000001c000e0101005000f3030000 | |
| 417 | + | 000000000000000000000000000000000000000001080f0103000000ef030000 | |
| 418 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 419 | + | 1c000f0101005000f30300000000000000000000000000000000000000000000 | |
| 420 | + | 0108100103000000ef0300000000000009000000000000000000000000000000 | |
| 421 | + | 6e6574207469746c650000001c00100101005000f30300000000000000000000 | |
| 422 | + | 0000000000000000000000000108110103000000ef0300000000000009000000 | |
| 423 | + | 0000000000000000000000006e6574207469746c650000001c00110101005000 | |
| 424 | + | f303000000000000000000000000000000000000000000000108120103000000 | |
| 425 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 426 | + | 650000001c00120101005000f303000000000000000000000000000000000000 | |
| 427 | + | 000000000108130103000000ef03000000000000090000000000000000000000 | |
| 428 | + | 000000006e6574207469746c650000001c00130101005000f303000000000000 | |
| 429 | + | 000000000000000000000000000000000108140103000000ef03000000000000 | |
| 430 | + | 090000000000000000000000000000006e6574207469746c650000001c001401 | |
| 431 | + | 01005000f3030000000000000000000000000000000000000000000001081501 | |
| 432 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 433 | + | 7469746c650000001c00150101005000f3030000000000000000000000000000 | |
| 434 | + | 00000000000000000108160103000000ef030000000000000900000000000000 | |
| 435 | + | 00000000000000006e6574207469746c650000001c00160101005000f3030000 | |
| 436 | + | 00000000000000000000000000000000000000000108170103000000ef030000 | |
| 437 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 438 | + | 1c00170101005000f30300000000000000000000000000000000000000000000 | |
| 439 | + | 0108180103000000ef0300000000000009000000000000000000000000000000 | |
| 440 | + | 6e6574207469746c650000001c00180101005000f30300000000000000000000 | |
| 441 | + | 0000000000000000000000000108190103000000ef0300000000000009000000 | |
| 442 | + | 0000000000000000000000006e6574207469746c650000001c00190101005000 | |
| 443 | + | f3030000000000000000000000000000000000000000000001081a0103000000 | |
| 444 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 445 | + | 650000001c001a0101005000f303000000000000000000000000000000000000 | |
| 446 | + | 0000000001081b0103000000ef03000000000000090000000000000000000000 | |
| 447 | + | 000000006e6574207469746c650000001c001b0101005000f303000000000000 | |
| 448 | + | 0000000000000000000000000000000001081c0103000000ef03000000000000 | |
| 449 | + | 090000000000000000000000000000006e6574207469746c650000001c001c01 | |
| 450 | + | 01005000f3030000000000000000000000000000000000000000000001081d01 | |
| 451 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 452 | + | 7469746c650000001c001d0101005000f3030000000000000000000000000000 | |
| 453 | + | 000000000000000001081e0103000000ef030000000000000900000000000000 | |
| 454 | + | 00000000000000006e6574207469746c650000001c001e0101005000f3030000 | |
| 455 | + | 000000000000000000000000000000000000000001081f0103000000ef030000 | |
| 456 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 457 | + | 1c001f0101005000f30300000000000000000000000000000000000000000000 | |
| 458 | + | 0108200103000000ef0300000000000009000000000000000000000000000000 | |
| 459 | + | 6e6574207469746c650000001c00200101005000f30300000000000000000000 | |
| 460 | + | 0000000000000000000000000108210103000000ef0300000000000009000000 | |
| 461 | + | 0000000000000000000000006e6574207469746c650000001c00210101005000 | |
| 462 | + | f303000000000000000000000000000000000000000000000108220103000000 | |
| 463 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 464 | + | 650000001c00220101005000f303000000000000000000000000000000000000 | |
| 465 | + | 000000000108230103000000ef03000000000000090000000000000000000000 | |
| 466 | + | 000000006e6574207469746c650000001c00230101005000f303000000000000 | |
| 467 | + | 000000000000000000000000000000000108240103000000ef03000000000000 | |
| 468 | + | 090000000000000000000000000000006e6574207469746c650000001c002401 | |
| 469 | + | 01005000f3030000000000000000000000000000000000000000000001082501 | |
| 470 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 471 | + | 7469746c650000001c00250101005000f3030000000000000000000000000000 | |
| 472 | + | 00000000000000000108260103000000ef030000000000000900000000000000 | |
| 473 | + | 00000000000000006e6574207469746c650000001c00260101005000f3030000 | |
| 474 | + | 00000000000000000000000000000000000000000108270103000000ef030000 | |
| 475 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 476 | + | 1c00270101005000f30300000000000000000000000000000000000000000000 | |
| 477 | + | 0108280103000000ef0300000000000009000000000000000000000000000000 | |
| 478 | + | 6e6574207469746c650000001c00280101005000f30300000000000000000000 | |
| 479 | + | 0000000000000000000000000108290103000000ef0300000000000009000000 | |
| 480 | + | 0000000000000000000000006e6574207469746c650000001c00290101005000 | |
| 481 | + | f3030000000000000000000000000000000000000000000001082a0103000000 | |
| 482 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 483 | + | 650000001c002a0101005000f303000000000000000000000000000000000000 | |
| 484 | + | 0000000001082b0103000000ef03000000000000090000000000000000000000 | |
| 485 | + | 000000006e6574207469746c650000001c002b0101005000f303000000000000 | |
| 486 | + | 0000000000000000000000000000000001082c0103000000ef03000000000000 | |
| 487 | + | 090000000000000000000000000000006e6574207469746c650000001c002c01 | |
| 488 | + | 01005000f3030000000000000000000000000000000000000000000001082d01 | |
| 489 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 490 | + | 7469746c650000001c002d0101005000f3030000000000000000000000000000 | |
| 491 | + | 000000000000000001082e0103000000ef030000000000000900000000000000 | |
| 492 | + | 00000000000000006e6574207469746c650000001c002e0101005000f3030000 | |
| 493 | + | 000000000000000000000000000000000000000001082f0103000000ef030000 | |
| 494 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 495 | + | 1c002f0101005000f30300000000000000000000000000000000000000000000 | |
| 496 | + | 0108300103000000ef0300000000000009000000000000000000000000000000 | |
| 497 | + | 6e6574207469746c650000001c00300101005000f30300000000000000000000 | |
| 498 | + | 0000000000000000000000000108310103000000ef0300000000000009000000 | |
| 499 | + | 0000000000000000000000006e6574207469746c650000001c00310101005000 | |
| 500 | + | f303000000000000000000000000000000000000000000000108320103000000 | |
| 501 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 502 | + | 650000001c00320101005000f303000000000000000000000000000000000000 | |
| 503 | + | 000000000108330103000000ef03000000000000090000000000000000000000 | |
| 504 | + | 000000006e6574207469746c650000001c00330101005000f303000000000000 | |
| 505 | + | 000000000000000000000000000000000108340103000000ef03000000000000 | |
| 506 | + | 090000000000000000000000000000006e6574207469746c650000001c003401 | |
| 507 | + | 01005000f3030000000000000000000000000000000000000000000001083501 | |
| 508 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 509 | + | 7469746c650000001c00350101005000f3030000000000000000000000000000 | |
| 510 | + | 00000000000000000108360103000000ef030000000000000900000000000000 | |
| 511 | + | 00000000000000006e6574207469746c650000001c00360101005000f3030000 | |
| 512 | + | 00000000000000000000000000000000000000000108370103000000ef030000 | |
| 513 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 514 | + | 1c00370101005000f30300000000000000000000000000000000000000000000 | |
| 515 | + | 0108380103000000ef0300000000000009000000000000000000000000000000 | |
| 516 | + | 6e6574207469746c650000001c00380101005000f30300000000000000000000 | |
| 517 | + | 0000000000000000000000000108390103000000ef0300000000000009000000 | |
| 518 | + | 0000000000000000000000006e6574207469746c650000001c00390101005000 | |
| 519 | + | f3030000000000000000000000000000000000000000000001083a0103000000 | |
| 520 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 521 | + | 650000001c003a0101005000f303000000000000000000000000000000000000 | |
| 522 | + | 0000000001083b0103000000ef03000000000000090000000000000000000000 | |
| 523 | + | 000000006e6574207469746c650000001c003b0101005000f303000000000000 | |
| 524 | + | 0000000000000000000000000000000001083c0103000000ef03000000000000 | |
| 525 | + | 090000000000000000000000000000006e6574207469746c650000001c003c01 | |
| 526 | + | 01005000f3030000000000000000000000000000000000000000000001083d01 | |
| 527 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 528 | + | 7469746c650000001c003d0101005000f3030000000000000000000000000000 | |
| 529 | + | 000000000000000001083e0103000000ef030000000000000900000000000000 | |
| 530 | + | 00000000000000006e6574207469746c650000001c003e0101005000f3030000 | |
| 531 | + | 000000000000000000000000000000000000000001083f0103000000ef030000 | |
| 532 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 533 | + | 1c003f0101005000f30300000000000000000000000000000000000000000000 | |
| 534 | + | 0108400103000000ef0300000000000009000000000000000000000000000000 | |
| 535 | + | 6e6574207469746c650000001c00400101005000f30300000000000000000000 | |
| 536 | + | 0000000000000000000000000108410103000000ef0300000000000009000000 | |
| 537 | + | 0000000000000000000000006e6574207469746c650000001c00410101005000 | |
| 538 | + | f303000000000000000000000000000000000000000000000108420103000000 | |
| 539 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 540 | + | 650000001c00420101005000f303000000000000000000000000000000000000 | |
| 541 | + | 000000000108430103000000ef03000000000000090000000000000000000000 | |
| 542 | + | 000000006e6574207469746c650000001c00430101005000f303000000000000 | |
| 543 | + | 000000000000000000000000000000000108440103000000ef03000000000000 | |
| 544 | + | 090000000000000000000000000000006e6574207469746c650000001c004401 | |
| 545 | + | 01005000f3030000000000000000000000000000000000000000000001084501 | |
| 546 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 547 | + | 7469746c650000001c00450101005000f3030000000000000000000000000000 | |
| 548 | + | 00000000000000000108460103000000ef030000000000000900000000000000 | |
| 549 | + | 00000000000000006e6574207469746c650000001c00460101005000f3030000 | |
| 550 | + | 00000000000000000000000000000000000000000108470103000000ef030000 | |
| 551 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 552 | + | 1c00470101005000f30300000000000000000000000000000000000000000000 | |
| 553 | + | 0108480103000000ef0300000000000009000000000000000000000000000000 | |
| 554 | + | 6e6574207469746c650000001c00480101005000f30300000000000000000000 | |
| 555 | + | 0000000000000000000000000108490103000000ef0300000000000009000000 | |
| 556 | + | 0000000000000000000000006e6574207469746c650000001c00490101005000 | |
| 557 | + | f3030000000000000000000000000000000000000000000001084a0103000000 | |
| 558 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 559 | + | 650000001c004a0101005000f303000000000000000000000000000000000000 | |
| 560 | + | 0000000001084b0103000000ef03000000000000090000000000000000000000 | |
| 561 | + | 000000006e6574207469746c650000001c004b0101005000f303000000000000 | |
| 562 | + | 0000000000000000000000000000000001084c0103000000ef03000000000000 | |
| 563 | + | 090000000000000000000000000000006e6574207469746c650000001c004c01 | |
| 564 | + | 01005000f3030000000000000000000000000000000000000000000001084d01 | |
| 565 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 566 | + | 7469746c650000001c004d0101005000f3030000000000000000000000000000 | |
| 567 | + | 000000000000000001084e0103000000ef030000000000000900000000000000 | |
| 568 | + | 00000000000000006e6574207469746c650000001c004e0101005000f3030000 | |
| 569 | + | 000000000000000000000000000000000000000001084f0103000000ef030000 | |
| 570 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 571 | + | 1c004f0101005000f30300000000000000000000000000000000000000000000 | |
| 572 | + | 0108500103000000ef0300000000000009000000000000000000000000000000 | |
| 573 | + | 6e6574207469746c650000001c00500101005000f30300000000000000000000 | |
| 574 | + | 0000000000000000000000000108510103000000ef0300000000000009000000 | |
| 575 | + | 0000000000000000000000006e6574207469746c650000001c00510101005000 | |
| 576 | + | f303000000000000000000000000000000000000000000000108520103000000 | |
| 577 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 578 | + | 650000001c00520101005000f303000000000000000000000000000000000000 | |
| 579 | + | 000000000108530103000000ef03000000000000090000000000000000000000 | |
| 580 | + | 000000006e6574207469746c650000001c00530101005000f303000000000000 | |
| 581 | + | 000000000000000000000000000000000108540103000000ef03000000000000 | |
| 582 | + | 090000000000000000000000000000006e6574207469746c650000001c005401 | |
| 583 | + | 01005000f3030000000000000000000000000000000000000000000001085501 | |
| 584 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 585 | + | 7469746c650000001c00550101005000f3030000000000000000000000000000 | |
| 586 | + | 00000000000000000108560103000000ef030000000000000900000000000000 | |
| 587 | + | 00000000000000006e6574207469746c650000001c00560101005000f3030000 | |
| 588 | + | 00000000000000000000000000000000000000000108570103000000ef030000 | |
| 589 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 590 | + | 1c00570101005000f30300000000000000000000000000000000000000000000 | |
| 591 | + | 0108580103000000ef0300000000000009000000000000000000000000000000 | |
| 592 | + | 6e6574207469746c650000001c00580101005000f30300000000000000000000 | |
| 593 | + | 0000000000000000000000000108590103000000ef0300000000000009000000 | |
| 594 | + | 0000000000000000000000006e6574207469746c650000001c00590101005000 | |
| 595 | + | f3030000000000000000000000000000000000000000000001085a0103000000 | |
| 596 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 597 | + | 650000001c005a0101005000f303000000000000000000000000000000000000 | |
| 598 | + | 0000000001085b0103000000ef03000000000000090000000000000000000000 | |
| 599 | + | 000000006e6574207469746c650000001c005b0101005000f303000000000000 | |
| 600 | + | 0000000000000000000000000000000001085c0103000000ef03000000000000 | |
| 601 | + | 090000000000000000000000000000006e6574207469746c650000001c005c01 | |
| 602 | + | 01005000f3030000000000000000000000000000000000000000000001085d01 | |
| 603 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 604 | + | 7469746c650000001c005d0101005000f3030000000000000000000000000000 | |
| 605 | + | 000000000000000001085e0103000000ef030000000000000900000000000000 | |
| 606 | + | 00000000000000006e6574207469746c650000001c005e0101005000f3030000 | |
| 607 | + | 000000000000000000000000000000000000000001085f0103000000ef030000 | |
| 608 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 609 | + | 1c005f0101005000f30300000000000000000000000000000000000000000000 | |
| 610 | + | 0108600103000000ef0300000000000009000000000000000000000000000000 | |
| 611 | + | 6e6574207469746c650000001c00600101005000f30300000000000000000000 | |
| 612 | + | 0000000000000000000000000108610103000000ef0300000000000009000000 | |
| 613 | + | 0000000000000000000000006e6574207469746c650000001c00610101005000 | |
| 614 | + | f303000000000000000000000000000000000000000000000108620103000000 | |
| 615 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 616 | + | 650000001c00620101005000f303000000000000000000000000000000000000 | |
| 617 | + | 000000000108630103000000ef03000000000000090000000000000000000000 | |
| 618 | + | 000000006e6574207469746c650000001c00630101005000f303000000000000 | |
| 619 | + | 000000000000000000000000000000000108640103000000ef03000000000000 | |
| 620 | + | 090000000000000000000000000000006e6574207469746c650000001c006401 | |
| 621 | + | 01005000f3030000000000000000000000000000000000000000000001086501 | |
| 622 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 623 | + | 7469746c650000001c00650101005000f3030000000000000000000000000000 | |
| 624 | + | 00000000000000000108660103000000ef030000000000000900000000000000 | |
| 625 | + | 00000000000000006e6574207469746c650000001c00660101005000f3030000 | |
| 626 | + | 00000000000000000000000000000000000000000108670103000000ef030000 | |
| 627 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 628 | + | 1c00670101005000f30300000000000000000000000000000000000000000000 | |
| 629 | + | 0108680103000000ef0300000000000009000000000000000000000000000000 | |
| 630 | + | 6e6574207469746c650000001c00680101005000f30300000000000000000000 | |
| 631 | + | 0000000000000000000000000108690103000000ef0300000000000009000000 | |
| 632 | + | 0000000000000000000000006e6574207469746c650000001c00690101005000 | |
| 633 | + | f3030000000000000000000000000000000000000000000001086a0103000000 | |
| 634 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 635 | + | 650000001c006a0101005000f303000000000000000000000000000000000000 | |
| 636 | + | 0000000001086b0103000000ef03000000000000090000000000000000000000 | |
| 637 | + | 000000006e6574207469746c650000001c006b0101005000f303000000000000 | |
| 638 | + | 0000000000000000000000000000000001086c0103000000ef03000000000000 | |
| 639 | + | 090000000000000000000000000000006e6574207469746c650000001c006c01 | |
| 640 | + | 01005000f3030000000000000000000000000000000000000000000001086d01 | |
| 641 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 642 | + | 7469746c650000001c006d0101005000f3030000000000000000000000000000 | |
| 643 | + | 000000000000000001086e0103000000ef030000000000000900000000000000 | |
| 644 | + | 00000000000000006e6574207469746c650000001c006e0101005000f3030000 | |
| 645 | + | 000000000000000000000000000000000000000001086f0103000000ef030000 | |
| 646 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 647 | + | 1c006f0101005000f30300000000000000000000000000000000000000000000 | |
| 648 | + | 0108700103000000ef0300000000000009000000000000000000000000000000 | |
| 649 | + | 6e6574207469746c650000001c00700101005000f30300000000000000000000 | |
| 650 | + | 0000000000000000000000000108710103000000ef0300000000000009000000 | |
| 651 | + | 0000000000000000000000006e6574207469746c650000001c00710101005000 | |
| 652 | + | f303000000000000000000000000000000000000000000000108720103000000 | |
| 653 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 654 | + | 650000001c00720101005000f303000000000000000000000000000000000000 | |
| 655 | + | 000000000108730103000000ef03000000000000090000000000000000000000 | |
| 656 | + | 000000006e6574207469746c650000001c00730101005000f303000000000000 | |
| 657 | + | 000000000000000000000000000000000108740103000000ef03000000000000 | |
| 658 | + | 090000000000000000000000000000006e6574207469746c650000001c007401 | |
| 659 | + | 01005000f3030000000000000000000000000000000000000000000001087501 | |
| 660 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 661 | + | 7469746c650000001c00750101005000f3030000000000000000000000000000 | |
| 662 | + | 00000000000000000108760103000000ef030000000000000900000000000000 | |
| 663 | + | 00000000000000006e6574207469746c650000001c00760101005000f3030000 | |
| 664 | + | 00000000000000000000000000000000000000000108770103000000ef030000 | |
| 665 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 666 | + | 1c00770101005000f30300000000000000000000000000000000000000000000 | |
| 667 | + | 0108780103000000ef0300000000000009000000000000000000000000000000 | |
| 668 | + | 6e6574207469746c650000001c00780101005000f30300000000000000000000 | |
| 669 | + | 0000000000000000000000000108790103000000ef0300000000000009000000 | |
| 670 | + | 0000000000000000000000006e6574207469746c650000001c00790101005000 | |
| 671 | + | f3030000000000000000000000000000000000000000000001087a0103000000 | |
| 672 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 673 | + | 650000001c007a0101005000f303000000000000000000000000000000000000 | |
| 674 | + | 0000000001087b0103000000ef03000000000000090000000000000000000000 | |
| 675 | + | 000000006e6574207469746c650000001c007b0101005000f303000000000000 | |
| 676 | + | 0000000000000000000000000000000001087c0103000000ef03000000000000 | |
| 677 | + | 090000000000000000000000000000006e6574207469746c650000001c007c01 | |
| 678 | + | 01005000f3030000000000000000000000000000000000000000000001087d01 | |
| 679 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 680 | + | 7469746c650000001c007d0101005000f3030000000000000000000000000000 | |
| 681 | + | 000000000000000001087e0103000000ef030000000000000900000000000000 | |
| 682 | + | 00000000000000006e6574207469746c650000001c007e0101005000f3030000 | |
| 683 | + | 000000000000000000000000000000000000000001087f0103000000ef030000 | |
| 684 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 685 | + | 1c007f0101005000f30300000000000000000000000000000000000000000000 | |
| 686 | + | 0108800103000000ef0300000000000009000000000000000000000000000000 | |
| 687 | + | 6e6574207469746c650000001c00800101005000f30300000000000000000000 | |
| 688 | + | 0000000000000000000000000108810103000000ef0300000000000009000000 | |
| 689 | + | 0000000000000000000000006e6574207469746c650000001c00810101005000 | |
| 690 | + | f303000000000000000000000000000000000000000000000108820103000000 | |
| 691 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 692 | + | 650000001c00820101005000f303000000000000000000000000000000000000 | |
| 693 | + | 000000000108830103000000ef03000000000000090000000000000000000000 | |
| 694 | + | 000000006e6574207469746c650000001c00830101005000f303000000000000 | |
| 695 | + | 000000000000000000000000000000000108840103000000ef03000000000000 | |
| 696 | + | 090000000000000000000000000000006e6574207469746c650000001c008401 | |
| 697 | + | 01005000f3030000000000000000000000000000000000000000000001088501 | |
| 698 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 699 | + | 7469746c650000001c00850101005000f3030000000000000000000000000000 | |
| 700 | + | 00000000000000000108860103000000ef030000000000000900000000000000 | |
| 701 | + | 00000000000000006e6574207469746c650000001c00860101005000f3030000 | |
| 702 | + | 00000000000000000000000000000000000000000108870103000000ef030000 | |
| 703 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 704 | + | 1c00870101005000f30300000000000000000000000000000000000000000000 | |
| 705 | + | 0108880103000000ef0300000000000009000000000000000000000000000000 | |
| 706 | + | 6e6574207469746c650000001c00880101005000f30300000000000000000000 | |
| 707 | + | 0000000000000000000000000108890103000000ef0300000000000009000000 | |
| 708 | + | 0000000000000000000000006e6574207469746c650000001c00890101005000 | |
| 709 | + | f3030000000000000000000000000000000000000000000001088a0103000000 | |
| 710 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 711 | + | 650000001c008a0101005000f303000000000000000000000000000000000000 | |
| 712 | + | 0000000001088b0103000000ef03000000000000090000000000000000000000 | |
| 713 | + | 000000006e6574207469746c650000001c008b0101005000f303000000000000 | |
| 714 | + | 0000000000000000000000000000000001088c0103000000ef03000000000000 | |
| 715 | + | 090000000000000000000000000000006e6574207469746c650000001c008c01 | |
| 716 | + | 01005000f3030000000000000000000000000000000000000000000001088d01 | |
| 717 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 718 | + | 7469746c650000001c008d0101005000f3030000000000000000000000000000 | |
| 719 | + | 000000000000000001088e0103000000ef030000000000000900000000000000 | |
| 720 | + | 00000000000000006e6574207469746c650000001c008e0101005000f3030000 | |
| 721 | + | 000000000000000000000000000000000000000001088f0103000000ef030000 | |
| 722 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 723 | + | 1c008f0101005000f30300000000000000000000000000000000000000000000 | |
| 724 | + | 0108900103000000ef0300000000000009000000000000000000000000000000 | |
| 725 | + | 6e6574207469746c650000001c00900101005000f30300000000000000000000 | |
| 726 | + | 0000000000000000000000000108910103000000ef0300000000000009000000 | |
| 727 | + | 0000000000000000000000006e6574207469746c650000001c00910101005000 | |
| 728 | + | f303000000000000000000000000000000000000000000000108920103000000 | |
| 729 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 730 | + | 650000001c00920101005000f303000000000000000000000000000000000000 | |
| 731 | + | 000000000108930103000000ef03000000000000090000000000000000000000 | |
| 732 | + | 000000006e6574207469746c650000001c00930101005000f303000000000000 | |
| 733 | + | 000000000000000000000000000000000108940103000000ef03000000000000 | |
| 734 | + | 090000000000000000000000000000006e6574207469746c650000001c009401 | |
| 735 | + | 01005000f3030000000000000000000000000000000000000000000001089501 | |
| 736 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 737 | + | 7469746c650000001c00950101005000f3030000000000000000000000000000 | |
| 738 | + | 00000000000000000108960103000000ef030000000000000900000000000000 | |
| 739 | + | 00000000000000006e6574207469746c650000001c00960101005000f3030000 | |
| 740 | + | 00000000000000000000000000000000000000000108970103000000ef030000 | |
| 741 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 742 | + | 1c00970101005000f30300000000000000000000000000000000000000000000 | |
| 743 | + | 0108980103000000ef0300000000000009000000000000000000000000000000 | |
| 744 | + | 6e6574207469746c650000001c00980101005000f30300000000000000000000 | |
| 745 | + | 0000000000000000000000000108990103000000ef0300000000000009000000 | |
| 746 | + | 0000000000000000000000006e6574207469746c650000001c00990101005000 | |
| 747 | + | f3030000000000000000000000000000000000000000000001089a0103000000 | |
| 748 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 749 | + | 650000001c009a0101005000f303000000000000000000000000000000000000 | |
| 750 | + | 0000000001089b0103000000ef03000000000000090000000000000000000000 | |
| 751 | + | 000000006e6574207469746c650000001c009b0101005000f303000000000000 | |
| 752 | + | 0000000000000000000000000000000001089c0103000000ef03000000000000 | |
| 753 | + | 090000000000000000000000000000006e6574207469746c650000001c009c01 | |
| 754 | + | 01005000f3030000000000000000000000000000000000000000000001089d01 | |
| 755 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 756 | + | 7469746c650000001c009d0101005000f3030000000000000000000000000000 | |
| 757 | + | 000000000000000001089e0103000000ef030000000000000900000000000000 | |
| 758 | + | 00000000000000006e6574207469746c650000001c009e0101005000f3030000 | |
| 759 | + | 000000000000000000000000000000000000000001089f0103000000ef030000 | |
| 760 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 761 | + | 1c009f0101005000f30300000000000000000000000000000000000000000000 | |
| 762 | + | 0108a00103000000ef0300000000000009000000000000000000000000000000 | |
| 763 | + | 6e6574207469746c650000001c00a00101005000f30300000000000000000000 | |
| 764 | + | 0000000000000000000000000108a10103000000ef0300000000000009000000 | |
| 765 | + | 0000000000000000000000006e6574207469746c650000001c00a10101005000 | |
| 766 | + | f303000000000000000000000000000000000000000000000108a20103000000 | |
| 767 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 768 | + | 650000001c00a20101005000f303000000000000000000000000000000000000 | |
| 769 | + | 000000000108a30103000000ef03000000000000090000000000000000000000 | |
| 770 | + | 000000006e6574207469746c650000001c00a30101005000f303000000000000 | |
| 771 | + | 000000000000000000000000000000000108a40103000000ef03000000000000 | |
| 772 | + | 090000000000000000000000000000006e6574207469746c650000001c00a401 | |
| 773 | + | 01005000f303000000000000000000000000000000000000000000000108a501 | |
| 774 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 775 | + | 7469746c650000001c00a50101005000f3030000000000000000000000000000 | |
| 776 | + | 00000000000000000108a60103000000ef030000000000000900000000000000 | |
| 777 | + | 00000000000000006e6574207469746c650000001c00a60101005000f3030000 | |
| 778 | + | 00000000000000000000000000000000000000000108a70103000000ef030000 | |
| 779 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 780 | + | 1c00a70101005000f30300000000000000000000000000000000000000000000 | |
| 781 | + | 0108a80103000000ef0300000000000009000000000000000000000000000000 | |
| 782 | + | 6e6574207469746c650000001c00a80101005000f30300000000000000000000 | |
| 783 | + | 0000000000000000000000000108a90103000000ef0300000000000009000000 | |
| 784 | + | 0000000000000000000000006e6574207469746c650000001c00a90101005000 | |
| 785 | + | f303000000000000000000000000000000000000000000000108aa0103000000 | |
| 786 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 787 | + | 650000001c00aa0101005000f303000000000000000000000000000000000000 | |
| 788 | + | 000000000108ab0103000000ef03000000000000090000000000000000000000 | |
| 789 | + | 000000006e6574207469746c650000001c00ab0101005000f303000000000000 | |
| 790 | + | 000000000000000000000000000000000108ac0103000000ef03000000000000 | |
| 791 | + | 090000000000000000000000000000006e6574207469746c650000001c00ac01 | |
| 792 | + | 01005000f303000000000000000000000000000000000000000000000108ad01 | |
| 793 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 794 | + | 7469746c650000001c00ad0101005000f3030000000000000000000000000000 | |
| 795 | + | 00000000000000000108ae0103000000ef030000000000000900000000000000 | |
| 796 | + | 00000000000000006e6574207469746c650000001c00ae0101005000f3030000 | |
| 797 | + | 00000000000000000000000000000000000000000108af0103000000ef030000 | |
| 798 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 799 | + | 1c00af0101005000f30300000000000000000000000000000000000000000000 | |
| 800 | + | 0108b00103000000ef0300000000000009000000000000000000000000000000 | |
| 801 | + | 6e6574207469746c650000001c00b00101005000f30300000000000000000000 | |
| 802 | + | 0000000000000000000000000108b10103000000ef0300000000000009000000 | |
| 803 | + | 0000000000000000000000006e6574207469746c650000001c00b10101005000 | |
| 804 | + | f303000000000000000000000000000000000000000000000108b20103000000 | |
| 805 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 806 | + | 650000001c00b20101005000f303000000000000000000000000000000000000 | |
| 807 | + | 000000000108b30103000000ef03000000000000090000000000000000000000 | |
| 808 | + | 000000006e6574207469746c650000001c00b30101005000f303000000000000 | |
| 809 | + | 000000000000000000000000000000000108b40103000000ef03000000000000 | |
| 810 | + | 090000000000000000000000000000006e6574207469746c650000001c00b401 | |
| 811 | + | 01005000f303000000000000000000000000000000000000000000000108b501 | |
| 812 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 813 | + | 7469746c650000001c00b50101005000f3030000000000000000000000000000 | |
| 814 | + | 00000000000000000108b60103000000ef030000000000000900000000000000 | |
| 815 | + | 00000000000000006e6574207469746c650000001c00b60101005000f3030000 | |
| 816 | + | 00000000000000000000000000000000000000000108b70103000000ef030000 | |
| 817 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 818 | + | 1c00b70101005000f30300000000000000000000000000000000000000000000 | |
| 819 | + | 0108b80103000000ef0300000000000009000000000000000000000000000000 | |
| 820 | + | 6e6574207469746c650000001c00b80101005000f30300000000000000000000 | |
| 821 | + | 0000000000000000000000000108b90103000000ef0300000000000009000000 | |
| 822 | + | 0000000000000000000000006e6574207469746c650000001c00b90101005000 | |
| 823 | + | f303000000000000000000000000000000000000000000000108ba0103000000 | |
| 824 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 825 | + | 650000001c00ba0101005000f303000000000000000000000000000000000000 | |
| 826 | + | 000000000108bb0103000000ef03000000000000090000000000000000000000 | |
| 827 | + | 000000006e6574207469746c650000001c00bb0101005000f303000000000000 | |
| 828 | + | 000000000000000000000000000000000108bc0103000000ef03000000000000 | |
| 829 | + | 090000000000000000000000000000006e6574207469746c650000001c00bc01 | |
| 830 | + | 01005000f303000000000000000000000000000000000000000000000108bd01 | |
| 831 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 832 | + | 7469746c650000001c00bd0101005000f3030000000000000000000000000000 | |
| 833 | + | 00000000000000000108be0103000000ef030000000000000900000000000000 | |
| 834 | + | 00000000000000006e6574207469746c650000001c00be0101005000f3030000 | |
| 835 | + | 00000000000000000000000000000000000000000108bf0103000000ef030000 | |
| 836 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 837 | + | 1c00bf0101005000f30300000000000000000000000000000000000000000000 | |
| 838 | + | 0108c00103000000ef0300000000000009000000000000000000000000000000 | |
| 839 | + | 6e6574207469746c650000001c00c00101005000f30300000000000000000000 | |
| 840 | + | 0000000000000000000000000108c10103000000ef0300000000000009000000 | |
| 841 | + | 0000000000000000000000006e6574207469746c650000001c00c10101005000 | |
| 842 | + | f303000000000000000000000000000000000000000000000108c20103000000 | |
| 843 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 844 | + | 650000001c00c20101005000f303000000000000000000000000000000000000 | |
| 845 | + | 000000000108c30103000000ef03000000000000090000000000000000000000 | |
| 846 | + | 000000006e6574207469746c650000001c00c30101005000f303000000000000 | |
| 847 | + | 000000000000000000000000000000000108c40103000000ef03000000000000 | |
| 848 | + | 090000000000000000000000000000006e6574207469746c650000001c00c401 | |
| 849 | + | 01005000f303000000000000000000000000000000000000000000000108c501 | |
| 850 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 851 | + | 7469746c650000001c00c50101005000f3030000000000000000000000000000 | |
| 852 | + | 00000000000000000108c60103000000ef030000000000000900000000000000 | |
| 853 | + | 00000000000000006e6574207469746c650000001c00c60101005000f3030000 | |
| 854 | + | 00000000000000000000000000000000000000000108c70103000000ef030000 | |
| 855 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 856 | + | 1c00c70101005000f30300000000000000000000000000000000000000000000 | |
| 857 | + | 0108c80103000000ef0300000000000009000000000000000000000000000000 | |
| 858 | + | 6e6574207469746c650000001c00c80101005000f30300000000000000000000 | |
| 859 | + | 0000000000000000000000000108c90103000000ef0300000000000009000000 | |
| 860 | + | 0000000000000000000000006e6574207469746c650000001c00c90101005000 | |
| 861 | + | f303000000000000000000000000000000000000000000000108ca0103000000 | |
| 862 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 863 | + | 650000001c00ca0101005000f303000000000000000000000000000000000000 | |
| 864 | + | 000000000108cb0103000000ef03000000000000090000000000000000000000 | |
| 865 | + | 000000006e6574207469746c650000001c00cb0101005000f303000000000000 | |
| 866 | + | 000000000000000000000000000000000108cc0103000000ef03000000000000 | |
| 867 | + | 090000000000000000000000000000006e6574207469746c650000001c00cc01 | |
| 868 | + | 01005000f303000000000000000000000000000000000000000000000108cd01 | |
| 869 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 870 | + | 7469746c650000001c00cd0101005000f3030000000000000000000000000000 | |
| 871 | + | 00000000000000000108ce0103000000ef030000000000000900000000000000 | |
| 872 | + | 00000000000000006e6574207469746c650000001c00ce0101005000f3030000 | |
| 873 | + | 00000000000000000000000000000000000000000108cf0103000000ef030000 | |
| 874 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 875 | + | 1c00cf0101005000f30300000000000000000000000000000000000000000000 | |
| 876 | + | 0108d00103000000ef0300000000000009000000000000000000000000000000 | |
| 877 | + | 6e6574207469746c650000001c00d00101005000f30300000000000000000000 | |
| 878 | + | 0000000000000000000000000108d10103000000ef0300000000000009000000 | |
| 879 | + | 0000000000000000000000006e6574207469746c650000001c00d10101005000 | |
| 880 | + | f303000000000000000000000000000000000000000000000108d20103000000 | |
| 881 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 882 | + | 650000001c00d20101005000f303000000000000000000000000000000000000 | |
| 883 | + | 000000000108d30103000000ef03000000000000090000000000000000000000 | |
| 884 | + | 000000006e6574207469746c650000001c00d30101005000f303000000000000 | |
| 885 | + | 000000000000000000000000000000000108d40103000000ef03000000000000 | |
| 886 | + | 090000000000000000000000000000006e6574207469746c650000001c00d401 | |
| 887 | + | 01005000f303000000000000000000000000000000000000000000000108d501 | |
| 888 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 889 | + | 7469746c650000001c00d50101005000f3030000000000000000000000000000 | |
| 890 | + | 00000000000000000108d60103000000ef030000000000000900000000000000 | |
| 891 | + | 00000000000000006e6574207469746c650000001c00d60101005000f3030000 | |
| 892 | + | 00000000000000000000000000000000000000000108d70103000000ef030000 | |
| 893 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 894 | + | 1c00d70101005000f30300000000000000000000000000000000000000000000 | |
| 895 | + | 0108d80103000000ef0300000000000009000000000000000000000000000000 | |
| 896 | + | 6e6574207469746c650000001c00d80101005000f30300000000000000000000 | |
| 897 | + | 0000000000000000000000000108d90103000000ef0300000000000009000000 | |
| 898 | + | 0000000000000000000000006e6574207469746c650000001c00d90101005000 | |
| 899 | + | f303000000000000000000000000000000000000000000000108da0103000000 | |
| 900 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 901 | + | 650000001c00da0101005000f303000000000000000000000000000000000000 | |
| 902 | + | 000000000108db0103000000ef03000000000000090000000000000000000000 | |
| 903 | + | 000000006e6574207469746c650000001c00db0101005000f303000000000000 | |
| 904 | + | 000000000000000000000000000000000108dc0103000000ef03000000000000 | |
| 905 | + | 090000000000000000000000000000006e6574207469746c650000001c00dc01 | |
| 906 | + | 01005000f303000000000000000000000000000000000000000000000108dd01 | |
| 907 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 908 | + | 7469746c650000001c00dd0101005000f3030000000000000000000000000000 | |
| 909 | + | 00000000000000000108de0103000000ef030000000000000900000000000000 | |
| 910 | + | 00000000000000006e6574207469746c650000001c00de0101005000f3030000 | |
| 911 | + | 00000000000000000000000000000000000000000108df0103000000ef030000 | |
| 912 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 913 | + | 1c00df0101005000f30300000000000000000000000000000000000000000000 | |
| 914 | + | 0108e00103000000ef0300000000000009000000000000000000000000000000 | |
| 915 | + | 6e6574207469746c650000001c00e00101005000f30300000000000000000000 | |
| 916 | + | 0000000000000000000000000108e10103000000ef0300000000000009000000 | |
| 917 | + | 0000000000000000000000006e6574207469746c650000001c00e10101005000 | |
| 918 | + | f303000000000000000000000000000000000000000000000108e20103000000 | |
| 919 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 920 | + | 650000001c00e20101005000f303000000000000000000000000000000000000 | |
| 921 | + | 000000000108e30103000000ef03000000000000090000000000000000000000 | |
| 922 | + | 000000006e6574207469746c650000001c00e30101005000f303000000000000 | |
| 923 | + | 000000000000000000000000000000000108e40103000000ef03000000000000 | |
| 924 | + | 090000000000000000000000000000006e6574207469746c650000001c00e401 | |
| 925 | + | 01005000f303000000000000000000000000000000000000000000000108e501 | |
| 926 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 927 | + | 7469746c650000001c00e50101005000f3030000000000000000000000000000 | |
| 928 | + | 00000000000000000108e60103000000ef030000000000000900000000000000 | |
| 929 | + | 00000000000000006e6574207469746c650000001c00e60101005000f3030000 | |
| 930 | + | 00000000000000000000000000000000000000000108e70103000000ef030000 | |
| 931 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| 932 | + | 1c00e70101005000f30300000000000000000000000000000000000000000000 | |
| 933 | + | 0108e80103000000ef0300000000000009000000000000000000000000000000 | |
| 934 | + | 6e6574207469746c650000001c00e80101005000f30300000000000000000000 | |
| 935 | + | 0000000000000000000000000108e90103000000ef0300000000000009000000 | |
| 936 | + | 0000000000000000000000006e6574207469746c650000001c00e90101005000 | |
| 937 | + | f303000000000000000000000000000000000000000000000108ea0103000000 | |
| 938 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |
| 939 | + | 650000001c00ea0101005000f303000000000000000000000000000000000000 | |
| 940 | + | 000000000108eb0103000000ef03000000000000090000000000000000000000 | |
| 941 | + | 000000006e6574207469746c650000001c00eb0101005000f303000000000000 | |
| 942 | + | 000000000000000000000000000000000108ec0103000000ef03000000000000 | |
| 943 | + | 090000000000000000000000000000006e6574207469746c650000001c00ec01 | |
| 944 | + | 01005000f303000000000000000000000000000000000000000000000108ed01 | |
| 945 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |
| 946 | + | 7469746c650000001c00ed0101005000f3030000000000000000000000000000 | |
| 947 | + | 00000000000000000108ee0103000000ef030000000000000900000000000000 | |
| 948 | + | 00000000000000006e6574207469746c650000001c00ee0101005000f3030000 | |
| 949 | + | 00000000000000000000000000000000000000000108ef0103000000ef030000 | |
| 950 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |
| @@ -0,0 +1,950 @@ | |||||
| 1 | + | 1c005f0001005000f30300000000000000000000000000000000000000000000 | |||
| 2 | + | 0108600003000000ef0300000000000009000000000000000000000000000000 | |||
| 3 | + | 6e6574207469746c650000001c00600001005000f30300000000000000000000 | |||
| 4 | + | 0000000000000000000000000108610003000000ef0300000000000009000000 | |||
| 5 | + | 0000000000000000000000006e6574207469746c650000001c00610001005000 | |||
| 6 | + | f303000000000000000000000000000000000000000000000108620003000000 | |||
| 7 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 8 | + | 650000001c00620001005000f303000000000000000000000000000000000000 | |||
| 9 | + | 000000000108630003000000ef03000000000000090000000000000000000000 | |||
| 10 | + | 000000006e6574207469746c650000001c00630001005000f303000000000000 | |||
| 11 | + | 000000000000000000000000000000000108640003000000ef03000000000000 | |||
| 12 | + | 090000000000000000000000000000006e6574207469746c650000001c006400 | |||
| 13 | + | 01005000f3030000000000000000000000000000000000000000000001086500 | |||
| 14 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 15 | + | 7469746c650000001c00650001005000f3030000000000000000000000000000 | |||
| 16 | + | 00000000000000000108660003000000ef030000000000000900000000000000 | |||
| 17 | + | 00000000000000006e6574207469746c650000001c00660001005000f3030000 | |||
| 18 | + | 00000000000000000000000000000000000000000108670003000000ef030000 | |||
| 19 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 20 | + | 1c00670001005000f30300000000000000000000000000000000000000000000 | |||
| 21 | + | 0108680003000000ef0300000000000009000000000000000000000000000000 | |||
| 22 | + | 6e6574207469746c650000001c00680001005000f30300000000000000000000 | |||
| 23 | + | 0000000000000000000000000108690003000000ef0300000000000009000000 | |||
| 24 | + | 0000000000000000000000006e6574207469746c650000001c00690001005000 | |||
| 25 | + | f3030000000000000000000000000000000000000000000001086a0003000000 | |||
| 26 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 27 | + | 650000001c006a0001005000f303000000000000000000000000000000000000 | |||
| 28 | + | 0000000001086b0003000000ef03000000000000090000000000000000000000 | |||
| 29 | + | 000000006e6574207469746c650000001c006b0001005000f303000000000000 | |||
| 30 | + | 0000000000000000000000000000000001086c0003000000ef03000000000000 | |||
| 31 | + | 090000000000000000000000000000006e6574207469746c650000001c006c00 | |||
| 32 | + | 01005000f3030000000000000000000000000000000000000000000001086d00 | |||
| 33 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 34 | + | 7469746c650000001c006d0001005000f3030000000000000000000000000000 | |||
| 35 | + | 000000000000000001086e0003000000ef030000000000000900000000000000 | |||
| 36 | + | 00000000000000006e6574207469746c650000001c006e0001005000f3030000 | |||
| 37 | + | 000000000000000000000000000000000000000001086f0003000000ef030000 | |||
| 38 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 39 | + | 1c006f0001005000f30300000000000000000000000000000000000000000000 | |||
| 40 | + | 0108700003000000ef0300000000000009000000000000000000000000000000 | |||
| 41 | + | 6e6574207469746c650000001c00700001005000f30300000000000000000000 | |||
| 42 | + | 0000000000000000000000000108710003000000ef0300000000000009000000 | |||
| 43 | + | 0000000000000000000000006e6574207469746c650000001c00710001005000 | |||
| 44 | + | f303000000000000000000000000000000000000000000000108720003000000 | |||
| 45 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 46 | + | 650000001c00720001005000f303000000000000000000000000000000000000 | |||
| 47 | + | 000000000108730003000000ef03000000000000090000000000000000000000 | |||
| 48 | + | 000000006e6574207469746c650000001c00730001005000f303000000000000 | |||
| 49 | + | 000000000000000000000000000000000108740003000000ef03000000000000 | |||
| 50 | + | 090000000000000000000000000000006e6574207469746c650000001c007400 | |||
| 51 | + | 01005000f3030000000000000000000000000000000000000000000001087500 | |||
| 52 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 53 | + | 7469746c650000001c00750001005000f3030000000000000000000000000000 | |||
| 54 | + | 00000000000000000108760003000000ef030000000000000900000000000000 | |||
| 55 | + | 00000000000000006e6574207469746c650000001c00760001005000f3030000 | |||
| 56 | + | 00000000000000000000000000000000000000000108770003000000ef030000 | |||
| 57 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 58 | + | 1c00770001005000f30300000000000000000000000000000000000000000000 | |||
| 59 | + | 0108780003000000ef0300000000000009000000000000000000000000000000 | |||
| 60 | + | 6e6574207469746c650000001c00780001005000f30300000000000000000000 | |||
| 61 | + | 0000000000000000000000000108790003000000ef0300000000000009000000 | |||
| 62 | + | 0000000000000000000000006e6574207469746c650000001c00790001005000 | |||
| 63 | + | f3030000000000000000000000000000000000000000000001087a0003000000 | |||
| 64 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 65 | + | 650000001c007a0001005000f303000000000000000000000000000000000000 | |||
| 66 | + | 0000000001087b0003000000ef03000000000000090000000000000000000000 | |||
| 67 | + | 000000006e6574207469746c650000001c007b0001005000f303000000000000 | |||
| 68 | + | 0000000000000000000000000000000001087c0003000000ef03000000000000 | |||
| 69 | + | 090000000000000000000000000000006e6574207469746c650000001c007c00 | |||
| 70 | + | 01005000f3030000000000000000000000000000000000000000000001087d00 | |||
| 71 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 72 | + | 7469746c650000001c007d0001005000f3030000000000000000000000000000 | |||
| 73 | + | 000000000000000001087e0003000000ef030000000000000900000000000000 | |||
| 74 | + | 00000000000000006e6574207469746c650000001c007e0001005000f3030000 | |||
| 75 | + | 000000000000000000000000000000000000000001087f0003000000ef030000 | |||
| 76 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 77 | + | 1c007f0001005000f30300000000000000000000000000000000000000000000 | |||
| 78 | + | 0108800003000000ef0300000000000009000000000000000000000000000000 | |||
| 79 | + | 6e6574207469746c650000001c00800001005000f30300000000000000000000 | |||
| 80 | + | 0000000000000000000000000108810003000000ef0300000000000009000000 | |||
| 81 | + | 0000000000000000000000006e6574207469746c650000001c00810001005000 | |||
| 82 | + | f303000000000000000000000000000000000000000000000108820003000000 | |||
| 83 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 84 | + | 650000001c00820001005000f303000000000000000000000000000000000000 | |||
| 85 | + | 000000000108830003000000ef03000000000000090000000000000000000000 | |||
| 86 | + | 000000006e6574207469746c650000001c00830001005000f303000000000000 | |||
| 87 | + | 000000000000000000000000000000000108840003000000ef03000000000000 | |||
| 88 | + | 090000000000000000000000000000006e6574207469746c650000001c008400 | |||
| 89 | + | 01005000f3030000000000000000000000000000000000000000000001088500 | |||
| 90 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 91 | + | 7469746c650000001c00850001005000f3030000000000000000000000000000 | |||
| 92 | + | 00000000000000000108860003000000ef030000000000000900000000000000 | |||
| 93 | + | 00000000000000006e6574207469746c650000001c00860001005000f3030000 | |||
| 94 | + | 00000000000000000000000000000000000000000108870003000000ef030000 | |||
| 95 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 96 | + | 1c00870001005000f30300000000000000000000000000000000000000000000 | |||
| 97 | + | 0108880003000000ef0300000000000009000000000000000000000000000000 | |||
| 98 | + | 6e6574207469746c650000001c00880001005000f30300000000000000000000 | |||
| 99 | + | 0000000000000000000000000108890003000000ef0300000000000009000000 | |||
| 100 | + | 0000000000000000000000006e6574207469746c650000001c00890001005000 | |||
| 101 | + | f3030000000000000000000000000000000000000000000001088a0003000000 | |||
| 102 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 103 | + | 650000001c008a0001005000f303000000000000000000000000000000000000 | |||
| 104 | + | 0000000001088b0003000000ef03000000000000090000000000000000000000 | |||
| 105 | + | 000000006e6574207469746c650000001c008b0001005000f303000000000000 | |||
| 106 | + | 0000000000000000000000000000000001088c0003000000ef03000000000000 | |||
| 107 | + | 090000000000000000000000000000006e6574207469746c650000001c008c00 | |||
| 108 | + | 01005000f3030000000000000000000000000000000000000000000001088d00 | |||
| 109 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 110 | + | 7469746c650000001c008d0001005000f3030000000000000000000000000000 | |||
| 111 | + | 000000000000000001088e0003000000ef030000000000000900000000000000 | |||
| 112 | + | 00000000000000006e6574207469746c650000001c008e0001005000f3030000 | |||
| 113 | + | 000000000000000000000000000000000000000001088f0003000000ef030000 | |||
| 114 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 115 | + | 1c008f0001005000f30300000000000000000000000000000000000000000000 | |||
| 116 | + | 0108900003000000ef0300000000000009000000000000000000000000000000 | |||
| 117 | + | 6e6574207469746c650000001c00900001005000f30300000000000000000000 | |||
| 118 | + | 0000000000000000000000000108910003000000ef0300000000000009000000 | |||
| 119 | + | 0000000000000000000000006e6574207469746c650000001c00910001005000 | |||
| 120 | + | f303000000000000000000000000000000000000000000000108920003000000 | |||
| 121 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 122 | + | 650000001c00920001005000f303000000000000000000000000000000000000 | |||
| 123 | + | 000000000108930003000000ef03000000000000090000000000000000000000 | |||
| 124 | + | 000000006e6574207469746c650000001c00930001005000f303000000000000 | |||
| 125 | + | 000000000000000000000000000000000108940003000000ef03000000000000 | |||
| 126 | + | 090000000000000000000000000000006e6574207469746c650000001c009400 | |||
| 127 | + | 01005000f3030000000000000000000000000000000000000000000001089500 | |||
| 128 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 129 | + | 7469746c650000001c00950001005000f3030000000000000000000000000000 | |||
| 130 | + | 00000000000000000108960003000000ef030000000000000900000000000000 | |||
| 131 | + | 00000000000000006e6574207469746c650000001c00960001005000f3030000 | |||
| 132 | + | 00000000000000000000000000000000000000000108970003000000ef030000 | |||
| 133 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 134 | + | 1c00970001005000f30300000000000000000000000000000000000000000000 | |||
| 135 | + | 0108980003000000ef0300000000000009000000000000000000000000000000 | |||
| 136 | + | 6e6574207469746c650000001c00980001005000f30300000000000000000000 | |||
| 137 | + | 0000000000000000000000000108990003000000ef0300000000000009000000 | |||
| 138 | + | 0000000000000000000000006e6574207469746c650000001c00990001005000 | |||
| 139 | + | f3030000000000000000000000000000000000000000000001089a0003000000 | |||
| 140 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 141 | + | 650000001c009a0001005000f303000000000000000000000000000000000000 | |||
| 142 | + | 0000000001089b0003000000ef03000000000000090000000000000000000000 | |||
| 143 | + | 000000006e6574207469746c650000001c009b0001005000f303000000000000 | |||
| 144 | + | 0000000000000000000000000000000001089c0003000000ef03000000000000 | |||
| 145 | + | 090000000000000000000000000000006e6574207469746c650000001c009c00 | |||
| 146 | + | 01005000f3030000000000000000000000000000000000000000000001089d00 | |||
| 147 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 148 | + | 7469746c650000001c009d0001005000f3030000000000000000000000000000 | |||
| 149 | + | 000000000000000001089e0003000000ef030000000000000900000000000000 | |||
| 150 | + | 00000000000000006e6574207469746c650000001c009e0001005000f3030000 | |||
| 151 | + | 000000000000000000000000000000000000000001089f0003000000ef030000 | |||
| 152 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 153 | + | 1c009f0001005000f30300000000000000000000000000000000000000000000 | |||
| 154 | + | 0108a00003000000ef0300000000000009000000000000000000000000000000 | |||
| 155 | + | 6e6574207469746c650000001c00a00001005000f30300000000000000000000 | |||
| 156 | + | 0000000000000000000000000108a10003000000ef0300000000000009000000 | |||
| 157 | + | 0000000000000000000000006e6574207469746c650000001c00a10001005000 | |||
| 158 | + | f303000000000000000000000000000000000000000000000108a20003000000 | |||
| 159 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 160 | + | 650000001c00a20001005000f303000000000000000000000000000000000000 | |||
| 161 | + | 000000000108a30003000000ef03000000000000090000000000000000000000 | |||
| 162 | + | 000000006e6574207469746c650000001c00a30001005000f303000000000000 | |||
| 163 | + | 000000000000000000000000000000000108a40003000000ef03000000000000 | |||
| 164 | + | 090000000000000000000000000000006e6574207469746c650000001c00a400 | |||
| 165 | + | 01005000f303000000000000000000000000000000000000000000000108a500 | |||
| 166 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 167 | + | 7469746c650000001c00a50001005000f3030000000000000000000000000000 | |||
| 168 | + | 00000000000000000108a60003000000ef030000000000000900000000000000 | |||
| 169 | + | 00000000000000006e6574207469746c650000001c00a60001005000f3030000 | |||
| 170 | + | 00000000000000000000000000000000000000000108a70003000000ef030000 | |||
| 171 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 172 | + | 1c00a70001005000f30300000000000000000000000000000000000000000000 | |||
| 173 | + | 0108a80003000000ef0300000000000009000000000000000000000000000000 | |||
| 174 | + | 6e6574207469746c650000001c00a80001005000f30300000000000000000000 | |||
| 175 | + | 0000000000000000000000000108a90003000000ef0300000000000009000000 | |||
| 176 | + | 0000000000000000000000006e6574207469746c650000001c00a90001005000 | |||
| 177 | + | f303000000000000000000000000000000000000000000000108aa0003000000 | |||
| 178 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 179 | + | 650000001c00aa0001005000f303000000000000000000000000000000000000 | |||
| 180 | + | 000000000108ab0003000000ef03000000000000090000000000000000000000 | |||
| 181 | + | 000000006e6574207469746c650000001c00ab0001005000f303000000000000 | |||
| 182 | + | 000000000000000000000000000000000108ac0003000000ef03000000000000 | |||
| 183 | + | 090000000000000000000000000000006e6574207469746c650000001c00ac00 | |||
| 184 | + | 01005000f303000000000000000000000000000000000000000000000108ad00 | |||
| 185 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 186 | + | 7469746c650000001c00ad0001005000f3030000000000000000000000000000 | |||
| 187 | + | 00000000000000000108ae0003000000ef030000000000000900000000000000 | |||
| 188 | + | 00000000000000006e6574207469746c650000001c00ae0001005000f3030000 | |||
| 189 | + | 00000000000000000000000000000000000000000108af0003000000ef030000 | |||
| 190 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 191 | + | 1c00af0001005000f30300000000000000000000000000000000000000000000 | |||
| 192 | + | 0108b00003000000ef0300000000000009000000000000000000000000000000 | |||
| 193 | + | 6e6574207469746c650000001c00b00001005000f30300000000000000000000 | |||
| 194 | + | 0000000000000000000000000108b10003000000ef0300000000000009000000 | |||
| 195 | + | 0000000000000000000000006e6574207469746c650000001c00b10001005000 | |||
| 196 | + | f303000000000000000000000000000000000000000000000108b20003000000 | |||
| 197 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 198 | + | 650000001c00b20001005000f303000000000000000000000000000000000000 | |||
| 199 | + | 000000000108b30003000000ef03000000000000090000000000000000000000 | |||
| 200 | + | 000000006e6574207469746c650000001c00b30001005000f303000000000000 | |||
| 201 | + | 000000000000000000000000000000000108b40003000000ef03000000000000 | |||
| 202 | + | 090000000000000000000000000000006e6574207469746c650000001c00b400 | |||
| 203 | + | 01005000f303000000000000000000000000000000000000000000000108b500 | |||
| 204 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 205 | + | 7469746c650000001c00b50001005000f3030000000000000000000000000000 | |||
| 206 | + | 00000000000000000108b60003000000ef030000000000000900000000000000 | |||
| 207 | + | 00000000000000006e6574207469746c650000001c00b60001005000f3030000 | |||
| 208 | + | 00000000000000000000000000000000000000000108b70003000000ef030000 | |||
| 209 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 210 | + | 1c00b70001005000f30300000000000000000000000000000000000000000000 | |||
| 211 | + | 0108b80003000000ef0300000000000009000000000000000000000000000000 | |||
| 212 | + | 6e6574207469746c650000001c00b80001005000f30300000000000000000000 | |||
| 213 | + | 0000000000000000000000000108b90003000000ef0300000000000009000000 | |||
| 214 | + | 0000000000000000000000006e6574207469746c650000001c00b90001005000 | |||
| 215 | + | f303000000000000000000000000000000000000000000000108ba0003000000 | |||
| 216 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 217 | + | 650000001c00ba0001005000f303000000000000000000000000000000000000 | |||
| 218 | + | 000000000108bb0003000000ef03000000000000090000000000000000000000 | |||
| 219 | + | 000000006e6574207469746c650000001c00bb0001005000f303000000000000 | |||
| 220 | + | 000000000000000000000000000000000108bc0003000000ef03000000000000 | |||
| 221 | + | 090000000000000000000000000000006e6574207469746c650000001c00bc00 | |||
| 222 | + | 01005000f303000000000000000000000000000000000000000000000108bd00 | |||
| 223 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 224 | + | 7469746c650000001c00bd0001005000f3030000000000000000000000000000 | |||
| 225 | + | 00000000000000000108be0003000000ef030000000000000900000000000000 | |||
| 226 | + | 00000000000000006e6574207469746c650000001c00be0001005000f3030000 | |||
| 227 | + | 00000000000000000000000000000000000000000108bf0003000000ef030000 | |||
| 228 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 229 | + | 1c00bf0001005000f30300000000000000000000000000000000000000000000 | |||
| 230 | + | 0108c00003000000ef0300000000000009000000000000000000000000000000 | |||
| 231 | + | 6e6574207469746c650000001c00c00001005000f30300000000000000000000 | |||
| 232 | + | 0000000000000000000000000108c10003000000ef0300000000000009000000 | |||
| 233 | + | 0000000000000000000000006e6574207469746c650000001c00c10001005000 | |||
| 234 | + | f303000000000000000000000000000000000000000000000108c20003000000 | |||
| 235 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 236 | + | 650000001c00c20001005000f303000000000000000000000000000000000000 | |||
| 237 | + | 000000000108c30003000000ef03000000000000090000000000000000000000 | |||
| 238 | + | 000000006e6574207469746c650000001c00c30001005000f303000000000000 | |||
| 239 | + | 000000000000000000000000000000000108c40003000000ef03000000000000 | |||
| 240 | + | 090000000000000000000000000000006e6574207469746c650000001c00c400 | |||
| 241 | + | 01005000f303000000000000000000000000000000000000000000000108c500 | |||
| 242 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 243 | + | 7469746c650000001c00c50001005000f3030000000000000000000000000000 | |||
| 244 | + | 00000000000000000108c60003000000ef030000000000000900000000000000 | |||
| 245 | + | 00000000000000006e6574207469746c650000001c00c60001005000f3030000 | |||
| 246 | + | 00000000000000000000000000000000000000000108c70003000000ef030000 | |||
| 247 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 248 | + | 1c00c70001005000f30300000000000000000000000000000000000000000000 | |||
| 249 | + | 0108c80003000000ef0300000000000009000000000000000000000000000000 | |||
| 250 | + | 6e6574207469746c650000001c00c80001005000f30300000000000000000000 | |||
| 251 | + | 0000000000000000000000000108c90003000000ef0300000000000009000000 | |||
| 252 | + | 0000000000000000000000006e6574207469746c650000001c00c90001005000 | |||
| 253 | + | f303000000000000000000000000000000000000000000000108ca0003000000 | |||
| 254 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 255 | + | 650000001c00ca0001005000f303000000000000000000000000000000000000 | |||
| 256 | + | 000000000108cb0003000000ef03000000000000090000000000000000000000 | |||
| 257 | + | 000000006e6574207469746c650000001c00cb0001005000f303000000000000 | |||
| 258 | + | 000000000000000000000000000000000108cc0003000000ef03000000000000 | |||
| 259 | + | 090000000000000000000000000000006e6574207469746c650000001c00cc00 | |||
| 260 | + | 01005000f303000000000000000000000000000000000000000000000108cd00 | |||
| 261 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 262 | + | 7469746c650000001c00cd0001005000f3030000000000000000000000000000 | |||
| 263 | + | 00000000000000000108ce0003000000ef030000000000000900000000000000 | |||
| 264 | + | 00000000000000006e6574207469746c650000001c00ce0001005000f3030000 | |||
| 265 | + | 00000000000000000000000000000000000000000108cf0003000000ef030000 | |||
| 266 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 267 | + | 1c00cf0001005000f30300000000000000000000000000000000000000000000 | |||
| 268 | + | 0108d00003000000ef0300000000000009000000000000000000000000000000 | |||
| 269 | + | 6e6574207469746c650000001c00d00001005000f30300000000000000000000 | |||
| 270 | + | 0000000000000000000000000108d10003000000ef0300000000000009000000 | |||
| 271 | + | 0000000000000000000000006e6574207469746c650000001c00d10001005000 | |||
| 272 | + | f303000000000000000000000000000000000000000000000108d20003000000 | |||
| 273 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 274 | + | 650000001c00d20001005000f303000000000000000000000000000000000000 | |||
| 275 | + | 000000000108d30003000000ef03000000000000090000000000000000000000 | |||
| 276 | + | 000000006e6574207469746c650000001c00d30001005000f303000000000000 | |||
| 277 | + | 000000000000000000000000000000000108d40003000000ef03000000000000 | |||
| 278 | + | 090000000000000000000000000000006e6574207469746c650000001c00d400 | |||
| 279 | + | 01005000f303000000000000000000000000000000000000000000000108d500 | |||
| 280 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 281 | + | 7469746c650000001c00d50001005000f3030000000000000000000000000000 | |||
| 282 | + | 00000000000000000108d60003000000ef030000000000000900000000000000 | |||
| 283 | + | 00000000000000006e6574207469746c650000001c00d60001005000f3030000 | |||
| 284 | + | 00000000000000000000000000000000000000000108d70003000000ef030000 | |||
| 285 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 286 | + | 1c00d70001005000f30300000000000000000000000000000000000000000000 | |||
| 287 | + | 0108d80003000000ef0300000000000009000000000000000000000000000000 | |||
| 288 | + | 6e6574207469746c650000001c00d80001005000f30300000000000000000000 | |||
| 289 | + | 0000000000000000000000000108d90003000000ef0300000000000009000000 | |||
| 290 | + | 0000000000000000000000006e6574207469746c650000001c00d90001005000 | |||
| 291 | + | f303000000000000000000000000000000000000000000000108da0003000000 | |||
| 292 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 293 | + | 650000001c00da0001005000f303000000000000000000000000000000000000 | |||
| 294 | + | 000000000108db0003000000ef03000000000000090000000000000000000000 | |||
| 295 | + | 000000006e6574207469746c650000001c00db0001005000f303000000000000 | |||
| 296 | + | 000000000000000000000000000000000108dc0003000000ef03000000000000 | |||
| 297 | + | 090000000000000000000000000000006e6574207469746c650000001c00dc00 | |||
| 298 | + | 01005000f303000000000000000000000000000000000000000000000108dd00 | |||
| 299 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 300 | + | 7469746c650000001c00dd0001005000f3030000000000000000000000000000 | |||
| 301 | + | 00000000000000000108de0003000000ef030000000000000900000000000000 | |||
| 302 | + | 00000000000000006e6574207469746c650000001c00de0001005000f3030000 | |||
| 303 | + | 00000000000000000000000000000000000000000108df0003000000ef030000 | |||
| 304 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 305 | + | 1c00df0001005000f30300000000000000000000000000000000000000000000 | |||
| 306 | + | 0108e00003000000ef0300000000000009000000000000000000000000000000 | |||
| 307 | + | 6e6574207469746c650000001c00e00001005000f30300000000000000000000 | |||
| 308 | + | 0000000000000000000000000108e10003000000ef0300000000000009000000 | |||
| 309 | + | 0000000000000000000000006e6574207469746c650000001c00e10001005000 | |||
| 310 | + | f303000000000000000000000000000000000000000000000108e20003000000 | |||
| 311 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 312 | + | 650000001c00e20001005000f303000000000000000000000000000000000000 | |||
| 313 | + | 000000000108e30003000000ef03000000000000090000000000000000000000 | |||
| 314 | + | 000000006e6574207469746c650000001c00e30001005000f303000000000000 | |||
| 315 | + | 000000000000000000000000000000000108e40003000000ef03000000000000 | |||
| 316 | + | 090000000000000000000000000000006e6574207469746c650000001c00e400 | |||
| 317 | + | 01005000f303000000000000000000000000000000000000000000000108e500 | |||
| 318 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 319 | + | 7469746c650000001c00e50001005000f3030000000000000000000000000000 | |||
| 320 | + | 00000000000000000108e60003000000ef030000000000000900000000000000 | |||
| 321 | + | 00000000000000006e6574207469746c650000001c00e60001005000f3030000 | |||
| 322 | + | 00000000000000000000000000000000000000000108e70003000000ef030000 | |||
| 323 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 324 | + | 1c00e70001005000f30300000000000000000000000000000000000000000000 | |||
| 325 | + | 0108e80003000000ef0300000000000009000000000000000000000000000000 | |||
| 326 | + | 6e6574207469746c650000001c00e80001005000f30300000000000000000000 | |||
| 327 | + | 0000000000000000000000000108e90003000000ef0300000000000009000000 | |||
| 328 | + | 0000000000000000000000006e6574207469746c650000001c00e90001005000 | |||
| 329 | + | f303000000000000000000000000000000000000000000000108ea0003000000 | |||
| 330 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 331 | + | 650000001c00ea0001005000f303000000000000000000000000000000000000 | |||
| 332 | + | 000000000108eb0003000000ef03000000000000090000000000000000000000 | |||
| 333 | + | 000000006e6574207469746c650000001c00eb0001005000f303000000000000 | |||
| 334 | + | 000000000000000000000000000000000108ec0003000000ef03000000000000 | |||
| 335 | + | 090000000000000000000000000000006e6574207469746c650000001c00ec00 | |||
| 336 | + | 01005000f303000000000000000000000000000000000000000000000108ed00 | |||
| 337 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 338 | + | 7469746c650000001c00ed0001005000f3030000000000000000000000000000 | |||
| 339 | + | 00000000000000000108ee0003000000ef030000000000000900000000000000 | |||
| 340 | + | 00000000000000006e6574207469746c650000001c00ee0001005000f3030000 | |||
| 341 | + | 00000000000000000000000000000000000000000108ef0003000000ef030000 | |||
| 342 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 343 | + | 1c00ef0001005000f30300000000000000000000000000000000000000000000 | |||
| 344 | + | 0108f00003000000ef0300000000000009000000000000000000000000000000 | |||
| 345 | + | 6e6574207469746c650000001c00f00001005000f30300000000000000000000 | |||
| 346 | + | 0000000000000000000000000108f10003000000ef0300000000000009000000 | |||
| 347 | + | 0000000000000000000000006e6574207469746c650000001c00f10001005000 | |||
| 348 | + | f303000000000000000000000000000000000000000000000108f20003000000 | |||
| 349 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 350 | + | 650000001c00f20001005000f303000000000000000000000000000000000000 | |||
| 351 | + | 000000000108f30003000000ef03000000000000090000000000000000000000 | |||
| 352 | + | 000000006e6574207469746c650000001c00f30001005000f303000000000000 | |||
| 353 | + | 000000000000000000000000000000000108f40003000000ef03000000000000 | |||
| 354 | + | 090000000000000000000000000000006e6574207469746c650000001c00f400 | |||
| 355 | + | 01005000f303000000000000000000000000000000000000000000000108f500 | |||
| 356 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 357 | + | 7469746c650000001c00f50001005000f3030000000000000000000000000000 | |||
| 358 | + | 00000000000000000108f60003000000ef030000000000000900000000000000 | |||
| 359 | + | 00000000000000006e6574207469746c650000001c00f60001005000f3030000 | |||
| 360 | + | 00000000000000000000000000000000000000000108f70003000000ef030000 | |||
| 361 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 362 | + | 1c00f70001005000f30300000000000000000000000000000000000000000000 | |||
| 363 | + | 0108f80003000000ef0300000000000009000000000000000000000000000000 | |||
| 364 | + | 6e6574207469746c650000001c00f80001005000f30300000000000000000000 | |||
| 365 | + | 0000000000000000000000000108f90003000000ef0300000000000009000000 | |||
| 366 | + | 0000000000000000000000006e6574207469746c650000001c00f90001005000 | |||
| 367 | + | f303000000000000000000000000000000000000000000000108fa0003000000 | |||
| 368 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 369 | + | 650000001c00fa0001005000f303000000000000000000000000000000000000 | |||
| 370 | + | 000000000108fb0003000000ef03000000000000090000000000000000000000 | |||
| 371 | + | 000000006e6574207469746c650000001c00fb0001005000f303000000000000 | |||
| 372 | + | 000000000000000000000000000000000108fc0003000000ef03000000000000 | |||
| 373 | + | 090000000000000000000000000000006e6574207469746c650000001c00fc00 | |||
| 374 | + | 01005000f303000000000000000000000000000000000000000000000108fd00 | |||
| 375 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 376 | + | 7469746c650000001c00fd0001005000f3030000000000000000000000000000 | |||
| 377 | + | 00000000000000000108fe0003000000ef030000000000000900000000000000 | |||
| 378 | + | 00000000000000006e6574207469746c650000001c00fe0001005000f3030000 | |||
| 379 | + | 00000000000000000000000000000000000000000108ff0003000000ef030000 | |||
| 380 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 381 | + | 1c00ff0001005000f30300000000000000000000000000000000000000000000 | |||
| 382 | + | 0108000103000000ef0300000000000009000000000000000000000000000000 | |||
| 383 | + | 6e6574207469746c650000001c00000101005000f30300000000000000000000 | |||
| 384 | + | 0000000000000000000000000108010103000000ef0300000000000009000000 | |||
| 385 | + | 0000000000000000000000006e6574207469746c650000001c00010101005000 | |||
| 386 | + | f303000000000000000000000000000000000000000000000108020103000000 | |||
| 387 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 388 | + | 650000001c00020101005000f303000000000000000000000000000000000000 | |||
| 389 | + | 000000000108030103000000ef03000000000000090000000000000000000000 | |||
| 390 | + | 000000006e6574207469746c650000001c00030101005000f303000000000000 | |||
| 391 | + | 000000000000000000000000000000000108040103000000ef03000000000000 | |||
| 392 | + | 090000000000000000000000000000006e6574207469746c650000001c000401 | |||
| 393 | + | 01005000f3030000000000000000000000000000000000000000000001080501 | |||
| 394 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 395 | + | 7469746c650000001c00050101005000f3030000000000000000000000000000 | |||
| 396 | + | 00000000000000000108060103000000ef030000000000000900000000000000 | |||
| 397 | + | 00000000000000006e6574207469746c650000001c00060101005000f3030000 | |||
| 398 | + | 00000000000000000000000000000000000000000108070103000000ef030000 | |||
| 399 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 400 | + | 1c00070101005000f30300000000000000000000000000000000000000000000 | |||
| 401 | + | 0108080103000000ef0300000000000009000000000000000000000000000000 | |||
| 402 | + | 6e6574207469746c650000001c00080101005000f30300000000000000000000 | |||
| 403 | + | 0000000000000000000000000108090103000000ef0300000000000009000000 | |||
| 404 | + | 0000000000000000000000006e6574207469746c650000001c00090101005000 | |||
| 405 | + | f3030000000000000000000000000000000000000000000001080a0103000000 | |||
| 406 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 407 | + | 650000001c000a0101005000f303000000000000000000000000000000000000 | |||
| 408 | + | 0000000001080b0103000000ef03000000000000090000000000000000000000 | |||
| 409 | + | 000000006e6574207469746c650000001c000b0101005000f303000000000000 | |||
| 410 | + | 0000000000000000000000000000000001080c0103000000ef03000000000000 | |||
| 411 | + | 090000000000000000000000000000006e6574207469746c650000001c000c01 | |||
| 412 | + | 01005000f3030000000000000000000000000000000000000000000001080d01 | |||
| 413 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 414 | + | 7469746c650000001c000d0101005000f3030000000000000000000000000000 | |||
| 415 | + | 000000000000000001080e0103000000ef030000000000000900000000000000 | |||
| 416 | + | 00000000000000006e6574207469746c650000001c000e0101005000f3030000 | |||
| 417 | + | 000000000000000000000000000000000000000001080f0103000000ef030000 | |||
| 418 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 419 | + | 1c000f0101005000f30300000000000000000000000000000000000000000000 | |||
| 420 | + | 0108100103000000ef0300000000000009000000000000000000000000000000 | |||
| 421 | + | 6e6574207469746c650000001c00100101005000f30300000000000000000000 | |||
| 422 | + | 0000000000000000000000000108110103000000ef0300000000000009000000 | |||
| 423 | + | 0000000000000000000000006e6574207469746c650000001c00110101005000 | |||
| 424 | + | f303000000000000000000000000000000000000000000000108120103000000 | |||
| 425 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 426 | + | 650000001c00120101005000f303000000000000000000000000000000000000 | |||
| 427 | + | 000000000108130103000000ef03000000000000090000000000000000000000 | |||
| 428 | + | 000000006e6574207469746c650000001c00130101005000f303000000000000 | |||
| 429 | + | 000000000000000000000000000000000108140103000000ef03000000000000 | |||
| 430 | + | 090000000000000000000000000000006e6574207469746c650000001c001401 | |||
| 431 | + | 01005000f3030000000000000000000000000000000000000000000001081501 | |||
| 432 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 433 | + | 7469746c650000001c00150101005000f3030000000000000000000000000000 | |||
| 434 | + | 00000000000000000108160103000000ef030000000000000900000000000000 | |||
| 435 | + | 00000000000000006e6574207469746c650000001c00160101005000f3030000 | |||
| 436 | + | 00000000000000000000000000000000000000000108170103000000ef030000 | |||
| 437 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 438 | + | 1c00170101005000f30300000000000000000000000000000000000000000000 | |||
| 439 | + | 0108180103000000ef0300000000000009000000000000000000000000000000 | |||
| 440 | + | 6e6574207469746c650000001c00180101005000f30300000000000000000000 | |||
| 441 | + | 0000000000000000000000000108190103000000ef0300000000000009000000 | |||
| 442 | + | 0000000000000000000000006e6574207469746c650000001c00190101005000 | |||
| 443 | + | f3030000000000000000000000000000000000000000000001081a0103000000 | |||
| 444 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 445 | + | 650000001c001a0101005000f303000000000000000000000000000000000000 | |||
| 446 | + | 0000000001081b0103000000ef03000000000000090000000000000000000000 | |||
| 447 | + | 000000006e6574207469746c650000001c001b0101005000f303000000000000 | |||
| 448 | + | 0000000000000000000000000000000001081c0103000000ef03000000000000 | |||
| 449 | + | 090000000000000000000000000000006e6574207469746c650000001c001c01 | |||
| 450 | + | 01005000f3030000000000000000000000000000000000000000000001081d01 | |||
| 451 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 452 | + | 7469746c650000001c001d0101005000f3030000000000000000000000000000 | |||
| 453 | + | 000000000000000001081e0103000000ef030000000000000900000000000000 | |||
| 454 | + | 00000000000000006e6574207469746c650000001c001e0101005000f3030000 | |||
| 455 | + | 000000000000000000000000000000000000000001081f0103000000ef030000 | |||
| 456 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 457 | + | 1c001f0101005000f30300000000000000000000000000000000000000000000 | |||
| 458 | + | 0108200103000000ef0300000000000009000000000000000000000000000000 | |||
| 459 | + | 6e6574207469746c650000001c00200101005000f30300000000000000000000 | |||
| 460 | + | 0000000000000000000000000108210103000000ef0300000000000009000000 | |||
| 461 | + | 0000000000000000000000006e6574207469746c650000001c00210101005000 | |||
| 462 | + | f303000000000000000000000000000000000000000000000108220103000000 | |||
| 463 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 464 | + | 650000001c00220101005000f303000000000000000000000000000000000000 | |||
| 465 | + | 000000000108230103000000ef03000000000000090000000000000000000000 | |||
| 466 | + | 000000006e6574207469746c650000001c00230101005000f303000000000000 | |||
| 467 | + | 000000000000000000000000000000000108240103000000ef03000000000000 | |||
| 468 | + | 090000000000000000000000000000006e6574207469746c650000001c002401 | |||
| 469 | + | 01005000f3030000000000000000000000000000000000000000000001082501 | |||
| 470 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 471 | + | 7469746c650000001c00250101005000f3030000000000000000000000000000 | |||
| 472 | + | 00000000000000000108260103000000ef030000000000000900000000000000 | |||
| 473 | + | 00000000000000006e6574207469746c650000001c00260101005000f3030000 | |||
| 474 | + | 00000000000000000000000000000000000000000108270103000000ef030000 | |||
| 475 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 476 | + | 1c00270101005000f30300000000000000000000000000000000000000000000 | |||
| 477 | + | 0108280103000000ef0300000000000009000000000000000000000000000000 | |||
| 478 | + | 6e6574207469746c650000001c00280101005000f30300000000000000000000 | |||
| 479 | + | 0000000000000000000000000108290103000000ef0300000000000009000000 | |||
| 480 | + | 0000000000000000000000006e6574207469746c650000001c00290101005000 | |||
| 481 | + | f3030000000000000000000000000000000000000000000001082a0103000000 | |||
| 482 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 483 | + | 650000001c002a0101005000f303000000000000000000000000000000000000 | |||
| 484 | + | 0000000001082b0103000000ef03000000000000090000000000000000000000 | |||
| 485 | + | 000000006e6574207469746c650000001c002b0101005000f303000000000000 | |||
| 486 | + | 0000000000000000000000000000000001082c0103000000ef03000000000000 | |||
| 487 | + | 090000000000000000000000000000006e6574207469746c650000001c002c01 | |||
| 488 | + | 01005000f3030000000000000000000000000000000000000000000001082d01 | |||
| 489 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 490 | + | 7469746c650000001c002d0101005000f3030000000000000000000000000000 | |||
| 491 | + | 000000000000000001082e0103000000ef030000000000000900000000000000 | |||
| 492 | + | 00000000000000006e6574207469746c650000001c002e0101005000f3030000 | |||
| 493 | + | 000000000000000000000000000000000000000001082f0103000000ef030000 | |||
| 494 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 495 | + | 1c002f0101005000f30300000000000000000000000000000000000000000000 | |||
| 496 | + | 0108300103000000ef0300000000000009000000000000000000000000000000 | |||
| 497 | + | 6e6574207469746c650000001c00300101005000f30300000000000000000000 | |||
| 498 | + | 0000000000000000000000000108310103000000ef0300000000000009000000 | |||
| 499 | + | 0000000000000000000000006e6574207469746c650000001c00310101005000 | |||
| 500 | + | f303000000000000000000000000000000000000000000000108320103000000 | |||
| 501 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 502 | + | 650000001c00320101005000f303000000000000000000000000000000000000 | |||
| 503 | + | 000000000108330103000000ef03000000000000090000000000000000000000 | |||
| 504 | + | 000000006e6574207469746c650000001c00330101005000f303000000000000 | |||
| 505 | + | 000000000000000000000000000000000108340103000000ef03000000000000 | |||
| 506 | + | 090000000000000000000000000000006e6574207469746c650000001c003401 | |||
| 507 | + | 01005000f3030000000000000000000000000000000000000000000001083501 | |||
| 508 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 509 | + | 7469746c650000001c00350101005000f3030000000000000000000000000000 | |||
| 510 | + | 00000000000000000108360103000000ef030000000000000900000000000000 | |||
| 511 | + | 00000000000000006e6574207469746c650000001c00360101005000f3030000 | |||
| 512 | + | 00000000000000000000000000000000000000000108370103000000ef030000 | |||
| 513 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 514 | + | 1c00370101005000f30300000000000000000000000000000000000000000000 | |||
| 515 | + | 0108380103000000ef0300000000000009000000000000000000000000000000 | |||
| 516 | + | 6e6574207469746c650000001c00380101005000f30300000000000000000000 | |||
| 517 | + | 0000000000000000000000000108390103000000ef0300000000000009000000 | |||
| 518 | + | 0000000000000000000000006e6574207469746c650000001c00390101005000 | |||
| 519 | + | f3030000000000000000000000000000000000000000000001083a0103000000 | |||
| 520 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 521 | + | 650000001c003a0101005000f303000000000000000000000000000000000000 | |||
| 522 | + | 0000000001083b0103000000ef03000000000000090000000000000000000000 | |||
| 523 | + | 000000006e6574207469746c650000001c003b0101005000f303000000000000 | |||
| 524 | + | 0000000000000000000000000000000001083c0103000000ef03000000000000 | |||
| 525 | + | 090000000000000000000000000000006e6574207469746c650000001c003c01 | |||
| 526 | + | 01005000f3030000000000000000000000000000000000000000000001083d01 | |||
| 527 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 528 | + | 7469746c650000001c003d0101005000f3030000000000000000000000000000 | |||
| 529 | + | 000000000000000001083e0103000000ef030000000000000900000000000000 | |||
| 530 | + | 00000000000000006e6574207469746c650000001c003e0101005000f3030000 | |||
| 531 | + | 000000000000000000000000000000000000000001083f0103000000ef030000 | |||
| 532 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 533 | + | 1c003f0101005000f30300000000000000000000000000000000000000000000 | |||
| 534 | + | 0108400103000000ef0300000000000009000000000000000000000000000000 | |||
| 535 | + | 6e6574207469746c650000001c00400101005000f30300000000000000000000 | |||
| 536 | + | 0000000000000000000000000108410103000000ef0300000000000009000000 | |||
| 537 | + | 0000000000000000000000006e6574207469746c650000001c00410101005000 | |||
| 538 | + | f303000000000000000000000000000000000000000000000108420103000000 | |||
| 539 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 540 | + | 650000001c00420101005000f303000000000000000000000000000000000000 | |||
| 541 | + | 000000000108430103000000ef03000000000000090000000000000000000000 | |||
| 542 | + | 000000006e6574207469746c650000001c00430101005000f303000000000000 | |||
| 543 | + | 000000000000000000000000000000000108440103000000ef03000000000000 | |||
| 544 | + | 090000000000000000000000000000006e6574207469746c650000001c004401 | |||
| 545 | + | 01005000f3030000000000000000000000000000000000000000000001084501 | |||
| 546 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 547 | + | 7469746c650000001c00450101005000f3030000000000000000000000000000 | |||
| 548 | + | 00000000000000000108460103000000ef030000000000000900000000000000 | |||
| 549 | + | 00000000000000006e6574207469746c650000001c00460101005000f3030000 | |||
| 550 | + | 00000000000000000000000000000000000000000108470103000000ef030000 | |||
| 551 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 552 | + | 1c00470101005000f30300000000000000000000000000000000000000000000 | |||
| 553 | + | 0108480103000000ef0300000000000009000000000000000000000000000000 | |||
| 554 | + | 6e6574207469746c650000001c00480101005000f30300000000000000000000 | |||
| 555 | + | 0000000000000000000000000108490103000000ef0300000000000009000000 | |||
| 556 | + | 0000000000000000000000006e6574207469746c650000001c00490101005000 | |||
| 557 | + | f3030000000000000000000000000000000000000000000001084a0103000000 | |||
| 558 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 559 | + | 650000001c004a0101005000f303000000000000000000000000000000000000 | |||
| 560 | + | 0000000001084b0103000000ef03000000000000090000000000000000000000 | |||
| 561 | + | 000000006e6574207469746c650000001c004b0101005000f303000000000000 | |||
| 562 | + | 0000000000000000000000000000000001084c0103000000ef03000000000000 | |||
| 563 | + | 090000000000000000000000000000006e6574207469746c650000001c004c01 | |||
| 564 | + | 01005000f3030000000000000000000000000000000000000000000001084d01 | |||
| 565 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 566 | + | 7469746c650000001c004d0101005000f3030000000000000000000000000000 | |||
| 567 | + | 000000000000000001084e0103000000ef030000000000000900000000000000 | |||
| 568 | + | 00000000000000006e6574207469746c650000001c004e0101005000f3030000 | |||
| 569 | + | 000000000000000000000000000000000000000001084f0103000000ef030000 | |||
| 570 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 571 | + | 1c004f0101005000f30300000000000000000000000000000000000000000000 | |||
| 572 | + | 0108500103000000ef0300000000000009000000000000000000000000000000 | |||
| 573 | + | 6e6574207469746c650000001c00500101005000f30300000000000000000000 | |||
| 574 | + | 0000000000000000000000000108510103000000ef0300000000000009000000 | |||
| 575 | + | 0000000000000000000000006e6574207469746c650000001c00510101005000 | |||
| 576 | + | f303000000000000000000000000000000000000000000000108520103000000 | |||
| 577 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 578 | + | 650000001c00520101005000f303000000000000000000000000000000000000 | |||
| 579 | + | 000000000108530103000000ef03000000000000090000000000000000000000 | |||
| 580 | + | 000000006e6574207469746c650000001c00530101005000f303000000000000 | |||
| 581 | + | 000000000000000000000000000000000108540103000000ef03000000000000 | |||
| 582 | + | 090000000000000000000000000000006e6574207469746c650000001c005401 | |||
| 583 | + | 01005000f3030000000000000000000000000000000000000000000001085501 | |||
| 584 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 585 | + | 7469746c650000001c00550101005000f3030000000000000000000000000000 | |||
| 586 | + | 00000000000000000108560103000000ef030000000000000900000000000000 | |||
| 587 | + | 00000000000000006e6574207469746c650000001c00560101005000f3030000 | |||
| 588 | + | 00000000000000000000000000000000000000000108570103000000ef030000 | |||
| 589 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 590 | + | 1c00570101005000f30300000000000000000000000000000000000000000000 | |||
| 591 | + | 0108580103000000ef0300000000000009000000000000000000000000000000 | |||
| 592 | + | 6e6574207469746c650000001c00580101005000f30300000000000000000000 | |||
| 593 | + | 0000000000000000000000000108590103000000ef0300000000000009000000 | |||
| 594 | + | 0000000000000000000000006e6574207469746c650000001c00590101005000 | |||
| 595 | + | f3030000000000000000000000000000000000000000000001085a0103000000 | |||
| 596 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 597 | + | 650000001c005a0101005000f303000000000000000000000000000000000000 | |||
| 598 | + | 0000000001085b0103000000ef03000000000000090000000000000000000000 | |||
| 599 | + | 000000006e6574207469746c650000001c005b0101005000f303000000000000 | |||
| 600 | + | 0000000000000000000000000000000001085c0103000000ef03000000000000 | |||
| 601 | + | 090000000000000000000000000000006e6574207469746c650000001c005c01 | |||
| 602 | + | 01005000f3030000000000000000000000000000000000000000000001085d01 | |||
| 603 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 604 | + | 7469746c650000001c005d0101005000f3030000000000000000000000000000 | |||
| 605 | + | 000000000000000001085e0103000000ef030000000000000900000000000000 | |||
| 606 | + | 00000000000000006e6574207469746c650000001c005e0101005000f3030000 | |||
| 607 | + | 000000000000000000000000000000000000000001085f0103000000ef030000 | |||
| 608 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 609 | + | 1c005f0101005000f30300000000000000000000000000000000000000000000 | |||
| 610 | + | 0108600103000000ef0300000000000009000000000000000000000000000000 | |||
| 611 | + | 6e6574207469746c650000001c00600101005000f30300000000000000000000 | |||
| 612 | + | 0000000000000000000000000108610103000000ef0300000000000009000000 | |||
| 613 | + | 0000000000000000000000006e6574207469746c650000001c00610101005000 | |||
| 614 | + | f303000000000000000000000000000000000000000000000108620103000000 | |||
| 615 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 616 | + | 650000001c00620101005000f303000000000000000000000000000000000000 | |||
| 617 | + | 000000000108630103000000ef03000000000000090000000000000000000000 | |||
| 618 | + | 000000006e6574207469746c650000001c00630101005000f303000000000000 | |||
| 619 | + | 000000000000000000000000000000000108640103000000ef03000000000000 | |||
| 620 | + | 090000000000000000000000000000006e6574207469746c650000001c006401 | |||
| 621 | + | 01005000f3030000000000000000000000000000000000000000000001086501 | |||
| 622 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 623 | + | 7469746c650000001c00650101005000f3030000000000000000000000000000 | |||
| 624 | + | 00000000000000000108660103000000ef030000000000000900000000000000 | |||
| 625 | + | 00000000000000006e6574207469746c650000001c00660101005000f3030000 | |||
| 626 | + | 00000000000000000000000000000000000000000108670103000000ef030000 | |||
| 627 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 628 | + | 1c00670101005000f30300000000000000000000000000000000000000000000 | |||
| 629 | + | 0108680103000000ef0300000000000009000000000000000000000000000000 | |||
| 630 | + | 6e6574207469746c650000001c00680101005000f30300000000000000000000 | |||
| 631 | + | 0000000000000000000000000108690103000000ef0300000000000009000000 | |||
| 632 | + | 0000000000000000000000006e6574207469746c650000001c00690101005000 | |||
| 633 | + | f3030000000000000000000000000000000000000000000001086a0103000000 | |||
| 634 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 635 | + | 650000001c006a0101005000f303000000000000000000000000000000000000 | |||
| 636 | + | 0000000001086b0103000000ef03000000000000090000000000000000000000 | |||
| 637 | + | 000000006e6574207469746c650000001c006b0101005000f303000000000000 | |||
| 638 | + | 0000000000000000000000000000000001086c0103000000ef03000000000000 | |||
| 639 | + | 090000000000000000000000000000006e6574207469746c650000001c006c01 | |||
| 640 | + | 01005000f3030000000000000000000000000000000000000000000001086d01 | |||
| 641 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 642 | + | 7469746c650000001c006d0101005000f3030000000000000000000000000000 | |||
| 643 | + | 000000000000000001086e0103000000ef030000000000000900000000000000 | |||
| 644 | + | 00000000000000006e6574207469746c650000001c006e0101005000f3030000 | |||
| 645 | + | 000000000000000000000000000000000000000001086f0103000000ef030000 | |||
| 646 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 647 | + | 1c006f0101005000f30300000000000000000000000000000000000000000000 | |||
| 648 | + | 0108700103000000ef0300000000000009000000000000000000000000000000 | |||
| 649 | + | 6e6574207469746c650000001c00700101005000f30300000000000000000000 | |||
| 650 | + | 0000000000000000000000000108710103000000ef0300000000000009000000 | |||
| 651 | + | 0000000000000000000000006e6574207469746c650000001c00710101005000 | |||
| 652 | + | f303000000000000000000000000000000000000000000000108720103000000 | |||
| 653 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 654 | + | 650000001c00720101005000f303000000000000000000000000000000000000 | |||
| 655 | + | 000000000108730103000000ef03000000000000090000000000000000000000 | |||
| 656 | + | 000000006e6574207469746c650000001c00730101005000f303000000000000 | |||
| 657 | + | 000000000000000000000000000000000108740103000000ef03000000000000 | |||
| 658 | + | 090000000000000000000000000000006e6574207469746c650000001c007401 | |||
| 659 | + | 01005000f3030000000000000000000000000000000000000000000001087501 | |||
| 660 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 661 | + | 7469746c650000001c00750101005000f3030000000000000000000000000000 | |||
| 662 | + | 00000000000000000108760103000000ef030000000000000900000000000000 | |||
| 663 | + | 00000000000000006e6574207469746c650000001c00760101005000f3030000 | |||
| 664 | + | 00000000000000000000000000000000000000000108770103000000ef030000 | |||
| 665 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 666 | + | 1c00770101005000f30300000000000000000000000000000000000000000000 | |||
| 667 | + | 0108780103000000ef0300000000000009000000000000000000000000000000 | |||
| 668 | + | 6e6574207469746c650000001c00780101005000f30300000000000000000000 | |||
| 669 | + | 0000000000000000000000000108790103000000ef0300000000000009000000 | |||
| 670 | + | 0000000000000000000000006e6574207469746c650000001c00790101005000 | |||
| 671 | + | f3030000000000000000000000000000000000000000000001087a0103000000 | |||
| 672 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 673 | + | 650000001c007a0101005000f303000000000000000000000000000000000000 | |||
| 674 | + | 0000000001087b0103000000ef03000000000000090000000000000000000000 | |||
| 675 | + | 000000006e6574207469746c650000001c007b0101005000f303000000000000 | |||
| 676 | + | 0000000000000000000000000000000001087c0103000000ef03000000000000 | |||
| 677 | + | 090000000000000000000000000000006e6574207469746c650000001c007c01 | |||
| 678 | + | 01005000f3030000000000000000000000000000000000000000000001087d01 | |||
| 679 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 680 | + | 7469746c650000001c007d0101005000f3030000000000000000000000000000 | |||
| 681 | + | 000000000000000001087e0103000000ef030000000000000900000000000000 | |||
| 682 | + | 00000000000000006e6574207469746c650000001c007e0101005000f3030000 | |||
| 683 | + | 000000000000000000000000000000000000000001087f0103000000ef030000 | |||
| 684 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 685 | + | 1c007f0101005000f30300000000000000000000000000000000000000000000 | |||
| 686 | + | 0108800103000000ef0300000000000009000000000000000000000000000000 | |||
| 687 | + | 6e6574207469746c650000001c00800101005000f30300000000000000000000 | |||
| 688 | + | 0000000000000000000000000108810103000000ef0300000000000009000000 | |||
| 689 | + | 0000000000000000000000006e6574207469746c650000001c00810101005000 | |||
| 690 | + | f303000000000000000000000000000000000000000000000108820103000000 | |||
| 691 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 692 | + | 650000001c00820101005000f303000000000000000000000000000000000000 | |||
| 693 | + | 000000000108830103000000ef03000000000000090000000000000000000000 | |||
| 694 | + | 000000006e6574207469746c650000001c00830101005000f303000000000000 | |||
| 695 | + | 000000000000000000000000000000000108840103000000ef03000000000000 | |||
| 696 | + | 090000000000000000000000000000006e6574207469746c650000001c008401 | |||
| 697 | + | 01005000f3030000000000000000000000000000000000000000000001088501 | |||
| 698 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 699 | + | 7469746c650000001c00850101005000f3030000000000000000000000000000 | |||
| 700 | + | 00000000000000000108860103000000ef030000000000000900000000000000 | |||
| 701 | + | 00000000000000006e6574207469746c650000001c00860101005000f3030000 | |||
| 702 | + | 00000000000000000000000000000000000000000108870103000000ef030000 | |||
| 703 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 704 | + | 1c00870101005000f30300000000000000000000000000000000000000000000 | |||
| 705 | + | 0108880103000000ef0300000000000009000000000000000000000000000000 | |||
| 706 | + | 6e6574207469746c650000001c00880101005000f30300000000000000000000 | |||
| 707 | + | 0000000000000000000000000108890103000000ef0300000000000009000000 | |||
| 708 | + | 0000000000000000000000006e6574207469746c650000001c00890101005000 | |||
| 709 | + | f3030000000000000000000000000000000000000000000001088a0103000000 | |||
| 710 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 711 | + | 650000001c008a0101005000f303000000000000000000000000000000000000 | |||
| 712 | + | 0000000001088b0103000000ef03000000000000090000000000000000000000 | |||
| 713 | + | 000000006e6574207469746c650000001c008b0101005000f303000000000000 | |||
| 714 | + | 0000000000000000000000000000000001088c0103000000ef03000000000000 | |||
| 715 | + | 090000000000000000000000000000006e6574207469746c650000001c008c01 | |||
| 716 | + | 01005000f3030000000000000000000000000000000000000000000001088d01 | |||
| 717 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 718 | + | 7469746c650000001c008d0101005000f3030000000000000000000000000000 | |||
| 719 | + | 000000000000000001088e0103000000ef030000000000000900000000000000 | |||
| 720 | + | 00000000000000006e6574207469746c650000001c008e0101005000f3030000 | |||
| 721 | + | 000000000000000000000000000000000000000001088f0103000000ef030000 | |||
| 722 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 723 | + | 1c008f0101005000f30300000000000000000000000000000000000000000000 | |||
| 724 | + | 0108900103000000ef0300000000000009000000000000000000000000000000 | |||
| 725 | + | 6e6574207469746c650000001c00900101005000f30300000000000000000000 | |||
| 726 | + | 0000000000000000000000000108910103000000ef0300000000000009000000 | |||
| 727 | + | 0000000000000000000000006e6574207469746c650000001c00910101005000 | |||
| 728 | + | f303000000000000000000000000000000000000000000000108920103000000 | |||
| 729 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 730 | + | 650000001c00920101005000f303000000000000000000000000000000000000 | |||
| 731 | + | 000000000108930103000000ef03000000000000090000000000000000000000 | |||
| 732 | + | 000000006e6574207469746c650000001c00930101005000f303000000000000 | |||
| 733 | + | 000000000000000000000000000000000108940103000000ef03000000000000 | |||
| 734 | + | 090000000000000000000000000000006e6574207469746c650000001c009401 | |||
| 735 | + | 01005000f3030000000000000000000000000000000000000000000001089501 | |||
| 736 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 737 | + | 7469746c650000001c00950101005000f3030000000000000000000000000000 | |||
| 738 | + | 00000000000000000108960103000000ef030000000000000900000000000000 | |||
| 739 | + | 00000000000000006e6574207469746c650000001c00960101005000f3030000 | |||
| 740 | + | 00000000000000000000000000000000000000000108970103000000ef030000 | |||
| 741 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 742 | + | 1c00970101005000f30300000000000000000000000000000000000000000000 | |||
| 743 | + | 0108980103000000ef0300000000000009000000000000000000000000000000 | |||
| 744 | + | 6e6574207469746c650000001c00980101005000f30300000000000000000000 | |||
| 745 | + | 0000000000000000000000000108990103000000ef0300000000000009000000 | |||
| 746 | + | 0000000000000000000000006e6574207469746c650000001c00990101005000 | |||
| 747 | + | f3030000000000000000000000000000000000000000000001089a0103000000 | |||
| 748 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 749 | + | 650000001c009a0101005000f303000000000000000000000000000000000000 | |||
| 750 | + | 0000000001089b0103000000ef03000000000000090000000000000000000000 | |||
| 751 | + | 000000006e6574207469746c650000001c009b0101005000f303000000000000 | |||
| 752 | + | 0000000000000000000000000000000001089c0103000000ef03000000000000 | |||
| 753 | + | 090000000000000000000000000000006e6574207469746c650000001c009c01 | |||
| 754 | + | 01005000f3030000000000000000000000000000000000000000000001089d01 | |||
| 755 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 756 | + | 7469746c650000001c009d0101005000f3030000000000000000000000000000 | |||
| 757 | + | 000000000000000001089e0103000000ef030000000000000900000000000000 | |||
| 758 | + | 00000000000000006e6574207469746c650000001c009e0101005000f3030000 | |||
| 759 | + | 000000000000000000000000000000000000000001089f0103000000ef030000 | |||
| 760 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 761 | + | 1c009f0101005000f30300000000000000000000000000000000000000000000 | |||
| 762 | + | 0108a00103000000ef0300000000000009000000000000000000000000000000 | |||
| 763 | + | 6e6574207469746c650000001c00a00101005000f30300000000000000000000 | |||
| 764 | + | 0000000000000000000000000108a10103000000ef0300000000000009000000 | |||
| 765 | + | 0000000000000000000000006e6574207469746c650000001c00a10101005000 | |||
| 766 | + | f303000000000000000000000000000000000000000000000108a20103000000 | |||
| 767 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 768 | + | 650000001c00a20101005000f303000000000000000000000000000000000000 | |||
| 769 | + | 000000000108a30103000000ef03000000000000090000000000000000000000 | |||
| 770 | + | 000000006e6574207469746c650000001c00a30101005000f303000000000000 | |||
| 771 | + | 000000000000000000000000000000000108a40103000000ef03000000000000 | |||
| 772 | + | 090000000000000000000000000000006e6574207469746c650000001c00a401 | |||
| 773 | + | 01005000f303000000000000000000000000000000000000000000000108a501 | |||
| 774 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 775 | + | 7469746c650000001c00a50101005000f3030000000000000000000000000000 | |||
| 776 | + | 00000000000000000108a60103000000ef030000000000000900000000000000 | |||
| 777 | + | 00000000000000006e6574207469746c650000001c00a60101005000f3030000 | |||
| 778 | + | 00000000000000000000000000000000000000000108a70103000000ef030000 | |||
| 779 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 780 | + | 1c00a70101005000f30300000000000000000000000000000000000000000000 | |||
| 781 | + | 0108a80103000000ef0300000000000009000000000000000000000000000000 | |||
| 782 | + | 6e6574207469746c650000001c00a80101005000f30300000000000000000000 | |||
| 783 | + | 0000000000000000000000000108a90103000000ef0300000000000009000000 | |||
| 784 | + | 0000000000000000000000006e6574207469746c650000001c00a90101005000 | |||
| 785 | + | f303000000000000000000000000000000000000000000000108aa0103000000 | |||
| 786 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 787 | + | 650000001c00aa0101005000f303000000000000000000000000000000000000 | |||
| 788 | + | 000000000108ab0103000000ef03000000000000090000000000000000000000 | |||
| 789 | + | 000000006e6574207469746c650000001c00ab0101005000f303000000000000 | |||
| 790 | + | 000000000000000000000000000000000108ac0103000000ef03000000000000 | |||
| 791 | + | 090000000000000000000000000000006e6574207469746c650000001c00ac01 | |||
| 792 | + | 01005000f303000000000000000000000000000000000000000000000108ad01 | |||
| 793 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 794 | + | 7469746c650000001c00ad0101005000f3030000000000000000000000000000 | |||
| 795 | + | 00000000000000000108ae0103000000ef030000000000000900000000000000 | |||
| 796 | + | 00000000000000006e6574207469746c650000001c00ae0101005000f3030000 | |||
| 797 | + | 00000000000000000000000000000000000000000108af0103000000ef030000 | |||
| 798 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 799 | + | 1c00af0101005000f30300000000000000000000000000000000000000000000 | |||
| 800 | + | 0108b00103000000ef0300000000000009000000000000000000000000000000 | |||
| 801 | + | 6e6574207469746c650000001c00b00101005000f30300000000000000000000 | |||
| 802 | + | 0000000000000000000000000108b10103000000ef0300000000000009000000 | |||
| 803 | + | 0000000000000000000000006e6574207469746c650000001c00b10101005000 | |||
| 804 | + | f303000000000000000000000000000000000000000000000108b20103000000 | |||
| 805 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 806 | + | 650000001c00b20101005000f303000000000000000000000000000000000000 | |||
| 807 | + | 000000000108b30103000000ef03000000000000090000000000000000000000 | |||
| 808 | + | 000000006e6574207469746c650000001c00b30101005000f303000000000000 | |||
| 809 | + | 000000000000000000000000000000000108b40103000000ef03000000000000 | |||
| 810 | + | 090000000000000000000000000000006e6574207469746c650000001c00b401 | |||
| 811 | + | 01005000f303000000000000000000000000000000000000000000000108b501 | |||
| 812 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 813 | + | 7469746c650000001c00b50101005000f3030000000000000000000000000000 | |||
| 814 | + | 00000000000000000108b60103000000ef030000000000000900000000000000 | |||
| 815 | + | 00000000000000006e6574207469746c650000001c00b60101005000f3030000 | |||
| 816 | + | 00000000000000000000000000000000000000000108b70103000000ef030000 | |||
| 817 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 818 | + | 1c00b70101005000f30300000000000000000000000000000000000000000000 | |||
| 819 | + | 0108b80103000000ef0300000000000009000000000000000000000000000000 | |||
| 820 | + | 6e6574207469746c650000001c00b80101005000f30300000000000000000000 | |||
| 821 | + | 0000000000000000000000000108b90103000000ef0300000000000009000000 | |||
| 822 | + | 0000000000000000000000006e6574207469746c650000001c00b90101005000 | |||
| 823 | + | f303000000000000000000000000000000000000000000000108ba0103000000 | |||
| 824 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 825 | + | 650000001c00ba0101005000f303000000000000000000000000000000000000 | |||
| 826 | + | 000000000108bb0103000000ef03000000000000090000000000000000000000 | |||
| 827 | + | 000000006e6574207469746c650000001c00bb0101005000f303000000000000 | |||
| 828 | + | 000000000000000000000000000000000108bc0103000000ef03000000000000 | |||
| 829 | + | 090000000000000000000000000000006e6574207469746c650000001c00bc01 | |||
| 830 | + | 01005000f303000000000000000000000000000000000000000000000108bd01 | |||
| 831 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 832 | + | 7469746c650000001c00bd0101005000f3030000000000000000000000000000 | |||
| 833 | + | 00000000000000000108be0103000000ef030000000000000900000000000000 | |||
| 834 | + | 00000000000000006e6574207469746c650000001c00be0101005000f3030000 | |||
| 835 | + | 00000000000000000000000000000000000000000108bf0103000000ef030000 | |||
| 836 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 837 | + | 1c00bf0101005000f30300000000000000000000000000000000000000000000 | |||
| 838 | + | 0108c00103000000ef0300000000000009000000000000000000000000000000 | |||
| 839 | + | 6e6574207469746c650000001c00c00101005000f30300000000000000000000 | |||
| 840 | + | 0000000000000000000000000108c10103000000ef0300000000000009000000 | |||
| 841 | + | 0000000000000000000000006e6574207469746c650000001c00c10101005000 | |||
| 842 | + | f303000000000000000000000000000000000000000000000108c20103000000 | |||
| 843 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 844 | + | 650000001c00c20101005000f303000000000000000000000000000000000000 | |||
| 845 | + | 000000000108c30103000000ef03000000000000090000000000000000000000 | |||
| 846 | + | 000000006e6574207469746c650000001c00c30101005000f303000000000000 | |||
| 847 | + | 000000000000000000000000000000000108c40103000000ef03000000000000 | |||
| 848 | + | 090000000000000000000000000000006e6574207469746c650000001c00c401 | |||
| 849 | + | 01005000f303000000000000000000000000000000000000000000000108c501 | |||
| 850 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 851 | + | 7469746c650000001c00c50101005000f3030000000000000000000000000000 | |||
| 852 | + | 00000000000000000108c60103000000ef030000000000000900000000000000 | |||
| 853 | + | 00000000000000006e6574207469746c650000001c00c60101005000f3030000 | |||
| 854 | + | 00000000000000000000000000000000000000000108c70103000000ef030000 | |||
| 855 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 856 | + | 1c00c70101005000f30300000000000000000000000000000000000000000000 | |||
| 857 | + | 0108c80103000000ef0300000000000009000000000000000000000000000000 | |||
| 858 | + | 6e6574207469746c650000001c00c80101005000f30300000000000000000000 | |||
| 859 | + | 0000000000000000000000000108c90103000000ef0300000000000009000000 | |||
| 860 | + | 0000000000000000000000006e6574207469746c650000001c00c90101005000 | |||
| 861 | + | f303000000000000000000000000000000000000000000000108ca0103000000 | |||
| 862 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 863 | + | 650000001c00ca0101005000f303000000000000000000000000000000000000 | |||
| 864 | + | 000000000108cb0103000000ef03000000000000090000000000000000000000 | |||
| 865 | + | 000000006e6574207469746c650000001c00cb0101005000f303000000000000 | |||
| 866 | + | 000000000000000000000000000000000108cc0103000000ef03000000000000 | |||
| 867 | + | 090000000000000000000000000000006e6574207469746c650000001c00cc01 | |||
| 868 | + | 01005000f303000000000000000000000000000000000000000000000108cd01 | |||
| 869 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 870 | + | 7469746c650000001c00cd0101005000f3030000000000000000000000000000 | |||
| 871 | + | 00000000000000000108ce0103000000ef030000000000000900000000000000 | |||
| 872 | + | 00000000000000006e6574207469746c650000001c00ce0101005000f3030000 | |||
| 873 | + | 00000000000000000000000000000000000000000108cf0103000000ef030000 | |||
| 874 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 875 | + | 1c00cf0101005000f30300000000000000000000000000000000000000000000 | |||
| 876 | + | 0108d00103000000ef0300000000000009000000000000000000000000000000 | |||
| 877 | + | 6e6574207469746c650000001c00d00101005000f30300000000000000000000 | |||
| 878 | + | 0000000000000000000000000108d10103000000ef0300000000000009000000 | |||
| 879 | + | 0000000000000000000000006e6574207469746c650000001c00d10101005000 | |||
| 880 | + | f303000000000000000000000000000000000000000000000108d20103000000 | |||
| 881 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 882 | + | 650000001c00d20101005000f303000000000000000000000000000000000000 | |||
| 883 | + | 000000000108d30103000000ef03000000000000090000000000000000000000 | |||
| 884 | + | 000000006e6574207469746c650000001c00d30101005000f303000000000000 | |||
| 885 | + | 000000000000000000000000000000000108d40103000000ef03000000000000 | |||
| 886 | + | 090000000000000000000000000000006e6574207469746c650000001c00d401 | |||
| 887 | + | 01005000f303000000000000000000000000000000000000000000000108d501 | |||
| 888 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 889 | + | 7469746c650000001c00d50101005000f3030000000000000000000000000000 | |||
| 890 | + | 00000000000000000108d60103000000ef030000000000000900000000000000 | |||
| 891 | + | 00000000000000006e6574207469746c650000001c00d60101005000f3030000 | |||
| 892 | + | 00000000000000000000000000000000000000000108d70103000000ef030000 | |||
| 893 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 894 | + | 1c00d70101005000f30300000000000000000000000000000000000000000000 | |||
| 895 | + | 0108d80103000000ef0300000000000009000000000000000000000000000000 | |||
| 896 | + | 6e6574207469746c650000001c00d80101005000f30300000000000000000000 | |||
| 897 | + | 0000000000000000000000000108d90103000000ef0300000000000009000000 | |||
| 898 | + | 0000000000000000000000006e6574207469746c650000001c00d90101005000 | |||
| 899 | + | f303000000000000000000000000000000000000000000000108da0103000000 | |||
| 900 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 901 | + | 650000001c00da0101005000f303000000000000000000000000000000000000 | |||
| 902 | + | 000000000108db0103000000ef03000000000000090000000000000000000000 | |||
| 903 | + | 000000006e6574207469746c650000001c00db0101005000f303000000000000 | |||
| 904 | + | 000000000000000000000000000000000108dc0103000000ef03000000000000 | |||
| 905 | + | 090000000000000000000000000000006e6574207469746c650000001c00dc01 | |||
| 906 | + | 01005000f303000000000000000000000000000000000000000000000108dd01 | |||
| 907 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 908 | + | 7469746c650000001c00dd0101005000f3030000000000000000000000000000 | |||
| 909 | + | 00000000000000000108de0103000000ef030000000000000900000000000000 | |||
| 910 | + | 00000000000000006e6574207469746c650000001c00de0101005000f3030000 | |||
| 911 | + | 00000000000000000000000000000000000000000108df0103000000ef030000 | |||
| 912 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 913 | + | 1c00df0101005000f30300000000000000000000000000000000000000000000 | |||
| 914 | + | 0108e00103000000ef0300000000000009000000000000000000000000000000 | |||
| 915 | + | 6e6574207469746c650000001c00e00101005000f30300000000000000000000 | |||
| 916 | + | 0000000000000000000000000108e10103000000ef0300000000000009000000 | |||
| 917 | + | 0000000000000000000000006e6574207469746c650000001c00e10101005000 | |||
| 918 | + | f303000000000000000000000000000000000000000000000108e20103000000 | |||
| 919 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 920 | + | 650000001c00e20101005000f303000000000000000000000000000000000000 | |||
| 921 | + | 000000000108e30103000000ef03000000000000090000000000000000000000 | |||
| 922 | + | 000000006e6574207469746c650000001c00e30101005000f303000000000000 | |||
| 923 | + | 000000000000000000000000000000000108e40103000000ef03000000000000 | |||
| 924 | + | 090000000000000000000000000000006e6574207469746c650000001c00e401 | |||
| 925 | + | 01005000f303000000000000000000000000000000000000000000000108e501 | |||
| 926 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 927 | + | 7469746c650000001c00e50101005000f3030000000000000000000000000000 | |||
| 928 | + | 00000000000000000108e60103000000ef030000000000000900000000000000 | |||
| 929 | + | 00000000000000006e6574207469746c650000001c00e60101005000f3030000 | |||
| 930 | + | 00000000000000000000000000000000000000000108e70103000000ef030000 | |||
| 931 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
| 932 | + | 1c00e70101005000f30300000000000000000000000000000000000000000000 | |||
| 933 | + | 0108e80103000000ef0300000000000009000000000000000000000000000000 | |||
| 934 | + | 6e6574207469746c650000001c00e80101005000f30300000000000000000000 | |||
| 935 | + | 0000000000000000000000000108e90103000000ef0300000000000009000000 | |||
| 936 | + | 0000000000000000000000006e6574207469746c650000001c00e90101005000 | |||
| 937 | + | f303000000000000000000000000000000000000000000000108ea0103000000 | |||
| 938 | + | ef03000000000000090000000000000000000000000000006e6574207469746c | |||
| 939 | + | 650000001c00ea0101005000f303000000000000000000000000000000000000 | |||
| 940 | + | 000000000108eb0103000000ef03000000000000090000000000000000000000 | |||
| 941 | + | 000000006e6574207469746c650000001c00eb0101005000f303000000000000 | |||
| 942 | + | 000000000000000000000000000000000108ec0103000000ef03000000000000 | |||
| 943 | + | 090000000000000000000000000000006e6574207469746c650000001c00ec01 | |||
| 944 | + | 01005000f303000000000000000000000000000000000000000000000108ed01 | |||
| 945 | + | 03000000ef03000000000000090000000000000000000000000000006e657420 | |||
| 946 | + | 7469746c650000001c00ed0101005000f3030000000000000000000000000000 | |||
| 947 | + | 00000000000000000108ee0103000000ef030000000000000900000000000000 | |||
| 948 | + | 00000000000000006e6574207469746c650000001c00ee0101005000f3030000 | |||
| 949 | + | 00000000000000000000000000000000000000000108ef0103000000ef030000 | |||
| 950 | + | 00000000090000000000000000000000000000006e6574207469746c65000000 | |||
A internal/adapters/wayland/xwm/testdata/streams/steady.hex +2150 -0 large diff (2150 lines changed): collapsed
M internal/adapters/wayland/xwm/xpeer_test.go +135 -3
| @@ -18,6 +18,7 @@ const ( | |||
| 18 | 18 | opChangeWindowAttributes = 2 | |
| 19 | 19 | opGetWindowAttributes = 3 | |
| 20 | 20 | opMapWindow = 8 | |
| 21 | + | opDeleteProperty = 19 | |
| 21 | 22 | opConfigureWindow = 12 | |
| 22 | 23 | opGetGeometry = 14 | |
| 23 | 24 | opQueryTree = 15 | |
| @@ -80,7 +81,13 @@ type xpeer struct { | |||
| 80 | 81 | geoms map[uint32]xpeerGeom | |
| 81 | 82 | attrs map[uint32][2]byte // window -> {overrideRedirect, mapState} | |
| 82 | 83 | children []uint32 | |
| 83 | - | denyRoot bool // answer the root event-mask request with BadAccess | |
| 84 | + | denyRoot bool // answer the root event-mask request with BadAccess | |
| 85 | + | pids map[uint32]uint32 // XRes QueryClientIds answers, by window | |
| 86 | + | bad map[uint32]bool // windows whose GetProperty/GetGeometry fail with BadWindow | |
| 87 | + | hold bool // keep replies until release | |
| 88 | + | held [][]byte | |
| 89 | + | tap []byte // everything written to the client, when recording | |
| 90 | + | record bool | |
| 84 | 91 | ||
| 85 | 92 | gate atomic.Pointer[chan struct{}] // closed = reading allowed | |
| 86 | 93 | done chan struct{} | |
| @@ -108,12 +115,14 @@ func startXPeer(t *testing.T, exts map[string]xpeerExt) (int, *xpeer) { | |||
| 108 | 115 | t: t, f: os.NewFile(uintptr(fds[1]), "xpeer"), | |
| 109 | 116 | exts: exts, atoms: map[string]uint32{}, nextAtom: 1000, | |
| 110 | 117 | props: map[uint32]map[uint32]xpeerProp{}, geoms: map[uint32]xpeerGeom{}, attrs: map[uint32][2]byte{}, | |
| 118 | + | pids: map[uint32]uint32{}, bad: map[uint32]bool{}, | |
| 111 | 119 | done: make(chan struct{}), | |
| 112 | 120 | } | |
| 113 | 121 | open := make(chan struct{}) | |
| 114 | 122 | close(open) | |
| 115 | 123 | p.gate.Store(&open) | |
| 116 | 124 | t.Cleanup(func() { | |
| 125 | + | p.resume() // a paused peer would never see the close | |
| 117 | 126 | p.f.Close() | |
| 118 | 127 | <-p.done | |
| 119 | 128 | }) | |
| @@ -179,7 +188,12 @@ func (p *xpeer) serve() { | |||
| 179 | 188 | } | |
| 180 | 189 | ||
| 181 | 190 | // write sends bytes to the client. The caller holds p.mu. | |
| 182 | - | func (p *xpeer) write(b []byte) { _, _ = p.f.Write(b) } | |
| 191 | + | func (p *xpeer) write(b []byte) { | |
| 192 | + | if p.record { | |
| 193 | + | p.tap = append(p.tap, b...) | |
| 194 | + | } | |
| 195 | + | _, _ = p.f.Write(b) | |
| 196 | + | } | |
| 183 | 197 | ||
| 184 | 198 | func (p *xpeer) reply(data uint8, body []byte) { | |
| 185 | 199 | words := (max(len(body), 24) - 24 + 3) / 4 | |
| @@ -188,9 +202,31 @@ func (p *xpeer) reply(data uint8, body []byte) { | |||
| 188 | 202 | binary.LittleEndian.PutUint16(b[2:], p.seq) | |
| 189 | 203 | binary.LittleEndian.PutUint32(b[4:], uint32(words)) | |
| 190 | 204 | copy(b[8:], body) | |
| 205 | + | if p.hold { | |
| 206 | + | p.held = append(p.held, b) | |
| 207 | + | return | |
| 208 | + | } | |
| 191 | 209 | p.write(b) | |
| 192 | 210 | } | |
| 193 | 211 | ||
| 212 | + | // release sends the held replies, in request order as a real server does. | |
| 213 | + | func (p *xpeer) release() { | |
| 214 | + | p.mu.Lock() | |
| 215 | + | defer p.mu.Unlock() | |
| 216 | + | p.hold = false | |
| 217 | + | for _, b := range p.held { | |
| 218 | + | p.write(b) | |
| 219 | + | } | |
| 220 | + | p.held = nil | |
| 221 | + | } | |
| 222 | + | ||
| 223 | + | // holdReplies keeps the replies of the following requests back. | |
| 224 | + | func (p *xpeer) holdReplies() { | |
| 225 | + | p.mu.Lock() | |
| 226 | + | p.hold = true | |
| 227 | + | p.mu.Unlock() | |
| 228 | + | } | |
| 229 | + | ||
| 194 | 230 | func (p *xpeer) errorPacket(code, major uint8, bad uint32) { | |
| 195 | 231 | b := make([]byte, 32) | |
| 196 | 232 | b[1] = code | |
| @@ -252,6 +288,8 @@ func (p *xpeer) answer(r xpeerReq, body []byte) { | |||
| 252 | 288 | b[18] = a[1] // map_state is byte 26 of the reply | |
| 253 | 289 | b[19] = a[0] // override_redirect, byte 27 | |
| 254 | 290 | p.reply(0, b) | |
| 291 | + | case (r.major == opGetGeometry || r.major == opGetProperty) && p.bad[binary.LittleEndian.Uint32(body)]: | |
| 292 | + | p.errorPacket(3, r.major, binary.LittleEndian.Uint32(body)) // BadWindow | |
| 255 | 293 | case r.major == opGetGeometry: | |
| 256 | 294 | g := p.geoms[binary.LittleEndian.Uint32(body)] | |
| 257 | 295 | b := make([]byte, 24) | |
| @@ -272,6 +310,8 @@ func (p *xpeer) answer(r xpeerReq, body []byte) { | |||
| 272 | 310 | typ: binary.LittleEndian.Uint32(body[8:]), format: format, | |
| 273 | 311 | data: append([]byte(nil), body[20:20+n*int(format)/8]...), | |
| 274 | 312 | } | |
| 313 | + | case r.major == opDeleteProperty: | |
| 314 | + | delete(p.props[binary.LittleEndian.Uint32(body)], binary.LittleEndian.Uint32(body[4:])) | |
| 275 | 315 | case r.major == opGetProperty: | |
| 276 | 316 | win, prop := binary.LittleEndian.Uint32(body), binary.LittleEndian.Uint32(body[4:]) | |
| 277 | 317 | v, ok := p.props[win][prop] | |
| @@ -300,8 +340,22 @@ func (p *xpeer) answer(r xpeerReq, body []byte) { | |||
| 300 | 340 | p.reply(0, le32(5, 4)) | |
| 301 | 341 | } | |
| 302 | 342 | case "X-Resource": | |
| 303 | - | if r.minor == 0 { | |
| 343 | + | switch r.minor { | |
| 344 | + | case 0: | |
| 304 | 345 | p.reply(0, []byte{1, 0, 2, 0}) | |
| 346 | + | case 4: // QueryClientIds: one spec, answered when a pid is scripted | |
| 347 | + | pid, ok := p.pids[r.u32(8)] | |
| 348 | + | if !ok { | |
| 349 | + | p.reply(0, le32(0)) | |
| 350 | + | break | |
| 351 | + | } | |
| 352 | + | b := make([]byte, 40) | |
| 353 | + | binary.LittleEndian.PutUint32(b[0:], 1) | |
| 354 | + | binary.LittleEndian.PutUint32(b[24:], r.u32(8)) | |
| 355 | + | binary.LittleEndian.PutUint32(b[28:], 2) // LocalClientPID | |
| 356 | + | binary.LittleEndian.PutUint32(b[32:], 4) | |
| 357 | + | binary.LittleEndian.PutUint32(b[36:], pid) | |
| 358 | + | p.reply(0, b) | |
| 305 | 359 | } | |
| 306 | 360 | } | |
| 307 | 361 | } | |
| @@ -409,3 +463,81 @@ func (p *xpeer) hangup() { | |||
| 409 | 463 | _ = rc.Control(func(fd uintptr) { _ = unix.Shutdown(int(fd), unix.SHUT_RDWR) }) | |
| 410 | 464 | } | |
| 411 | 465 | } | |
| 466 | + | ||
| 467 | + | // setProp scripts a window property for GetProperty. | |
| 468 | + | func (p *xpeer) setProp(win, atom, typ uint32, format uint8, data []byte) { | |
| 469 | + | p.mu.Lock() | |
| 470 | + | defer p.mu.Unlock() | |
| 471 | + | if p.props[win] == nil { | |
| 472 | + | p.props[win] = map[uint32]xpeerProp{} | |
| 473 | + | } | |
| 474 | + | p.props[win][atom] = xpeerProp{typ: typ, format: format, data: data} | |
| 475 | + | } | |
| 476 | + | ||
| 477 | + | func (p *xpeer) mapRequest(win uint32) { | |
| 478 | + | p.event(20, func(b *[32]byte) { | |
| 479 | + | binary.LittleEndian.PutUint32(b[4:], peerRoot) | |
| 480 | + | binary.LittleEndian.PutUint32(b[8:], win) | |
| 481 | + | }) | |
| 482 | + | } | |
| 483 | + | ||
| 484 | + | func (p *xpeer) mapNotify(win uint32) { | |
| 485 | + | p.event(19, func(b *[32]byte) { | |
| 486 | + | binary.LittleEndian.PutUint32(b[4:], peerRoot) | |
| 487 | + | binary.LittleEndian.PutUint32(b[8:], win) | |
| 488 | + | }) | |
| 489 | + | } | |
| 490 | + | ||
| 491 | + | func (p *xpeer) unmapNotify(win uint32, synthetic bool) { | |
| 492 | + | p.event(18, func(b *[32]byte) { | |
| 493 | + | if synthetic { | |
| 494 | + | b[0] |= 0x80 | |
| 495 | + | } | |
| 496 | + | binary.LittleEndian.PutUint32(b[4:], peerRoot) | |
| 497 | + | binary.LittleEndian.PutUint32(b[8:], win) | |
| 498 | + | }) | |
| 499 | + | } | |
| 500 | + | ||
| 501 | + | func (p *xpeer) propertyNotify(win, atom uint32, deleted bool) { | |
| 502 | + | p.event(28, func(b *[32]byte) { | |
| 503 | + | binary.LittleEndian.PutUint32(b[4:], win) | |
| 504 | + | binary.LittleEndian.PutUint32(b[8:], atom) | |
| 505 | + | if deleted { | |
| 506 | + | b[16] = 1 | |
| 507 | + | } | |
| 508 | + | }) | |
| 509 | + | } | |
| 510 | + | ||
| 511 | + | func (p *xpeer) reparentNotify(win, parent uint32) { | |
| 512 | + | p.event(21, func(b *[32]byte) { | |
| 513 | + | binary.LittleEndian.PutUint32(b[4:], peerRoot) | |
| 514 | + | binary.LittleEndian.PutUint32(b[8:], win) | |
| 515 | + | binary.LittleEndian.PutUint32(b[12:], parent) | |
| 516 | + | }) | |
| 517 | + | } | |
| 518 | + | ||
| 519 | + | func (p *xpeer) clientMessage(win, typ uint32, data ...uint32) { | |
| 520 | + | p.event(33, func(b *[32]byte) { | |
| 521 | + | b[1] = 32 | |
| 522 | + | binary.LittleEndian.PutUint32(b[4:], win) | |
| 523 | + | binary.LittleEndian.PutUint32(b[8:], typ) | |
| 524 | + | for i, d := range data { | |
| 525 | + | binary.LittleEndian.PutUint32(b[12+4*i:], d) | |
| 526 | + | } | |
| 527 | + | }) | |
| 528 | + | } | |
| 529 | + | ||
| 530 | + | func (p *xpeer) focusIn(win uint32) { | |
| 531 | + | p.event(9, func(b *[32]byte) { binary.LittleEndian.PutUint32(b[4:], win) }) | |
| 532 | + | } | |
| 533 | + | ||
| 534 | + | func (p *xpeer) configureNotify(win uint32) { | |
| 535 | + | p.event(22, func(b *[32]byte) { | |
| 536 | + | binary.LittleEndian.PutUint32(b[4:], win) | |
| 537 | + | binary.LittleEndian.PutUint32(b[8:], win) | |
| 538 | + | binary.LittleEndian.PutUint16(b[20:], 10) | |
| 539 | + | binary.LittleEndian.PutUint16(b[22:], 20) | |
| 540 | + | binary.LittleEndian.PutUint16(b[24:], 300) | |
| 541 | + | binary.LittleEndian.PutUint16(b[26:], 200) | |
| 542 | + | }) | |
| 543 | + | } | |
| @@ -18,6 +18,7 @@ const ( | |||||
| 18 | opChangeWindowAttributes = 2 | 18 | opChangeWindowAttributes = 2 | ||
| 19 | opGetWindowAttributes = 3 | 19 | opGetWindowAttributes = 3 | ||
| 20 | opMapWindow = 8 | 20 | opMapWindow = 8 | ||
| 21 | + | opDeleteProperty = 19 | |||
| 21 | opConfigureWindow = 12 | 22 | opConfigureWindow = 12 | ||
| 22 | opGetGeometry = 14 | 23 | opGetGeometry = 14 | ||
| 23 | opQueryTree = 15 | 24 | opQueryTree = 15 | ||
| @@ -80,7 +81,13 @@ type xpeer struct { | |||||
| 80 | geoms map[uint32]xpeerGeom | 81 | geoms map[uint32]xpeerGeom | ||
| 81 | attrs map[uint32][2]byte // window -> {overrideRedirect, mapState} | 82 | attrs map[uint32][2]byte // window -> {overrideRedirect, mapState} | ||
| 82 | children []uint32 | 83 | children []uint32 | ||
| 83 | - | denyRoot bool // answer the root event-mask request with BadAccess | 84 | + | denyRoot bool // answer the root event-mask request with BadAccess |
| 85 | + | pids map[uint32]uint32 // XRes QueryClientIds answers, by window | |||
| 86 | + | bad map[uint32]bool // windows whose GetProperty/GetGeometry fail with BadWindow | |||
| 87 | + | hold bool // keep replies until release | |||
| 88 | + | held [][]byte | |||
| 89 | + | tap []byte // everything written to the client, when recording | |||
| 90 | + | record bool | |||
| 84 | 91 | ||||
| 85 | gate atomic.Pointer[chan struct{}] // closed = reading allowed | 92 | gate atomic.Pointer[chan struct{}] // closed = reading allowed | ||
| 86 | done chan struct{} | 93 | done chan struct{} | ||
| @@ -108,12 +115,14 @@ func startXPeer(t *testing.T, exts map[string]xpeerExt) (int, *xpeer) { | |||||
| 108 | t: t, f: os.NewFile(uintptr(fds[1]), "xpeer"), | 115 | t: t, f: os.NewFile(uintptr(fds[1]), "xpeer"), | ||
| 109 | exts: exts, atoms: map[string]uint32{}, nextAtom: 1000, | 116 | exts: exts, atoms: map[string]uint32{}, nextAtom: 1000, | ||
| 110 | props: map[uint32]map[uint32]xpeerProp{}, geoms: map[uint32]xpeerGeom{}, attrs: map[uint32][2]byte{}, | 117 | props: map[uint32]map[uint32]xpeerProp{}, geoms: map[uint32]xpeerGeom{}, attrs: map[uint32][2]byte{}, | ||
| 118 | + | pids: map[uint32]uint32{}, bad: map[uint32]bool{}, | |||
| 111 | done: make(chan struct{}), | 119 | done: make(chan struct{}), | ||
| 112 | } | 120 | } | ||
| 113 | open := make(chan struct{}) | 121 | open := make(chan struct{}) | ||
| 114 | close(open) | 122 | close(open) | ||
| 115 | p.gate.Store(&open) | 123 | p.gate.Store(&open) | ||
| 116 | t.Cleanup(func() { | 124 | t.Cleanup(func() { | ||
| 125 | + | p.resume() // a paused peer would never see the close | |||
| 117 | p.f.Close() | 126 | p.f.Close() | ||
| 118 | <-p.done | 127 | <-p.done | ||
| 119 | }) | 128 | }) | ||
| @@ -179,7 +188,12 @@ func (p *xpeer) serve() { | |||||
| 179 | } | 188 | } | ||
| 180 | 189 | ||||
| 181 | // write sends bytes to the client. The caller holds p.mu. | 190 | // write sends bytes to the client. The caller holds p.mu. | ||
| 182 | - | func (p *xpeer) write(b []byte) { _, _ = p.f.Write(b) } | 191 | + | func (p *xpeer) write(b []byte) { |
| 192 | + | if p.record { | |||
| 193 | + | p.tap = append(p.tap, b...) | |||
| 194 | + | } | |||
| 195 | + | _, _ = p.f.Write(b) | |||
| 196 | + | } | |||
| 183 | 197 | ||||
| 184 | func (p *xpeer) reply(data uint8, body []byte) { | 198 | func (p *xpeer) reply(data uint8, body []byte) { | ||
| 185 | words := (max(len(body), 24) - 24 + 3) / 4 | 199 | words := (max(len(body), 24) - 24 + 3) / 4 | ||
| @@ -188,9 +202,31 @@ func (p *xpeer) reply(data uint8, body []byte) { | |||||
| 188 | binary.LittleEndian.PutUint16(b[2:], p.seq) | 202 | binary.LittleEndian.PutUint16(b[2:], p.seq) | ||
| 189 | binary.LittleEndian.PutUint32(b[4:], uint32(words)) | 203 | binary.LittleEndian.PutUint32(b[4:], uint32(words)) | ||
| 190 | copy(b[8:], body) | 204 | copy(b[8:], body) | ||
| 205 | + | if p.hold { | |||
| 206 | + | p.held = append(p.held, b) | |||
| 207 | + | return | |||
| 208 | + | } | |||
| 191 | p.write(b) | 209 | p.write(b) | ||
| 192 | } | 210 | } | ||
| 193 | 211 | ||||
| 212 | + | // release sends the held replies, in request order as a real server does. | |||
| 213 | + | func (p *xpeer) release() { | |||
| 214 | + | p.mu.Lock() | |||
| 215 | + | defer p.mu.Unlock() | |||
| 216 | + | p.hold = false | |||
| 217 | + | for _, b := range p.held { | |||
| 218 | + | p.write(b) | |||
| 219 | + | } | |||
| 220 | + | p.held = nil | |||
| 221 | + | } | |||
| 222 | + | ||||
| 223 | + | // holdReplies keeps the replies of the following requests back. | |||
| 224 | + | func (p *xpeer) holdReplies() { | |||
| 225 | + | p.mu.Lock() | |||
| 226 | + | p.hold = true | |||
| 227 | + | p.mu.Unlock() | |||
| 228 | + | } | |||
| 229 | + | ||||
| 194 | func (p *xpeer) errorPacket(code, major uint8, bad uint32) { | 230 | func (p *xpeer) errorPacket(code, major uint8, bad uint32) { | ||
| 195 | b := make([]byte, 32) | 231 | b := make([]byte, 32) | ||
| 196 | b[1] = code | 232 | b[1] = code | ||
| @@ -252,6 +288,8 @@ func (p *xpeer) answer(r xpeerReq, body []byte) { | |||||
| 252 | b[18] = a[1] // map_state is byte 26 of the reply | 288 | b[18] = a[1] // map_state is byte 26 of the reply | ||
| 253 | b[19] = a[0] // override_redirect, byte 27 | 289 | b[19] = a[0] // override_redirect, byte 27 | ||
| 254 | p.reply(0, b) | 290 | p.reply(0, b) | ||
| 291 | + | case (r.major == opGetGeometry || r.major == opGetProperty) && p.bad[binary.LittleEndian.Uint32(body)]: | |||
| 292 | + | p.errorPacket(3, r.major, binary.LittleEndian.Uint32(body)) // BadWindow | |||
| 255 | case r.major == opGetGeometry: | 293 | case r.major == opGetGeometry: | ||
| 256 | g := p.geoms[binary.LittleEndian.Uint32(body)] | 294 | g := p.geoms[binary.LittleEndian.Uint32(body)] | ||
| 257 | b := make([]byte, 24) | 295 | b := make([]byte, 24) | ||
| @@ -272,6 +310,8 @@ func (p *xpeer) answer(r xpeerReq, body []byte) { | |||||
| 272 | typ: binary.LittleEndian.Uint32(body[8:]), format: format, | 310 | typ: binary.LittleEndian.Uint32(body[8:]), format: format, | ||
| 273 | data: append([]byte(nil), body[20:20+n*int(format)/8]...), | 311 | data: append([]byte(nil), body[20:20+n*int(format)/8]...), | ||
| 274 | } | 312 | } | ||
| 313 | + | case r.major == opDeleteProperty: | |||
| 314 | + | delete(p.props[binary.LittleEndian.Uint32(body)], binary.LittleEndian.Uint32(body[4:])) | |||
| 275 | case r.major == opGetProperty: | 315 | case r.major == opGetProperty: | ||
| 276 | win, prop := binary.LittleEndian.Uint32(body), binary.LittleEndian.Uint32(body[4:]) | 316 | win, prop := binary.LittleEndian.Uint32(body), binary.LittleEndian.Uint32(body[4:]) | ||
| 277 | v, ok := p.props[win][prop] | 317 | v, ok := p.props[win][prop] | ||
| @@ -300,8 +340,22 @@ func (p *xpeer) answer(r xpeerReq, body []byte) { | |||||
| 300 | p.reply(0, le32(5, 4)) | 340 | p.reply(0, le32(5, 4)) | ||
| 301 | } | 341 | } | ||
| 302 | case "X-Resource": | 342 | case "X-Resource": | ||
| 303 | - | if r.minor == 0 { | 343 | + | switch r.minor { |
| 344 | + | case 0: | |||
| 304 | p.reply(0, []byte{1, 0, 2, 0}) | 345 | p.reply(0, []byte{1, 0, 2, 0}) | ||
| 346 | + | case 4: // QueryClientIds: one spec, answered when a pid is scripted | |||
| 347 | + | pid, ok := p.pids[r.u32(8)] | |||
| 348 | + | if !ok { | |||
| 349 | + | p.reply(0, le32(0)) | |||
| 350 | + | break | |||
| 351 | + | } | |||
| 352 | + | b := make([]byte, 40) | |||
| 353 | + | binary.LittleEndian.PutUint32(b[0:], 1) | |||
| 354 | + | binary.LittleEndian.PutUint32(b[24:], r.u32(8)) | |||
| 355 | + | binary.LittleEndian.PutUint32(b[28:], 2) // LocalClientPID | |||
| 356 | + | binary.LittleEndian.PutUint32(b[32:], 4) | |||
| 357 | + | binary.LittleEndian.PutUint32(b[36:], pid) | |||
| 358 | + | p.reply(0, b) | |||
| 305 | } | 359 | } | ||
| 306 | } | 360 | } | ||
| 307 | } | 361 | } | ||
| @@ -409,3 +463,81 @@ func (p *xpeer) hangup() { | |||||
| 409 | _ = rc.Control(func(fd uintptr) { _ = unix.Shutdown(int(fd), unix.SHUT_RDWR) }) | 463 | _ = rc.Control(func(fd uintptr) { _ = unix.Shutdown(int(fd), unix.SHUT_RDWR) }) | ||
| 410 | } | 464 | } | ||
| 411 | } | 465 | } | ||
| 466 | + | ||||
| 467 | + | // setProp scripts a window property for GetProperty. | |||
| 468 | + | func (p *xpeer) setProp(win, atom, typ uint32, format uint8, data []byte) { | |||
| 469 | + | p.mu.Lock() | |||
| 470 | + | defer p.mu.Unlock() | |||
| 471 | + | if p.props[win] == nil { | |||
| 472 | + | p.props[win] = map[uint32]xpeerProp{} | |||
| 473 | + | } | |||
| 474 | + | p.props[win][atom] = xpeerProp{typ: typ, format: format, data: data} | |||
| 475 | + | } | |||
| 476 | + | ||||
| 477 | + | func (p *xpeer) mapRequest(win uint32) { | |||
| 478 | + | p.event(20, func(b *[32]byte) { | |||
| 479 | + | binary.LittleEndian.PutUint32(b[4:], peerRoot) | |||
| 480 | + | binary.LittleEndian.PutUint32(b[8:], win) | |||
| 481 | + | }) | |||
| 482 | + | } | |||
| 483 | + | ||||
| 484 | + | func (p *xpeer) mapNotify(win uint32) { | |||
| 485 | + | p.event(19, func(b *[32]byte) { | |||
| 486 | + | binary.LittleEndian.PutUint32(b[4:], peerRoot) | |||
| 487 | + | binary.LittleEndian.PutUint32(b[8:], win) | |||
| 488 | + | }) | |||
| 489 | + | } | |||
| 490 | + | ||||
| 491 | + | func (p *xpeer) unmapNotify(win uint32, synthetic bool) { | |||
| 492 | + | p.event(18, func(b *[32]byte) { | |||
| 493 | + | if synthetic { | |||
| 494 | + | b[0] |= 0x80 | |||
| 495 | + | } | |||
| 496 | + | binary.LittleEndian.PutUint32(b[4:], peerRoot) | |||
| 497 | + | binary.LittleEndian.PutUint32(b[8:], win) | |||
| 498 | + | }) | |||
| 499 | + | } | |||
| 500 | + | ||||
| 501 | + | func (p *xpeer) propertyNotify(win, atom uint32, deleted bool) { | |||
| 502 | + | p.event(28, func(b *[32]byte) { | |||
| 503 | + | binary.LittleEndian.PutUint32(b[4:], win) | |||
| 504 | + | binary.LittleEndian.PutUint32(b[8:], atom) | |||
| 505 | + | if deleted { | |||
| 506 | + | b[16] = 1 | |||
| 507 | + | } | |||
| 508 | + | }) | |||
| 509 | + | } | |||
| 510 | + | ||||
| 511 | + | func (p *xpeer) reparentNotify(win, parent uint32) { | |||
| 512 | + | p.event(21, func(b *[32]byte) { | |||
| 513 | + | binary.LittleEndian.PutUint32(b[4:], peerRoot) | |||
| 514 | + | binary.LittleEndian.PutUint32(b[8:], win) | |||
| 515 | + | binary.LittleEndian.PutUint32(b[12:], parent) | |||
| 516 | + | }) | |||
| 517 | + | } | |||
| 518 | + | ||||
| 519 | + | func (p *xpeer) clientMessage(win, typ uint32, data ...uint32) { | |||
| 520 | + | p.event(33, func(b *[32]byte) { | |||
| 521 | + | b[1] = 32 | |||
| 522 | + | binary.LittleEndian.PutUint32(b[4:], win) | |||
| 523 | + | binary.LittleEndian.PutUint32(b[8:], typ) | |||
| 524 | + | for i, d := range data { | |||
| 525 | + | binary.LittleEndian.PutUint32(b[12+4*i:], d) | |||
| 526 | + | } | |||
| 527 | + | }) | |||
| 528 | + | } | |||
| 529 | + | ||||
| 530 | + | func (p *xpeer) focusIn(win uint32) { | |||
| 531 | + | p.event(9, func(b *[32]byte) { binary.LittleEndian.PutUint32(b[4:], win) }) | |||
| 532 | + | } | |||
| 533 | + | ||||
| 534 | + | func (p *xpeer) configureNotify(win uint32) { | |||
| 535 | + | p.event(22, func(b *[32]byte) { | |||
| 536 | + | binary.LittleEndian.PutUint32(b[4:], win) | |||
| 537 | + | binary.LittleEndian.PutUint32(b[8:], win) | |||
| 538 | + | binary.LittleEndian.PutUint16(b[20:], 10) | |||
| 539 | + | binary.LittleEndian.PutUint16(b[22:], 20) | |||
| 540 | + | binary.LittleEndian.PutUint16(b[24:], 300) | |||
| 541 | + | binary.LittleEndian.PutUint16(b[26:], 200) | |||
| 542 | + | }) | |||
| 543 | + | } | |||
M internal/adapters/wayland/xwm/xwm.go +2 -1
| @@ -1,4 +1,4 @@ | |||
| 1 | - | //lint:file-ignore U1000 pairing, focus and stacking state is used by the flows that build on this skeleton | |
| 1 | + | //lint:file-ignore U1000 refocus and listsDirty are used by the focus and configure flows | |
| 2 | 2 | ||
| 3 | 3 | // Package xwm is the built-in X11 window manager for Xwayland: it speaks the | |
| 4 | 4 | // X protocol over the -wm socket with xturbo and reports managed windows to | |
| @@ -66,6 +66,7 @@ type XWM struct { | |||
| 66 | 66 | posted, writable, closed bool | |
| 67 | 67 | bootErr error | |
| 68 | 68 | warnedRing, warnedFull bool | |
| 69 | + | warnedUnpaired bool | |
| 69 | 70 | ||
| 70 | 71 | scratch []byte // encode buffer for 32-bit property values, 4 bytes per slot | |
| 71 | 72 | ||
| @@ -1,4 +1,4 @@ | |||||
| 1 | - | //lint:file-ignore U1000 pairing, focus and stacking state is used by the flows that build on this skeleton | 1 | + | //lint:file-ignore U1000 refocus and listsDirty are used by the focus and configure flows |
| 2 | 2 | ||||
| 3 | // Package xwm is the built-in X11 window manager for Xwayland: it speaks the | 3 | // Package xwm is the built-in X11 window manager for Xwayland: it speaks the | ||
| 4 | // X protocol over the -wm socket with xturbo and reports managed windows to | 4 | // X protocol over the -wm socket with xturbo and reports managed windows to | ||
| @@ -66,6 +66,7 @@ type XWM struct { | |||||
| 66 | posted, writable, closed bool | 66 | posted, writable, closed bool | ||
| 67 | bootErr error | 67 | bootErr error | ||
| 68 | warnedRing, warnedFull bool | 68 | warnedRing, warnedFull bool | ||
| 69 | + | warnedUnpaired bool | |||
| 69 | 70 | ||||
| 70 | scratch []byte // encode buffer for 32-bit property values, 4 bytes per slot | 71 | scratch []byte // encode buffer for 32-bit property values, 4 bytes per slot | ||
| 71 | 72 | ||||