feat(bindings): generate client and server bindings for 64 protocols
- commit
- 902a4e7a7fe24e53db5b8765247500b612834aa3
- author
- brice · · 2026-10-01 03:41 UTC
- parent
- bea8f48
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
148 files · +48871 -0
A client/alphamodifier/alphamodifier_generated.go +138 -0
| @@ -0,0 +1,138 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: alpha_modifier_v1 | |
| 3 | + | // Source: alpha-modifier-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2024 Xaver Hugl | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package alphamodifier | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 31 | + | "github.com/bnema/wlturbo/wl" | |
| 32 | + | ) | |
| 33 | + | ||
| 34 | + | // ERROR_ALREADY_CONSTRUCTED is the error already_constructed value. | |
| 35 | + | const ERROR_ALREADY_CONSTRUCTED = 0 | |
| 36 | + | ||
| 37 | + | // ERROR_NO_SURFACE is the error no_surface value. | |
| 38 | + | const ERROR_NO_SURFACE = 0 | |
| 39 | + | ||
| 40 | + | // WpAlphaModifierInterface is the protocol interface name. | |
| 41 | + | const WpAlphaModifierInterface = "wp_alpha_modifier_v1" | |
| 42 | + | ||
| 43 | + | // WpAlphaModifier is the generated binding for wp_alpha_modifier_v1 version 1. | |
| 44 | + | type WpAlphaModifier struct { | |
| 45 | + | wl.BaseProxy | |
| 46 | + | } | |
| 47 | + | ||
| 48 | + | // NewWpAlphaModifier returns an unbound WpAlphaModifier. | |
| 49 | + | func NewWpAlphaModifier(ctx *wl.Context) *WpAlphaModifier { | |
| 50 | + | obj := &WpAlphaModifier{} | |
| 51 | + | obj.SetContext(ctx) | |
| 52 | + | ctx.Register(obj) | |
| 53 | + | return obj | |
| 54 | + | } | |
| 55 | + | ||
| 56 | + | // Destroy the alpha modifier manager. This doesn't destroy objects created with the manager. | |
| 57 | + | func (o *WpAlphaModifier) Destroy() error { | |
| 58 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_alpha_modifier_v1.destroy", Destructor: true}); err != nil { | |
| 59 | + | return err | |
| 60 | + | } | |
| 61 | + | return nil | |
| 62 | + | } | |
| 63 | + | ||
| 64 | + | // Create a new alpha modifier surface object associated with the given wl_surface. If there is already such an object associated with the wl_surface, the already_constructed error will be raised. | |
| 65 | + | func (o *WpAlphaModifier) GetSurface(surface *cross_wl_surface.Surface) (*WpAlphaModifierSurface, error) { | |
| 66 | + | var arg1 wl.Object | |
| 67 | + | if surface != nil { | |
| 68 | + | arg1 = surface | |
| 69 | + | } | |
| 70 | + | child := &WpAlphaModifierSurface{} | |
| 71 | + | child.SetContext(o.Context()) | |
| 72 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_alpha_modifier_v1.get_surface", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 73 | + | return nil, err | |
| 74 | + | } | |
| 75 | + | return child, nil | |
| 76 | + | } | |
| 77 | + | ||
| 78 | + | // EventSignature returns the declared event argument types in wire order. | |
| 79 | + | func (o *WpAlphaModifier) EventSignature(opcode uint16) (string, bool) { | |
| 80 | + | switch opcode { | |
| 81 | + | default: | |
| 82 | + | return "", false | |
| 83 | + | } | |
| 84 | + | } | |
| 85 | + | ||
| 86 | + | // Dispatch decodes one event on wp_alpha_modifier_v1 and calls the registered handlers. | |
| 87 | + | func (o *WpAlphaModifier) Dispatch(event *wl.Event) { | |
| 88 | + | switch event.Opcode { | |
| 89 | + | default: | |
| 90 | + | } | |
| 91 | + | } | |
| 92 | + | ||
| 93 | + | // WpAlphaModifierSurfaceInterface is the protocol interface name. | |
| 94 | + | const WpAlphaModifierSurfaceInterface = "wp_alpha_modifier_surface_v1" | |
| 95 | + | ||
| 96 | + | // WpAlphaModifierSurface is the generated binding for wp_alpha_modifier_surface_v1 version 1. | |
| 97 | + | type WpAlphaModifierSurface struct { | |
| 98 | + | wl.BaseProxy | |
| 99 | + | } | |
| 100 | + | ||
| 101 | + | // NewWpAlphaModifierSurface returns an unbound WpAlphaModifierSurface. | |
| 102 | + | func NewWpAlphaModifierSurface(ctx *wl.Context) *WpAlphaModifierSurface { | |
| 103 | + | obj := &WpAlphaModifierSurface{} | |
| 104 | + | obj.SetContext(ctx) | |
| 105 | + | ctx.Register(obj) | |
| 106 | + | return obj | |
| 107 | + | } | |
| 108 | + | ||
| 109 | + | // This destroys the object, and is equivalent to set_multiplier with a value of UINT32_MAX, with the same double-buffered semantics as set_multiplier. | |
| 110 | + | func (o *WpAlphaModifierSurface) Destroy() error { | |
| 111 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_alpha_modifier_surface_v1.destroy", Destructor: true}); err != nil { | |
| 112 | + | return err | |
| 113 | + | } | |
| 114 | + | return nil | |
| 115 | + | } | |
| 116 | + | ||
| 117 | + | // Sets the alpha multiplier for the surface. The alpha multiplier is double-buffered state, see wl_surface.commit for details. This factor is applied in the compositor's blending space, as an additional step after the processing of per-pixel alpha values for the wl_surface. The exact meaning of the factor is thus undefined, unless the blending space is specified in a different extension. This multiplier is applied even if the buffer attached to the wl_surface doesn't have an alpha channel; in that case an alpha value of one is used instead. Zero means completely transparent, UINT32_MAX means completely opaque. | |
| 118 | + | func (o *WpAlphaModifierSurface) SetMultiplier(factor uint32) error { | |
| 119 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_alpha_modifier_surface_v1.set_multiplier"}, wl.ArgUint(factor)); err != nil { | |
| 120 | + | return err | |
| 121 | + | } | |
| 122 | + | return nil | |
| 123 | + | } | |
| 124 | + | ||
| 125 | + | // EventSignature returns the declared event argument types in wire order. | |
| 126 | + | func (o *WpAlphaModifierSurface) EventSignature(opcode uint16) (string, bool) { | |
| 127 | + | switch opcode { | |
| 128 | + | default: | |
| 129 | + | return "", false | |
| 130 | + | } | |
| 131 | + | } | |
| 132 | + | ||
| 133 | + | // Dispatch decodes one event on wp_alpha_modifier_surface_v1 and calls the registered handlers. | |
| 134 | + | func (o *WpAlphaModifierSurface) Dispatch(event *wl.Event) { | |
| 135 | + | switch event.Opcode { | |
| 136 | + | default: | |
| 137 | + | } | |
| 138 | + | } | |
A client/colormanagement/colormanagement_generated.go +1554 -0
| @@ -0,0 +1,1554 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: color_management_v1 | |
| 3 | + | // Source: color-management-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright 2019 Sebastian Wick | |
| 7 | + | // Copyright 2019 Erwin Burema | |
| 8 | + | // Copyright 2020 AMD | |
| 9 | + | // Copyright 2020-2024 Collabora, Ltd. | |
| 10 | + | // Copyright 2024 Xaver Hugl | |
| 11 | + | // Copyright 2022-2025 Red Hat, Inc. | |
| 12 | + | // | |
| 13 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 14 | + | // copy of this software and associated documentation files (the "Software"), | |
| 15 | + | // to deal in the Software without restriction, including without limitation | |
| 16 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 17 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 18 | + | // Software is furnished to do so, subject to the following conditions: | |
| 19 | + | // | |
| 20 | + | // The above copyright notice and this permission notice (including the next | |
| 21 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 22 | + | // Software. | |
| 23 | + | // | |
| 24 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 25 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 26 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 27 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 28 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 29 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 30 | + | // DEALINGS IN THE SOFTWARE. | |
| 31 | + | ||
| 32 | + | package colormanagement | |
| 33 | + | ||
| 34 | + | import ( | |
| 35 | + | "sync" | |
| 36 | + | ||
| 37 | + | cross_wl_output "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 38 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 39 | + | "github.com/bnema/wlturbo/wl" | |
| 40 | + | ) | |
| 41 | + | ||
| 42 | + | // WP_COLOR_MANAGER_V1_ERROR_UNSUPPORTED_FEATURE is the error unsupported_feature value. | |
| 43 | + | const WP_COLOR_MANAGER_V1_ERROR_UNSUPPORTED_FEATURE = 0 | |
| 44 | + | ||
| 45 | + | // ERROR_SURFACE_EXISTS is the error surface_exists value. | |
| 46 | + | const ERROR_SURFACE_EXISTS = 1 | |
| 47 | + | ||
| 48 | + | // RENDER_INTENT_PERCEPTUAL is the render_intent perceptual value. | |
| 49 | + | const RENDER_INTENT_PERCEPTUAL = 0 | |
| 50 | + | ||
| 51 | + | // RENDER_INTENT_RELATIVE is the render_intent relative value. | |
| 52 | + | const RENDER_INTENT_RELATIVE = 1 | |
| 53 | + | ||
| 54 | + | // RENDER_INTENT_SATURATION is the render_intent saturation value. | |
| 55 | + | const RENDER_INTENT_SATURATION = 2 | |
| 56 | + | ||
| 57 | + | // RENDER_INTENT_ABSOLUTE is the render_intent absolute value. | |
| 58 | + | const RENDER_INTENT_ABSOLUTE = 3 | |
| 59 | + | ||
| 60 | + | // RENDER_INTENT_RELATIVE_BPC is the render_intent relative_bpc value. | |
| 61 | + | const RENDER_INTENT_RELATIVE_BPC = 4 | |
| 62 | + | ||
| 63 | + | // RENDER_INTENT_ABSOLUTE_NO_ADAPTATION is the render_intent absolute_no_adaptation value. | |
| 64 | + | const RENDER_INTENT_ABSOLUTE_NO_ADAPTATION = 5 | |
| 65 | + | ||
| 66 | + | // FEATURE_ICC_V2_V4 is the feature icc_v2_v4 value. | |
| 67 | + | const FEATURE_ICC_V2_V4 = 0 | |
| 68 | + | ||
| 69 | + | // FEATURE_PARAMETRIC is the feature parametric value. | |
| 70 | + | const FEATURE_PARAMETRIC = 1 | |
| 71 | + | ||
| 72 | + | // FEATURE_SET_PRIMARIES is the feature set_primaries value. | |
| 73 | + | const FEATURE_SET_PRIMARIES = 2 | |
| 74 | + | ||
| 75 | + | // FEATURE_SET_TF_POWER is the feature set_tf_power value. | |
| 76 | + | const FEATURE_SET_TF_POWER = 3 | |
| 77 | + | ||
| 78 | + | // FEATURE_SET_LUMINANCES is the feature set_luminances value. | |
| 79 | + | const FEATURE_SET_LUMINANCES = 4 | |
| 80 | + | ||
| 81 | + | // FEATURE_SET_MASTERING_DISPLAY_PRIMARIES is the feature set_mastering_display_primaries value. | |
| 82 | + | const FEATURE_SET_MASTERING_DISPLAY_PRIMARIES = 5 | |
| 83 | + | ||
| 84 | + | // FEATURE_EXTENDED_TARGET_VOLUME is the feature extended_target_volume value. | |
| 85 | + | const FEATURE_EXTENDED_TARGET_VOLUME = 6 | |
| 86 | + | ||
| 87 | + | // FEATURE_WINDOWS_SCRGB is the feature windows_scrgb value. | |
| 88 | + | const FEATURE_WINDOWS_SCRGB = 7 | |
| 89 | + | ||
| 90 | + | // FEATURE_WINDOWS_BT2100 is the feature windows_bt2100 value. | |
| 91 | + | const FEATURE_WINDOWS_BT2100 = 8 | |
| 92 | + | ||
| 93 | + | // PRIMARIES_SRGB is the primaries srgb value. | |
| 94 | + | const PRIMARIES_SRGB = 1 | |
| 95 | + | ||
| 96 | + | // PRIMARIES_PAL_M is the primaries pal_m value. | |
| 97 | + | const PRIMARIES_PAL_M = 2 | |
| 98 | + | ||
| 99 | + | // PRIMARIES_PAL is the primaries pal value. | |
| 100 | + | const PRIMARIES_PAL = 3 | |
| 101 | + | ||
| 102 | + | // PRIMARIES_NTSC is the primaries ntsc value. | |
| 103 | + | const PRIMARIES_NTSC = 4 | |
| 104 | + | ||
| 105 | + | // PRIMARIES_GENERIC_FILM is the primaries generic_film value. | |
| 106 | + | const PRIMARIES_GENERIC_FILM = 5 | |
| 107 | + | ||
| 108 | + | // PRIMARIES_BT2020 is the primaries bt2020 value. | |
| 109 | + | const PRIMARIES_BT2020 = 6 | |
| 110 | + | ||
| 111 | + | // PRIMARIES_CIE1931_XYZ is the primaries cie1931_xyz value. | |
| 112 | + | const PRIMARIES_CIE1931_XYZ = 7 | |
| 113 | + | ||
| 114 | + | // PRIMARIES_DCI_P3 is the primaries dci_p3 value. | |
| 115 | + | const PRIMARIES_DCI_P3 = 8 | |
| 116 | + | ||
| 117 | + | // PRIMARIES_DISPLAY_P3 is the primaries display_p3 value. | |
| 118 | + | const PRIMARIES_DISPLAY_P3 = 9 | |
| 119 | + | ||
| 120 | + | // PRIMARIES_ADOBE_RGB is the primaries adobe_rgb value. | |
| 121 | + | const PRIMARIES_ADOBE_RGB = 10 | |
| 122 | + | ||
| 123 | + | // TRANSFER_FUNCTION_BT1886 is the transfer_function bt1886 value. | |
| 124 | + | const TRANSFER_FUNCTION_BT1886 = 1 | |
| 125 | + | ||
| 126 | + | // TRANSFER_FUNCTION_GAMMA22 is the transfer_function gamma22 value. | |
| 127 | + | const TRANSFER_FUNCTION_GAMMA22 = 2 | |
| 128 | + | ||
| 129 | + | // TRANSFER_FUNCTION_GAMMA28 is the transfer_function gamma28 value. | |
| 130 | + | const TRANSFER_FUNCTION_GAMMA28 = 3 | |
| 131 | + | ||
| 132 | + | // TRANSFER_FUNCTION_ST240 is the transfer_function st240 value. | |
| 133 | + | const TRANSFER_FUNCTION_ST240 = 4 | |
| 134 | + | ||
| 135 | + | // TRANSFER_FUNCTION_EXT_LINEAR is the transfer_function ext_linear value. | |
| 136 | + | const TRANSFER_FUNCTION_EXT_LINEAR = 5 | |
| 137 | + | ||
| 138 | + | // TRANSFER_FUNCTION_LOG_100 is the transfer_function log_100 value. | |
| 139 | + | const TRANSFER_FUNCTION_LOG_100 = 6 | |
| 140 | + | ||
| 141 | + | // TRANSFER_FUNCTION_LOG_316 is the transfer_function log_316 value. | |
| 142 | + | const TRANSFER_FUNCTION_LOG_316 = 7 | |
| 143 | + | ||
| 144 | + | // TRANSFER_FUNCTION_XVYCC is the transfer_function xvycc value. | |
| 145 | + | const TRANSFER_FUNCTION_XVYCC = 8 | |
| 146 | + | ||
| 147 | + | // TRANSFER_FUNCTION_SRGB is the transfer_function srgb value. | |
| 148 | + | const TRANSFER_FUNCTION_SRGB = 9 | |
| 149 | + | ||
| 150 | + | // TRANSFER_FUNCTION_EXT_SRGB is the transfer_function ext_srgb value. | |
| 151 | + | const TRANSFER_FUNCTION_EXT_SRGB = 10 | |
| 152 | + | ||
| 153 | + | // TRANSFER_FUNCTION_ST2084_PQ is the transfer_function st2084_pq value. | |
| 154 | + | const TRANSFER_FUNCTION_ST2084_PQ = 11 | |
| 155 | + | ||
| 156 | + | // TRANSFER_FUNCTION_ST428 is the transfer_function st428 value. | |
| 157 | + | const TRANSFER_FUNCTION_ST428 = 12 | |
| 158 | + | ||
| 159 | + | // TRANSFER_FUNCTION_HLG is the transfer_function hlg value. | |
| 160 | + | const TRANSFER_FUNCTION_HLG = 13 | |
| 161 | + | ||
| 162 | + | // TRANSFER_FUNCTION_COMPOUND_POWER_2_4 is the transfer_function compound_power_2_4 value. | |
| 163 | + | const TRANSFER_FUNCTION_COMPOUND_POWER_2_4 = 14 | |
| 164 | + | ||
| 165 | + | // ERROR_RENDER_INTENT is the error render_intent value. | |
| 166 | + | const ERROR_RENDER_INTENT = 0 | |
| 167 | + | ||
| 168 | + | // ERROR_IMAGE_DESCRIPTION is the error image_description value. | |
| 169 | + | const ERROR_IMAGE_DESCRIPTION = 1 | |
| 170 | + | ||
| 171 | + | // WP_COLOR_MANAGEMENT_SURFACE_V1_ERROR_INERT is the error inert value. | |
| 172 | + | const WP_COLOR_MANAGEMENT_SURFACE_V1_ERROR_INERT = 2 | |
| 173 | + | ||
| 174 | + | // WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_ERROR_INERT is the error inert value. | |
| 175 | + | const WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_ERROR_INERT = 0 | |
| 176 | + | ||
| 177 | + | // WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_ERROR_UNSUPPORTED_FEATURE is the error unsupported_feature value. | |
| 178 | + | const WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_ERROR_UNSUPPORTED_FEATURE = 1 | |
| 179 | + | ||
| 180 | + | // WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_ERROR_INCOMPLETE_SET is the error incomplete_set value. | |
| 181 | + | const WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_ERROR_INCOMPLETE_SET = 0 | |
| 182 | + | ||
| 183 | + | // WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_ERROR_ALREADY_SET is the error already_set value. | |
| 184 | + | const WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_ERROR_ALREADY_SET = 1 | |
| 185 | + | ||
| 186 | + | // ERROR_BAD_FD is the error bad_fd value. | |
| 187 | + | const ERROR_BAD_FD = 2 | |
| 188 | + | ||
| 189 | + | // ERROR_BAD_SIZE is the error bad_size value. | |
| 190 | + | const ERROR_BAD_SIZE = 3 | |
| 191 | + | ||
| 192 | + | // ERROR_OUT_OF_FILE is the error out_of_file value. | |
| 193 | + | const ERROR_OUT_OF_FILE = 4 | |
| 194 | + | ||
| 195 | + | // WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INCOMPLETE_SET is the error incomplete_set value. | |
| 196 | + | const WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INCOMPLETE_SET = 0 | |
| 197 | + | ||
| 198 | + | // WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ALREADY_SET is the error already_set value. | |
| 199 | + | const WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ALREADY_SET = 1 | |
| 200 | + | ||
| 201 | + | // WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_UNSUPPORTED_FEATURE is the error unsupported_feature value. | |
| 202 | + | const WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_UNSUPPORTED_FEATURE = 2 | |
| 203 | + | ||
| 204 | + | // ERROR_INVALID_TF is the error invalid_tf value. | |
| 205 | + | const ERROR_INVALID_TF = 3 | |
| 206 | + | ||
| 207 | + | // ERROR_INVALID_PRIMARIES_NAMED is the error invalid_primaries_named value. | |
| 208 | + | const ERROR_INVALID_PRIMARIES_NAMED = 4 | |
| 209 | + | ||
| 210 | + | // ERROR_INVALID_LUMINANCE is the error invalid_luminance value. | |
| 211 | + | const ERROR_INVALID_LUMINANCE = 5 | |
| 212 | + | ||
| 213 | + | // ERROR_NOT_READY is the error not_ready value. | |
| 214 | + | const ERROR_NOT_READY = 0 | |
| 215 | + | ||
| 216 | + | // ERROR_NO_INFORMATION is the error no_information value. | |
| 217 | + | const ERROR_NO_INFORMATION = 1 | |
| 218 | + | ||
| 219 | + | // CAUSE_LOW_VERSION is the cause low_version value. | |
| 220 | + | const CAUSE_LOW_VERSION = 0 | |
| 221 | + | ||
| 222 | + | // CAUSE_UNSUPPORTED is the cause unsupported value. | |
| 223 | + | const CAUSE_UNSUPPORTED = 1 | |
| 224 | + | ||
| 225 | + | // CAUSE_OPERATING_SYSTEM is the cause operating_system value. | |
| 226 | + | const CAUSE_OPERATING_SYSTEM = 2 | |
| 227 | + | ||
| 228 | + | // CAUSE_NO_OUTPUT is the cause no_output value. | |
| 229 | + | const CAUSE_NO_OUTPUT = 3 | |
| 230 | + | ||
| 231 | + | // WpColorManagerInterface is the protocol interface name. | |
| 232 | + | const WpColorManagerInterface = "wp_color_manager_v1" | |
| 233 | + | ||
| 234 | + | // WpColorManager is the generated binding for wp_color_manager_v1 version 3. | |
| 235 | + | type WpColorManager struct { | |
| 236 | + | wl.BaseProxy | |
| 237 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 238 | + | // handlers while another goroutine dispatches events. | |
| 239 | + | handlersMu sync.Mutex | |
| 240 | + | onSupportedIntent []func(renderIntent uint32) | |
| 241 | + | onSupportedFeature []func(feature uint32) | |
| 242 | + | onSupportedTfNamed []func(tf uint32) | |
| 243 | + | onSupportedPrimariesNamed []func(primaries uint32) | |
| 244 | + | onDone []func() | |
| 245 | + | } | |
| 246 | + | ||
| 247 | + | // NewWpColorManager returns an unbound WpColorManager. | |
| 248 | + | func NewWpColorManager(ctx *wl.Context) *WpColorManager { | |
| 249 | + | obj := &WpColorManager{} | |
| 250 | + | obj.SetContext(ctx) | |
| 251 | + | ctx.Register(obj) | |
| 252 | + | return obj | |
| 253 | + | } | |
| 254 | + | ||
| 255 | + | // Destroy the wp_color_manager_v1 object. This does not affect any other objects in any way. | |
| 256 | + | func (o *WpColorManager) Destroy() error { | |
| 257 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_color_manager_v1.destroy", Destructor: true}); err != nil { | |
| 258 | + | return err | |
| 259 | + | } | |
| 260 | + | return nil | |
| 261 | + | } | |
| 262 | + | ||
| 263 | + | // This creates a new wp_color_management_output_v1 object for the given wl_output. See the wp_color_management_output_v1 interface for more details. | |
| 264 | + | func (o *WpColorManager) GetOutput(output *cross_wl_output.Output) (*WpColorManagementOutput, error) { | |
| 265 | + | var arg1 wl.Object | |
| 266 | + | if output != nil { | |
| 267 | + | arg1 = output | |
| 268 | + | } | |
| 269 | + | child := &WpColorManagementOutput{} | |
| 270 | + | child.SetContext(o.Context()) | |
| 271 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_color_manager_v1.get_output", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 272 | + | return nil, err | |
| 273 | + | } | |
| 274 | + | return child, nil | |
| 275 | + | } | |
| 276 | + | ||
| 277 | + | // If a wp_color_management_surface_v1 object already exists for the given wl_surface, the protocol error surface_exists is raised. This creates a new color wp_color_management_surface_v1 object for the given wl_surface. See the wp_color_management_surface_v1 interface for more details. | |
| 278 | + | func (o *WpColorManager) GetSurface(surface *cross_wl_surface.Surface) (*WpColorManagementSurface, error) { | |
| 279 | + | var arg1 wl.Object | |
| 280 | + | if surface != nil { | |
| 281 | + | arg1 = surface | |
| 282 | + | } | |
| 283 | + | child := &WpColorManagementSurface{} | |
| 284 | + | child.SetContext(o.Context()) | |
| 285 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wp_color_manager_v1.get_surface", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 286 | + | return nil, err | |
| 287 | + | } | |
| 288 | + | return child, nil | |
| 289 | + | } | |
| 290 | + | ||
| 291 | + | // This creates a new color wp_color_management_surface_feedback_v1 object for the given wl_surface. See the wp_color_management_surface_feedback_v1 interface for more details. | |
| 292 | + | func (o *WpColorManager) GetSurfaceFeedback(surface *cross_wl_surface.Surface) (*WpColorManagementSurfaceFeedback, error) { | |
| 293 | + | var arg1 wl.Object | |
| 294 | + | if surface != nil { | |
| 295 | + | arg1 = surface | |
| 296 | + | } | |
| 297 | + | child := &WpColorManagementSurfaceFeedback{} | |
| 298 | + | child.SetContext(o.Context()) | |
| 299 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "wp_color_manager_v1.get_surface_feedback", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 300 | + | return nil, err | |
| 301 | + | } | |
| 302 | + | return child, nil | |
| 303 | + | } | |
| 304 | + | ||
| 305 | + | // Makes a new ICC-based image description creator object with all properties initially unset. The client can then use the object's interface to define all the required properties for an image description and finally create a wp_image_description_v1 object. This request can be used when the compositor advertises wp_color_manager_v1.feature.icc_v2_v4. Otherwise this request raises the protocol error unsupported_feature. | |
| 306 | + | func (o *WpColorManager) CreateIccCreator() (*WpImageDescriptionCreatorIcc, error) { | |
| 307 | + | child := &WpImageDescriptionCreatorIcc{} | |
| 308 | + | child.SetContext(o.Context()) | |
| 309 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 4, Name: "wp_color_manager_v1.create_icc_creator", Child: child}, wl.ArgObject(child)); err != nil { | |
| 310 | + | return nil, err | |
| 311 | + | } | |
| 312 | + | return child, nil | |
| 313 | + | } | |
| 314 | + | ||
| 315 | + | // Makes a new parametric image description creator object with all properties initially unset. The client can then use the object's interface to define all the required properties for an image description and finally create a wp_image_description_v1 object. This request can be used when the compositor advertises wp_color_manager_v1.feature.parametric. Otherwise this request raises the protocol error unsupported_feature. | |
| 316 | + | func (o *WpColorManager) CreateParametricCreator() (*WpImageDescriptionCreatorParams, error) { | |
| 317 | + | child := &WpImageDescriptionCreatorParams{} | |
| 318 | + | child.SetContext(o.Context()) | |
| 319 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 5, Name: "wp_color_manager_v1.create_parametric_creator", Child: child}, wl.ArgObject(child)); err != nil { | |
| 320 | + | return nil, err | |
| 321 | + | } | |
| 322 | + | return child, nil | |
| 323 | + | } | |
| 324 | + | ||
| 325 | + | // This creates a pre-defined image description for the so-called Windows-scRGB stimulus encoding. This comes from the Windows 10 handling of its own definition of an scRGB color space for an HDR screen driven in BT.2100/PQ signalling mode. Windows-scRGB uses sRGB (BT.709) color primaries and white point. The transfer characteristic is extended linear. The nominal color channel value range is extended, meaning it includes negative and greater than 1.0 values. Negative values are used to escape the sRGB color gamut boundaries. To make use of the extended range, the client needs to use a pixel format that can represent those values, e.g. floating-point 16 bits per channel. Nominal color value R=G=B=0.0 corresponds to BT.2100/PQ system 0 cd/m², and R=G=B=1.0 corresponds to BT.2100/PQ system 80 cd/m². The maximum is R=G=B=125.0 corresponding to 10k cd/m². Windows-scRGB is displayed by Windows 10 by converting it to BT.2100/PQ, maintaining the CIE 1931 chromaticity and mapping the luminance as above. No adjustment is made to the signal to account for the viewing conditions. The reference white level of Windows-scRGB is unknown. If a reference white level must be assumed for compositor processing, it should be R=G=B=2.5375 corresponding to 203 cd/m² of Report ITU-R BT.2408-7. The target color volume of Windows-scRGB is unknown. The color gamut may be anything between sRGB and BT.2100. Note: EGL_EXT_gl_colorspace_scrgb_linear definition differs from Windows-scRGB by using R=G=B=1.0 as the reference white level, while Windows-scRGB reference white level is unknown or varies. However, it seems probable that Windows implements both EGL_EXT_gl_colorspace_scrgb_linear and Vulkan VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT as Windows-scRGB. This request can be used when the compositor advertises wp_color_manager_v1.feature.windows_scrgb. Otherwise this request raises the protocol error unsupported_feature. The resulting image description object does not allow get_information request. The wp_image_description_v1.ready event shall be sent. | |
| 326 | + | func (o *WpColorManager) CreateWindowsScrgb() (*WpImageDescription, error) { | |
| 327 | + | child := &WpImageDescription{} | |
| 328 | + | child.SetContext(o.Context()) | |
| 329 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 6, Name: "wp_color_manager_v1.create_windows_scrgb", Child: child}, wl.ArgObject(child)); err != nil { | |
| 330 | + | return nil, err | |
| 331 | + | } | |
| 332 | + | return child, nil | |
| 333 | + | } | |
| 334 | + | ||
| 335 | + | // This request retrieves the image description backing a reference. The get_information request can be used if and only if the request that creates the reference allows it. | |
| 336 | + | func (o *WpColorManager) GetImageDescription(reference *WpImageDescriptionReference) (*WpImageDescription, error) { | |
| 337 | + | var arg1 wl.Object | |
| 338 | + | if reference != nil { | |
| 339 | + | arg1 = reference | |
| 340 | + | } | |
| 341 | + | child := &WpImageDescription{} | |
| 342 | + | child.SetContext(o.Context()) | |
| 343 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 7, Name: "wp_color_manager_v1.get_image_description", Since: 2, Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 344 | + | return nil, err | |
| 345 | + | } | |
| 346 | + | return child, nil | |
| 347 | + | } | |
| 348 | + | ||
| 349 | + | // This creates a pre-defined image description for the so-called Windows-BT.2100 stimulus encoding. This comes from the Windows 10 handling of its own definition of a BT.2100 color space for an HDR screen driven in BT.2100/PQ signalling mode. Windows-BT.2100 uses BT.2020 color primaries and white point. The transfer characteristic is st2084_pq. Windows-BT.2100 is generally displayed by Windows 10 without any adjustments to the signal to account for viewing conditions. The reference white level of Windows-BT.2100 is unknown. If a reference white level must be assumed for compositor processing, it should be 203 cd/m² of Report ITU-R BT.2408-7. The target color volume of Windows-BT.2100 is unknown. The color gamut may be anything up to BT.2100. This request can be used when the compositor advertises wp_color_manager_v1.feature.windows_bt2100. Otherwise this request raises the protocol error unsupported_feature. The resulting image description object does not allow get_information request. The wp_image_description_v1.ready event shall be sent. | |
| 350 | + | func (o *WpColorManager) CreateWindowsBt2100() (*WpImageDescription, error) { | |
| 351 | + | child := &WpImageDescription{} | |
| 352 | + | child.SetContext(o.Context()) | |
| 353 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 8, Name: "wp_color_manager_v1.create_windows_bt2100", Since: 3, Child: child}, wl.ArgObject(child)); err != nil { | |
| 354 | + | return nil, err | |
| 355 | + | } | |
| 356 | + | return child, nil | |
| 357 | + | } | |
| 358 | + | ||
| 359 | + | // OnSupportedIntent registers a handler for the supported_intent event. | |
| 360 | + | // | |
| 361 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 362 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 363 | + | func (o *WpColorManager) OnSupportedIntent(handler func(renderIntent uint32)) { | |
| 364 | + | if handler == nil { | |
| 365 | + | return | |
| 366 | + | } | |
| 367 | + | o.handlersMu.Lock() | |
| 368 | + | defer o.handlersMu.Unlock() | |
| 369 | + | o.onSupportedIntent = append(o.onSupportedIntent, handler) | |
| 370 | + | } | |
| 371 | + | ||
| 372 | + | // handlersForSupportedIntent returns the handlers registered for supported_intent, taken | |
| 373 | + | // under the lock so a handler may register another handler while events are | |
| 374 | + | // being dispatched. | |
| 375 | + | func (o *WpColorManager) handlersForSupportedIntent() []func(renderIntent uint32) { | |
| 376 | + | o.handlersMu.Lock() | |
| 377 | + | defer o.handlersMu.Unlock() | |
| 378 | + | return o.onSupportedIntent | |
| 379 | + | } | |
| 380 | + | ||
| 381 | + | // OnSupportedFeature registers a handler for the supported_feature event. | |
| 382 | + | // | |
| 383 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 384 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 385 | + | func (o *WpColorManager) OnSupportedFeature(handler func(feature uint32)) { | |
| 386 | + | if handler == nil { | |
| 387 | + | return | |
| 388 | + | } | |
| 389 | + | o.handlersMu.Lock() | |
| 390 | + | defer o.handlersMu.Unlock() | |
| 391 | + | o.onSupportedFeature = append(o.onSupportedFeature, handler) | |
| 392 | + | } | |
| 393 | + | ||
| 394 | + | // handlersForSupportedFeature returns the handlers registered for supported_feature, taken | |
| 395 | + | // under the lock so a handler may register another handler while events are | |
| 396 | + | // being dispatched. | |
| 397 | + | func (o *WpColorManager) handlersForSupportedFeature() []func(feature uint32) { | |
| 398 | + | o.handlersMu.Lock() | |
| 399 | + | defer o.handlersMu.Unlock() | |
| 400 | + | return o.onSupportedFeature | |
| 401 | + | } | |
| 402 | + | ||
| 403 | + | // OnSupportedTfNamed registers a handler for the supported_tf_named event. | |
| 404 | + | // | |
| 405 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 406 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 407 | + | func (o *WpColorManager) OnSupportedTfNamed(handler func(tf uint32)) { | |
| 408 | + | if handler == nil { | |
| 409 | + | return | |
| 410 | + | } | |
| 411 | + | o.handlersMu.Lock() | |
| 412 | + | defer o.handlersMu.Unlock() | |
| 413 | + | o.onSupportedTfNamed = append(o.onSupportedTfNamed, handler) | |
| 414 | + | } | |
| 415 | + | ||
| 416 | + | // handlersForSupportedTfNamed returns the handlers registered for supported_tf_named, taken | |
| 417 | + | // under the lock so a handler may register another handler while events are | |
| 418 | + | // being dispatched. | |
| 419 | + | func (o *WpColorManager) handlersForSupportedTfNamed() []func(tf uint32) { | |
| 420 | + | o.handlersMu.Lock() | |
| 421 | + | defer o.handlersMu.Unlock() | |
| 422 | + | return o.onSupportedTfNamed | |
| 423 | + | } | |
| 424 | + | ||
| 425 | + | // OnSupportedPrimariesNamed registers a handler for the supported_primaries_named event. | |
| 426 | + | // | |
| 427 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 428 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 429 | + | func (o *WpColorManager) OnSupportedPrimariesNamed(handler func(primaries uint32)) { | |
| 430 | + | if handler == nil { | |
| 431 | + | return | |
| 432 | + | } | |
| 433 | + | o.handlersMu.Lock() | |
| 434 | + | defer o.handlersMu.Unlock() | |
| 435 | + | o.onSupportedPrimariesNamed = append(o.onSupportedPrimariesNamed, handler) | |
| 436 | + | } | |
| 437 | + | ||
| 438 | + | // handlersForSupportedPrimariesNamed returns the handlers registered for supported_primaries_named, taken | |
| 439 | + | // under the lock so a handler may register another handler while events are | |
| 440 | + | // being dispatched. | |
| 441 | + | func (o *WpColorManager) handlersForSupportedPrimariesNamed() []func(primaries uint32) { | |
| 442 | + | o.handlersMu.Lock() | |
| 443 | + | defer o.handlersMu.Unlock() | |
| 444 | + | return o.onSupportedPrimariesNamed | |
| 445 | + | } | |
| 446 | + | ||
| 447 | + | // OnDone registers a handler for the done event. | |
| 448 | + | // | |
| 449 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 450 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 451 | + | func (o *WpColorManager) OnDone(handler func()) { | |
| 452 | + | if handler == nil { | |
| 453 | + | return | |
| 454 | + | } | |
| 455 | + | o.handlersMu.Lock() | |
| 456 | + | defer o.handlersMu.Unlock() | |
| 457 | + | o.onDone = append(o.onDone, handler) | |
| 458 | + | } | |
| 459 | + | ||
| 460 | + | // handlersForDone returns the handlers registered for done, taken | |
| 461 | + | // under the lock so a handler may register another handler while events are | |
| 462 | + | // being dispatched. | |
| 463 | + | func (o *WpColorManager) handlersForDone() []func() { | |
| 464 | + | o.handlersMu.Lock() | |
| 465 | + | defer o.handlersMu.Unlock() | |
| 466 | + | return o.onDone | |
| 467 | + | } | |
| 468 | + | ||
| 469 | + | // EventSignature returns the declared event argument types in wire order. | |
| 470 | + | func (o *WpColorManager) EventSignature(opcode uint16) (string, bool) { | |
| 471 | + | switch opcode { | |
| 472 | + | case 0: | |
| 473 | + | return "uint,", true | |
| 474 | + | case 1: | |
| 475 | + | return "uint,", true | |
| 476 | + | case 2: | |
| 477 | + | return "uint,", true | |
| 478 | + | case 3: | |
| 479 | + | return "uint,", true | |
| 480 | + | case 4: | |
| 481 | + | return "", true | |
| 482 | + | default: | |
| 483 | + | return "", false | |
| 484 | + | } | |
| 485 | + | } | |
| 486 | + | ||
| 487 | + | // Dispatch decodes one event on wp_color_manager_v1 and calls the registered handlers. | |
| 488 | + | func (o *WpColorManager) Dispatch(event *wl.Event) { | |
| 489 | + | switch event.Opcode { | |
| 490 | + | case 0: // supported_intent | |
| 491 | + | renderIntent := event.Uint32() | |
| 492 | + | ||
| 493 | + | for i, handler := range o.handlersForSupportedIntent() { | |
| 494 | + | _ = i | |
| 495 | + | handler(renderIntent) | |
| 496 | + | } | |
| 497 | + | case 1: // supported_feature | |
| 498 | + | feature := event.Uint32() | |
| 499 | + | ||
| 500 | + | for i, handler := range o.handlersForSupportedFeature() { | |
| 501 | + | _ = i | |
| 502 | + | handler(feature) | |
| 503 | + | } | |
| 504 | + | case 2: // supported_tf_named | |
| 505 | + | tf := event.Uint32() | |
| 506 | + | ||
| 507 | + | for i, handler := range o.handlersForSupportedTfNamed() { | |
| 508 | + | _ = i | |
| 509 | + | handler(tf) | |
| 510 | + | } | |
| 511 | + | case 3: // supported_primaries_named | |
| 512 | + | primaries := event.Uint32() | |
| 513 | + | ||
| 514 | + | for i, handler := range o.handlersForSupportedPrimariesNamed() { | |
| 515 | + | _ = i | |
| 516 | + | handler(primaries) | |
| 517 | + | } | |
| 518 | + | case 4: // done | |
| 519 | + | ||
| 520 | + | for i, handler := range o.handlersForDone() { | |
| 521 | + | _ = i | |
| 522 | + | handler() | |
| 523 | + | } | |
| 524 | + | default: | |
| 525 | + | } | |
| 526 | + | } | |
| 527 | + | ||
| 528 | + | // WpColorManagementOutputInterface is the protocol interface name. | |
| 529 | + | const WpColorManagementOutputInterface = "wp_color_management_output_v1" | |
| 530 | + | ||
| 531 | + | // WpColorManagementOutput is the generated binding for wp_color_management_output_v1 version 3. | |
| 532 | + | type WpColorManagementOutput struct { | |
| 533 | + | wl.BaseProxy | |
| 534 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 535 | + | // handlers while another goroutine dispatches events. | |
| 536 | + | handlersMu sync.Mutex | |
| 537 | + | onImageDescriptionChanged []func() | |
| 538 | + | } | |
| 539 | + | ||
| 540 | + | // NewWpColorManagementOutput returns an unbound WpColorManagementOutput. | |
| 541 | + | func NewWpColorManagementOutput(ctx *wl.Context) *WpColorManagementOutput { | |
| 542 | + | obj := &WpColorManagementOutput{} | |
| 543 | + | obj.SetContext(ctx) | |
| 544 | + | ctx.Register(obj) | |
| 545 | + | return obj | |
| 546 | + | } | |
| 547 | + | ||
| 548 | + | // Destroy the color wp_color_management_output_v1 object. This does not affect any remaining protocol objects. | |
| 549 | + | func (o *WpColorManagementOutput) Destroy() error { | |
| 550 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_color_management_output_v1.destroy", Destructor: true}); err != nil { | |
| 551 | + | return err | |
| 552 | + | } | |
| 553 | + | return nil | |
| 554 | + | } | |
| 555 | + | ||
| 556 | + | // This creates a new wp_image_description_v1 object for the current image description of the output. There always is exactly one image description active for an output so the client should destroy the image description created by earlier invocations of this request. This request is usually sent as a reaction to the image_description_changed event or when creating a wp_color_management_output_v1 object. The image description of an output represents the color encoding the output expects. There might be performance and power advantages, as well as improved color reproduction, if a content update matches the image description of the output it is being shown on. If a content update is shown on any other output than the one it matches the image description of, then the color reproduction on those outputs might be considerably worse. The created wp_image_description_v1 object preserves the image description of the output from the time the object was created. The resulting image description object allows get_information request. If this protocol object is inert, the resulting image description object shall immediately deliver the wp_image_description_v1.failed event with the no_output cause. If the interface version is inadequate for the output's image description, meaning that the client does not support all the events needed to deliver the crucial information, the resulting image description object shall immediately deliver the wp_image_description_v1.failed event with the low_version cause. Otherwise the object shall immediately deliver the ready event. | |
| 557 | + | func (o *WpColorManagementOutput) GetImageDescription() (*WpImageDescription, error) { | |
| 558 | + | child := &WpImageDescription{} | |
| 559 | + | child.SetContext(o.Context()) | |
| 560 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_color_management_output_v1.get_image_description", Child: child}, wl.ArgObject(child)); err != nil { | |
| 561 | + | return nil, err | |
| 562 | + | } | |
| 563 | + | return child, nil | |
| 564 | + | } | |
| 565 | + | ||
| 566 | + | // OnImageDescriptionChanged registers a handler for the image_description_changed event. | |
| 567 | + | // | |
| 568 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 569 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 570 | + | func (o *WpColorManagementOutput) OnImageDescriptionChanged(handler func()) { | |
| 571 | + | if handler == nil { | |
| 572 | + | return | |
| 573 | + | } | |
| 574 | + | o.handlersMu.Lock() | |
| 575 | + | defer o.handlersMu.Unlock() | |
| 576 | + | o.onImageDescriptionChanged = append(o.onImageDescriptionChanged, handler) | |
| 577 | + | } | |
| 578 | + | ||
| 579 | + | // handlersForImageDescriptionChanged returns the handlers registered for image_description_changed, taken | |
| 580 | + | // under the lock so a handler may register another handler while events are | |
| 581 | + | // being dispatched. | |
| 582 | + | func (o *WpColorManagementOutput) handlersForImageDescriptionChanged() []func() { | |
| 583 | + | o.handlersMu.Lock() | |
| 584 | + | defer o.handlersMu.Unlock() | |
| 585 | + | return o.onImageDescriptionChanged | |
| 586 | + | } | |
| 587 | + | ||
| 588 | + | // EventSignature returns the declared event argument types in wire order. | |
| 589 | + | func (o *WpColorManagementOutput) EventSignature(opcode uint16) (string, bool) { | |
| 590 | + | switch opcode { | |
| 591 | + | case 0: | |
| 592 | + | return "", true | |
| 593 | + | default: | |
| 594 | + | return "", false | |
| 595 | + | } | |
| 596 | + | } | |
| 597 | + | ||
| 598 | + | // Dispatch decodes one event on wp_color_management_output_v1 and calls the registered handlers. | |
| 599 | + | func (o *WpColorManagementOutput) Dispatch(event *wl.Event) { | |
| 600 | + | switch event.Opcode { | |
| 601 | + | case 0: // image_description_changed | |
| 602 | + | ||
| 603 | + | for i, handler := range o.handlersForImageDescriptionChanged() { | |
| 604 | + | _ = i | |
| 605 | + | handler() | |
| 606 | + | } | |
| 607 | + | default: | |
| 608 | + | } | |
| 609 | + | } | |
| 610 | + | ||
| 611 | + | // WpColorManagementSurfaceInterface is the protocol interface name. | |
| 612 | + | const WpColorManagementSurfaceInterface = "wp_color_management_surface_v1" | |
| 613 | + | ||
| 614 | + | // WpColorManagementSurface is the generated binding for wp_color_management_surface_v1 version 3. | |
| 615 | + | type WpColorManagementSurface struct { | |
| 616 | + | wl.BaseProxy | |
| 617 | + | } | |
| 618 | + | ||
| 619 | + | // NewWpColorManagementSurface returns an unbound WpColorManagementSurface. | |
| 620 | + | func NewWpColorManagementSurface(ctx *wl.Context) *WpColorManagementSurface { | |
| 621 | + | obj := &WpColorManagementSurface{} | |
| 622 | + | obj.SetContext(ctx) | |
| 623 | + | ctx.Register(obj) | |
| 624 | + | return obj | |
| 625 | + | } | |
| 626 | + | ||
| 627 | + | // Destroy the wp_color_management_surface_v1 object and do the same as unset_image_description. | |
| 628 | + | func (o *WpColorManagementSurface) Destroy() error { | |
| 629 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_color_management_surface_v1.destroy", Destructor: true}); err != nil { | |
| 630 | + | return err | |
| 631 | + | } | |
| 632 | + | return nil | |
| 633 | + | } | |
| 634 | + | ||
| 635 | + | // If this protocol object is inert, the protocol error inert is raised. Set the image description of the underlying surface. The image description and rendering intent are double-buffered state, see wl_surface.commit. It is the client's responsibility to understand the image description it sets on a surface, and to provide content that matches that image description. Compositors might convert images to match their own or any other image descriptions. Image descriptions which are not ready (see wp_image_description_v1) are forbidden in this request, and in such case the protocol error image_description is raised. All image descriptions which are ready (see wp_image_description_v1) are allowed and must always be accepted by the compositor. When an image description is set on a surface, it establishes an explicit link between surface pixel values and surface colorimetry. This link may be undefined for some pixel values, see the image description creator interfaces for the conditions. Non-finite floating-point values (NaN, Inf) always have an undefined colorimetry. A rendering intent provides the client's preference on how surface colorimetry should be mapped to each output. The render_intent value must be one advertised by the compositor with wp_color_manager_v1.render_intent event, otherwise the protocol error render_intent is raised. By default, a surface does not have an associated image description nor a rendering intent. The handling of color on such surfaces is compositor implementation defined. Compositors should handle such surfaces as sRGB, but may handle them differently if they have specific requirements. Setting the image description has copy semantics; after this request, the image description can be immediately destroyed without affecting the pending state of the surface. | |
| 636 | + | func (o *WpColorManagementSurface) SetImageDescription(imageDescription *WpImageDescription, renderIntent uint32) error { | |
| 637 | + | var arg0 wl.Object | |
| 638 | + | if imageDescription != nil { | |
| 639 | + | arg0 = imageDescription | |
| 640 | + | } | |
| 641 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_color_management_surface_v1.set_image_description"}, wl.ArgObject(arg0), wl.ArgUint(renderIntent)); err != nil { | |
| 642 | + | return err | |
| 643 | + | } | |
| 644 | + | return nil | |
| 645 | + | } | |
| 646 | + | ||
| 647 | + | // If this protocol object is inert, the protocol error inert is raised. This request removes any image description from the surface. See set_image_description for how a compositor handles a surface without an image description. This is double-buffered state, see wl_surface.commit. | |
| 648 | + | func (o *WpColorManagementSurface) UnsetImageDescription() error { | |
| 649 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wp_color_management_surface_v1.unset_image_description"}); err != nil { | |
| 650 | + | return err | |
| 651 | + | } | |
| 652 | + | return nil | |
| 653 | + | } | |
| 654 | + | ||
| 655 | + | // EventSignature returns the declared event argument types in wire order. | |
| 656 | + | func (o *WpColorManagementSurface) EventSignature(opcode uint16) (string, bool) { | |
| 657 | + | switch opcode { | |
| 658 | + | default: | |
| 659 | + | return "", false | |
| 660 | + | } | |
| 661 | + | } | |
| 662 | + | ||
| 663 | + | // Dispatch decodes one event on wp_color_management_surface_v1 and calls the registered handlers. | |
| 664 | + | func (o *WpColorManagementSurface) Dispatch(event *wl.Event) { | |
| 665 | + | switch event.Opcode { | |
| 666 | + | default: | |
| 667 | + | } | |
| 668 | + | } | |
| 669 | + | ||
| 670 | + | // WpColorManagementSurfaceFeedbackInterface is the protocol interface name. | |
| 671 | + | const WpColorManagementSurfaceFeedbackInterface = "wp_color_management_surface_feedback_v1" | |
| 672 | + | ||
| 673 | + | // WpColorManagementSurfaceFeedback is the generated binding for wp_color_management_surface_feedback_v1 version 3. | |
| 674 | + | type WpColorManagementSurfaceFeedback struct { | |
| 675 | + | wl.BaseProxy | |
| 676 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 677 | + | // handlers while another goroutine dispatches events. | |
| 678 | + | handlersMu sync.Mutex | |
| 679 | + | onPreferredChanged []func(identity uint32) | |
| 680 | + | onPreferredChanged2 []func(identityHi uint32, identityLo uint32) | |
| 681 | + | } | |
| 682 | + | ||
| 683 | + | // NewWpColorManagementSurfaceFeedback returns an unbound WpColorManagementSurfaceFeedback. | |
| 684 | + | func NewWpColorManagementSurfaceFeedback(ctx *wl.Context) *WpColorManagementSurfaceFeedback { | |
| 685 | + | obj := &WpColorManagementSurfaceFeedback{} | |
| 686 | + | obj.SetContext(ctx) | |
| 687 | + | ctx.Register(obj) | |
| 688 | + | return obj | |
| 689 | + | } | |
| 690 | + | ||
| 691 | + | // Destroy the wp_color_management_surface_feedback_v1 object. | |
| 692 | + | func (o *WpColorManagementSurfaceFeedback) Destroy() error { | |
| 693 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_color_management_surface_feedback_v1.destroy", Destructor: true}); err != nil { | |
| 694 | + | return err | |
| 695 | + | } | |
| 696 | + | return nil | |
| 697 | + | } | |
| 698 | + | ||
| 699 | + | // If this protocol object is inert, the protocol error inert is raised. The preferred image description represents the compositor's preferred color encoding for this wl_surface at the current time. There might be performance and power advantages, as well as improved color reproduction, if the image description of a content update matches the preferred image description. This creates a new wp_image_description_v1 object for the currently preferred image description for the wl_surface. The client should stop using and destroy the image descriptions created by earlier invocations of this request for the associated wl_surface. This request is usually sent as a reaction to the preferred_changed event or when creating a wp_color_management_surface_feedback_v1 object if the client is capable of adapting to image descriptions. The created wp_image_description_v1 object preserves the preferred image description of the wl_surface from the time the object was created. The resulting image description object allows get_information request. If the image description is parametric, the client should set it on its wl_surface only if the image description is an exact match with the client content. Particularly if everything else matches, but the target color volume is greater than what the client needs, the client should create its own parameric image description with its exact parameters. If the interface version is inadequate for the preferred image description, meaning that the client does not support all the events needed to deliver the crucial information, the resulting image description object shall immediately deliver the wp_image_description_v1.failed event with the low_version cause, otherwise the object shall immediately deliver the ready event. | |
| 700 | + | func (o *WpColorManagementSurfaceFeedback) GetPreferred() (*WpImageDescription, error) { | |
| 701 | + | child := &WpImageDescription{} | |
| 702 | + | child.SetContext(o.Context()) | |
| 703 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_color_management_surface_feedback_v1.get_preferred", Child: child}, wl.ArgObject(child)); err != nil { | |
| 704 | + | return nil, err | |
| 705 | + | } | |
| 706 | + | return child, nil | |
| 707 | + | } | |
| 708 | + | ||
| 709 | + | // The same description as for get_preferred applies, except the returned image description is guaranteed to be parametric. This is meant for clients that can only deal with parametric image descriptions. If the compositor doesn't support parametric image descriptions, the unsupported_feature error is emitted. | |
| 710 | + | func (o *WpColorManagementSurfaceFeedback) GetPreferredParametric() (*WpImageDescription, error) { | |
| 711 | + | child := &WpImageDescription{} | |
| 712 | + | child.SetContext(o.Context()) | |
| 713 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wp_color_management_surface_feedback_v1.get_preferred_parametric", Child: child}, wl.ArgObject(child)); err != nil { | |
| 714 | + | return nil, err | |
| 715 | + | } | |
| 716 | + | return child, nil | |
| 717 | + | } | |
| 718 | + | ||
| 719 | + | // OnPreferredChanged registers a handler for the preferred_changed event. | |
| 720 | + | // | |
| 721 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 722 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 723 | + | func (o *WpColorManagementSurfaceFeedback) OnPreferredChanged(handler func(identity uint32)) { | |
| 724 | + | if handler == nil { | |
| 725 | + | return | |
| 726 | + | } | |
| 727 | + | o.handlersMu.Lock() | |
| 728 | + | defer o.handlersMu.Unlock() | |
| 729 | + | o.onPreferredChanged = append(o.onPreferredChanged, handler) | |
| 730 | + | } | |
| 731 | + | ||
| 732 | + | // handlersForPreferredChanged returns the handlers registered for preferred_changed, taken | |
| 733 | + | // under the lock so a handler may register another handler while events are | |
| 734 | + | // being dispatched. | |
| 735 | + | func (o *WpColorManagementSurfaceFeedback) handlersForPreferredChanged() []func(identity uint32) { | |
| 736 | + | o.handlersMu.Lock() | |
| 737 | + | defer o.handlersMu.Unlock() | |
| 738 | + | return o.onPreferredChanged | |
| 739 | + | } | |
| 740 | + | ||
| 741 | + | // OnPreferredChanged2 registers a handler for the preferred_changed2 event. | |
| 742 | + | // | |
| 743 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 744 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 745 | + | func (o *WpColorManagementSurfaceFeedback) OnPreferredChanged2(handler func(identityHi uint32, identityLo uint32)) { | |
| 746 | + | if handler == nil { | |
| 747 | + | return | |
| 748 | + | } | |
| 749 | + | o.handlersMu.Lock() | |
| 750 | + | defer o.handlersMu.Unlock() | |
| 751 | + | o.onPreferredChanged2 = append(o.onPreferredChanged2, handler) | |
| 752 | + | } | |
| 753 | + | ||
| 754 | + | // handlersForPreferredChanged2 returns the handlers registered for preferred_changed2, taken | |
| 755 | + | // under the lock so a handler may register another handler while events are | |
| 756 | + | // being dispatched. | |
| 757 | + | func (o *WpColorManagementSurfaceFeedback) handlersForPreferredChanged2() []func(identityHi uint32, identityLo uint32) { | |
| 758 | + | o.handlersMu.Lock() | |
| 759 | + | defer o.handlersMu.Unlock() | |
| 760 | + | return o.onPreferredChanged2 | |
| 761 | + | } | |
| 762 | + | ||
| 763 | + | // EventSignature returns the declared event argument types in wire order. | |
| 764 | + | func (o *WpColorManagementSurfaceFeedback) EventSignature(opcode uint16) (string, bool) { | |
| 765 | + | switch opcode { | |
| 766 | + | case 0: | |
| 767 | + | return "uint,", true | |
| 768 | + | case 1: | |
| 769 | + | return "uint,uint,", true | |
| 770 | + | default: | |
| 771 | + | return "", false | |
| 772 | + | } | |
| 773 | + | } | |
| 774 | + | ||
| 775 | + | // Dispatch decodes one event on wp_color_management_surface_feedback_v1 and calls the registered handlers. | |
| 776 | + | func (o *WpColorManagementSurfaceFeedback) Dispatch(event *wl.Event) { | |
| 777 | + | switch event.Opcode { | |
| 778 | + | case 0: // preferred_changed | |
| 779 | + | identity := event.Uint32() | |
| 780 | + | ||
| 781 | + | for i, handler := range o.handlersForPreferredChanged() { | |
| 782 | + | _ = i | |
| 783 | + | handler(identity) | |
| 784 | + | } | |
| 785 | + | case 1: // preferred_changed2 | |
| 786 | + | identityHi := event.Uint32() | |
| 787 | + | identityLo := event.Uint32() | |
| 788 | + | ||
| 789 | + | for i, handler := range o.handlersForPreferredChanged2() { | |
| 790 | + | _ = i | |
| 791 | + | handler(identityHi, identityLo) | |
| 792 | + | } | |
| 793 | + | default: | |
| 794 | + | } | |
| 795 | + | } | |
| 796 | + | ||
| 797 | + | // WpImageDescriptionCreatorIccInterface is the protocol interface name. | |
| 798 | + | const WpImageDescriptionCreatorIccInterface = "wp_image_description_creator_icc_v1" | |
| 799 | + | ||
| 800 | + | // WpImageDescriptionCreatorIcc is the generated binding for wp_image_description_creator_icc_v1 version 3. | |
| 801 | + | type WpImageDescriptionCreatorIcc struct { | |
| 802 | + | wl.BaseProxy | |
| 803 | + | } | |
| 804 | + | ||
| 805 | + | // NewWpImageDescriptionCreatorIcc returns an unbound WpImageDescriptionCreatorIcc. | |
| 806 | + | func NewWpImageDescriptionCreatorIcc(ctx *wl.Context) *WpImageDescriptionCreatorIcc { | |
| 807 | + | obj := &WpImageDescriptionCreatorIcc{} | |
| 808 | + | obj.SetContext(ctx) | |
| 809 | + | ctx.Register(obj) | |
| 810 | + | return obj | |
| 811 | + | } | |
| 812 | + | ||
| 813 | + | // Create an image description object based on the ICC information previously set on this object. A compositor must parse the ICC data in some undefined but finite amount of time. The completeness of the parameter set is verified. If the set is not complete, the protocol error incomplete_set is raised. For the definition of a complete set, see the description of this interface. If the particular combination of the information is not supported by the compositor, the resulting image description object shall immediately deliver the wp_image_description_v1.failed event with the 'unsupported' cause. If a valid image description was created from the information, the wp_image_description_v1.ready event will eventually be sent instead. This request destroys the wp_image_description_creator_icc_v1 object. The resulting image description object does not allow get_information request. | |
| 814 | + | func (o *WpImageDescriptionCreatorIcc) Create() (*WpImageDescription, error) { | |
| 815 | + | child := &WpImageDescription{} | |
| 816 | + | child.SetContext(o.Context()) | |
| 817 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_image_description_creator_icc_v1.create", Destructor: true, Child: child}, wl.ArgObject(child)); err != nil { | |
| 818 | + | return nil, err | |
| 819 | + | } | |
| 820 | + | return child, nil | |
| 821 | + | } | |
| 822 | + | ||
| 823 | + | // Sets the ICC profile file to be used as the basis of the image description. The data shall be found through the given fd at the given offset, having the given length. The fd must be seekable and readable. Violating these requirements raises the bad_fd protocol error. If reading the data fails due to an error independent of the client, the compositor shall send the wp_image_description_v1.failed event on the created wp_image_description_v1 with the 'operating_system' cause. The maximum size of the ICC profile is 32 MB. If length is greater than that or zero, the protocol error bad_size is raised. If offset + length exceeds the file size, the protocol error out_of_file is raised. A compositor may read the file at any time starting from this request and only until whichever happens first: - If create request was issued, the wp_image_description_v1 object delivers either failed or ready event; or - if create request was not issued, this wp_image_description_creator_icc_v1 object is destroyed. A compositor shall not modify the contents of the file, and the fd may be sealed for writes and size changes. The client must ensure to its best ability that the data does not change while the compositor is reading it. The data must represent a valid ICC profile. The ICC profile version must be 2 or 4, it must be a 3 channel profile and the class must be Display or ColorSpace. Violating these requirements will not result in a protocol error, but will eventually send the wp_image_description_v1.failed event on the created wp_image_description_v1 with the 'unsupported' cause. See the International Color Consortium specification ICC.1:2022 for more details about ICC profiles. If ICC file has already been set on this object, the protocol error already_set is raised. | |
| 824 | + | func (o *WpImageDescriptionCreatorIcc) SetIccFile(iccProfile int, offset uint32, length uint32) error { | |
| 825 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_image_description_creator_icc_v1.set_icc_file", FDs: []int{iccProfile}}, wl.ArgFD(), wl.ArgUint(offset), wl.ArgUint(length)); err != nil { | |
| 826 | + | return err | |
| 827 | + | } | |
| 828 | + | return nil | |
| 829 | + | } | |
| 830 | + | ||
| 831 | + | // EventSignature returns the declared event argument types in wire order. | |
| 832 | + | func (o *WpImageDescriptionCreatorIcc) EventSignature(opcode uint16) (string, bool) { | |
| 833 | + | switch opcode { | |
| 834 | + | default: | |
| 835 | + | return "", false | |
| 836 | + | } | |
| 837 | + | } | |
| 838 | + | ||
| 839 | + | // Dispatch decodes one event on wp_image_description_creator_icc_v1 and calls the registered handlers. | |
| 840 | + | func (o *WpImageDescriptionCreatorIcc) Dispatch(event *wl.Event) { | |
| 841 | + | switch event.Opcode { | |
| 842 | + | default: | |
| 843 | + | } | |
| 844 | + | } | |
| 845 | + | ||
| 846 | + | // WpImageDescriptionCreatorParamsInterface is the protocol interface name. | |
| 847 | + | const WpImageDescriptionCreatorParamsInterface = "wp_image_description_creator_params_v1" | |
| 848 | + | ||
| 849 | + | // WpImageDescriptionCreatorParams is the generated binding for wp_image_description_creator_params_v1 version 3. | |
| 850 | + | type WpImageDescriptionCreatorParams struct { | |
| 851 | + | wl.BaseProxy | |
| 852 | + | } | |
| 853 | + | ||
| 854 | + | // NewWpImageDescriptionCreatorParams returns an unbound WpImageDescriptionCreatorParams. | |
| 855 | + | func NewWpImageDescriptionCreatorParams(ctx *wl.Context) *WpImageDescriptionCreatorParams { | |
| 856 | + | obj := &WpImageDescriptionCreatorParams{} | |
| 857 | + | obj.SetContext(ctx) | |
| 858 | + | ctx.Register(obj) | |
| 859 | + | return obj | |
| 860 | + | } | |
| 861 | + | ||
| 862 | + | // Create an image description object based on the parameters previously set on this object. The completeness of the parameter set is verified. If the set is not complete, the protocol error incomplete_set is raised. For the definition of a complete set, see the description of this interface. When both max_cll and max_fall are set, max_fall must be less or equal to max_cll otherwise the invalid_luminance protocol error is raised. In version 1, these following conditions also result in the invalid_luminance protocol error. Version 2 and later do not have this requirement. - When max_cll is set, it must be greater than min L and less or equal to max L of the mastering luminance range. - When max_fall is set, it must be greater than min L and less or equal to max L of the mastering luminance range. If the particular combination of the parameter set is not supported by the compositor, the resulting image description object shall immediately deliver the wp_image_description_v1.failed event with the 'unsupported' cause. If a valid image description was created from the parameter set, the wp_image_description_v1.ready event will eventually be sent instead. This request destroys the wp_image_description_creator_params_v1 object. The resulting image description object does not allow get_information request. | |
| 863 | + | func (o *WpImageDescriptionCreatorParams) Create() (*WpImageDescription, error) { | |
| 864 | + | child := &WpImageDescription{} | |
| 865 | + | child.SetContext(o.Context()) | |
| 866 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_image_description_creator_params_v1.create", Destructor: true, Child: child}, wl.ArgObject(child)); err != nil { | |
| 867 | + | return nil, err | |
| 868 | + | } | |
| 869 | + | return child, nil | |
| 870 | + | } | |
| 871 | + | ||
| 872 | + | // Sets the transfer characteristic using explicitly enumerated named functions. When the resulting image description is attached to an image, the content should be decoded according to the industry standard practices for the transfer characteristic. Only names advertised with wp_color_manager_v1 event supported_tf_named are allowed. Other values shall raise the protocol error invalid_tf. If transfer characteristic has already been set on this object, the protocol error already_set is raised. | |
| 873 | + | func (o *WpImageDescriptionCreatorParams) SetTfNamed(tf uint32) error { | |
| 874 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_image_description_creator_params_v1.set_tf_named"}, wl.ArgUint(tf)); err != nil { | |
| 875 | + | return err | |
| 876 | + | } | |
| 877 | + | return nil | |
| 878 | + | } | |
| 879 | + | ||
| 880 | + | // Sets the color component transfer characteristic to a power curve with the given exponent. Negative values are handled by mirroring the positive half of the curve through the origin. The valid domain and range of the curve are all finite real numbers. This curve represents the conversion from electrical to optical color channel values. The curve exponent shall be multiplied by 10000 to get the argument eexp value to carry the precision of 4 decimals. The curve exponent must be at least 1.0 and at most 10.0. Otherwise the protocol error invalid_tf is raised. If transfer characteristic has already been set on this object, the protocol error already_set is raised. This request can be used when the compositor advertises wp_color_manager_v1.feature.set_tf_power. Otherwise this request raises the protocol error unsupported_feature. | |
| 881 | + | func (o *WpImageDescriptionCreatorParams) SetTfPower(eexp uint32) error { | |
| 882 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wp_image_description_creator_params_v1.set_tf_power"}, wl.ArgUint(eexp)); err != nil { | |
| 883 | + | return err | |
| 884 | + | } | |
| 885 | + | return nil | |
| 886 | + | } | |
| 887 | + | ||
| 888 | + | // Sets the color primaries and white point using explicitly named sets. This describes the primary color volume which is the basis for color value encoding. Only names advertised with wp_color_manager_v1 event supported_primaries_named are allowed. Other values shall raise the protocol error invalid_primaries_named. If primaries have already been set on this object, the protocol error already_set is raised. | |
| 889 | + | func (o *WpImageDescriptionCreatorParams) SetPrimariesNamed(primaries uint32) error { | |
| 890 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "wp_image_description_creator_params_v1.set_primaries_named"}, wl.ArgUint(primaries)); err != nil { | |
| 891 | + | return err | |
| 892 | + | } | |
| 893 | + | return nil | |
| 894 | + | } | |
| 895 | + | ||
| 896 | + | // Sets the color primaries and white point using CIE 1931 xy chromaticity coordinates. This describes the primary color volume which is the basis for color value encoding. Each coordinate value is multiplied by 1 million to get the argument value to carry precision of 6 decimals. If primaries have already been set on this object, the protocol error already_set is raised. This request can be used if the compositor advertises wp_color_manager_v1.feature.set_primaries. Otherwise this request raises the protocol error unsupported_feature. | |
| 897 | + | func (o *WpImageDescriptionCreatorParams) SetPrimaries(rX int32, rY int32, gX int32, gY int32, bX int32, bY int32, wX int32, wY int32) error { | |
| 898 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 4, Name: "wp_image_description_creator_params_v1.set_primaries"}, wl.ArgInt(rX), wl.ArgInt(rY), wl.ArgInt(gX), wl.ArgInt(gY), wl.ArgInt(bX), wl.ArgInt(bY), wl.ArgInt(wX), wl.ArgInt(wY)); err != nil { | |
| 899 | + | return err | |
| 900 | + | } | |
| 901 | + | return nil | |
| 902 | + | } | |
| 903 | + | ||
| 904 | + | // Sets the primary color volume luminance range and the reference white luminance level. These values include the minimum display emission, but not external flare. The minimum display emission is assumed to have the chromaticity of the primary color volume white point. The default luminances from https://www.color.org/chardata/rgb/srgb.xalter are - primary color volume minimum: 0.2 cd/m² - primary color volume maximum: 80 cd/m² - reference white: 80 cd/m² Setting a named transfer characteristic can imply other default luminances. The default luminances get overwritten when this request is used. With transfer_function.st2084_pq the given 'max_lum' value is ignored, and 'max_lum' is taken as 'min_lum' + 10000 cd/m². 'min_lum' and 'max_lum' specify the minimum and maximum luminances of the primary color volume as reproduced by the targeted display. 'reference_lum' specifies the luminance of the reference white as reproduced by the targeted display, and reflects the targeted viewing environment. Compositors should make sure that all content is anchored, meaning that an input signal level of 'reference_lum' on one image description and another input signal level of 'reference_lum' on another image description should produce the same output level, even though the 'reference_lum' on both image representations can be different. 'reference_lum' may be higher than 'max_lum'. In that case reaching the reference white output level in image content requires the 'extended_target_volume' feature support. If 'max_lum' or 'reference_lum' are less than or equal to 'min_lum', the protocol error invalid_luminance is raised. The minimum luminance is multiplied by 10000 to get the argument 'min_lum' value and carries precision of 4 decimals. The maximum luminance and reference white luminance values are unscaled. If the primary color volume luminance range and the reference white luminance level have already been set on this object, the protocol error already_set is raised. This request can be used if the compositor advertises wp_color_manager_v1.feature.set_luminances. Otherwise this request raises the protocol error unsupported_feature. | |
| 905 | + | func (o *WpImageDescriptionCreatorParams) SetLuminances(minLum uint32, maxLum uint32, referenceLum uint32) error { | |
| 906 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 5, Name: "wp_image_description_creator_params_v1.set_luminances"}, wl.ArgUint(minLum), wl.ArgUint(maxLum), wl.ArgUint(referenceLum)); err != nil { | |
| 907 | + | return err | |
| 908 | + | } | |
| 909 | + | return nil | |
| 910 | + | } | |
| 911 | + | ||
| 912 | + | // Provides the color primaries and white point of the mastering display using CIE 1931 xy chromaticity coordinates. This is compatible with the SMPTE ST 2086 definition of HDR static metadata. The mastering display primaries and mastering display luminances define the target color volume. If mastering display primaries are not explicitly set, the target color volume is assumed to have the same primaries as the primary color volume. The target color volume is defined by all tristimulus values between 0.0 and 1.0 (inclusive) of the color space defined by the given mastering display primaries and white point. The colorimetry is identical between the container color space and the mastering display color space, including that no chromatic adaptation is applied even if the white points differ. The target color volume can exceed the primary color volume to allow for a greater color volume with an existing color space definition (for example scRGB). It can be smaller than the primary color volume to minimize gamut and tone mapping distances for big color spaces (HDR metadata). To make use of the entire target color volume a suitable pixel format has to be chosen (e.g. floating point to exceed the primary color volume, or abusing limited quantization range as with xvYCC). Each coordinate value is multiplied by 1 million to get the argument value to carry precision of 6 decimals. If mastering display primaries have already been set on this object, the protocol error already_set is raised. This request can be used if the compositor advertises wp_color_manager_v1.feature.set_mastering_display_primaries. Otherwise this request raises the protocol error unsupported_feature. The advertisement implies support only for target color volumes fully contained within the primary color volume. If a compositor additionally supports target color volume exceeding the primary color volume, it must advertise wp_color_manager_v1.feature.extended_target_volume. If a client uses target color volume exceeding the primary color volume and the compositor does not support it, the result is implementation defined. Compositors are recommended to detect this case and fail the image description gracefully, but it may as well result in color artifacts. | |
| 913 | + | func (o *WpImageDescriptionCreatorParams) SetMasteringDisplayPrimaries(rX int32, rY int32, gX int32, gY int32, bX int32, bY int32, wX int32, wY int32) error { | |
| 914 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 6, Name: "wp_image_description_creator_params_v1.set_mastering_display_primaries"}, wl.ArgInt(rX), wl.ArgInt(rY), wl.ArgInt(gX), wl.ArgInt(gY), wl.ArgInt(bX), wl.ArgInt(bY), wl.ArgInt(wX), wl.ArgInt(wY)); err != nil { | |
| 915 | + | return err | |
| 916 | + | } | |
| 917 | + | return nil | |
| 918 | + | } | |
| 919 | + | ||
| 920 | + | // Sets the luminance range that was used during the content mastering process as the minimum and maximum absolute luminance L. These values include the minimum display emission and ambient flare luminances, assumed to be optically additive and have the chromaticity of the primary color volume white point. This should be compatible with the SMPTE ST 2086 definition of HDR static metadata. The mastering display primaries and mastering display luminances define the target color volume. If mastering luminances are not explicitly set, the target color volume is assumed to have the same min and max luminances as the primary color volume. If max L is less than or equal to min L, the protocol error invalid_luminance is raised. Min L value is multiplied by 10000 to get the argument min_lum value and carry precision of 4 decimals. Max L value is unscaled for max_lum. This request can be used if the compositor advertises wp_color_manager_v1.feature.set_mastering_display_primaries. Otherwise this request raises the protocol error unsupported_feature. The advertisement implies support only for target color volumes fully contained within the primary color volume. If a compositor additionally supports target color volume exceeding the primary color volume, it must advertise wp_color_manager_v1.feature.extended_target_volume. If a client uses target color volume exceeding the primary color volume and the compositor does not support it, the result is implementation defined. Compositors are recommended to detect this case and fail the image description gracefully, but it may as well result in color artifacts. | |
| 921 | + | func (o *WpImageDescriptionCreatorParams) SetMasteringLuminance(minLum uint32, maxLum uint32) error { | |
| 922 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 7, Name: "wp_image_description_creator_params_v1.set_mastering_luminance"}, wl.ArgUint(minLum), wl.ArgUint(maxLum)); err != nil { | |
| 923 | + | return err | |
| 924 | + | } | |
| 925 | + | return nil | |
| 926 | + | } | |
| 927 | + | ||
| 928 | + | // Sets the maximum content light level (max_cll) as defined by CTA-861-H. max_cll is undefined by default. | |
| 929 | + | func (o *WpImageDescriptionCreatorParams) SetMaxCll(maxCll uint32) error { | |
| 930 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 8, Name: "wp_image_description_creator_params_v1.set_max_cll"}, wl.ArgUint(maxCll)); err != nil { | |
| 931 | + | return err | |
| 932 | + | } | |
| 933 | + | return nil | |
| 934 | + | } | |
| 935 | + | ||
| 936 | + | // Sets the maximum frame-average light level (max_fall) as defined by CTA-861-H. max_fall is undefined by default. | |
| 937 | + | func (o *WpImageDescriptionCreatorParams) SetMaxFall(maxFall uint32) error { | |
| 938 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 9, Name: "wp_image_description_creator_params_v1.set_max_fall"}, wl.ArgUint(maxFall)); err != nil { | |
| 939 | + | return err | |
| 940 | + | } | |
| 941 | + | return nil | |
| 942 | + | } | |
| 943 | + | ||
| 944 | + | // EventSignature returns the declared event argument types in wire order. | |
| 945 | + | func (o *WpImageDescriptionCreatorParams) EventSignature(opcode uint16) (string, bool) { | |
| 946 | + | switch opcode { | |
| 947 | + | default: | |
| 948 | + | return "", false | |
| 949 | + | } | |
| 950 | + | } | |
| 951 | + | ||
| 952 | + | // Dispatch decodes one event on wp_image_description_creator_params_v1 and calls the registered handlers. | |
| 953 | + | func (o *WpImageDescriptionCreatorParams) Dispatch(event *wl.Event) { | |
| 954 | + | switch event.Opcode { | |
| 955 | + | default: | |
| 956 | + | } | |
| 957 | + | } | |
| 958 | + | ||
| 959 | + | // WpImageDescriptionInterface is the protocol interface name. | |
| 960 | + | const WpImageDescriptionInterface = "wp_image_description_v1" | |
| 961 | + | ||
| 962 | + | // WpImageDescription is the generated binding for wp_image_description_v1 version 3. | |
| 963 | + | type WpImageDescription struct { | |
| 964 | + | wl.BaseProxy | |
| 965 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 966 | + | // handlers while another goroutine dispatches events. | |
| 967 | + | handlersMu sync.Mutex | |
| 968 | + | onFailed []func(cause uint32, msg string) | |
| 969 | + | onReady []func(identity uint32) | |
| 970 | + | onReady2 []func(identityHi uint32, identityLo uint32) | |
| 971 | + | } | |
| 972 | + | ||
| 973 | + | // NewWpImageDescription returns an unbound WpImageDescription. | |
| 974 | + | func NewWpImageDescription(ctx *wl.Context) *WpImageDescription { | |
| 975 | + | obj := &WpImageDescription{} | |
| 976 | + | obj.SetContext(ctx) | |
| 977 | + | ctx.Register(obj) | |
| 978 | + | return obj | |
| 979 | + | } | |
| 980 | + | ||
| 981 | + | // Destroy this object. It is safe to destroy an object which is not ready. Destroying a wp_image_description_v1 object has no side-effects, not even if a wp_color_management_surface_v1.set_image_description has not yet been followed by a wl_surface.commit. | |
| 982 | + | func (o *WpImageDescription) Destroy() error { | |
| 983 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_image_description_v1.destroy", Destructor: true}); err != nil { | |
| 984 | + | return err | |
| 985 | + | } | |
| 986 | + | return nil | |
| 987 | + | } | |
| 988 | + | ||
| 989 | + | // Creates a wp_image_description_info_v1 object which delivers the information that makes up the image description. Not all image description protocol objects allow get_information request. Whether it is allowed or not is defined by the request that created the object. If get_information is not allowed, the protocol error no_information is raised. | |
| 990 | + | func (o *WpImageDescription) GetInformation() (*WpImageDescriptionInfo, error) { | |
| 991 | + | child := &WpImageDescriptionInfo{} | |
| 992 | + | child.SetContext(o.Context()) | |
| 993 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_image_description_v1.get_information", Child: child}, wl.ArgObject(child)); err != nil { | |
| 994 | + | return nil, err | |
| 995 | + | } | |
| 996 | + | return child, nil | |
| 997 | + | } | |
| 998 | + | ||
| 999 | + | // OnFailed registers a handler for the failed event. | |
| 1000 | + | // | |
| 1001 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1002 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1003 | + | func (o *WpImageDescription) OnFailed(handler func(cause uint32, msg string)) { | |
| 1004 | + | if handler == nil { | |
| 1005 | + | return | |
| 1006 | + | } | |
| 1007 | + | o.handlersMu.Lock() | |
| 1008 | + | defer o.handlersMu.Unlock() | |
| 1009 | + | o.onFailed = append(o.onFailed, handler) | |
| 1010 | + | } | |
| 1011 | + | ||
| 1012 | + | // handlersForFailed returns the handlers registered for failed, taken | |
| 1013 | + | // under the lock so a handler may register another handler while events are | |
| 1014 | + | // being dispatched. | |
| 1015 | + | func (o *WpImageDescription) handlersForFailed() []func(cause uint32, msg string) { | |
| 1016 | + | o.handlersMu.Lock() | |
| 1017 | + | defer o.handlersMu.Unlock() | |
| 1018 | + | return o.onFailed | |
| 1019 | + | } | |
| 1020 | + | ||
| 1021 | + | // OnReady registers a handler for the ready event. | |
| 1022 | + | // | |
| 1023 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1024 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1025 | + | func (o *WpImageDescription) OnReady(handler func(identity uint32)) { | |
| 1026 | + | if handler == nil { | |
| 1027 | + | return | |
| 1028 | + | } | |
| 1029 | + | o.handlersMu.Lock() | |
| 1030 | + | defer o.handlersMu.Unlock() | |
| 1031 | + | o.onReady = append(o.onReady, handler) | |
| 1032 | + | } | |
| 1033 | + | ||
| 1034 | + | // handlersForReady returns the handlers registered for ready, taken | |
| 1035 | + | // under the lock so a handler may register another handler while events are | |
| 1036 | + | // being dispatched. | |
| 1037 | + | func (o *WpImageDescription) handlersForReady() []func(identity uint32) { | |
| 1038 | + | o.handlersMu.Lock() | |
| 1039 | + | defer o.handlersMu.Unlock() | |
| 1040 | + | return o.onReady | |
| 1041 | + | } | |
| 1042 | + | ||
| 1043 | + | // OnReady2 registers a handler for the ready2 event. | |
| 1044 | + | // | |
| 1045 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1046 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1047 | + | func (o *WpImageDescription) OnReady2(handler func(identityHi uint32, identityLo uint32)) { | |
| 1048 | + | if handler == nil { | |
| 1049 | + | return | |
| 1050 | + | } | |
| 1051 | + | o.handlersMu.Lock() | |
| 1052 | + | defer o.handlersMu.Unlock() | |
| 1053 | + | o.onReady2 = append(o.onReady2, handler) | |
| 1054 | + | } | |
| 1055 | + | ||
| 1056 | + | // handlersForReady2 returns the handlers registered for ready2, taken | |
| 1057 | + | // under the lock so a handler may register another handler while events are | |
| 1058 | + | // being dispatched. | |
| 1059 | + | func (o *WpImageDescription) handlersForReady2() []func(identityHi uint32, identityLo uint32) { | |
| 1060 | + | o.handlersMu.Lock() | |
| 1061 | + | defer o.handlersMu.Unlock() | |
| 1062 | + | return o.onReady2 | |
| 1063 | + | } | |
| 1064 | + | ||
| 1065 | + | // EventSignature returns the declared event argument types in wire order. | |
| 1066 | + | func (o *WpImageDescription) EventSignature(opcode uint16) (string, bool) { | |
| 1067 | + | switch opcode { | |
| 1068 | + | case 0: | |
| 1069 | + | return "uint,string,", true | |
| 1070 | + | case 1: | |
| 1071 | + | return "uint,", true | |
| 1072 | + | case 2: | |
| 1073 | + | return "uint,uint,", true | |
| 1074 | + | default: | |
| 1075 | + | return "", false | |
| 1076 | + | } | |
| 1077 | + | } | |
| 1078 | + | ||
| 1079 | + | // Dispatch decodes one event on wp_image_description_v1 and calls the registered handlers. | |
| 1080 | + | func (o *WpImageDescription) Dispatch(event *wl.Event) { | |
| 1081 | + | switch event.Opcode { | |
| 1082 | + | case 0: // failed | |
| 1083 | + | cause := event.Uint32() | |
| 1084 | + | msg := event.String() | |
| 1085 | + | ||
| 1086 | + | for i, handler := range o.handlersForFailed() { | |
| 1087 | + | _ = i | |
| 1088 | + | handler(cause, msg) | |
| 1089 | + | } | |
| 1090 | + | case 1: // ready | |
| 1091 | + | identity := event.Uint32() | |
| 1092 | + | ||
| 1093 | + | for i, handler := range o.handlersForReady() { | |
| 1094 | + | _ = i | |
| 1095 | + | handler(identity) | |
| 1096 | + | } | |
| 1097 | + | case 2: // ready2 | |
| 1098 | + | identityHi := event.Uint32() | |
| 1099 | + | identityLo := event.Uint32() | |
| 1100 | + | ||
| 1101 | + | for i, handler := range o.handlersForReady2() { | |
| 1102 | + | _ = i | |
| 1103 | + | handler(identityHi, identityLo) | |
| 1104 | + | } | |
| 1105 | + | default: | |
| 1106 | + | } | |
| 1107 | + | } | |
| 1108 | + | ||
| 1109 | + | // WpImageDescriptionInfoInterface is the protocol interface name. | |
| 1110 | + | const WpImageDescriptionInfoInterface = "wp_image_description_info_v1" | |
| 1111 | + | ||
| 1112 | + | // WpImageDescriptionInfo is the generated binding for wp_image_description_info_v1 version 3. | |
| 1113 | + | type WpImageDescriptionInfo struct { | |
| 1114 | + | wl.BaseProxy | |
| 1115 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 1116 | + | // handlers while another goroutine dispatches events. | |
| 1117 | + | handlersMu sync.Mutex | |
| 1118 | + | onDone []func() | |
| 1119 | + | onIccFile []func(icc *wl.OwnedFD, iccSize uint32) | |
| 1120 | + | onPrimaries []func(rX int32, rY int32, gX int32, gY int32, bX int32, bY int32, wX int32, wY int32) | |
| 1121 | + | onPrimariesNamed []func(primaries uint32) | |
| 1122 | + | onTfPower []func(eexp uint32) | |
| 1123 | + | onTfNamed []func(tf uint32) | |
| 1124 | + | onLuminances []func(minLum uint32, maxLum uint32, referenceLum uint32) | |
| 1125 | + | onTargetPrimaries []func(rX int32, rY int32, gX int32, gY int32, bX int32, bY int32, wX int32, wY int32) | |
| 1126 | + | onTargetLuminance []func(minLum uint32, maxLum uint32) | |
| 1127 | + | onTargetMaxCll []func(maxCll uint32) | |
| 1128 | + | onTargetMaxFall []func(maxFall uint32) | |
| 1129 | + | } | |
| 1130 | + | ||
| 1131 | + | // NewWpImageDescriptionInfo returns an unbound WpImageDescriptionInfo. | |
| 1132 | + | func NewWpImageDescriptionInfo(ctx *wl.Context) *WpImageDescriptionInfo { | |
| 1133 | + | obj := &WpImageDescriptionInfo{} | |
| 1134 | + | obj.SetContext(ctx) | |
| 1135 | + | ctx.Register(obj) | |
| 1136 | + | return obj | |
| 1137 | + | } | |
| 1138 | + | ||
| 1139 | + | // OnDone registers a handler for the done event. | |
| 1140 | + | // | |
| 1141 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1142 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1143 | + | func (o *WpImageDescriptionInfo) OnDone(handler func()) { | |
| 1144 | + | if handler == nil { | |
| 1145 | + | return | |
| 1146 | + | } | |
| 1147 | + | o.handlersMu.Lock() | |
| 1148 | + | defer o.handlersMu.Unlock() | |
| 1149 | + | o.onDone = append(o.onDone, handler) | |
| 1150 | + | } | |
| 1151 | + | ||
| 1152 | + | // handlersForDone returns the handlers registered for done, taken | |
| 1153 | + | // under the lock so a handler may register another handler while events are | |
| 1154 | + | // being dispatched. | |
| 1155 | + | func (o *WpImageDescriptionInfo) handlersForDone() []func() { | |
| 1156 | + | o.handlersMu.Lock() | |
| 1157 | + | defer o.handlersMu.Unlock() | |
| 1158 | + | return o.onDone | |
| 1159 | + | } | |
| 1160 | + | ||
| 1161 | + | // OnIccFile registers a handler for the icc_file event. | |
| 1162 | + | // | |
| 1163 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1164 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1165 | + | func (o *WpImageDescriptionInfo) OnIccFile(handler func(icc *wl.OwnedFD, iccSize uint32)) { | |
| 1166 | + | if handler == nil { | |
| 1167 | + | return | |
| 1168 | + | } | |
| 1169 | + | o.handlersMu.Lock() | |
| 1170 | + | defer o.handlersMu.Unlock() | |
| 1171 | + | o.onIccFile = append(o.onIccFile, handler) | |
| 1172 | + | } | |
| 1173 | + | ||
| 1174 | + | // handlersForIccFile returns the handlers registered for icc_file, taken | |
| 1175 | + | // under the lock so a handler may register another handler while events are | |
| 1176 | + | // being dispatched. | |
| 1177 | + | func (o *WpImageDescriptionInfo) handlersForIccFile() []func(icc *wl.OwnedFD, iccSize uint32) { | |
| 1178 | + | o.handlersMu.Lock() | |
| 1179 | + | defer o.handlersMu.Unlock() | |
| 1180 | + | return o.onIccFile | |
| 1181 | + | } | |
| 1182 | + | ||
| 1183 | + | // OnPrimaries registers a handler for the primaries event. | |
| 1184 | + | // | |
| 1185 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1186 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1187 | + | func (o *WpImageDescriptionInfo) OnPrimaries(handler func(rX int32, rY int32, gX int32, gY int32, bX int32, bY int32, wX int32, wY int32)) { | |
| 1188 | + | if handler == nil { | |
| 1189 | + | return | |
| 1190 | + | } | |
| 1191 | + | o.handlersMu.Lock() | |
| 1192 | + | defer o.handlersMu.Unlock() | |
| 1193 | + | o.onPrimaries = append(o.onPrimaries, handler) | |
| 1194 | + | } | |
| 1195 | + | ||
| 1196 | + | // handlersForPrimaries returns the handlers registered for primaries, taken | |
| 1197 | + | // under the lock so a handler may register another handler while events are | |
| 1198 | + | // being dispatched. | |
| 1199 | + | func (o *WpImageDescriptionInfo) handlersForPrimaries() []func(rX int32, rY int32, gX int32, gY int32, bX int32, bY int32, wX int32, wY int32) { | |
| 1200 | + | o.handlersMu.Lock() | |
| 1201 | + | defer o.handlersMu.Unlock() | |
| 1202 | + | return o.onPrimaries | |
| 1203 | + | } | |
| 1204 | + | ||
| 1205 | + | // OnPrimariesNamed registers a handler for the primaries_named event. | |
| 1206 | + | // | |
| 1207 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1208 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1209 | + | func (o *WpImageDescriptionInfo) OnPrimariesNamed(handler func(primaries uint32)) { | |
| 1210 | + | if handler == nil { | |
| 1211 | + | return | |
| 1212 | + | } | |
| 1213 | + | o.handlersMu.Lock() | |
| 1214 | + | defer o.handlersMu.Unlock() | |
| 1215 | + | o.onPrimariesNamed = append(o.onPrimariesNamed, handler) | |
| 1216 | + | } | |
| 1217 | + | ||
| 1218 | + | // handlersForPrimariesNamed returns the handlers registered for primaries_named, taken | |
| 1219 | + | // under the lock so a handler may register another handler while events are | |
| 1220 | + | // being dispatched. | |
| 1221 | + | func (o *WpImageDescriptionInfo) handlersForPrimariesNamed() []func(primaries uint32) { | |
| 1222 | + | o.handlersMu.Lock() | |
| 1223 | + | defer o.handlersMu.Unlock() | |
| 1224 | + | return o.onPrimariesNamed | |
| 1225 | + | } | |
| 1226 | + | ||
| 1227 | + | // OnTfPower registers a handler for the tf_power event. | |
| 1228 | + | // | |
| 1229 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1230 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1231 | + | func (o *WpImageDescriptionInfo) OnTfPower(handler func(eexp uint32)) { | |
| 1232 | + | if handler == nil { | |
| 1233 | + | return | |
| 1234 | + | } | |
| 1235 | + | o.handlersMu.Lock() | |
| 1236 | + | defer o.handlersMu.Unlock() | |
| 1237 | + | o.onTfPower = append(o.onTfPower, handler) | |
| 1238 | + | } | |
| 1239 | + | ||
| 1240 | + | // handlersForTfPower returns the handlers registered for tf_power, taken | |
| 1241 | + | // under the lock so a handler may register another handler while events are | |
| 1242 | + | // being dispatched. | |
| 1243 | + | func (o *WpImageDescriptionInfo) handlersForTfPower() []func(eexp uint32) { | |
| 1244 | + | o.handlersMu.Lock() | |
| 1245 | + | defer o.handlersMu.Unlock() | |
| 1246 | + | return o.onTfPower | |
| 1247 | + | } | |
| 1248 | + | ||
| 1249 | + | // OnTfNamed registers a handler for the tf_named event. | |
| 1250 | + | // | |
| 1251 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1252 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1253 | + | func (o *WpImageDescriptionInfo) OnTfNamed(handler func(tf uint32)) { | |
| 1254 | + | if handler == nil { | |
| 1255 | + | return | |
| 1256 | + | } | |
| 1257 | + | o.handlersMu.Lock() | |
| 1258 | + | defer o.handlersMu.Unlock() | |
| 1259 | + | o.onTfNamed = append(o.onTfNamed, handler) | |
| 1260 | + | } | |
| 1261 | + | ||
| 1262 | + | // handlersForTfNamed returns the handlers registered for tf_named, taken | |
| 1263 | + | // under the lock so a handler may register another handler while events are | |
| 1264 | + | // being dispatched. | |
| 1265 | + | func (o *WpImageDescriptionInfo) handlersForTfNamed() []func(tf uint32) { | |
| 1266 | + | o.handlersMu.Lock() | |
| 1267 | + | defer o.handlersMu.Unlock() | |
| 1268 | + | return o.onTfNamed | |
| 1269 | + | } | |
| 1270 | + | ||
| 1271 | + | // OnLuminances registers a handler for the luminances event. | |
| 1272 | + | // | |
| 1273 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1274 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1275 | + | func (o *WpImageDescriptionInfo) OnLuminances(handler func(minLum uint32, maxLum uint32, referenceLum uint32)) { | |
| 1276 | + | if handler == nil { | |
| 1277 | + | return | |
| 1278 | + | } | |
| 1279 | + | o.handlersMu.Lock() | |
| 1280 | + | defer o.handlersMu.Unlock() | |
| 1281 | + | o.onLuminances = append(o.onLuminances, handler) | |
| 1282 | + | } | |
| 1283 | + | ||
| 1284 | + | // handlersForLuminances returns the handlers registered for luminances, taken | |
| 1285 | + | // under the lock so a handler may register another handler while events are | |
| 1286 | + | // being dispatched. | |
| 1287 | + | func (o *WpImageDescriptionInfo) handlersForLuminances() []func(minLum uint32, maxLum uint32, referenceLum uint32) { | |
| 1288 | + | o.handlersMu.Lock() | |
| 1289 | + | defer o.handlersMu.Unlock() | |
| 1290 | + | return o.onLuminances | |
| 1291 | + | } | |
| 1292 | + | ||
| 1293 | + | // OnTargetPrimaries registers a handler for the target_primaries event. | |
| 1294 | + | // | |
| 1295 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1296 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1297 | + | func (o *WpImageDescriptionInfo) OnTargetPrimaries(handler func(rX int32, rY int32, gX int32, gY int32, bX int32, bY int32, wX int32, wY int32)) { | |
| 1298 | + | if handler == nil { | |
| 1299 | + | return | |
| 1300 | + | } | |
| 1301 | + | o.handlersMu.Lock() | |
| 1302 | + | defer o.handlersMu.Unlock() | |
| 1303 | + | o.onTargetPrimaries = append(o.onTargetPrimaries, handler) | |
| 1304 | + | } | |
| 1305 | + | ||
| 1306 | + | // handlersForTargetPrimaries returns the handlers registered for target_primaries, taken | |
| 1307 | + | // under the lock so a handler may register another handler while events are | |
| 1308 | + | // being dispatched. | |
| 1309 | + | func (o *WpImageDescriptionInfo) handlersForTargetPrimaries() []func(rX int32, rY int32, gX int32, gY int32, bX int32, bY int32, wX int32, wY int32) { | |
| 1310 | + | o.handlersMu.Lock() | |
| 1311 | + | defer o.handlersMu.Unlock() | |
| 1312 | + | return o.onTargetPrimaries | |
| 1313 | + | } | |
| 1314 | + | ||
| 1315 | + | // OnTargetLuminance registers a handler for the target_luminance event. | |
| 1316 | + | // | |
| 1317 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1318 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1319 | + | func (o *WpImageDescriptionInfo) OnTargetLuminance(handler func(minLum uint32, maxLum uint32)) { | |
| 1320 | + | if handler == nil { | |
| 1321 | + | return | |
| 1322 | + | } | |
| 1323 | + | o.handlersMu.Lock() | |
| 1324 | + | defer o.handlersMu.Unlock() | |
| 1325 | + | o.onTargetLuminance = append(o.onTargetLuminance, handler) | |
| 1326 | + | } | |
| 1327 | + | ||
| 1328 | + | // handlersForTargetLuminance returns the handlers registered for target_luminance, taken | |
| 1329 | + | // under the lock so a handler may register another handler while events are | |
| 1330 | + | // being dispatched. | |
| 1331 | + | func (o *WpImageDescriptionInfo) handlersForTargetLuminance() []func(minLum uint32, maxLum uint32) { | |
| 1332 | + | o.handlersMu.Lock() | |
| 1333 | + | defer o.handlersMu.Unlock() | |
| 1334 | + | return o.onTargetLuminance | |
| 1335 | + | } | |
| 1336 | + | ||
| 1337 | + | // OnTargetMaxCll registers a handler for the target_max_cll event. | |
| 1338 | + | // | |
| 1339 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1340 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1341 | + | func (o *WpImageDescriptionInfo) OnTargetMaxCll(handler func(maxCll uint32)) { | |
| 1342 | + | if handler == nil { | |
| 1343 | + | return | |
| 1344 | + | } | |
| 1345 | + | o.handlersMu.Lock() | |
| 1346 | + | defer o.handlersMu.Unlock() | |
| 1347 | + | o.onTargetMaxCll = append(o.onTargetMaxCll, handler) | |
| 1348 | + | } | |
| 1349 | + | ||
| 1350 | + | // handlersForTargetMaxCll returns the handlers registered for target_max_cll, taken | |
| 1351 | + | // under the lock so a handler may register another handler while events are | |
| 1352 | + | // being dispatched. | |
| 1353 | + | func (o *WpImageDescriptionInfo) handlersForTargetMaxCll() []func(maxCll uint32) { | |
| 1354 | + | o.handlersMu.Lock() | |
| 1355 | + | defer o.handlersMu.Unlock() | |
| 1356 | + | return o.onTargetMaxCll | |
| 1357 | + | } | |
| 1358 | + | ||
| 1359 | + | // OnTargetMaxFall registers a handler for the target_max_fall event. | |
| 1360 | + | // | |
| 1361 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1362 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1363 | + | func (o *WpImageDescriptionInfo) OnTargetMaxFall(handler func(maxFall uint32)) { | |
| 1364 | + | if handler == nil { | |
| 1365 | + | return | |
| 1366 | + | } | |
| 1367 | + | o.handlersMu.Lock() | |
| 1368 | + | defer o.handlersMu.Unlock() | |
| 1369 | + | o.onTargetMaxFall = append(o.onTargetMaxFall, handler) | |
| 1370 | + | } | |
| 1371 | + | ||
| 1372 | + | // handlersForTargetMaxFall returns the handlers registered for target_max_fall, taken | |
| 1373 | + | // under the lock so a handler may register another handler while events are | |
| 1374 | + | // being dispatched. | |
| 1375 | + | func (o *WpImageDescriptionInfo) handlersForTargetMaxFall() []func(maxFall uint32) { | |
| 1376 | + | o.handlersMu.Lock() | |
| 1377 | + | defer o.handlersMu.Unlock() | |
| 1378 | + | return o.onTargetMaxFall | |
| 1379 | + | } | |
| 1380 | + | ||
| 1381 | + | // EventSignature returns the declared event argument types in wire order. | |
| 1382 | + | func (o *WpImageDescriptionInfo) EventSignature(opcode uint16) (string, bool) { | |
| 1383 | + | switch opcode { | |
| 1384 | + | case 0: | |
| 1385 | + | return "", true | |
| 1386 | + | case 1: | |
| 1387 | + | return "fd,uint,", true | |
| 1388 | + | case 2: | |
| 1389 | + | return "int,int,int,int,int,int,int,int,", true | |
| 1390 | + | case 3: | |
| 1391 | + | return "uint,", true | |
| 1392 | + | case 4: | |
| 1393 | + | return "uint,", true | |
| 1394 | + | case 5: | |
| 1395 | + | return "uint,", true | |
| 1396 | + | case 6: | |
| 1397 | + | return "uint,uint,uint,", true | |
| 1398 | + | case 7: | |
| 1399 | + | return "int,int,int,int,int,int,int,int,", true | |
| 1400 | + | case 8: | |
| 1401 | + | return "uint,uint,", true | |
| 1402 | + | case 9: | |
| 1403 | + | return "uint,", true | |
| 1404 | + | case 10: | |
| 1405 | + | return "uint,", true | |
| 1406 | + | default: | |
| 1407 | + | return "", false | |
| 1408 | + | } | |
| 1409 | + | } | |
| 1410 | + | ||
| 1411 | + | // Dispatch decodes one event on wp_image_description_info_v1 and calls the registered handlers. | |
| 1412 | + | func (o *WpImageDescriptionInfo) Dispatch(event *wl.Event) { | |
| 1413 | + | switch event.Opcode { | |
| 1414 | + | case 0: // done | |
| 1415 | + | ||
| 1416 | + | for i, handler := range o.handlersForDone() { | |
| 1417 | + | _ = i | |
| 1418 | + | handler() | |
| 1419 | + | } | |
| 1420 | + | o.Context().Unregister(o) | |
| 1421 | + | case 1: // icc_file | |
| 1422 | + | icc := event.FD() | |
| 1423 | + | iccSize := event.Uint32() | |
| 1424 | + | ownedicc := icc | |
| 1425 | + | defer ownedicc.Close() | |
| 1426 | + | ||
| 1427 | + | for i, handler := range o.handlersForIccFile() { | |
| 1428 | + | if i > 0 { | |
| 1429 | + | icc = nil | |
| 1430 | + | } | |
| 1431 | + | handler(icc, iccSize) | |
| 1432 | + | } | |
| 1433 | + | case 2: // primaries | |
| 1434 | + | rX := event.Int32() | |
| 1435 | + | rY := event.Int32() | |
| 1436 | + | gX := event.Int32() | |
| 1437 | + | gY := event.Int32() | |
| 1438 | + | bX := event.Int32() | |
| 1439 | + | bY := event.Int32() | |
| 1440 | + | wX := event.Int32() | |
| 1441 | + | wY := event.Int32() | |
| 1442 | + | ||
| 1443 | + | for i, handler := range o.handlersForPrimaries() { | |
| 1444 | + | _ = i | |
| 1445 | + | handler(rX, rY, gX, gY, bX, bY, wX, wY) | |
| 1446 | + | } | |
| 1447 | + | case 3: // primaries_named | |
| 1448 | + | primaries := event.Uint32() | |
| 1449 | + | ||
| 1450 | + | for i, handler := range o.handlersForPrimariesNamed() { | |
| 1451 | + | _ = i | |
| 1452 | + | handler(primaries) | |
| 1453 | + | } | |
| 1454 | + | case 4: // tf_power | |
| 1455 | + | eexp := event.Uint32() | |
| 1456 | + | ||
| 1457 | + | for i, handler := range o.handlersForTfPower() { | |
| 1458 | + | _ = i | |
| 1459 | + | handler(eexp) | |
| 1460 | + | } | |
| 1461 | + | case 5: // tf_named | |
| 1462 | + | tf := event.Uint32() | |
| 1463 | + | ||
| 1464 | + | for i, handler := range o.handlersForTfNamed() { | |
| 1465 | + | _ = i | |
| 1466 | + | handler(tf) | |
| 1467 | + | } | |
| 1468 | + | case 6: // luminances | |
| 1469 | + | minLum := event.Uint32() | |
| 1470 | + | maxLum := event.Uint32() | |
| 1471 | + | referenceLum := event.Uint32() | |
| 1472 | + | ||
| 1473 | + | for i, handler := range o.handlersForLuminances() { | |
| 1474 | + | _ = i | |
| 1475 | + | handler(minLum, maxLum, referenceLum) | |
| 1476 | + | } | |
| 1477 | + | case 7: // target_primaries | |
| 1478 | + | rX := event.Int32() | |
| 1479 | + | rY := event.Int32() | |
| 1480 | + | gX := event.Int32() | |
| 1481 | + | gY := event.Int32() | |
| 1482 | + | bX := event.Int32() | |
| 1483 | + | bY := event.Int32() | |
| 1484 | + | wX := event.Int32() | |
| 1485 | + | wY := event.Int32() | |
| 1486 | + | ||
| 1487 | + | for i, handler := range o.handlersForTargetPrimaries() { | |
| 1488 | + | _ = i | |
| 1489 | + | handler(rX, rY, gX, gY, bX, bY, wX, wY) | |
| 1490 | + | } | |
| 1491 | + | case 8: // target_luminance | |
| 1492 | + | minLum := event.Uint32() | |
| 1493 | + | maxLum := event.Uint32() | |
| 1494 | + | ||
| 1495 | + | for i, handler := range o.handlersForTargetLuminance() { | |
| 1496 | + | _ = i | |
| 1497 | + | handler(minLum, maxLum) | |
| 1498 | + | } | |
| 1499 | + | case 9: // target_max_cll | |
| 1500 | + | maxCll := event.Uint32() | |
| 1501 | + | ||
| 1502 | + | for i, handler := range o.handlersForTargetMaxCll() { | |
| 1503 | + | _ = i | |
| 1504 | + | handler(maxCll) | |
| 1505 | + | } | |
| 1506 | + | case 10: // target_max_fall | |
| 1507 | + | maxFall := event.Uint32() | |
| 1508 | + | ||
| 1509 | + | for i, handler := range o.handlersForTargetMaxFall() { | |
| 1510 | + | _ = i | |
| 1511 | + | handler(maxFall) | |
| 1512 | + | } | |
| 1513 | + | default: | |
| 1514 | + | } | |
| 1515 | + | } | |
| 1516 | + | ||
| 1517 | + | // WpImageDescriptionReferenceInterface is the protocol interface name. | |
| 1518 | + | const WpImageDescriptionReferenceInterface = "wp_image_description_reference_v1" | |
| 1519 | + | ||
| 1520 | + | // WpImageDescriptionReference is the generated binding for wp_image_description_reference_v1 version 1. | |
| 1521 | + | type WpImageDescriptionReference struct { | |
| 1522 | + | wl.BaseProxy | |
| 1523 | + | } | |
| 1524 | + | ||
| 1525 | + | // NewWpImageDescriptionReference returns an unbound WpImageDescriptionReference. | |
| 1526 | + | func NewWpImageDescriptionReference(ctx *wl.Context) *WpImageDescriptionReference { | |
| 1527 | + | obj := &WpImageDescriptionReference{} | |
| 1528 | + | obj.SetContext(ctx) | |
| 1529 | + | ctx.Register(obj) | |
| 1530 | + | return obj | |
| 1531 | + | } | |
| 1532 | + | ||
| 1533 | + | // Destroy this object. This has no effect on the referenced image description. | |
| 1534 | + | func (o *WpImageDescriptionReference) Destroy() error { | |
| 1535 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_image_description_reference_v1.destroy", Destructor: true}); err != nil { | |
| 1536 | + | return err | |
| 1537 | + | } | |
| 1538 | + | return nil | |
| 1539 | + | } | |
| 1540 | + | ||
| 1541 | + | // EventSignature returns the declared event argument types in wire order. | |
| 1542 | + | func (o *WpImageDescriptionReference) EventSignature(opcode uint16) (string, bool) { | |
| 1543 | + | switch opcode { | |
| 1544 | + | default: | |
| 1545 | + | return "", false | |
| 1546 | + | } | |
| 1547 | + | } | |
| 1548 | + | ||
| 1549 | + | // Dispatch decodes one event on wp_image_description_reference_v1 and calls the registered handlers. | |
| 1550 | + | func (o *WpImageDescriptionReference) Dispatch(event *wl.Event) { | |
| 1551 | + | switch event.Opcode { | |
| 1552 | + | default: | |
| 1553 | + | } | |
| 1554 | + | } | |
A client/colorrepresentation/colorrepresentation_generated.go +327 -0
| @@ -0,0 +1,327 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: color_representation_v1 | |
| 3 | + | // Source: color-representation-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright 2022 Simon Ser | |
| 7 | + | // Copyright 2022 Red Hat, Inc. | |
| 8 | + | // Copyright 2022 Collabora, Ltd. | |
| 9 | + | // Copyright 2022-2025 Red Hat, Inc. | |
| 10 | + | // | |
| 11 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 12 | + | // copy of this software and associated documentation files (the "Software"), | |
| 13 | + | // to deal in the Software without restriction, including without limitation | |
| 14 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 15 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 16 | + | // Software is furnished to do so, subject to the following conditions: | |
| 17 | + | // | |
| 18 | + | // The above copyright notice and this permission notice (including the next | |
| 19 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 20 | + | // Software. | |
| 21 | + | // | |
| 22 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 23 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 24 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 25 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 26 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 27 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 28 | + | // DEALINGS IN THE SOFTWARE. | |
| 29 | + | ||
| 30 | + | package colorrepresentation | |
| 31 | + | ||
| 32 | + | import ( | |
| 33 | + | "sync" | |
| 34 | + | ||
| 35 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 36 | + | "github.com/bnema/wlturbo/wl" | |
| 37 | + | ) | |
| 38 | + | ||
| 39 | + | // ERROR_SURFACE_EXISTS is the error surface_exists value. | |
| 40 | + | const ERROR_SURFACE_EXISTS = 1 | |
| 41 | + | ||
| 42 | + | // ERROR_ALPHA_MODE is the error alpha_mode value. | |
| 43 | + | const ERROR_ALPHA_MODE = 1 | |
| 44 | + | ||
| 45 | + | // ERROR_COEFFICIENTS is the error coefficients value. | |
| 46 | + | const ERROR_COEFFICIENTS = 2 | |
| 47 | + | ||
| 48 | + | // ERROR_PIXEL_FORMAT is the error pixel_format value. | |
| 49 | + | const ERROR_PIXEL_FORMAT = 3 | |
| 50 | + | ||
| 51 | + | // ERROR_INERT is the error inert value. | |
| 52 | + | const ERROR_INERT = 4 | |
| 53 | + | ||
| 54 | + | // ERROR_CHROMA_LOCATION is the error chroma_location value. | |
| 55 | + | const ERROR_CHROMA_LOCATION = 5 | |
| 56 | + | ||
| 57 | + | // ALPHA_MODE_PREMULTIPLIED_ELECTRICAL is the alpha_mode premultiplied_electrical value. | |
| 58 | + | const ALPHA_MODE_PREMULTIPLIED_ELECTRICAL = 0 | |
| 59 | + | ||
| 60 | + | // ALPHA_MODE_PREMULTIPLIED_OPTICAL is the alpha_mode premultiplied_optical value. | |
| 61 | + | const ALPHA_MODE_PREMULTIPLIED_OPTICAL = 1 | |
| 62 | + | ||
| 63 | + | // ALPHA_MODE_STRAIGHT is the alpha_mode straight value. | |
| 64 | + | const ALPHA_MODE_STRAIGHT = 2 | |
| 65 | + | ||
| 66 | + | // COEFFICIENTS_IDENTITY is the coefficients identity value. | |
| 67 | + | const COEFFICIENTS_IDENTITY = 1 | |
| 68 | + | ||
| 69 | + | // COEFFICIENTS_BT709 is the coefficients bt709 value. | |
| 70 | + | const COEFFICIENTS_BT709 = 2 | |
| 71 | + | ||
| 72 | + | // COEFFICIENTS_FCC is the coefficients fcc value. | |
| 73 | + | const COEFFICIENTS_FCC = 3 | |
| 74 | + | ||
| 75 | + | // COEFFICIENTS_BT601 is the coefficients bt601 value. | |
| 76 | + | const COEFFICIENTS_BT601 = 4 | |
| 77 | + | ||
| 78 | + | // COEFFICIENTS_SMPTE240 is the coefficients smpte240 value. | |
| 79 | + | const COEFFICIENTS_SMPTE240 = 5 | |
| 80 | + | ||
| 81 | + | // COEFFICIENTS_BT2020 is the coefficients bt2020 value. | |
| 82 | + | const COEFFICIENTS_BT2020 = 6 | |
| 83 | + | ||
| 84 | + | // COEFFICIENTS_BT2020_CL is the coefficients bt2020_cl value. | |
| 85 | + | const COEFFICIENTS_BT2020_CL = 7 | |
| 86 | + | ||
| 87 | + | // COEFFICIENTS_ICTCP is the coefficients ictcp value. | |
| 88 | + | const COEFFICIENTS_ICTCP = 8 | |
| 89 | + | ||
| 90 | + | // RANGE_FULL is the range full value. | |
| 91 | + | const RANGE_FULL = 1 | |
| 92 | + | ||
| 93 | + | // RANGE_LIMITED is the range limited value. | |
| 94 | + | const RANGE_LIMITED = 2 | |
| 95 | + | ||
| 96 | + | // CHROMA_LOCATION_TYPE_0 is the chroma_location type_0 value. | |
| 97 | + | const CHROMA_LOCATION_TYPE_0 = 1 | |
| 98 | + | ||
| 99 | + | // CHROMA_LOCATION_TYPE_1 is the chroma_location type_1 value. | |
| 100 | + | const CHROMA_LOCATION_TYPE_1 = 2 | |
| 101 | + | ||
| 102 | + | // CHROMA_LOCATION_TYPE_2 is the chroma_location type_2 value. | |
| 103 | + | const CHROMA_LOCATION_TYPE_2 = 3 | |
| 104 | + | ||
| 105 | + | // CHROMA_LOCATION_TYPE_3 is the chroma_location type_3 value. | |
| 106 | + | const CHROMA_LOCATION_TYPE_3 = 4 | |
| 107 | + | ||
| 108 | + | // CHROMA_LOCATION_TYPE_4 is the chroma_location type_4 value. | |
| 109 | + | const CHROMA_LOCATION_TYPE_4 = 5 | |
| 110 | + | ||
| 111 | + | // CHROMA_LOCATION_TYPE_5 is the chroma_location type_5 value. | |
| 112 | + | const CHROMA_LOCATION_TYPE_5 = 6 | |
| 113 | + | ||
| 114 | + | // WpColorRepresentationManagerInterface is the protocol interface name. | |
| 115 | + | const WpColorRepresentationManagerInterface = "wp_color_representation_manager_v1" | |
| 116 | + | ||
| 117 | + | // WpColorRepresentationManager is the generated binding for wp_color_representation_manager_v1 version 1. | |
| 118 | + | type WpColorRepresentationManager struct { | |
| 119 | + | wl.BaseProxy | |
| 120 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 121 | + | // handlers while another goroutine dispatches events. | |
| 122 | + | handlersMu sync.Mutex | |
| 123 | + | onSupportedAlphaMode []func(alphaMode uint32) | |
| 124 | + | onSupportedCoefficientsAndRanges []func(coefficients uint32, rangeArg uint32) | |
| 125 | + | onDone []func() | |
| 126 | + | } | |
| 127 | + | ||
| 128 | + | // NewWpColorRepresentationManager returns an unbound WpColorRepresentationManager. | |
| 129 | + | func NewWpColorRepresentationManager(ctx *wl.Context) *WpColorRepresentationManager { | |
| 130 | + | obj := &WpColorRepresentationManager{} | |
| 131 | + | obj.SetContext(ctx) | |
| 132 | + | ctx.Register(obj) | |
| 133 | + | return obj | |
| 134 | + | } | |
| 135 | + | ||
| 136 | + | // Destroy the wp_color_representation_manager_v1 object. This does not affect any other objects in any way. | |
| 137 | + | func (o *WpColorRepresentationManager) Destroy() error { | |
| 138 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_color_representation_manager_v1.destroy", Destructor: true}); err != nil { | |
| 139 | + | return err | |
| 140 | + | } | |
| 141 | + | return nil | |
| 142 | + | } | |
| 143 | + | ||
| 144 | + | // If a wp_color_representation_surface_v1 object already exists for the given wl_surface, the protocol error surface_exists is raised. This creates a new color wp_color_representation_surface_v1 object for the given wl_surface. See the wp_color_representation_surface_v1 interface for more details. | |
| 145 | + | func (o *WpColorRepresentationManager) GetSurface(surface *cross_wl_surface.Surface) (*WpColorRepresentationSurface, error) { | |
| 146 | + | var arg1 wl.Object | |
| 147 | + | if surface != nil { | |
| 148 | + | arg1 = surface | |
| 149 | + | } | |
| 150 | + | child := &WpColorRepresentationSurface{} | |
| 151 | + | child.SetContext(o.Context()) | |
| 152 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_color_representation_manager_v1.get_surface", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 153 | + | return nil, err | |
| 154 | + | } | |
| 155 | + | return child, nil | |
| 156 | + | } | |
| 157 | + | ||
| 158 | + | // OnSupportedAlphaMode registers a handler for the supported_alpha_mode event. | |
| 159 | + | // | |
| 160 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 161 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 162 | + | func (o *WpColorRepresentationManager) OnSupportedAlphaMode(handler func(alphaMode uint32)) { | |
| 163 | + | if handler == nil { | |
| 164 | + | return | |
| 165 | + | } | |
| 166 | + | o.handlersMu.Lock() | |
| 167 | + | defer o.handlersMu.Unlock() | |
| 168 | + | o.onSupportedAlphaMode = append(o.onSupportedAlphaMode, handler) | |
| 169 | + | } | |
| 170 | + | ||
| 171 | + | // handlersForSupportedAlphaMode returns the handlers registered for supported_alpha_mode, taken | |
| 172 | + | // under the lock so a handler may register another handler while events are | |
| 173 | + | // being dispatched. | |
| 174 | + | func (o *WpColorRepresentationManager) handlersForSupportedAlphaMode() []func(alphaMode uint32) { | |
| 175 | + | o.handlersMu.Lock() | |
| 176 | + | defer o.handlersMu.Unlock() | |
| 177 | + | return o.onSupportedAlphaMode | |
| 178 | + | } | |
| 179 | + | ||
| 180 | + | // OnSupportedCoefficientsAndRanges registers a handler for the supported_coefficients_and_ranges event. | |
| 181 | + | // | |
| 182 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 183 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 184 | + | func (o *WpColorRepresentationManager) OnSupportedCoefficientsAndRanges(handler func(coefficients uint32, rangeArg uint32)) { | |
| 185 | + | if handler == nil { | |
| 186 | + | return | |
| 187 | + | } | |
| 188 | + | o.handlersMu.Lock() | |
| 189 | + | defer o.handlersMu.Unlock() | |
| 190 | + | o.onSupportedCoefficientsAndRanges = append(o.onSupportedCoefficientsAndRanges, handler) | |
| 191 | + | } | |
| 192 | + | ||
| 193 | + | // handlersForSupportedCoefficientsAndRanges returns the handlers registered for supported_coefficients_and_ranges, taken | |
| 194 | + | // under the lock so a handler may register another handler while events are | |
| 195 | + | // being dispatched. | |
| 196 | + | func (o *WpColorRepresentationManager) handlersForSupportedCoefficientsAndRanges() []func(coefficients uint32, rangeArg uint32) { | |
| 197 | + | o.handlersMu.Lock() | |
| 198 | + | defer o.handlersMu.Unlock() | |
| 199 | + | return o.onSupportedCoefficientsAndRanges | |
| 200 | + | } | |
| 201 | + | ||
| 202 | + | // OnDone registers a handler for the done event. | |
| 203 | + | // | |
| 204 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 205 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 206 | + | func (o *WpColorRepresentationManager) OnDone(handler func()) { | |
| 207 | + | if handler == nil { | |
| 208 | + | return | |
| 209 | + | } | |
| 210 | + | o.handlersMu.Lock() | |
| 211 | + | defer o.handlersMu.Unlock() | |
| 212 | + | o.onDone = append(o.onDone, handler) | |
| 213 | + | } | |
| 214 | + | ||
| 215 | + | // handlersForDone returns the handlers registered for done, taken | |
| 216 | + | // under the lock so a handler may register another handler while events are | |
| 217 | + | // being dispatched. | |
| 218 | + | func (o *WpColorRepresentationManager) handlersForDone() []func() { | |
| 219 | + | o.handlersMu.Lock() | |
| 220 | + | defer o.handlersMu.Unlock() | |
| 221 | + | return o.onDone | |
| 222 | + | } | |
| 223 | + | ||
| 224 | + | // EventSignature returns the declared event argument types in wire order. | |
| 225 | + | func (o *WpColorRepresentationManager) EventSignature(opcode uint16) (string, bool) { | |
| 226 | + | switch opcode { | |
| 227 | + | case 0: | |
| 228 | + | return "uint,", true | |
| 229 | + | case 1: | |
| 230 | + | return "uint,uint,", true | |
| 231 | + | case 2: | |
| 232 | + | return "", true | |
| 233 | + | default: | |
| 234 | + | return "", false | |
| 235 | + | } | |
| 236 | + | } | |
| 237 | + | ||
| 238 | + | // Dispatch decodes one event on wp_color_representation_manager_v1 and calls the registered handlers. | |
| 239 | + | func (o *WpColorRepresentationManager) Dispatch(event *wl.Event) { | |
| 240 | + | switch event.Opcode { | |
| 241 | + | case 0: // supported_alpha_mode | |
| 242 | + | alphaMode := event.Uint32() | |
| 243 | + | ||
| 244 | + | for i, handler := range o.handlersForSupportedAlphaMode() { | |
| 245 | + | _ = i | |
| 246 | + | handler(alphaMode) | |
| 247 | + | } | |
| 248 | + | case 1: // supported_coefficients_and_ranges | |
| 249 | + | coefficients := event.Uint32() | |
| 250 | + | rangeArg := event.Uint32() | |
| 251 | + | ||
| 252 | + | for i, handler := range o.handlersForSupportedCoefficientsAndRanges() { | |
| 253 | + | _ = i | |
| 254 | + | handler(coefficients, rangeArg) | |
| 255 | + | } | |
| 256 | + | case 2: // done | |
| 257 | + | ||
| 258 | + | for i, handler := range o.handlersForDone() { | |
| 259 | + | _ = i | |
| 260 | + | handler() | |
| 261 | + | } | |
| 262 | + | default: | |
| 263 | + | } | |
| 264 | + | } | |
| 265 | + | ||
| 266 | + | // WpColorRepresentationSurfaceInterface is the protocol interface name. | |
| 267 | + | const WpColorRepresentationSurfaceInterface = "wp_color_representation_surface_v1" | |
| 268 | + | ||
| 269 | + | // WpColorRepresentationSurface is the generated binding for wp_color_representation_surface_v1 version 1. | |
| 270 | + | type WpColorRepresentationSurface struct { | |
| 271 | + | wl.BaseProxy | |
| 272 | + | } | |
| 273 | + | ||
| 274 | + | // NewWpColorRepresentationSurface returns an unbound WpColorRepresentationSurface. | |
| 275 | + | func NewWpColorRepresentationSurface(ctx *wl.Context) *WpColorRepresentationSurface { | |
| 276 | + | obj := &WpColorRepresentationSurface{} | |
| 277 | + | obj.SetContext(ctx) | |
| 278 | + | ctx.Register(obj) | |
| 279 | + | return obj | |
| 280 | + | } | |
| 281 | + | ||
| 282 | + | // Destroy the wp_color_representation_surface_v1 object. Destroying this object unsets all the color representation metadata from the surface. See the wp_color_representation_surface_v1 interface description for how a compositor handles a surface without color representation metadata. Unsetting is double-buffered state, see wl_surface.commit. | |
| 283 | + | func (o *WpColorRepresentationSurface) Destroy() error { | |
| 284 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_color_representation_surface_v1.destroy", Destructor: true}); err != nil { | |
| 285 | + | return err | |
| 286 | + | } | |
| 287 | + | return nil | |
| 288 | + | } | |
| 289 | + | ||
| 290 | + | // If this protocol object is inert, the protocol error inert is raised. Assuming an alpha channel exists, it is always linear. The alpha mode determines whether and how the color channels include pre-multiplied alpha. Using straight alpha might have performance benefits. Only alpha modes advertised by the compositor are allowed to be used as argument for this request. The "alpha_mode" protocol error is raised otherwise. Alpha mode is double buffered, see wl_surface.commit. | |
| 291 | + | func (o *WpColorRepresentationSurface) SetAlphaMode(alphaMode uint32) error { | |
| 292 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_color_representation_surface_v1.set_alpha_mode"}, wl.ArgUint(alphaMode)); err != nil { | |
| 293 | + | return err | |
| 294 | + | } | |
| 295 | + | return nil | |
| 296 | + | } | |
| 297 | + | ||
| 298 | + | // If this protocol object is inert, the protocol error inert is raised. Set the matrix coefficients and video range which defines the formula and the related constants used to derive red, green and blue signals. Usually coefficients correspond to MatrixCoefficients code points in H.273. Only combinations advertised by the compositor are allowed to be used as argument for this request. The "coefficients" protocol error is raised otherwise. A call to wl_surface.commit verifies that the pixel format and the coefficients-range combination in the committed surface contents are compatible, if contents exist. The "pixel_format" protocol error is raised otherwise. A pixel format is compatible with the coefficients-range combination if the related equations and conventions as defined in H.273 can produce the color channels (RGB or YCbCr) of the pixel format. For the definition of the supported combination, see the wp_color_representation_surface_v1::coefficients and wp_color_representation_surface_v1::range enums. The coefficients-range combination is double-buffered, see wl_surface.commit. | |
| 299 | + | func (o *WpColorRepresentationSurface) SetCoefficientsAndRange(coefficients uint32, rangeArg uint32) error { | |
| 300 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wp_color_representation_surface_v1.set_coefficients_and_range"}, wl.ArgUint(coefficients), wl.ArgUint(rangeArg)); err != nil { | |
| 301 | + | return err | |
| 302 | + | } | |
| 303 | + | return nil | |
| 304 | + | } | |
| 305 | + | ||
| 306 | + | // If this protocol object is inert, the protocol error inert is raised. Set the chroma location type which defines the position of downsampled chroma samples, corresponding to Chroma420SampleLocType code points in H.273. An invalid chroma location enum value raises the "chroma_location" protocol error. A call to wl_surface.commit verifies that the pixel format and chroma location type in the committed surface contents are compatible, if contents exist. The "pixel_format" protocol error is raised otherwise. For the definition of the supported chroma location types, see the wp_color_representation_surface_v1::chroma_location enum. The chroma location type is double-buffered, see wl_surface.commit. | |
| 307 | + | func (o *WpColorRepresentationSurface) SetChromaLocation(chromaLocation uint32) error { | |
| 308 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "wp_color_representation_surface_v1.set_chroma_location"}, wl.ArgUint(chromaLocation)); err != nil { | |
| 309 | + | return err | |
| 310 | + | } | |
| 311 | + | return nil | |
| 312 | + | } | |
| 313 | + | ||
| 314 | + | // EventSignature returns the declared event argument types in wire order. | |
| 315 | + | func (o *WpColorRepresentationSurface) EventSignature(opcode uint16) (string, bool) { | |
| 316 | + | switch opcode { | |
| 317 | + | default: | |
| 318 | + | return "", false | |
| 319 | + | } | |
| 320 | + | } | |
| 321 | + | ||
| 322 | + | // Dispatch decodes one event on wp_color_representation_surface_v1 and calls the registered handlers. | |
| 323 | + | func (o *WpColorRepresentationSurface) Dispatch(event *wl.Event) { | |
| 324 | + | switch event.Opcode { | |
| 325 | + | default: | |
| 326 | + | } | |
| 327 | + | } | |
A client/committiming/committiming_generated.go +144 -0
| @@ -0,0 +1,144 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: commit_timing_v1 | |
| 3 | + | // Source: commit-timing-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2023 Valve Corporation | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package committiming | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 31 | + | "github.com/bnema/wlturbo/wl" | |
| 32 | + | ) | |
| 33 | + | ||
| 34 | + | // ERROR_COMMIT_TIMER_EXISTS is the error commit_timer_exists value. | |
| 35 | + | const ERROR_COMMIT_TIMER_EXISTS = 0 | |
| 36 | + | ||
| 37 | + | // ERROR_INVALID_TIMESTAMP is the error invalid_timestamp value. | |
| 38 | + | const ERROR_INVALID_TIMESTAMP = 0 | |
| 39 | + | ||
| 40 | + | // ERROR_TIMESTAMP_EXISTS is the error timestamp_exists value. | |
| 41 | + | const ERROR_TIMESTAMP_EXISTS = 1 | |
| 42 | + | ||
| 43 | + | // ERROR_SURFACE_DESTROYED is the error surface_destroyed value. | |
| 44 | + | const ERROR_SURFACE_DESTROYED = 2 | |
| 45 | + | ||
| 46 | + | // WpCommitTimingManagerInterface is the protocol interface name. | |
| 47 | + | const WpCommitTimingManagerInterface = "wp_commit_timing_manager_v1" | |
| 48 | + | ||
| 49 | + | // WpCommitTimingManager is the generated binding for wp_commit_timing_manager_v1 version 1. | |
| 50 | + | type WpCommitTimingManager struct { | |
| 51 | + | wl.BaseProxy | |
| 52 | + | } | |
| 53 | + | ||
| 54 | + | // NewWpCommitTimingManager returns an unbound WpCommitTimingManager. | |
| 55 | + | func NewWpCommitTimingManager(ctx *wl.Context) *WpCommitTimingManager { | |
| 56 | + | obj := &WpCommitTimingManager{} | |
| 57 | + | obj.SetContext(ctx) | |
| 58 | + | ctx.Register(obj) | |
| 59 | + | return obj | |
| 60 | + | } | |
| 61 | + | ||
| 62 | + | // Informs the server that the client will no longer be using this protocol object. Existing objects created by this object are not affected. | |
| 63 | + | func (o *WpCommitTimingManager) Destroy() error { | |
| 64 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_commit_timing_manager_v1.destroy", Destructor: true}); err != nil { | |
| 65 | + | return err | |
| 66 | + | } | |
| 67 | + | return nil | |
| 68 | + | } | |
| 69 | + | ||
| 70 | + | // Establish a timing controller for a surface. Only one commit timer can be created for a surface, or a commit_timer_exists protocol error will be generated. | |
| 71 | + | func (o *WpCommitTimingManager) GetTimer(surface *cross_wl_surface.Surface) (*WpCommitTimer, error) { | |
| 72 | + | var arg1 wl.Object | |
| 73 | + | if surface != nil { | |
| 74 | + | arg1 = surface | |
| 75 | + | } | |
| 76 | + | child := &WpCommitTimer{} | |
| 77 | + | child.SetContext(o.Context()) | |
| 78 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_commit_timing_manager_v1.get_timer", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 79 | + | return nil, err | |
| 80 | + | } | |
| 81 | + | return child, nil | |
| 82 | + | } | |
| 83 | + | ||
| 84 | + | // EventSignature returns the declared event argument types in wire order. | |
| 85 | + | func (o *WpCommitTimingManager) EventSignature(opcode uint16) (string, bool) { | |
| 86 | + | switch opcode { | |
| 87 | + | default: | |
| 88 | + | return "", false | |
| 89 | + | } | |
| 90 | + | } | |
| 91 | + | ||
| 92 | + | // Dispatch decodes one event on wp_commit_timing_manager_v1 and calls the registered handlers. | |
| 93 | + | func (o *WpCommitTimingManager) Dispatch(event *wl.Event) { | |
| 94 | + | switch event.Opcode { | |
| 95 | + | default: | |
| 96 | + | } | |
| 97 | + | } | |
| 98 | + | ||
| 99 | + | // WpCommitTimerInterface is the protocol interface name. | |
| 100 | + | const WpCommitTimerInterface = "wp_commit_timer_v1" | |
| 101 | + | ||
| 102 | + | // WpCommitTimer is the generated binding for wp_commit_timer_v1 version 1. | |
| 103 | + | type WpCommitTimer struct { | |
| 104 | + | wl.BaseProxy | |
| 105 | + | } | |
| 106 | + | ||
| 107 | + | // NewWpCommitTimer returns an unbound WpCommitTimer. | |
| 108 | + | func NewWpCommitTimer(ctx *wl.Context) *WpCommitTimer { | |
| 109 | + | obj := &WpCommitTimer{} | |
| 110 | + | obj.SetContext(ctx) | |
| 111 | + | ctx.Register(obj) | |
| 112 | + | return obj | |
| 113 | + | } | |
| 114 | + | ||
| 115 | + | // Provide a timing constraint for a surface content update. A set_timestamp request may be made before a wl_surface.commit to tell the compositor that the content is intended to be presented as closely as possible to, but not before, the specified time. The time is in the domain of the compositor's presentation clock. An invalid_timestamp error will be generated for invalid tv_nsec. If a timestamp already exists on the surface, a timestamp_exists error is generated. Requesting set_timestamp after the commit_timer object's surface is destroyed will generate a "surface_destroyed" error. | |
| 116 | + | func (o *WpCommitTimer) SetTimestamp(tvSecHi uint32, tvSecLo uint32, tvNsec uint32) error { | |
| 117 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_commit_timer_v1.set_timestamp"}, wl.ArgUint(tvSecHi), wl.ArgUint(tvSecLo), wl.ArgUint(tvNsec)); err != nil { | |
| 118 | + | return err | |
| 119 | + | } | |
| 120 | + | return nil | |
| 121 | + | } | |
| 122 | + | ||
| 123 | + | // Informs the server that the client will no longer be using this protocol object. Existing timing constraints are not affected by the destruction. | |
| 124 | + | func (o *WpCommitTimer) Destroy() error { | |
| 125 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_commit_timer_v1.destroy", Destructor: true}); err != nil { | |
| 126 | + | return err | |
| 127 | + | } | |
| 128 | + | return nil | |
| 129 | + | } | |
| 130 | + | ||
| 131 | + | // EventSignature returns the declared event argument types in wire order. | |
| 132 | + | func (o *WpCommitTimer) EventSignature(opcode uint16) (string, bool) { | |
| 133 | + | switch opcode { | |
| 134 | + | default: | |
| 135 | + | return "", false | |
| 136 | + | } | |
| 137 | + | } | |
| 138 | + | ||
| 139 | + | // Dispatch decodes one event on wp_commit_timer_v1 and calls the registered handlers. | |
| 140 | + | func (o *WpCommitTimer) Dispatch(event *wl.Event) { | |
| 141 | + | switch event.Opcode { | |
| 142 | + | default: | |
| 143 | + | } | |
| 144 | + | } | |
A client/contenttype/contenttype_generated.go +148 -0
| @@ -0,0 +1,148 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: content_type_v1 | |
| 3 | + | // Source: content-type-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2021 Emmanuel Gil Peyrot | |
| 7 | + | // Copyright © 2022 Xaver Hugl | |
| 8 | + | // | |
| 9 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 10 | + | // copy of this software and associated documentation files (the "Software"), | |
| 11 | + | // to deal in the Software without restriction, including without limitation | |
| 12 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 13 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 14 | + | // Software is furnished to do so, subject to the following conditions: | |
| 15 | + | // | |
| 16 | + | // The above copyright notice and this permission notice (including the next | |
| 17 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 18 | + | // Software. | |
| 19 | + | // | |
| 20 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 21 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 22 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 23 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 24 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 25 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 26 | + | // DEALINGS IN THE SOFTWARE. | |
| 27 | + | ||
| 28 | + | package contenttype | |
| 29 | + | ||
| 30 | + | import ( | |
| 31 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 32 | + | "github.com/bnema/wlturbo/wl" | |
| 33 | + | ) | |
| 34 | + | ||
| 35 | + | // ERROR_ALREADY_CONSTRUCTED is the error already_constructed value. | |
| 36 | + | const ERROR_ALREADY_CONSTRUCTED = 0 | |
| 37 | + | ||
| 38 | + | // TYPE_NONE is the type none value. | |
| 39 | + | const TYPE_NONE = 0 | |
| 40 | + | ||
| 41 | + | // TYPE_PHOTO is the type photo value. | |
| 42 | + | const TYPE_PHOTO = 1 | |
| 43 | + | ||
| 44 | + | // TYPE_VIDEO is the type video value. | |
| 45 | + | const TYPE_VIDEO = 2 | |
| 46 | + | ||
| 47 | + | // TYPE_GAME is the type game value. | |
| 48 | + | const TYPE_GAME = 3 | |
| 49 | + | ||
| 50 | + | // WpContentTypeManagerInterface is the protocol interface name. | |
| 51 | + | const WpContentTypeManagerInterface = "wp_content_type_manager_v1" | |
| 52 | + | ||
| 53 | + | // WpContentTypeManager is the generated binding for wp_content_type_manager_v1 version 1. | |
| 54 | + | type WpContentTypeManager struct { | |
| 55 | + | wl.BaseProxy | |
| 56 | + | } | |
| 57 | + | ||
| 58 | + | // NewWpContentTypeManager returns an unbound WpContentTypeManager. | |
| 59 | + | func NewWpContentTypeManager(ctx *wl.Context) *WpContentTypeManager { | |
| 60 | + | obj := &WpContentTypeManager{} | |
| 61 | + | obj.SetContext(ctx) | |
| 62 | + | ctx.Register(obj) | |
| 63 | + | return obj | |
| 64 | + | } | |
| 65 | + | ||
| 66 | + | // Destroy the content type manager. This doesn't destroy objects created with the manager. | |
| 67 | + | func (o *WpContentTypeManager) Destroy() error { | |
| 68 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_content_type_manager_v1.destroy", Destructor: true}); err != nil { | |
| 69 | + | return err | |
| 70 | + | } | |
| 71 | + | return nil | |
| 72 | + | } | |
| 73 | + | ||
| 74 | + | // Create a new content type object associated with the given surface. Creating a wp_content_type_v1 from a wl_surface which already has one attached is a client error: already_constructed. | |
| 75 | + | func (o *WpContentTypeManager) GetSurfaceContentType(surface *cross_wl_surface.Surface) (*WpContentType, error) { | |
| 76 | + | var arg1 wl.Object | |
| 77 | + | if surface != nil { | |
| 78 | + | arg1 = surface | |
| 79 | + | } | |
| 80 | + | child := &WpContentType{} | |
| 81 | + | child.SetContext(o.Context()) | |
| 82 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_content_type_manager_v1.get_surface_content_type", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 83 | + | return nil, err | |
| 84 | + | } | |
| 85 | + | return child, nil | |
| 86 | + | } | |
| 87 | + | ||
| 88 | + | // EventSignature returns the declared event argument types in wire order. | |
| 89 | + | func (o *WpContentTypeManager) EventSignature(opcode uint16) (string, bool) { | |
| 90 | + | switch opcode { | |
| 91 | + | default: | |
| 92 | + | return "", false | |
| 93 | + | } | |
| 94 | + | } | |
| 95 | + | ||
| 96 | + | // Dispatch decodes one event on wp_content_type_manager_v1 and calls the registered handlers. | |
| 97 | + | func (o *WpContentTypeManager) Dispatch(event *wl.Event) { | |
| 98 | + | switch event.Opcode { | |
| 99 | + | default: | |
| 100 | + | } | |
| 101 | + | } | |
| 102 | + | ||
| 103 | + | // WpContentTypeInterface is the protocol interface name. | |
| 104 | + | const WpContentTypeInterface = "wp_content_type_v1" | |
| 105 | + | ||
| 106 | + | // WpContentType is the generated binding for wp_content_type_v1 version 1. | |
| 107 | + | type WpContentType struct { | |
| 108 | + | wl.BaseProxy | |
| 109 | + | } | |
| 110 | + | ||
| 111 | + | // NewWpContentType returns an unbound WpContentType. | |
| 112 | + | func NewWpContentType(ctx *wl.Context) *WpContentType { | |
| 113 | + | obj := &WpContentType{} | |
| 114 | + | obj.SetContext(ctx) | |
| 115 | + | ctx.Register(obj) | |
| 116 | + | return obj | |
| 117 | + | } | |
| 118 | + | ||
| 119 | + | // Switch back to not specifying the content type of this surface. This is equivalent to setting the content type to none, including double buffering semantics. See set_content_type for details. | |
| 120 | + | func (o *WpContentType) Destroy() error { | |
| 121 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_content_type_v1.destroy", Destructor: true}); err != nil { | |
| 122 | + | return err | |
| 123 | + | } | |
| 124 | + | return nil | |
| 125 | + | } | |
| 126 | + | ||
| 127 | + | // Set the surface content type. This informs the compositor that the client believes it is displaying buffers matching this content type. This is purely a hint for the compositor, which can be used to adjust its behavior or hardware settings to fit the presented content best. The content type is double-buffered state, see wl_surface.commit for details. | |
| 128 | + | func (o *WpContentType) SetContentType(contentType uint32) error { | |
| 129 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_content_type_v1.set_content_type"}, wl.ArgUint(contentType)); err != nil { | |
| 130 | + | return err | |
| 131 | + | } | |
| 132 | + | return nil | |
| 133 | + | } | |
| 134 | + | ||
| 135 | + | // EventSignature returns the declared event argument types in wire order. | |
| 136 | + | func (o *WpContentType) EventSignature(opcode uint16) (string, bool) { | |
| 137 | + | switch opcode { | |
| 138 | + | default: | |
| 139 | + | return "", false | |
| 140 | + | } | |
| 141 | + | } | |
| 142 | + | ||
| 143 | + | // Dispatch decodes one event on wp_content_type_v1 and calls the registered handlers. | |
| 144 | + | func (o *WpContentType) Dispatch(event *wl.Event) { | |
| 145 | + | switch event.Opcode { | |
| 146 | + | default: | |
| 147 | + | } | |
| 148 | + | } | |
A client/cursorshape/cursorshape_generated.go +257 -0
| @@ -0,0 +1,257 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: cursor_shape_v1 | |
| 3 | + | // Source: cursor-shape-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright 2018 The Chromium Authors | |
| 7 | + | // Copyright 2023 Simon Ser | |
| 8 | + | // | |
| 9 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 10 | + | // copy of this software and associated documentation files (the "Software"), | |
| 11 | + | // to deal in the Software without restriction, including without limitation | |
| 12 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 13 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 14 | + | // Software is furnished to do so, subject to the following conditions: | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 21 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 23 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 24 | + | // DEALINGS IN THE SOFTWARE. | |
| 25 | + | ||
| 26 | + | package cursorshape | |
| 27 | + | ||
| 28 | + | import ( | |
| 29 | + | cross_zwp_tablet_tool_v2 "github.com/bnema/go-wayland-bindings/client/tablet" | |
| 30 | + | cross_wl_pointer "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 31 | + | "github.com/bnema/wlturbo/wl" | |
| 32 | + | ) | |
| 33 | + | ||
| 34 | + | // SHAPE_DEFAULT is the shape default value. | |
| 35 | + | const SHAPE_DEFAULT = 1 | |
| 36 | + | ||
| 37 | + | // SHAPE_CONTEXT_MENU is the shape context_menu value. | |
| 38 | + | const SHAPE_CONTEXT_MENU = 2 | |
| 39 | + | ||
| 40 | + | // SHAPE_HELP is the shape help value. | |
| 41 | + | const SHAPE_HELP = 3 | |
| 42 | + | ||
| 43 | + | // SHAPE_POINTER is the shape pointer value. | |
| 44 | + | const SHAPE_POINTER = 4 | |
| 45 | + | ||
| 46 | + | // SHAPE_PROGRESS is the shape progress value. | |
| 47 | + | const SHAPE_PROGRESS = 5 | |
| 48 | + | ||
| 49 | + | // SHAPE_WAIT is the shape wait value. | |
| 50 | + | const SHAPE_WAIT = 6 | |
| 51 | + | ||
| 52 | + | // SHAPE_CELL is the shape cell value. | |
| 53 | + | const SHAPE_CELL = 7 | |
| 54 | + | ||
| 55 | + | // SHAPE_CROSSHAIR is the shape crosshair value. | |
| 56 | + | const SHAPE_CROSSHAIR = 8 | |
| 57 | + | ||
| 58 | + | // SHAPE_TEXT is the shape text value. | |
| 59 | + | const SHAPE_TEXT = 9 | |
| 60 | + | ||
| 61 | + | // SHAPE_VERTICAL_TEXT is the shape vertical_text value. | |
| 62 | + | const SHAPE_VERTICAL_TEXT = 10 | |
| 63 | + | ||
| 64 | + | // SHAPE_ALIAS is the shape alias value. | |
| 65 | + | const SHAPE_ALIAS = 11 | |
| 66 | + | ||
| 67 | + | // SHAPE_COPY is the shape copy value. | |
| 68 | + | const SHAPE_COPY = 12 | |
| 69 | + | ||
| 70 | + | // SHAPE_MOVE is the shape move value. | |
| 71 | + | const SHAPE_MOVE = 13 | |
| 72 | + | ||
| 73 | + | // SHAPE_NO_DROP is the shape no_drop value. | |
| 74 | + | const SHAPE_NO_DROP = 14 | |
| 75 | + | ||
| 76 | + | // SHAPE_NOT_ALLOWED is the shape not_allowed value. | |
| 77 | + | const SHAPE_NOT_ALLOWED = 15 | |
| 78 | + | ||
| 79 | + | // SHAPE_GRAB is the shape grab value. | |
| 80 | + | const SHAPE_GRAB = 16 | |
| 81 | + | ||
| 82 | + | // SHAPE_GRABBING is the shape grabbing value. | |
| 83 | + | const SHAPE_GRABBING = 17 | |
| 84 | + | ||
| 85 | + | // SHAPE_E_RESIZE is the shape e_resize value. | |
| 86 | + | const SHAPE_E_RESIZE = 18 | |
| 87 | + | ||
| 88 | + | // SHAPE_N_RESIZE is the shape n_resize value. | |
| 89 | + | const SHAPE_N_RESIZE = 19 | |
| 90 | + | ||
| 91 | + | // SHAPE_NE_RESIZE is the shape ne_resize value. | |
| 92 | + | const SHAPE_NE_RESIZE = 20 | |
| 93 | + | ||
| 94 | + | // SHAPE_NW_RESIZE is the shape nw_resize value. | |
| 95 | + | const SHAPE_NW_RESIZE = 21 | |
| 96 | + | ||
| 97 | + | // SHAPE_S_RESIZE is the shape s_resize value. | |
| 98 | + | const SHAPE_S_RESIZE = 22 | |
| 99 | + | ||
| 100 | + | // SHAPE_SE_RESIZE is the shape se_resize value. | |
| 101 | + | const SHAPE_SE_RESIZE = 23 | |
| 102 | + | ||
| 103 | + | // SHAPE_SW_RESIZE is the shape sw_resize value. | |
| 104 | + | const SHAPE_SW_RESIZE = 24 | |
| 105 | + | ||
| 106 | + | // SHAPE_W_RESIZE is the shape w_resize value. | |
| 107 | + | const SHAPE_W_RESIZE = 25 | |
| 108 | + | ||
| 109 | + | // SHAPE_EW_RESIZE is the shape ew_resize value. | |
| 110 | + | const SHAPE_EW_RESIZE = 26 | |
| 111 | + | ||
| 112 | + | // SHAPE_NS_RESIZE is the shape ns_resize value. | |
| 113 | + | const SHAPE_NS_RESIZE = 27 | |
| 114 | + | ||
| 115 | + | // SHAPE_NESW_RESIZE is the shape nesw_resize value. | |
| 116 | + | const SHAPE_NESW_RESIZE = 28 | |
| 117 | + | ||
| 118 | + | // SHAPE_NWSE_RESIZE is the shape nwse_resize value. | |
| 119 | + | const SHAPE_NWSE_RESIZE = 29 | |
| 120 | + | ||
| 121 | + | // SHAPE_COL_RESIZE is the shape col_resize value. | |
| 122 | + | const SHAPE_COL_RESIZE = 30 | |
| 123 | + | ||
| 124 | + | // SHAPE_ROW_RESIZE is the shape row_resize value. | |
| 125 | + | const SHAPE_ROW_RESIZE = 31 | |
| 126 | + | ||
| 127 | + | // SHAPE_ALL_SCROLL is the shape all_scroll value. | |
| 128 | + | const SHAPE_ALL_SCROLL = 32 | |
| 129 | + | ||
| 130 | + | // SHAPE_ZOOM_IN is the shape zoom_in value. | |
| 131 | + | const SHAPE_ZOOM_IN = 33 | |
| 132 | + | ||
| 133 | + | // SHAPE_ZOOM_OUT is the shape zoom_out value. | |
| 134 | + | const SHAPE_ZOOM_OUT = 34 | |
| 135 | + | ||
| 136 | + | // SHAPE_DND_ASK is the shape dnd_ask value. | |
| 137 | + | const SHAPE_DND_ASK = 35 | |
| 138 | + | ||
| 139 | + | // SHAPE_ALL_RESIZE is the shape all_resize value. | |
| 140 | + | const SHAPE_ALL_RESIZE = 36 | |
| 141 | + | ||
| 142 | + | // ERROR_INVALID_SHAPE is the error invalid_shape value. | |
| 143 | + | const ERROR_INVALID_SHAPE = 1 | |
| 144 | + | ||
| 145 | + | // WpCursorShapeManagerInterface is the protocol interface name. | |
| 146 | + | const WpCursorShapeManagerInterface = "wp_cursor_shape_manager_v1" | |
| 147 | + | ||
| 148 | + | // WpCursorShapeManager is the generated binding for wp_cursor_shape_manager_v1 version 2. | |
| 149 | + | type WpCursorShapeManager struct { | |
| 150 | + | wl.BaseProxy | |
| 151 | + | } | |
| 152 | + | ||
| 153 | + | // NewWpCursorShapeManager returns an unbound WpCursorShapeManager. | |
| 154 | + | func NewWpCursorShapeManager(ctx *wl.Context) *WpCursorShapeManager { | |
| 155 | + | obj := &WpCursorShapeManager{} | |
| 156 | + | obj.SetContext(ctx) | |
| 157 | + | ctx.Register(obj) | |
| 158 | + | return obj | |
| 159 | + | } | |
| 160 | + | ||
| 161 | + | // Destroy the cursor shape manager. | |
| 162 | + | func (o *WpCursorShapeManager) Destroy() error { | |
| 163 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_cursor_shape_manager_v1.destroy", Destructor: true}); err != nil { | |
| 164 | + | return err | |
| 165 | + | } | |
| 166 | + | return nil | |
| 167 | + | } | |
| 168 | + | ||
| 169 | + | // Obtain a wp_cursor_shape_device_v1 for a wl_pointer object. When the pointer capability is removed from the wl_seat, the wp_cursor_shape_device_v1 object becomes inert. | |
| 170 | + | func (o *WpCursorShapeManager) GetPointer(pointer *cross_wl_pointer.Pointer) (*WpCursorShapeDevice, error) { | |
| 171 | + | var arg1 wl.Object | |
| 172 | + | if pointer != nil { | |
| 173 | + | arg1 = pointer | |
| 174 | + | } | |
| 175 | + | child := &WpCursorShapeDevice{} | |
| 176 | + | child.SetContext(o.Context()) | |
| 177 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_cursor_shape_manager_v1.get_pointer", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 178 | + | return nil, err | |
| 179 | + | } | |
| 180 | + | return child, nil | |
| 181 | + | } | |
| 182 | + | ||
| 183 | + | // Obtain a wp_cursor_shape_device_v1 for a zwp_tablet_tool_v2 object. When the zwp_tablet_tool_v2 is removed, the wp_cursor_shape_device_v1 object becomes inert. | |
| 184 | + | func (o *WpCursorShapeManager) GetTabletTool(tabletTool *cross_zwp_tablet_tool_v2.TabletTool) (*WpCursorShapeDevice, error) { | |
| 185 | + | var arg1 wl.Object | |
| 186 | + | if tabletTool != nil { | |
| 187 | + | arg1 = tabletTool | |
| 188 | + | } | |
| 189 | + | child := &WpCursorShapeDevice{} | |
| 190 | + | child.SetContext(o.Context()) | |
| 191 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wp_cursor_shape_manager_v1.get_tablet_tool_v2", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 192 | + | return nil, err | |
| 193 | + | } | |
| 194 | + | return child, nil | |
| 195 | + | } | |
| 196 | + | ||
| 197 | + | // EventSignature returns the declared event argument types in wire order. | |
| 198 | + | func (o *WpCursorShapeManager) EventSignature(opcode uint16) (string, bool) { | |
| 199 | + | switch opcode { | |
| 200 | + | default: | |
| 201 | + | return "", false | |
| 202 | + | } | |
| 203 | + | } | |
| 204 | + | ||
| 205 | + | // Dispatch decodes one event on wp_cursor_shape_manager_v1 and calls the registered handlers. | |
| 206 | + | func (o *WpCursorShapeManager) Dispatch(event *wl.Event) { | |
| 207 | + | switch event.Opcode { | |
| 208 | + | default: | |
| 209 | + | } | |
| 210 | + | } | |
| 211 | + | ||
| 212 | + | // WpCursorShapeDeviceInterface is the protocol interface name. | |
| 213 | + | const WpCursorShapeDeviceInterface = "wp_cursor_shape_device_v1" | |
| 214 | + | ||
| 215 | + | // WpCursorShapeDevice is the generated binding for wp_cursor_shape_device_v1 version 2. | |
| 216 | + | type WpCursorShapeDevice struct { | |
| 217 | + | wl.BaseProxy | |
| 218 | + | } | |
| 219 | + | ||
| 220 | + | // NewWpCursorShapeDevice returns an unbound WpCursorShapeDevice. | |
| 221 | + | func NewWpCursorShapeDevice(ctx *wl.Context) *WpCursorShapeDevice { | |
| 222 | + | obj := &WpCursorShapeDevice{} | |
| 223 | + | obj.SetContext(ctx) | |
| 224 | + | ctx.Register(obj) | |
| 225 | + | return obj | |
| 226 | + | } | |
| 227 | + | ||
| 228 | + | // Destroy the cursor shape device. The device cursor shape remains unchanged. | |
| 229 | + | func (o *WpCursorShapeDevice) Destroy() error { | |
| 230 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_cursor_shape_device_v1.destroy", Destructor: true}); err != nil { | |
| 231 | + | return err | |
| 232 | + | } | |
| 233 | + | return nil | |
| 234 | + | } | |
| 235 | + | ||
| 236 | + | // Sets the device cursor to the specified shape. The compositor will change the cursor image based on the specified shape. The cursor actually changes only if the input device focus is one of the requesting client's surfaces. If any, the previous cursor image (surface or shape) is replaced. The "shape" argument must be a valid enum entry, otherwise the invalid_shape protocol error is raised. This is similar to the wl_pointer.set_cursor and zwp_tablet_tool_v2.set_cursor requests, but this request accepts a shape instead of contents in the form of a surface. Clients can mix set_cursor and set_shape requests. The serial parameter must match the latest wl_pointer.enter or zwp_tablet_tool_v2.proximity_in serial number sent to the client. Otherwise the request will be ignored. | |
| 237 | + | func (o *WpCursorShapeDevice) SetShape(serial uint32, shape uint32) error { | |
| 238 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_cursor_shape_device_v1.set_shape"}, wl.ArgUint(serial), wl.ArgUint(shape)); err != nil { | |
| 239 | + | return err | |
| 240 | + | } | |
| 241 | + | return nil | |
| 242 | + | } | |
| 243 | + | ||
| 244 | + | // EventSignature returns the declared event argument types in wire order. | |
| 245 | + | func (o *WpCursorShapeDevice) EventSignature(opcode uint16) (string, bool) { | |
| 246 | + | switch opcode { | |
| 247 | + | default: | |
| 248 | + | return "", false | |
| 249 | + | } | |
| 250 | + | } | |
| 251 | + | ||
| 252 | + | // Dispatch decodes one event on wp_cursor_shape_device_v1 and calls the registered handlers. | |
| 253 | + | func (o *WpCursorShapeDevice) Dispatch(event *wl.Event) { | |
| 254 | + | switch event.Opcode { | |
| 255 | + | default: | |
| 256 | + | } | |
| 257 | + | } | |
A client/drmlease/drmlease_generated.go +594 -0
| @@ -0,0 +1,594 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: drm_lease_v1 | |
| 3 | + | // Source: drm-lease-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2018 NXP | |
| 7 | + | // Copyright © 2019 Status Research & Development GmbH. | |
| 8 | + | // Copyright © 2021 Xaver Hugl | |
| 9 | + | // | |
| 10 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 11 | + | // copy of this software and associated documentation files (the "Software"), | |
| 12 | + | // to deal in the Software without restriction, including without limitation | |
| 13 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 14 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 15 | + | // Software is furnished to do so, subject to the following conditions: | |
| 16 | + | // | |
| 17 | + | // The above copyright notice and this permission notice (including the next | |
| 18 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 19 | + | // Software. | |
| 20 | + | // | |
| 21 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 22 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 23 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 24 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 25 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 26 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 27 | + | // DEALINGS IN THE SOFTWARE. | |
| 28 | + | ||
| 29 | + | package drmlease | |
| 30 | + | ||
| 31 | + | import ( | |
| 32 | + | "sync" | |
| 33 | + | ||
| 34 | + | "github.com/bnema/wlturbo/wl" | |
| 35 | + | ) | |
| 36 | + | ||
| 37 | + | // ERROR_WRONG_DEVICE is the error wrong_device value. | |
| 38 | + | const ERROR_WRONG_DEVICE = 0 | |
| 39 | + | ||
| 40 | + | // ERROR_DUPLICATE_CONNECTOR is the error duplicate_connector value. | |
| 41 | + | const ERROR_DUPLICATE_CONNECTOR = 1 | |
| 42 | + | ||
| 43 | + | // ERROR_EMPTY_LEASE is the error empty_lease value. | |
| 44 | + | const ERROR_EMPTY_LEASE = 2 | |
| 45 | + | ||
| 46 | + | // WpDrmLeaseDeviceInterface is the protocol interface name. | |
| 47 | + | const WpDrmLeaseDeviceInterface = "wp_drm_lease_device_v1" | |
| 48 | + | ||
| 49 | + | // WpDrmLeaseDevice is the generated binding for wp_drm_lease_device_v1 version 1. | |
| 50 | + | type WpDrmLeaseDevice struct { | |
| 51 | + | wl.BaseProxy | |
| 52 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 53 | + | // handlers while another goroutine dispatches events. | |
| 54 | + | handlersMu sync.Mutex | |
| 55 | + | onDrmFd []func(fd *wl.OwnedFD) | |
| 56 | + | onConnector []func(idObject *WpDrmLeaseConnector) | |
| 57 | + | onDone []func() | |
| 58 | + | onReleased []func() | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | // NewWpDrmLeaseDevice returns an unbound WpDrmLeaseDevice. | |
| 62 | + | func NewWpDrmLeaseDevice(ctx *wl.Context) *WpDrmLeaseDevice { | |
| 63 | + | obj := &WpDrmLeaseDevice{} | |
| 64 | + | obj.SetContext(ctx) | |
| 65 | + | ctx.Register(obj) | |
| 66 | + | return obj | |
| 67 | + | } | |
| 68 | + | ||
| 69 | + | // Creates a lease request object. See the documentation for wp_drm_lease_request_v1 for details. | |
| 70 | + | func (o *WpDrmLeaseDevice) CreateLeaseRequest() (*WpDrmLeaseRequest, error) { | |
| 71 | + | child := &WpDrmLeaseRequest{} | |
| 72 | + | child.SetContext(o.Context()) | |
| 73 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_drm_lease_device_v1.create_lease_request", Child: child}, wl.ArgObject(child)); err != nil { | |
| 74 | + | return nil, err | |
| 75 | + | } | |
| 76 | + | return child, nil | |
| 77 | + | } | |
| 78 | + | ||
| 79 | + | // Indicates the client no longer wishes to use this object. In response the compositor will immediately send the released event and destroy this object. It can however not guarantee that the client won't receive connector events before the released event. The client must not send any requests after this one, doing so will raise a wl_display error. Existing connectors, lease request and leases will not be affected. | |
| 80 | + | func (o *WpDrmLeaseDevice) Release() error { | |
| 81 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_drm_lease_device_v1.release"}); err != nil { | |
| 82 | + | return err | |
| 83 | + | } | |
| 84 | + | return nil | |
| 85 | + | } | |
| 86 | + | ||
| 87 | + | // OnDrmFd registers a handler for the drm_fd event. | |
| 88 | + | // | |
| 89 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 90 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 91 | + | func (o *WpDrmLeaseDevice) OnDrmFd(handler func(fd *wl.OwnedFD)) { | |
| 92 | + | if handler == nil { | |
| 93 | + | return | |
| 94 | + | } | |
| 95 | + | o.handlersMu.Lock() | |
| 96 | + | defer o.handlersMu.Unlock() | |
| 97 | + | o.onDrmFd = append(o.onDrmFd, handler) | |
| 98 | + | } | |
| 99 | + | ||
| 100 | + | // handlersForDrmFd returns the handlers registered for drm_fd, taken | |
| 101 | + | // under the lock so a handler may register another handler while events are | |
| 102 | + | // being dispatched. | |
| 103 | + | func (o *WpDrmLeaseDevice) handlersForDrmFd() []func(fd *wl.OwnedFD) { | |
| 104 | + | o.handlersMu.Lock() | |
| 105 | + | defer o.handlersMu.Unlock() | |
| 106 | + | return o.onDrmFd | |
| 107 | + | } | |
| 108 | + | ||
| 109 | + | // OnConnector registers a handler for the connector event. | |
| 110 | + | // | |
| 111 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 112 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 113 | + | func (o *WpDrmLeaseDevice) OnConnector(handler func(idObject *WpDrmLeaseConnector)) { | |
| 114 | + | if handler == nil { | |
| 115 | + | return | |
| 116 | + | } | |
| 117 | + | o.handlersMu.Lock() | |
| 118 | + | defer o.handlersMu.Unlock() | |
| 119 | + | o.onConnector = append(o.onConnector, handler) | |
| 120 | + | } | |
| 121 | + | ||
| 122 | + | // handlersForConnector returns the handlers registered for connector, taken | |
| 123 | + | // under the lock so a handler may register another handler while events are | |
| 124 | + | // being dispatched. | |
| 125 | + | func (o *WpDrmLeaseDevice) handlersForConnector() []func(idObject *WpDrmLeaseConnector) { | |
| 126 | + | o.handlersMu.Lock() | |
| 127 | + | defer o.handlersMu.Unlock() | |
| 128 | + | return o.onConnector | |
| 129 | + | } | |
| 130 | + | ||
| 131 | + | // OnDone registers a handler for the done event. | |
| 132 | + | // | |
| 133 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 134 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 135 | + | func (o *WpDrmLeaseDevice) OnDone(handler func()) { | |
| 136 | + | if handler == nil { | |
| 137 | + | return | |
| 138 | + | } | |
| 139 | + | o.handlersMu.Lock() | |
| 140 | + | defer o.handlersMu.Unlock() | |
| 141 | + | o.onDone = append(o.onDone, handler) | |
| 142 | + | } | |
| 143 | + | ||
| 144 | + | // handlersForDone returns the handlers registered for done, taken | |
| 145 | + | // under the lock so a handler may register another handler while events are | |
| 146 | + | // being dispatched. | |
| 147 | + | func (o *WpDrmLeaseDevice) handlersForDone() []func() { | |
| 148 | + | o.handlersMu.Lock() | |
| 149 | + | defer o.handlersMu.Unlock() | |
| 150 | + | return o.onDone | |
| 151 | + | } | |
| 152 | + | ||
| 153 | + | // OnReleased registers a handler for the released event. | |
| 154 | + | // | |
| 155 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 156 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 157 | + | func (o *WpDrmLeaseDevice) OnReleased(handler func()) { | |
| 158 | + | if handler == nil { | |
| 159 | + | return | |
| 160 | + | } | |
| 161 | + | o.handlersMu.Lock() | |
| 162 | + | defer o.handlersMu.Unlock() | |
| 163 | + | o.onReleased = append(o.onReleased, handler) | |
| 164 | + | } | |
| 165 | + | ||
| 166 | + | // handlersForReleased returns the handlers registered for released, taken | |
| 167 | + | // under the lock so a handler may register another handler while events are | |
| 168 | + | // being dispatched. | |
| 169 | + | func (o *WpDrmLeaseDevice) handlersForReleased() []func() { | |
| 170 | + | o.handlersMu.Lock() | |
| 171 | + | defer o.handlersMu.Unlock() | |
| 172 | + | return o.onReleased | |
| 173 | + | } | |
| 174 | + | ||
| 175 | + | // EventSignature returns the declared event argument types in wire order. | |
| 176 | + | func (o *WpDrmLeaseDevice) EventSignature(opcode uint16) (string, bool) { | |
| 177 | + | switch opcode { | |
| 178 | + | case 0: | |
| 179 | + | return "fd,", true | |
| 180 | + | case 1: | |
| 181 | + | return "new_id,", true | |
| 182 | + | case 2: | |
| 183 | + | return "", true | |
| 184 | + | case 3: | |
| 185 | + | return "", true | |
| 186 | + | default: | |
| 187 | + | return "", false | |
| 188 | + | } | |
| 189 | + | } | |
| 190 | + | ||
| 191 | + | // Dispatch decodes one event on wp_drm_lease_device_v1 and calls the registered handlers. | |
| 192 | + | func (o *WpDrmLeaseDevice) Dispatch(event *wl.Event) { | |
| 193 | + | switch event.Opcode { | |
| 194 | + | case 0: // drm_fd | |
| 195 | + | fd := event.FD() | |
| 196 | + | ownedfd := fd | |
| 197 | + | defer ownedfd.Close() | |
| 198 | + | ||
| 199 | + | for i, handler := range o.handlersForDrmFd() { | |
| 200 | + | if i > 0 { | |
| 201 | + | fd = nil | |
| 202 | + | } | |
| 203 | + | handler(fd) | |
| 204 | + | } | |
| 205 | + | case 1: // connector | |
| 206 | + | idID := event.Uint32() | |
| 207 | + | idObject := &WpDrmLeaseConnector{} | |
| 208 | + | idObject.SetContext(o.Context()) | |
| 209 | + | idObject.SetID(idID) | |
| 210 | + | idObject.SetVersion(o.Version()) | |
| 211 | + | o.Context().Register(idObject) | |
| 212 | + | ||
| 213 | + | for i, handler := range o.handlersForConnector() { | |
| 214 | + | _ = i | |
| 215 | + | handler(idObject) | |
| 216 | + | } | |
| 217 | + | case 2: // done | |
| 218 | + | ||
| 219 | + | for i, handler := range o.handlersForDone() { | |
| 220 | + | _ = i | |
| 221 | + | handler() | |
| 222 | + | } | |
| 223 | + | case 3: // released | |
| 224 | + | ||
| 225 | + | for i, handler := range o.handlersForReleased() { | |
| 226 | + | _ = i | |
| 227 | + | handler() | |
| 228 | + | } | |
| 229 | + | o.Context().Unregister(o) | |
| 230 | + | default: | |
| 231 | + | } | |
| 232 | + | } | |
| 233 | + | ||
| 234 | + | // WpDrmLeaseConnectorInterface is the protocol interface name. | |
| 235 | + | const WpDrmLeaseConnectorInterface = "wp_drm_lease_connector_v1" | |
| 236 | + | ||
| 237 | + | // WpDrmLeaseConnector is the generated binding for wp_drm_lease_connector_v1 version 1. | |
| 238 | + | type WpDrmLeaseConnector struct { | |
| 239 | + | wl.BaseProxy | |
| 240 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 241 | + | // handlers while another goroutine dispatches events. | |
| 242 | + | handlersMu sync.Mutex | |
| 243 | + | onName []func(name string) | |
| 244 | + | onDescription []func(description string) | |
| 245 | + | onConnectorId []func(connectorId uint32) | |
| 246 | + | onDone []func() | |
| 247 | + | onWithdrawn []func() | |
| 248 | + | } | |
| 249 | + | ||
| 250 | + | // NewWpDrmLeaseConnector returns an unbound WpDrmLeaseConnector. | |
| 251 | + | func NewWpDrmLeaseConnector(ctx *wl.Context) *WpDrmLeaseConnector { | |
| 252 | + | obj := &WpDrmLeaseConnector{} | |
| 253 | + | obj.SetContext(ctx) | |
| 254 | + | ctx.Register(obj) | |
| 255 | + | return obj | |
| 256 | + | } | |
| 257 | + | ||
| 258 | + | // The client may send this request to indicate that it will not use this connector. Clients are encouraged to send this after receiving the "withdrawn" event so that the server can release the resources associated with this connector offer. Neither existing lease requests nor leases will be affected. | |
| 259 | + | func (o *WpDrmLeaseConnector) Destroy() error { | |
| 260 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_drm_lease_connector_v1.destroy", Destructor: true}); err != nil { | |
| 261 | + | return err | |
| 262 | + | } | |
| 263 | + | return nil | |
| 264 | + | } | |
| 265 | + | ||
| 266 | + | // OnName registers a handler for the name event. | |
| 267 | + | // | |
| 268 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 269 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 270 | + | func (o *WpDrmLeaseConnector) OnName(handler func(name string)) { | |
| 271 | + | if handler == nil { | |
| 272 | + | return | |
| 273 | + | } | |
| 274 | + | o.handlersMu.Lock() | |
| 275 | + | defer o.handlersMu.Unlock() | |
| 276 | + | o.onName = append(o.onName, handler) | |
| 277 | + | } | |
| 278 | + | ||
| 279 | + | // handlersForName returns the handlers registered for name, taken | |
| 280 | + | // under the lock so a handler may register another handler while events are | |
| 281 | + | // being dispatched. | |
| 282 | + | func (o *WpDrmLeaseConnector) handlersForName() []func(name string) { | |
| 283 | + | o.handlersMu.Lock() | |
| 284 | + | defer o.handlersMu.Unlock() | |
| 285 | + | return o.onName | |
| 286 | + | } | |
| 287 | + | ||
| 288 | + | // OnDescription registers a handler for the description event. | |
| 289 | + | // | |
| 290 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 291 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 292 | + | func (o *WpDrmLeaseConnector) OnDescription(handler func(description string)) { | |
| 293 | + | if handler == nil { | |
| 294 | + | return | |
| 295 | + | } | |
| 296 | + | o.handlersMu.Lock() | |
| 297 | + | defer o.handlersMu.Unlock() | |
| 298 | + | o.onDescription = append(o.onDescription, handler) | |
| 299 | + | } | |
| 300 | + | ||
| 301 | + | // handlersForDescription returns the handlers registered for description, taken | |
| 302 | + | // under the lock so a handler may register another handler while events are | |
| 303 | + | // being dispatched. | |
| 304 | + | func (o *WpDrmLeaseConnector) handlersForDescription() []func(description string) { | |
| 305 | + | o.handlersMu.Lock() | |
| 306 | + | defer o.handlersMu.Unlock() | |
| 307 | + | return o.onDescription | |
| 308 | + | } | |
| 309 | + | ||
| 310 | + | // OnConnectorId registers a handler for the connector_id event. | |
| 311 | + | // | |
| 312 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 313 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 314 | + | func (o *WpDrmLeaseConnector) OnConnectorId(handler func(connectorId uint32)) { | |
| 315 | + | if handler == nil { | |
| 316 | + | return | |
| 317 | + | } | |
| 318 | + | o.handlersMu.Lock() | |
| 319 | + | defer o.handlersMu.Unlock() | |
| 320 | + | o.onConnectorId = append(o.onConnectorId, handler) | |
| 321 | + | } | |
| 322 | + | ||
| 323 | + | // handlersForConnectorId returns the handlers registered for connector_id, taken | |
| 324 | + | // under the lock so a handler may register another handler while events are | |
| 325 | + | // being dispatched. | |
| 326 | + | func (o *WpDrmLeaseConnector) handlersForConnectorId() []func(connectorId uint32) { | |
| 327 | + | o.handlersMu.Lock() | |
| 328 | + | defer o.handlersMu.Unlock() | |
| 329 | + | return o.onConnectorId | |
| 330 | + | } | |
| 331 | + | ||
| 332 | + | // OnDone registers a handler for the done event. | |
| 333 | + | // | |
| 334 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 335 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 336 | + | func (o *WpDrmLeaseConnector) OnDone(handler func()) { | |
| 337 | + | if handler == nil { | |
| 338 | + | return | |
| 339 | + | } | |
| 340 | + | o.handlersMu.Lock() | |
| 341 | + | defer o.handlersMu.Unlock() | |
| 342 | + | o.onDone = append(o.onDone, handler) | |
| 343 | + | } | |
| 344 | + | ||
| 345 | + | // handlersForDone returns the handlers registered for done, taken | |
| 346 | + | // under the lock so a handler may register another handler while events are | |
| 347 | + | // being dispatched. | |
| 348 | + | func (o *WpDrmLeaseConnector) handlersForDone() []func() { | |
| 349 | + | o.handlersMu.Lock() | |
| 350 | + | defer o.handlersMu.Unlock() | |
| 351 | + | return o.onDone | |
| 352 | + | } | |
| 353 | + | ||
| 354 | + | // OnWithdrawn registers a handler for the withdrawn event. | |
| 355 | + | // | |
| 356 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 357 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 358 | + | func (o *WpDrmLeaseConnector) OnWithdrawn(handler func()) { | |
| 359 | + | if handler == nil { | |
| 360 | + | return | |
| 361 | + | } | |
| 362 | + | o.handlersMu.Lock() | |
| 363 | + | defer o.handlersMu.Unlock() | |
| 364 | + | o.onWithdrawn = append(o.onWithdrawn, handler) | |
| 365 | + | } | |
| 366 | + | ||
| 367 | + | // handlersForWithdrawn returns the handlers registered for withdrawn, taken | |
| 368 | + | // under the lock so a handler may register another handler while events are | |
| 369 | + | // being dispatched. | |
| 370 | + | func (o *WpDrmLeaseConnector) handlersForWithdrawn() []func() { | |
| 371 | + | o.handlersMu.Lock() | |
| 372 | + | defer o.handlersMu.Unlock() | |
| 373 | + | return o.onWithdrawn | |
| 374 | + | } | |
| 375 | + | ||
| 376 | + | // EventSignature returns the declared event argument types in wire order. | |
| 377 | + | func (o *WpDrmLeaseConnector) EventSignature(opcode uint16) (string, bool) { | |
| 378 | + | switch opcode { | |
| 379 | + | case 0: | |
| 380 | + | return "string,", true | |
| 381 | + | case 1: | |
| 382 | + | return "string,", true | |
| 383 | + | case 2: | |
| 384 | + | return "uint,", true | |
| 385 | + | case 3: | |
| 386 | + | return "", true | |
| 387 | + | case 4: | |
| 388 | + | return "", true | |
| 389 | + | default: | |
| 390 | + | return "", false | |
| 391 | + | } | |
| 392 | + | } | |
| 393 | + | ||
| 394 | + | // Dispatch decodes one event on wp_drm_lease_connector_v1 and calls the registered handlers. | |
| 395 | + | func (o *WpDrmLeaseConnector) Dispatch(event *wl.Event) { | |
| 396 | + | switch event.Opcode { | |
| 397 | + | case 0: // name | |
| 398 | + | name := event.String() | |
| 399 | + | ||
| 400 | + | for i, handler := range o.handlersForName() { | |
| 401 | + | _ = i | |
| 402 | + | handler(name) | |
| 403 | + | } | |
| 404 | + | case 1: // description | |
| 405 | + | description := event.String() | |
| 406 | + | ||
| 407 | + | for i, handler := range o.handlersForDescription() { | |
| 408 | + | _ = i | |
| 409 | + | handler(description) | |
| 410 | + | } | |
| 411 | + | case 2: // connector_id | |
| 412 | + | connectorId := event.Uint32() | |
| 413 | + | ||
| 414 | + | for i, handler := range o.handlersForConnectorId() { | |
| 415 | + | _ = i | |
| 416 | + | handler(connectorId) | |
| 417 | + | } | |
| 418 | + | case 3: // done | |
| 419 | + | ||
| 420 | + | for i, handler := range o.handlersForDone() { | |
| 421 | + | _ = i | |
| 422 | + | handler() | |
| 423 | + | } | |
| 424 | + | case 4: // withdrawn | |
| 425 | + | ||
| 426 | + | for i, handler := range o.handlersForWithdrawn() { | |
| 427 | + | _ = i | |
| 428 | + | handler() | |
| 429 | + | } | |
| 430 | + | default: | |
| 431 | + | } | |
| 432 | + | } | |
| 433 | + | ||
| 434 | + | // WpDrmLeaseRequestInterface is the protocol interface name. | |
| 435 | + | const WpDrmLeaseRequestInterface = "wp_drm_lease_request_v1" | |
| 436 | + | ||
| 437 | + | // WpDrmLeaseRequest is the generated binding for wp_drm_lease_request_v1 version 1. | |
| 438 | + | type WpDrmLeaseRequest struct { | |
| 439 | + | wl.BaseProxy | |
| 440 | + | } | |
| 441 | + | ||
| 442 | + | // NewWpDrmLeaseRequest returns an unbound WpDrmLeaseRequest. | |
| 443 | + | func NewWpDrmLeaseRequest(ctx *wl.Context) *WpDrmLeaseRequest { | |
| 444 | + | obj := &WpDrmLeaseRequest{} | |
| 445 | + | obj.SetContext(ctx) | |
| 446 | + | ctx.Register(obj) | |
| 447 | + | return obj | |
| 448 | + | } | |
| 449 | + | ||
| 450 | + | // Indicates that the client would like to lease the given connector. This is only used as a suggestion, the compositor may choose to include any resources in the lease it issues, or change the set of leased resources at any time. Compositors are however encouraged to include the requested connector and other resources necessary to drive the connected output in the lease. Requesting a connector that was created from a different lease device than this lease request raises the wrong_device error. Requesting a connector twice will raise the duplicate_connector error. | |
| 451 | + | func (o *WpDrmLeaseRequest) RequestConnector(connector *WpDrmLeaseConnector) error { | |
| 452 | + | var arg0 wl.Object | |
| 453 | + | if connector != nil { | |
| 454 | + | arg0 = connector | |
| 455 | + | } | |
| 456 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_drm_lease_request_v1.request_connector"}, wl.ArgObject(arg0)); err != nil { | |
| 457 | + | return err | |
| 458 | + | } | |
| 459 | + | return nil | |
| 460 | + | } | |
| 461 | + | ||
| 462 | + | // Submits the lease request and creates a new wp_drm_lease_v1 object. After calling submit the compositor will immediately destroy this object, issuing any more requests will cause a wl_display error. The compositor doesn't make any guarantees about the events of the lease object, clients cannot expect an immediate response. Not requesting any connectors before submitting the lease request will raise the empty_lease error. | |
| 463 | + | func (o *WpDrmLeaseRequest) Submit() (*WpDrmLease, error) { | |
| 464 | + | child := &WpDrmLease{} | |
| 465 | + | child.SetContext(o.Context()) | |
| 466 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_drm_lease_request_v1.submit", Destructor: true, Child: child}, wl.ArgObject(child)); err != nil { | |
| 467 | + | return nil, err | |
| 468 | + | } | |
| 469 | + | return child, nil | |
| 470 | + | } | |
| 471 | + | ||
| 472 | + | // EventSignature returns the declared event argument types in wire order. | |
| 473 | + | func (o *WpDrmLeaseRequest) EventSignature(opcode uint16) (string, bool) { | |
| 474 | + | switch opcode { | |
| 475 | + | default: | |
| 476 | + | return "", false | |
| 477 | + | } | |
| 478 | + | } | |
| 479 | + | ||
| 480 | + | // Dispatch decodes one event on wp_drm_lease_request_v1 and calls the registered handlers. | |
| 481 | + | func (o *WpDrmLeaseRequest) Dispatch(event *wl.Event) { | |
| 482 | + | switch event.Opcode { | |
| 483 | + | default: | |
| 484 | + | } | |
| 485 | + | } | |
| 486 | + | ||
| 487 | + | // WpDrmLeaseInterface is the protocol interface name. | |
| 488 | + | const WpDrmLeaseInterface = "wp_drm_lease_v1" | |
| 489 | + | ||
| 490 | + | // WpDrmLease is the generated binding for wp_drm_lease_v1 version 1. | |
| 491 | + | type WpDrmLease struct { | |
| 492 | + | wl.BaseProxy | |
| 493 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 494 | + | // handlers while another goroutine dispatches events. | |
| 495 | + | handlersMu sync.Mutex | |
| 496 | + | onLeaseFd []func(leasedFd *wl.OwnedFD) | |
| 497 | + | onFinished []func() | |
| 498 | + | } | |
| 499 | + | ||
| 500 | + | // NewWpDrmLease returns an unbound WpDrmLease. | |
| 501 | + | func NewWpDrmLease(ctx *wl.Context) *WpDrmLease { | |
| 502 | + | obj := &WpDrmLease{} | |
| 503 | + | obj.SetContext(ctx) | |
| 504 | + | ctx.Register(obj) | |
| 505 | + | return obj | |
| 506 | + | } | |
| 507 | + | ||
| 508 | + | // The client should send this to indicate that it no longer wishes to use this lease. The compositor should use drmModeRevokeLease on the appropriate file descriptor, if necessary. Upon destruction, the compositor should advertise the connector for leasing again by sending the connector event through the wp_drm_lease_device_v1 interface. | |
| 509 | + | func (o *WpDrmLease) Destroy() error { | |
| 510 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_drm_lease_v1.destroy", Destructor: true}); err != nil { | |
| 511 | + | return err | |
| 512 | + | } | |
| 513 | + | return nil | |
| 514 | + | } | |
| 515 | + | ||
| 516 | + | // OnLeaseFd registers a handler for the lease_fd event. | |
| 517 | + | // | |
| 518 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 519 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 520 | + | func (o *WpDrmLease) OnLeaseFd(handler func(leasedFd *wl.OwnedFD)) { | |
| 521 | + | if handler == nil { | |
| 522 | + | return | |
| 523 | + | } | |
| 524 | + | o.handlersMu.Lock() | |
| 525 | + | defer o.handlersMu.Unlock() | |
| 526 | + | o.onLeaseFd = append(o.onLeaseFd, handler) | |
| 527 | + | } | |
| 528 | + | ||
| 529 | + | // handlersForLeaseFd returns the handlers registered for lease_fd, taken | |
| 530 | + | // under the lock so a handler may register another handler while events are | |
| 531 | + | // being dispatched. | |
| 532 | + | func (o *WpDrmLease) handlersForLeaseFd() []func(leasedFd *wl.OwnedFD) { | |
| 533 | + | o.handlersMu.Lock() | |
| 534 | + | defer o.handlersMu.Unlock() | |
| 535 | + | return o.onLeaseFd | |
| 536 | + | } | |
| 537 | + | ||
| 538 | + | // OnFinished registers a handler for the finished event. | |
| 539 | + | // | |
| 540 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 541 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 542 | + | func (o *WpDrmLease) OnFinished(handler func()) { | |
| 543 | + | if handler == nil { | |
| 544 | + | return | |
| 545 | + | } | |
| 546 | + | o.handlersMu.Lock() | |
| 547 | + | defer o.handlersMu.Unlock() | |
| 548 | + | o.onFinished = append(o.onFinished, handler) | |
| 549 | + | } | |
| 550 | + | ||
| 551 | + | // handlersForFinished returns the handlers registered for finished, taken | |
| 552 | + | // under the lock so a handler may register another handler while events are | |
| 553 | + | // being dispatched. | |
| 554 | + | func (o *WpDrmLease) handlersForFinished() []func() { | |
| 555 | + | o.handlersMu.Lock() | |
| 556 | + | defer o.handlersMu.Unlock() | |
| 557 | + | return o.onFinished | |
| 558 | + | } | |
| 559 | + | ||
| 560 | + | // EventSignature returns the declared event argument types in wire order. | |
| 561 | + | func (o *WpDrmLease) EventSignature(opcode uint16) (string, bool) { | |
| 562 | + | switch opcode { | |
| 563 | + | case 0: | |
| 564 | + | return "fd,", true | |
| 565 | + | case 1: | |
| 566 | + | return "", true | |
| 567 | + | default: | |
| 568 | + | return "", false | |
| 569 | + | } | |
| 570 | + | } | |
| 571 | + | ||
| 572 | + | // Dispatch decodes one event on wp_drm_lease_v1 and calls the registered handlers. | |
| 573 | + | func (o *WpDrmLease) Dispatch(event *wl.Event) { | |
| 574 | + | switch event.Opcode { | |
| 575 | + | case 0: // lease_fd | |
| 576 | + | leasedFd := event.FD() | |
| 577 | + | ownedleasedFd := leasedFd | |
| 578 | + | defer ownedleasedFd.Close() | |
| 579 | + | ||
| 580 | + | for i, handler := range o.handlersForLeaseFd() { | |
| 581 | + | if i > 0 { | |
| 582 | + | leasedFd = nil | |
| 583 | + | } | |
| 584 | + | handler(leasedFd) | |
| 585 | + | } | |
| 586 | + | case 1: // finished | |
| 587 | + | ||
| 588 | + | for i, handler := range o.handlersForFinished() { | |
| 589 | + | _ = i | |
| 590 | + | handler() | |
| 591 | + | } | |
| 592 | + | default: | |
| 593 | + | } | |
| 594 | + | } | |
A client/extbackgroundeffect/extbackgroundeffect_generated.go +186 -0
| @@ -0,0 +1,186 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: ext_background_effect_v1 | |
| 3 | + | // Source: ext-background-effect-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright (C) 2015 Martin Gräßlin | |
| 7 | + | // Copyright (C) 2015 Marco Martin | |
| 8 | + | // Copyright (C) 2020 Vlad Zahorodnii | |
| 9 | + | // Copyright (C) 2024 Xaver Hugl | |
| 10 | + | // | |
| 11 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 12 | + | // copy of this software and associated documentation files (the "Software"), | |
| 13 | + | // to deal in the Software without restriction, including without limitation | |
| 14 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 15 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 16 | + | // Software is furnished to do so, subject to the following conditions: | |
| 17 | + | // | |
| 18 | + | // The above copyright notice and this permission notice (including the next | |
| 19 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 20 | + | // Software. | |
| 21 | + | // | |
| 22 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 23 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 24 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 25 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 26 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 27 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 28 | + | // DEALINGS IN THE SOFTWARE. | |
| 29 | + | ||
| 30 | + | package extbackgroundeffect | |
| 31 | + | ||
| 32 | + | import ( | |
| 33 | + | "sync" | |
| 34 | + | ||
| 35 | + | cross_wl_region "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 36 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 37 | + | "github.com/bnema/wlturbo/wl" | |
| 38 | + | ) | |
| 39 | + | ||
| 40 | + | // ERROR_BACKGROUND_EFFECT_EXISTS is the error background_effect_exists value. | |
| 41 | + | const ERROR_BACKGROUND_EFFECT_EXISTS = 0 | |
| 42 | + | ||
| 43 | + | // CAPABILITY_BLUR is the capability blur value. | |
| 44 | + | const CAPABILITY_BLUR = 1 | |
| 45 | + | ||
| 46 | + | // ERROR_SURFACE_DESTROYED is the error surface_destroyed value. | |
| 47 | + | const ERROR_SURFACE_DESTROYED = 0 | |
| 48 | + | ||
| 49 | + | // ExtBackgroundEffectManagerInterface is the protocol interface name. | |
| 50 | + | const ExtBackgroundEffectManagerInterface = "ext_background_effect_manager_v1" | |
| 51 | + | ||
| 52 | + | // ExtBackgroundEffectManager is the generated binding for ext_background_effect_manager_v1 version 1. | |
| 53 | + | type ExtBackgroundEffectManager struct { | |
| 54 | + | wl.BaseProxy | |
| 55 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 56 | + | // handlers while another goroutine dispatches events. | |
| 57 | + | handlersMu sync.Mutex | |
| 58 | + | onCapabilities []func(flags uint32) | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | // NewExtBackgroundEffectManager returns an unbound ExtBackgroundEffectManager. | |
| 62 | + | func NewExtBackgroundEffectManager(ctx *wl.Context) *ExtBackgroundEffectManager { | |
| 63 | + | obj := &ExtBackgroundEffectManager{} | |
| 64 | + | obj.SetContext(ctx) | |
| 65 | + | ctx.Register(obj) | |
| 66 | + | return obj | |
| 67 | + | } | |
| 68 | + | ||
| 69 | + | // Informs the server that the client will no longer be using this protocol object. Existing objects created by this object are not affected. | |
| 70 | + | func (o *ExtBackgroundEffectManager) Destroy() error { | |
| 71 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_background_effect_manager_v1.destroy", Destructor: true}); err != nil { | |
| 72 | + | return err | |
| 73 | + | } | |
| 74 | + | return nil | |
| 75 | + | } | |
| 76 | + | ||
| 77 | + | // Instantiate an interface extension for the given wl_surface to add effects like blur for the background behind it. If the given wl_surface already has a ext_background_effect_surface_v1 object associated, the background_effect_exists protocol error will be raised. | |
| 78 | + | func (o *ExtBackgroundEffectManager) GetBackgroundEffect(surface *cross_wl_surface.Surface) (*ExtBackgroundEffectSurface, error) { | |
| 79 | + | var arg1 wl.Object | |
| 80 | + | if surface != nil { | |
| 81 | + | arg1 = surface | |
| 82 | + | } | |
| 83 | + | child := &ExtBackgroundEffectSurface{} | |
| 84 | + | child.SetContext(o.Context()) | |
| 85 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_background_effect_manager_v1.get_background_effect", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 86 | + | return nil, err | |
| 87 | + | } | |
| 88 | + | return child, nil | |
| 89 | + | } | |
| 90 | + | ||
| 91 | + | // OnCapabilities registers a handler for the capabilities event. | |
| 92 | + | // | |
| 93 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 94 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 95 | + | func (o *ExtBackgroundEffectManager) OnCapabilities(handler func(flags uint32)) { | |
| 96 | + | if handler == nil { | |
| 97 | + | return | |
| 98 | + | } | |
| 99 | + | o.handlersMu.Lock() | |
| 100 | + | defer o.handlersMu.Unlock() | |
| 101 | + | o.onCapabilities = append(o.onCapabilities, handler) | |
| 102 | + | } | |
| 103 | + | ||
| 104 | + | // handlersForCapabilities returns the handlers registered for capabilities, taken | |
| 105 | + | // under the lock so a handler may register another handler while events are | |
| 106 | + | // being dispatched. | |
| 107 | + | func (o *ExtBackgroundEffectManager) handlersForCapabilities() []func(flags uint32) { | |
| 108 | + | o.handlersMu.Lock() | |
| 109 | + | defer o.handlersMu.Unlock() | |
| 110 | + | return o.onCapabilities | |
| 111 | + | } | |
| 112 | + | ||
| 113 | + | // EventSignature returns the declared event argument types in wire order. | |
| 114 | + | func (o *ExtBackgroundEffectManager) EventSignature(opcode uint16) (string, bool) { | |
| 115 | + | switch opcode { | |
| 116 | + | case 0: | |
| 117 | + | return "uint,", true | |
| 118 | + | default: | |
| 119 | + | return "", false | |
| 120 | + | } | |
| 121 | + | } | |
| 122 | + | ||
| 123 | + | // Dispatch decodes one event on ext_background_effect_manager_v1 and calls the registered handlers. | |
| 124 | + | func (o *ExtBackgroundEffectManager) Dispatch(event *wl.Event) { | |
| 125 | + | switch event.Opcode { | |
| 126 | + | case 0: // capabilities | |
| 127 | + | flags := event.Uint32() | |
| 128 | + | ||
| 129 | + | for i, handler := range o.handlersForCapabilities() { | |
| 130 | + | _ = i | |
| 131 | + | handler(flags) | |
| 132 | + | } | |
| 133 | + | default: | |
| 134 | + | } | |
| 135 | + | } | |
| 136 | + | ||
| 137 | + | // ExtBackgroundEffectSurfaceInterface is the protocol interface name. | |
| 138 | + | const ExtBackgroundEffectSurfaceInterface = "ext_background_effect_surface_v1" | |
| 139 | + | ||
| 140 | + | // ExtBackgroundEffectSurface is the generated binding for ext_background_effect_surface_v1 version 1. | |
| 141 | + | type ExtBackgroundEffectSurface struct { | |
| 142 | + | wl.BaseProxy | |
| 143 | + | } | |
| 144 | + | ||
| 145 | + | // NewExtBackgroundEffectSurface returns an unbound ExtBackgroundEffectSurface. | |
| 146 | + | func NewExtBackgroundEffectSurface(ctx *wl.Context) *ExtBackgroundEffectSurface { | |
| 147 | + | obj := &ExtBackgroundEffectSurface{} | |
| 148 | + | obj.SetContext(ctx) | |
| 149 | + | ctx.Register(obj) | |
| 150 | + | return obj | |
| 151 | + | } | |
| 152 | + | ||
| 153 | + | // Informs the server that the client will no longer be using this protocol object. The effect regions will be removed on the next commit. | |
| 154 | + | func (o *ExtBackgroundEffectSurface) Destroy() error { | |
| 155 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_background_effect_surface_v1.destroy", Destructor: true}); err != nil { | |
| 156 | + | return err | |
| 157 | + | } | |
| 158 | + | return nil | |
| 159 | + | } | |
| 160 | + | ||
| 161 | + | // This request sets the region of the surface that will have its background blurred. The blur region is specified in the surface-local coordinates, and clipped by the compositor to the surface size. The initial value for the blur region is empty. Setting the pending blur region has copy semantics, and the wl_region object can be destroyed immediately. A NULL wl_region removes the effect. The blur region is double-buffered state, and will be applied on the next wl_surface.commit. The blur algorithm is subject to compositor policies. If the associated surface has been destroyed, the surface_destroyed error will be raised. | |
| 162 | + | func (o *ExtBackgroundEffectSurface) SetBlurRegion(region *cross_wl_region.Region) error { | |
| 163 | + | var arg0 wl.Object | |
| 164 | + | if region != nil { | |
| 165 | + | arg0 = region | |
| 166 | + | } | |
| 167 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_background_effect_surface_v1.set_blur_region"}, wl.ArgObject(arg0)); err != nil { | |
| 168 | + | return err | |
| 169 | + | } | |
| 170 | + | return nil | |
| 171 | + | } | |
| 172 | + | ||
| 173 | + | // EventSignature returns the declared event argument types in wire order. | |
| 174 | + | func (o *ExtBackgroundEffectSurface) EventSignature(opcode uint16) (string, bool) { | |
| 175 | + | switch opcode { | |
| 176 | + | default: | |
| 177 | + | return "", false | |
| 178 | + | } | |
| 179 | + | } | |
| 180 | + | ||
| 181 | + | // Dispatch decodes one event on ext_background_effect_surface_v1 and calls the registered handlers. | |
| 182 | + | func (o *ExtBackgroundEffectSurface) Dispatch(event *wl.Event) { | |
| 183 | + | switch event.Opcode { | |
| 184 | + | default: | |
| 185 | + | } | |
| 186 | + | } | |
A client/extdatacontrol/extdatacontrol_generated.go +505 -0
| @@ -0,0 +1,505 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: ext_data_control_v1 | |
| 3 | + | // Source: ext-data-control-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2018 Simon Ser | |
| 7 | + | // Copyright © 2019 Ivan Molodetskikh | |
| 8 | + | // Copyright © 2024 Neal Gompa | |
| 9 | + | // | |
| 10 | + | // Permission to use, copy, modify, distribute, and sell this | |
| 11 | + | // software and its documentation for any purpose is hereby granted | |
| 12 | + | // without fee, provided that the above copyright notice appear in | |
| 13 | + | // all copies and that both that copyright notice and this permission | |
| 14 | + | // notice appear in supporting documentation, and that the name of | |
| 15 | + | // the copyright holders not be used in advertising or publicity | |
| 16 | + | // pertaining to distribution of the software without specific, | |
| 17 | + | // written prior permission. The copyright holders make no | |
| 18 | + | // representations about the suitability of this software for any | |
| 19 | + | // purpose. It is provided "as is" without express or implied | |
| 20 | + | // warranty. | |
| 21 | + | // | |
| 22 | + | // THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
| 23 | + | // SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| 24 | + | // FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| 25 | + | // SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 26 | + | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
| 27 | + | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
| 28 | + | // ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| 29 | + | // THIS SOFTWARE. | |
| 30 | + | ||
| 31 | + | package extdatacontrol | |
| 32 | + | ||
| 33 | + | import ( | |
| 34 | + | "sync" | |
| 35 | + | ||
| 36 | + | cross_wl_seat "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 37 | + | "github.com/bnema/wlturbo/wl" | |
| 38 | + | ) | |
| 39 | + | ||
| 40 | + | // ERROR_USED_SOURCE is the error used_source value. | |
| 41 | + | const ERROR_USED_SOURCE = 1 | |
| 42 | + | ||
| 43 | + | // ERROR_INVALID_OFFER is the error invalid_offer value. | |
| 44 | + | const ERROR_INVALID_OFFER = 1 | |
| 45 | + | ||
| 46 | + | // ExtDataControlManagerInterface is the protocol interface name. | |
| 47 | + | const ExtDataControlManagerInterface = "ext_data_control_manager_v1" | |
| 48 | + | ||
| 49 | + | // ExtDataControlManager is the generated binding for ext_data_control_manager_v1 version 1. | |
| 50 | + | type ExtDataControlManager struct { | |
| 51 | + | wl.BaseProxy | |
| 52 | + | } | |
| 53 | + | ||
| 54 | + | // NewExtDataControlManager returns an unbound ExtDataControlManager. | |
| 55 | + | func NewExtDataControlManager(ctx *wl.Context) *ExtDataControlManager { | |
| 56 | + | obj := &ExtDataControlManager{} | |
| 57 | + | obj.SetContext(ctx) | |
| 58 | + | ctx.Register(obj) | |
| 59 | + | return obj | |
| 60 | + | } | |
| 61 | + | ||
| 62 | + | // Create a new data source. | |
| 63 | + | func (o *ExtDataControlManager) CreateDataSource() (*ExtDataControlSource, error) { | |
| 64 | + | child := &ExtDataControlSource{} | |
| 65 | + | child.SetContext(o.Context()) | |
| 66 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_data_control_manager_v1.create_data_source", Child: child}, wl.ArgObject(child)); err != nil { | |
| 67 | + | return nil, err | |
| 68 | + | } | |
| 69 | + | return child, nil | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | // Create a data device that can be used to manage a seat's selection. | |
| 73 | + | func (o *ExtDataControlManager) GetDataDevice(seat *cross_wl_seat.Seat) (*ExtDataControlDevice, error) { | |
| 74 | + | var arg1 wl.Object | |
| 75 | + | if seat != nil { | |
| 76 | + | arg1 = seat | |
| 77 | + | } | |
| 78 | + | child := &ExtDataControlDevice{} | |
| 79 | + | child.SetContext(o.Context()) | |
| 80 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_data_control_manager_v1.get_data_device", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 81 | + | return nil, err | |
| 82 | + | } | |
| 83 | + | return child, nil | |
| 84 | + | } | |
| 85 | + | ||
| 86 | + | // All objects created by the manager will still remain valid, until their appropriate destroy request has been called. | |
| 87 | + | func (o *ExtDataControlManager) Destroy() error { | |
| 88 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "ext_data_control_manager_v1.destroy", Destructor: true}); err != nil { | |
| 89 | + | return err | |
| 90 | + | } | |
| 91 | + | return nil | |
| 92 | + | } | |
| 93 | + | ||
| 94 | + | // EventSignature returns the declared event argument types in wire order. | |
| 95 | + | func (o *ExtDataControlManager) EventSignature(opcode uint16) (string, bool) { | |
| 96 | + | switch opcode { | |
| 97 | + | default: | |
| 98 | + | return "", false | |
| 99 | + | } | |
| 100 | + | } | |
| 101 | + | ||
| 102 | + | // Dispatch decodes one event on ext_data_control_manager_v1 and calls the registered handlers. | |
| 103 | + | func (o *ExtDataControlManager) Dispatch(event *wl.Event) { | |
| 104 | + | switch event.Opcode { | |
| 105 | + | default: | |
| 106 | + | } | |
| 107 | + | } | |
| 108 | + | ||
| 109 | + | // ExtDataControlDeviceInterface is the protocol interface name. | |
| 110 | + | const ExtDataControlDeviceInterface = "ext_data_control_device_v1" | |
| 111 | + | ||
| 112 | + | // ExtDataControlDevice is the generated binding for ext_data_control_device_v1 version 1. | |
| 113 | + | type ExtDataControlDevice struct { | |
| 114 | + | wl.BaseProxy | |
| 115 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 116 | + | // handlers while another goroutine dispatches events. | |
| 117 | + | handlersMu sync.Mutex | |
| 118 | + | onDataOffer []func(idObject *ExtDataControlOffer) | |
| 119 | + | onSelection []func(idID uint32) | |
| 120 | + | onFinished []func() | |
| 121 | + | onPrimarySelection []func(idID uint32) | |
| 122 | + | } | |
| 123 | + | ||
| 124 | + | // NewExtDataControlDevice returns an unbound ExtDataControlDevice. | |
| 125 | + | func NewExtDataControlDevice(ctx *wl.Context) *ExtDataControlDevice { | |
| 126 | + | obj := &ExtDataControlDevice{} | |
| 127 | + | obj.SetContext(ctx) | |
| 128 | + | ctx.Register(obj) | |
| 129 | + | return obj | |
| 130 | + | } | |
| 131 | + | ||
| 132 | + | // This request asks the compositor to set the selection to the data from the source on behalf of the client. The given source may not be used in any further set_selection or set_primary_selection requests. Attempting to use a previously used source triggers the used_source protocol error. To unset the selection, set the source to NULL. | |
| 133 | + | func (o *ExtDataControlDevice) SetSelection(source *ExtDataControlSource) error { | |
| 134 | + | var arg0 wl.Object | |
| 135 | + | if source != nil { | |
| 136 | + | arg0 = source | |
| 137 | + | } | |
| 138 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_data_control_device_v1.set_selection"}, wl.ArgObject(arg0)); err != nil { | |
| 139 | + | return err | |
| 140 | + | } | |
| 141 | + | return nil | |
| 142 | + | } | |
| 143 | + | ||
| 144 | + | // Destroys the data device object. | |
| 145 | + | func (o *ExtDataControlDevice) Destroy() error { | |
| 146 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_data_control_device_v1.destroy", Destructor: true}); err != nil { | |
| 147 | + | return err | |
| 148 | + | } | |
| 149 | + | return nil | |
| 150 | + | } | |
| 151 | + | ||
| 152 | + | // This request asks the compositor to set the primary selection to the data from the source on behalf of the client. The given source may not be used in any further set_selection or set_primary_selection requests. Attempting to use a previously used source triggers the used_source protocol error. To unset the primary selection, set the source to NULL. The compositor will ignore this request if it does not support primary selection. | |
| 153 | + | func (o *ExtDataControlDevice) SetPrimarySelection(source *ExtDataControlSource) error { | |
| 154 | + | var arg0 wl.Object | |
| 155 | + | if source != nil { | |
| 156 | + | arg0 = source | |
| 157 | + | } | |
| 158 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "ext_data_control_device_v1.set_primary_selection"}, wl.ArgObject(arg0)); err != nil { | |
| 159 | + | return err | |
| 160 | + | } | |
| 161 | + | return nil | |
| 162 | + | } | |
| 163 | + | ||
| 164 | + | // OnDataOffer registers a handler for the data_offer event. | |
| 165 | + | // | |
| 166 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 167 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 168 | + | func (o *ExtDataControlDevice) OnDataOffer(handler func(idObject *ExtDataControlOffer)) { | |
| 169 | + | if handler == nil { | |
| 170 | + | return | |
| 171 | + | } | |
| 172 | + | o.handlersMu.Lock() | |
| 173 | + | defer o.handlersMu.Unlock() | |
| 174 | + | o.onDataOffer = append(o.onDataOffer, handler) | |
| 175 | + | } | |
| 176 | + | ||
| 177 | + | // handlersForDataOffer returns the handlers registered for data_offer, taken | |
| 178 | + | // under the lock so a handler may register another handler while events are | |
| 179 | + | // being dispatched. | |
| 180 | + | func (o *ExtDataControlDevice) handlersForDataOffer() []func(idObject *ExtDataControlOffer) { | |
| 181 | + | o.handlersMu.Lock() | |
| 182 | + | defer o.handlersMu.Unlock() | |
| 183 | + | return o.onDataOffer | |
| 184 | + | } | |
| 185 | + | ||
| 186 | + | // OnSelection registers a handler for the selection event. | |
| 187 | + | // | |
| 188 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 189 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 190 | + | func (o *ExtDataControlDevice) OnSelection(handler func(idID uint32)) { | |
| 191 | + | if handler == nil { | |
| 192 | + | return | |
| 193 | + | } | |
| 194 | + | o.handlersMu.Lock() | |
| 195 | + | defer o.handlersMu.Unlock() | |
| 196 | + | o.onSelection = append(o.onSelection, handler) | |
| 197 | + | } | |
| 198 | + | ||
| 199 | + | // handlersForSelection returns the handlers registered for selection, taken | |
| 200 | + | // under the lock so a handler may register another handler while events are | |
| 201 | + | // being dispatched. | |
| 202 | + | func (o *ExtDataControlDevice) handlersForSelection() []func(idID uint32) { | |
| 203 | + | o.handlersMu.Lock() | |
| 204 | + | defer o.handlersMu.Unlock() | |
| 205 | + | return o.onSelection | |
| 206 | + | } | |
| 207 | + | ||
| 208 | + | // OnFinished registers a handler for the finished event. | |
| 209 | + | // | |
| 210 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 211 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 212 | + | func (o *ExtDataControlDevice) OnFinished(handler func()) { | |
| 213 | + | if handler == nil { | |
| 214 | + | return | |
| 215 | + | } | |
| 216 | + | o.handlersMu.Lock() | |
| 217 | + | defer o.handlersMu.Unlock() | |
| 218 | + | o.onFinished = append(o.onFinished, handler) | |
| 219 | + | } | |
| 220 | + | ||
| 221 | + | // handlersForFinished returns the handlers registered for finished, taken | |
| 222 | + | // under the lock so a handler may register another handler while events are | |
| 223 | + | // being dispatched. | |
| 224 | + | func (o *ExtDataControlDevice) handlersForFinished() []func() { | |
| 225 | + | o.handlersMu.Lock() | |
| 226 | + | defer o.handlersMu.Unlock() | |
| 227 | + | return o.onFinished | |
| 228 | + | } | |
| 229 | + | ||
| 230 | + | // OnPrimarySelection registers a handler for the primary_selection event. | |
| 231 | + | // | |
| 232 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 233 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 234 | + | func (o *ExtDataControlDevice) OnPrimarySelection(handler func(idID uint32)) { | |
| 235 | + | if handler == nil { | |
| 236 | + | return | |
| 237 | + | } | |
| 238 | + | o.handlersMu.Lock() | |
| 239 | + | defer o.handlersMu.Unlock() | |
| 240 | + | o.onPrimarySelection = append(o.onPrimarySelection, handler) | |
| 241 | + | } | |
| 242 | + | ||
| 243 | + | // handlersForPrimarySelection returns the handlers registered for primary_selection, taken | |
| 244 | + | // under the lock so a handler may register another handler while events are | |
| 245 | + | // being dispatched. | |
| 246 | + | func (o *ExtDataControlDevice) handlersForPrimarySelection() []func(idID uint32) { | |
| 247 | + | o.handlersMu.Lock() | |
| 248 | + | defer o.handlersMu.Unlock() | |
| 249 | + | return o.onPrimarySelection | |
| 250 | + | } | |
| 251 | + | ||
| 252 | + | // EventSignature returns the declared event argument types in wire order. | |
| 253 | + | func (o *ExtDataControlDevice) EventSignature(opcode uint16) (string, bool) { | |
| 254 | + | switch opcode { | |
| 255 | + | case 0: | |
| 256 | + | return "new_id,", true | |
| 257 | + | case 1: | |
| 258 | + | return "object,", true | |
| 259 | + | case 2: | |
| 260 | + | return "", true | |
| 261 | + | case 3: | |
| 262 | + | return "object,", true | |
| 263 | + | default: | |
| 264 | + | return "", false | |
| 265 | + | } | |
| 266 | + | } | |
| 267 | + | ||
| 268 | + | // Dispatch decodes one event on ext_data_control_device_v1 and calls the registered handlers. | |
| 269 | + | func (o *ExtDataControlDevice) Dispatch(event *wl.Event) { | |
| 270 | + | switch event.Opcode { | |
| 271 | + | case 0: // data_offer | |
| 272 | + | idID := event.Uint32() | |
| 273 | + | idObject := &ExtDataControlOffer{} | |
| 274 | + | idObject.SetContext(o.Context()) | |
| 275 | + | idObject.SetID(idID) | |
| 276 | + | idObject.SetVersion(o.Version()) | |
| 277 | + | o.Context().Register(idObject) | |
| 278 | + | ||
| 279 | + | for i, handler := range o.handlersForDataOffer() { | |
| 280 | + | _ = i | |
| 281 | + | handler(idObject) | |
| 282 | + | } | |
| 283 | + | case 1: // selection | |
| 284 | + | idID := event.Uint32() | |
| 285 | + | ||
| 286 | + | for i, handler := range o.handlersForSelection() { | |
| 287 | + | _ = i | |
| 288 | + | handler(idID) | |
| 289 | + | } | |
| 290 | + | case 2: // finished | |
| 291 | + | ||
| 292 | + | for i, handler := range o.handlersForFinished() { | |
| 293 | + | _ = i | |
| 294 | + | handler() | |
| 295 | + | } | |
| 296 | + | case 3: // primary_selection | |
| 297 | + | idID := event.Uint32() | |
| 298 | + | ||
| 299 | + | for i, handler := range o.handlersForPrimarySelection() { | |
| 300 | + | _ = i | |
| 301 | + | handler(idID) | |
| 302 | + | } | |
| 303 | + | default: | |
| 304 | + | } | |
| 305 | + | } | |
| 306 | + | ||
| 307 | + | // ExtDataControlSourceInterface is the protocol interface name. | |
| 308 | + | const ExtDataControlSourceInterface = "ext_data_control_source_v1" | |
| 309 | + | ||
| 310 | + | // ExtDataControlSource is the generated binding for ext_data_control_source_v1 version 1. | |
| 311 | + | type ExtDataControlSource struct { | |
| 312 | + | wl.BaseProxy | |
| 313 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 314 | + | // handlers while another goroutine dispatches events. | |
| 315 | + | handlersMu sync.Mutex | |
| 316 | + | onSend []func(mimeType string, fd *wl.OwnedFD) | |
| 317 | + | onCancelled []func() | |
| 318 | + | } | |
| 319 | + | ||
| 320 | + | // NewExtDataControlSource returns an unbound ExtDataControlSource. | |
| 321 | + | func NewExtDataControlSource(ctx *wl.Context) *ExtDataControlSource { | |
| 322 | + | obj := &ExtDataControlSource{} | |
| 323 | + | obj.SetContext(ctx) | |
| 324 | + | ctx.Register(obj) | |
| 325 | + | return obj | |
| 326 | + | } | |
| 327 | + | ||
| 328 | + | // This request adds a MIME type to the set of MIME types advertised to targets. Can be called several times to offer multiple types. Calling this after ext_data_control_device.set_selection is a protocol error. | |
| 329 | + | func (o *ExtDataControlSource) Offer(mimeType string) error { | |
| 330 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_data_control_source_v1.offer"}, wl.ArgString(mimeType)); err != nil { | |
| 331 | + | return err | |
| 332 | + | } | |
| 333 | + | return nil | |
| 334 | + | } | |
| 335 | + | ||
| 336 | + | // Destroys the data source object. | |
| 337 | + | func (o *ExtDataControlSource) Destroy() error { | |
| 338 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_data_control_source_v1.destroy", Destructor: true}); err != nil { | |
| 339 | + | return err | |
| 340 | + | } | |
| 341 | + | return nil | |
| 342 | + | } | |
| 343 | + | ||
| 344 | + | // OnSend registers a handler for the send event. | |
| 345 | + | // | |
| 346 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 347 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 348 | + | func (o *ExtDataControlSource) OnSend(handler func(mimeType string, fd *wl.OwnedFD)) { | |
| 349 | + | if handler == nil { | |
| 350 | + | return | |
| 351 | + | } | |
| 352 | + | o.handlersMu.Lock() | |
| 353 | + | defer o.handlersMu.Unlock() | |
| 354 | + | o.onSend = append(o.onSend, handler) | |
| 355 | + | } | |
| 356 | + | ||
| 357 | + | // handlersForSend returns the handlers registered for send, taken | |
| 358 | + | // under the lock so a handler may register another handler while events are | |
| 359 | + | // being dispatched. | |
| 360 | + | func (o *ExtDataControlSource) handlersForSend() []func(mimeType string, fd *wl.OwnedFD) { | |
| 361 | + | o.handlersMu.Lock() | |
| 362 | + | defer o.handlersMu.Unlock() | |
| 363 | + | return o.onSend | |
| 364 | + | } | |
| 365 | + | ||
| 366 | + | // OnCancelled registers a handler for the cancelled event. | |
| 367 | + | // | |
| 368 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 369 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 370 | + | func (o *ExtDataControlSource) OnCancelled(handler func()) { | |
| 371 | + | if handler == nil { | |
| 372 | + | return | |
| 373 | + | } | |
| 374 | + | o.handlersMu.Lock() | |
| 375 | + | defer o.handlersMu.Unlock() | |
| 376 | + | o.onCancelled = append(o.onCancelled, handler) | |
| 377 | + | } | |
| 378 | + | ||
| 379 | + | // handlersForCancelled returns the handlers registered for cancelled, taken | |
| 380 | + | // under the lock so a handler may register another handler while events are | |
| 381 | + | // being dispatched. | |
| 382 | + | func (o *ExtDataControlSource) handlersForCancelled() []func() { | |
| 383 | + | o.handlersMu.Lock() | |
| 384 | + | defer o.handlersMu.Unlock() | |
| 385 | + | return o.onCancelled | |
| 386 | + | } | |
| 387 | + | ||
| 388 | + | // EventSignature returns the declared event argument types in wire order. | |
| 389 | + | func (o *ExtDataControlSource) EventSignature(opcode uint16) (string, bool) { | |
| 390 | + | switch opcode { | |
| 391 | + | case 0: | |
| 392 | + | return "string,fd,", true | |
| 393 | + | case 1: | |
| 394 | + | return "", true | |
| 395 | + | default: | |
| 396 | + | return "", false | |
| 397 | + | } | |
| 398 | + | } | |
| 399 | + | ||
| 400 | + | // Dispatch decodes one event on ext_data_control_source_v1 and calls the registered handlers. | |
| 401 | + | func (o *ExtDataControlSource) Dispatch(event *wl.Event) { | |
| 402 | + | switch event.Opcode { | |
| 403 | + | case 0: // send | |
| 404 | + | mimeType := event.String() | |
| 405 | + | fd := event.FD() | |
| 406 | + | ownedfd := fd | |
| 407 | + | defer ownedfd.Close() | |
| 408 | + | ||
| 409 | + | for i, handler := range o.handlersForSend() { | |
| 410 | + | if i > 0 { | |
| 411 | + | fd = nil | |
| 412 | + | } | |
| 413 | + | handler(mimeType, fd) | |
| 414 | + | } | |
| 415 | + | case 1: // cancelled | |
| 416 | + | ||
| 417 | + | for i, handler := range o.handlersForCancelled() { | |
| 418 | + | _ = i | |
| 419 | + | handler() | |
| 420 | + | } | |
| 421 | + | default: | |
| 422 | + | } | |
| 423 | + | } | |
| 424 | + | ||
| 425 | + | // ExtDataControlOfferInterface is the protocol interface name. | |
| 426 | + | const ExtDataControlOfferInterface = "ext_data_control_offer_v1" | |
| 427 | + | ||
| 428 | + | // ExtDataControlOffer is the generated binding for ext_data_control_offer_v1 version 1. | |
| 429 | + | type ExtDataControlOffer struct { | |
| 430 | + | wl.BaseProxy | |
| 431 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 432 | + | // handlers while another goroutine dispatches events. | |
| 433 | + | handlersMu sync.Mutex | |
| 434 | + | onOffer []func(mimeType string) | |
| 435 | + | } | |
| 436 | + | ||
| 437 | + | // NewExtDataControlOffer returns an unbound ExtDataControlOffer. | |
| 438 | + | func NewExtDataControlOffer(ctx *wl.Context) *ExtDataControlOffer { | |
| 439 | + | obj := &ExtDataControlOffer{} | |
| 440 | + | obj.SetContext(ctx) | |
| 441 | + | ctx.Register(obj) | |
| 442 | + | return obj | |
| 443 | + | } | |
| 444 | + | ||
| 445 | + | // To transfer the offered data, the client issues this request and indicates the MIME type it wants to receive. The transfer happens through the passed file descriptor (typically created with the pipe system call). The source client writes the data in the MIME type representation requested and then closes the file descriptor. The receiving client reads from the read end of the pipe until EOF and then closes its end, at which point the transfer is complete. This request may happen multiple times for different MIME types. | |
| 446 | + | func (o *ExtDataControlOffer) Receive(mimeType string, fd int) error { | |
| 447 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_data_control_offer_v1.receive", FDs: []int{fd}}, wl.ArgString(mimeType), wl.ArgFD()); err != nil { | |
| 448 | + | return err | |
| 449 | + | } | |
| 450 | + | return nil | |
| 451 | + | } | |
| 452 | + | ||
| 453 | + | // Destroys the data offer object. | |
| 454 | + | func (o *ExtDataControlOffer) Destroy() error { | |
| 455 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_data_control_offer_v1.destroy", Destructor: true}); err != nil { | |
| 456 | + | return err | |
| 457 | + | } | |
| 458 | + | return nil | |
| 459 | + | } | |
| 460 | + | ||
| 461 | + | // OnOffer registers a handler for the offer event. | |
| 462 | + | // | |
| 463 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 464 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 465 | + | func (o *ExtDataControlOffer) OnOffer(handler func(mimeType string)) { | |
| 466 | + | if handler == nil { | |
| 467 | + | return | |
| 468 | + | } | |
| 469 | + | o.handlersMu.Lock() | |
| 470 | + | defer o.handlersMu.Unlock() | |
| 471 | + | o.onOffer = append(o.onOffer, handler) | |
| 472 | + | } | |
| 473 | + | ||
| 474 | + | // handlersForOffer returns the handlers registered for offer, taken | |
| 475 | + | // under the lock so a handler may register another handler while events are | |
| 476 | + | // being dispatched. | |
| 477 | + | func (o *ExtDataControlOffer) handlersForOffer() []func(mimeType string) { | |
| 478 | + | o.handlersMu.Lock() | |
| 479 | + | defer o.handlersMu.Unlock() | |
| 480 | + | return o.onOffer | |
| 481 | + | } | |
| 482 | + | ||
| 483 | + | // EventSignature returns the declared event argument types in wire order. | |
| 484 | + | func (o *ExtDataControlOffer) EventSignature(opcode uint16) (string, bool) { | |
| 485 | + | switch opcode { | |
| 486 | + | case 0: | |
| 487 | + | return "string,", true | |
| 488 | + | default: | |
| 489 | + | return "", false | |
| 490 | + | } | |
| 491 | + | } | |
| 492 | + | ||
| 493 | + | // Dispatch decodes one event on ext_data_control_offer_v1 and calls the registered handlers. | |
| 494 | + | func (o *ExtDataControlOffer) Dispatch(event *wl.Event) { | |
| 495 | + | switch event.Opcode { | |
| 496 | + | case 0: // offer | |
| 497 | + | mimeType := event.String() | |
| 498 | + | ||
| 499 | + | for i, handler := range o.handlersForOffer() { | |
| 500 | + | _ = i | |
| 501 | + | handler(mimeType) | |
| 502 | + | } | |
| 503 | + | default: | |
| 504 | + | } | |
| 505 | + | } | |
A client/extensions_test.go +722 -0
| @@ -0,0 +1,722 @@ | |||
| 1 | + | //go:build linux | |
| 2 | + | ||
| 3 | + | package client_test | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "encoding/binary" | |
| 7 | + | "errors" | |
| 8 | + | "net" | |
| 9 | + | "os" | |
| 10 | + | "slices" | |
| 11 | + | "strings" | |
| 12 | + | "testing" | |
| 13 | + | "time" | |
| 14 | + | ||
| 15 | + | "github.com/bnema/go-wayland-bindings/client/cursorshape" | |
| 16 | + | "github.com/bnema/go-wayland-bindings/client/fractionalscale" | |
| 17 | + | "github.com/bnema/go-wayland-bindings/client/linuxdmabuf" | |
| 18 | + | drmsyncobj "github.com/bnema/go-wayland-bindings/client/linuxdrmsyncobj" | |
| 19 | + | "github.com/bnema/go-wayland-bindings/client/textinput" | |
| 20 | + | "github.com/bnema/go-wayland-bindings/client/viewporter" | |
| 21 | + | "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 22 | + | "github.com/bnema/go-wayland-bindings/client/xdgshell" | |
| 23 | + | "github.com/bnema/wlturbo" | |
| 24 | + | "golang.org/x/sys/unix" | |
| 25 | + | ) | |
| 26 | + | ||
| 27 | + | func pair(t *testing.T) (*net.UnixConn, *net.UnixConn) { | |
| 28 | + | t.Helper() | |
| 29 | + | fds, e := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0) | |
| 30 | + | if e != nil { | |
| 31 | + | t.Fatal(e) | |
| 32 | + | } | |
| 33 | + | a := os.NewFile(uintptr(fds[0]), "a") | |
| 34 | + | b := os.NewFile(uintptr(fds[1]), "b") | |
| 35 | + | ca, e := net.FileConn(a) | |
| 36 | + | a.Close() | |
| 37 | + | if e != nil { | |
| 38 | + | t.Fatal(e) | |
| 39 | + | } | |
| 40 | + | cb, e := net.FileConn(b) | |
| 41 | + | b.Close() | |
| 42 | + | if e != nil { | |
| 43 | + | t.Fatal(e) | |
| 44 | + | } | |
| 45 | + | t.Cleanup(func() { ca.Close(); cb.Close() }) | |
| 46 | + | return ca.(*net.UnixConn), cb.(*net.UnixConn) | |
| 47 | + | } | |
| 48 | + | func msg(id uint32, op uint16, body ...uint32) []byte { | |
| 49 | + | b := make([]byte, 8+4*len(body)) | |
| 50 | + | binary.NativeEndian.PutUint32(b, id) | |
| 51 | + | binary.NativeEndian.PutUint32(b[4:], uint32(len(b))<<16|uint32(op)) | |
| 52 | + | for i, v := range body { | |
| 53 | + | binary.NativeEndian.PutUint32(b[8+i*4:], v) | |
| 54 | + | } | |
| 55 | + | return b | |
| 56 | + | } | |
| 57 | + | func payload(id uint32, op uint16, b ...byte) []byte { | |
| 58 | + | p := make([]byte, 8+len(b)) | |
| 59 | + | copy(p, msg(id, op)) | |
| 60 | + | copy(p[8:], b) | |
| 61 | + | binary.NativeEndian.PutUint32(p[4:], uint32(len(p))<<16|uint32(op)) | |
| 62 | + | return p | |
| 63 | + | } | |
| 64 | + | func arr(b []byte) []byte { | |
| 65 | + | out := make([]byte, 4+(len(b)+3)&^3) | |
| 66 | + | binary.NativeEndian.PutUint32(out, uint32(len(b))) | |
| 67 | + | copy(out[4:], b) | |
| 68 | + | return out | |
| 69 | + | } | |
| 70 | + | func str(s string) []byte { return arr(append([]byte(s), 0)) } | |
| 71 | + | func send(t *testing.T, p *net.UnixConn, b []byte, fd ...int) { | |
| 72 | + | t.Helper() | |
| 73 | + | var rights []byte | |
| 74 | + | if len(fd) > 0 { | |
| 75 | + | rights = unix.UnixRights(fd...) | |
| 76 | + | } | |
| 77 | + | if _, _, e := p.WriteMsgUnix(b, rights, nil); e != nil { | |
| 78 | + | t.Fatal(e) | |
| 79 | + | } | |
| 80 | + | } | |
| 81 | + | func request(t *testing.T, p *net.UnixConn) (uint32, uint16, []byte) { | |
| 82 | + | t.Helper() | |
| 83 | + | p.SetReadDeadline(time.Now().Add(2 * time.Second)) | |
| 84 | + | b := make([]byte, 4096) | |
| 85 | + | n, e := p.Read(b) | |
| 86 | + | if e != nil { | |
| 87 | + | t.Fatal(e) | |
| 88 | + | } | |
| 89 | + | if n < 8 { | |
| 90 | + | t.Fatal("short request") | |
| 91 | + | } | |
| 92 | + | return binary.NativeEndian.Uint32(b), uint16(binary.NativeEndian.Uint32(b[4:])), b[8:n] | |
| 93 | + | } | |
| 94 | + | func noerr(t *testing.T, e error) { | |
| 95 | + | t.Helper() | |
| 96 | + | if e != nil { | |
| 97 | + | t.Fatal(e) | |
| 98 | + | } | |
| 99 | + | } | |
| 100 | + | func bind(t *testing.T, d *wlturbo.Display, p *net.UnixConn, name uint32, iface string, announced uint32, supported uint32, proxy wlturbo.Proxy) { | |
| 101 | + | t.Helper() | |
| 102 | + | // A fake server must advertise a global before clients can negotiate it. | |
| 103 | + | announcement := append(msg(0, 0, name)[8:], str(iface)...) | |
| 104 | + | announcement = append(announcement, msg(0, 0, announced)[8:]...) | |
| 105 | + | send(t, p, payload(d.Registry().ID(), 0, announcement...)) | |
| 106 | + | noerr(t, d.Dispatch()) | |
| 107 | + | v, err := d.Registry().BindNegotiated(iface, supported, proxy) | |
| 108 | + | noerr(t, err) | |
| 109 | + | want := min(announced, supported) | |
| 110 | + | _, op, b := request(t, p) | |
| 111 | + | if op != 0 || v != want || binary.NativeEndian.Uint32(b) != name || binary.NativeEndian.Uint32(b[len(b)-8:]) != want || binary.NativeEndian.Uint32(b[len(b)-4:]) != proxy.ID() { | |
| 112 | + | t.Fatalf("bad bind %s announced=%d supported=%d negotiated=%d wire=%x", iface, announced, supported, v, b) | |
| 113 | + | } | |
| 114 | + | } | |
| 115 | + | ||
| 116 | + | // serverID is the first server-allocated object ID on the wire. | |
| 117 | + | const serverID = 0xff000000 | |
| 118 | + | ||
| 119 | + | // wordBytes encodes 32-bit words as a message body in native byte order. | |
| 120 | + | func wordBytes(v ...uint32) []byte { return msg(0, 0, v...)[8:] } | |
| 121 | + | ||
| 122 | + | // cat concatenates message body fragments. | |
| 123 | + | func cat(parts ...[]byte) []byte { | |
| 124 | + | var out []byte | |
| 125 | + | for _, p := range parts { | |
| 126 | + | out = append(out, p...) | |
| 127 | + | } | |
| 128 | + | return out | |
| 129 | + | } | |
| 130 | + | ||
| 131 | + | // decodeWords splits a message body into 32-bit words. | |
| 132 | + | func decodeWords(b []byte) []uint32 { | |
| 133 | + | w := make([]uint32, len(b)/4) | |
| 134 | + | for i := range w { | |
| 135 | + | w[i] = binary.NativeEndian.Uint32(b[i*4:]) | |
| 136 | + | } | |
| 137 | + | return w | |
| 138 | + | } | |
| 139 | + | ||
| 140 | + | // wantWords requires a request body to be exactly the given 32-bit words. | |
| 141 | + | func wantWords(t *testing.T, what string, b []byte, want ...uint32) { | |
| 142 | + | t.Helper() | |
| 143 | + | if got := decodeWords(b); !slices.Equal(got, want) { // nil and empty are equal | |
| 144 | + | t.Fatalf("%s wire = %v, want %v", what, got, want) | |
| 145 | + | } | |
| 146 | + | } | |
| 147 | + | ||
| 148 | + | // wantRequestWords reads one request and requires its exact object, opcode and | |
| 149 | + | // 32-bit word arguments. | |
| 150 | + | func wantRequestWords(t *testing.T, p *net.UnixConn, id uint32, op uint16, want ...uint32) { | |
| 151 | + | t.Helper() | |
| 152 | + | gid, gop, body := request(t, p) | |
| 153 | + | if gid != id || gop != op || len(body) != 4*len(want) { | |
| 154 | + | t.Fatalf("request object=%d op=%d body=%x, want object=%d op=%d words=%v", gid, gop, body, id, op, want) | |
| 155 | + | } | |
| 156 | + | wantWords(t, "request", body, want...) | |
| 157 | + | } | |
| 158 | + | ||
| 159 | + | // requireFDClosed fails if fd is still open in this process: the binding must | |
| 160 | + | // close its copy of a descriptor once the kernel took it with a request. Call | |
| 161 | + | // it before reading the request, because the received duplicate may reuse the | |
| 162 | + | // same descriptor number. | |
| 163 | + | func requireFDClosed(t *testing.T, fd int) { | |
| 164 | + | t.Helper() | |
| 165 | + | if _, e := unix.FcntlInt(uintptr(fd), unix.F_GETFD, 0); e == nil { | |
| 166 | + | t.Fatalf("descriptor %d sent by the client was not closed", fd) | |
| 167 | + | } | |
| 168 | + | } | |
| 169 | + | ||
| 170 | + | // requireNoWrite fails unless the client wrote nothing within a short deadline. | |
| 171 | + | func requireNoWrite(t *testing.T, p *net.UnixConn) { | |
| 172 | + | t.Helper() | |
| 173 | + | p.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) | |
| 174 | + | var b [64]byte | |
| 175 | + | n, e := p.Read(b[:]) | |
| 176 | + | if e == nil { | |
| 177 | + | t.Fatalf("unexpected bytes on the wire: %x", b[:n]) | |
| 178 | + | } | |
| 179 | + | if !errors.Is(e, os.ErrDeadlineExceeded) { | |
| 180 | + | t.Fatal(e) | |
| 181 | + | } | |
| 182 | + | } | |
| 183 | + | ||
| 184 | + | // recvRequestFDs reads one client message and the descriptors that came with | |
| 185 | + | // it. Every received descriptor is closed before a fatal failure, so a failed | |
| 186 | + | // check cannot leak them; on success the caller owns fds. | |
| 187 | + | func recvRequestFDs(t *testing.T, p *net.UnixConn) (id uint32, op uint16, body []byte, fds []int) { | |
| 188 | + | t.Helper() | |
| 189 | + | fail := func(format string, args ...any) { | |
| 190 | + | t.Helper() | |
| 191 | + | for _, fd := range fds { | |
| 192 | + | unix.Close(fd) | |
| 193 | + | } | |
| 194 | + | t.Fatalf(format, args...) | |
| 195 | + | } | |
| 196 | + | p.SetReadDeadline(time.Now().Add(2 * time.Second)) | |
| 197 | + | b := make([]byte, 4096) | |
| 198 | + | oob := make([]byte, 256) | |
| 199 | + | n, oobn, _, _, e := p.ReadMsgUnix(b, oob) | |
| 200 | + | if oobn > 0 { | |
| 201 | + | msgs, pe := unix.ParseSocketControlMessage(oob[:oobn]) | |
| 202 | + | for i := range msgs { | |
| 203 | + | r, re := unix.ParseUnixRights(&msgs[i]) | |
| 204 | + | fds = append(fds, r...) | |
| 205 | + | if re != nil && pe == nil { | |
| 206 | + | pe = re | |
| 207 | + | } | |
| 208 | + | } | |
| 209 | + | if pe != nil { | |
| 210 | + | fail("control message: %v", pe) | |
| 211 | + | } | |
| 212 | + | } | |
| 213 | + | if e != nil { | |
| 214 | + | fail("read request: %v", e) | |
| 215 | + | } | |
| 216 | + | if n < 8 { | |
| 217 | + | fail("short request (%d bytes)", n) | |
| 218 | + | } | |
| 219 | + | if size := int(binary.NativeEndian.Uint32(b[4:]) >> 16); size != n { | |
| 220 | + | fail("header size %d != %d bytes read", size, n) | |
| 221 | + | } | |
| 222 | + | return binary.NativeEndian.Uint32(b), uint16(binary.NativeEndian.Uint32(b[4:])), b[8:n], fds | |
| 223 | + | } | |
| 224 | + | ||
| 225 | + | // requestWithFD reads the next request, requires its object and opcode, and | |
| 226 | + | // requires exactly one descriptor, which the caller then owns. | |
| 227 | + | func requestWithFD(t *testing.T, p *net.UnixConn, id uint32, op uint16) ([]byte, int) { | |
| 228 | + | t.Helper() | |
| 229 | + | gid, gop, body, fds := recvRequestFDs(t, p) | |
| 230 | + | if gid != id || gop != op || len(fds) != 1 { | |
| 231 | + | for _, fd := range fds { | |
| 232 | + | unix.Close(fd) | |
| 233 | + | } | |
| 234 | + | t.Fatalf("request object=%d op=%d fds=%d, want object=%d op=%d with 1 descriptor (body %x)", gid, gop, len(fds), id, op, body) | |
| 235 | + | } | |
| 236 | + | return body, fds[0] | |
| 237 | + | } | |
| 238 | + | ||
| 239 | + | // register gives a proxy a client-allocated ID and registers it with d. | |
| 240 | + | func register(d *wlturbo.Display, o wlturbo.Proxy) { | |
| 241 | + | o.SetID(d.AllocateID()) | |
| 242 | + | d.Context().Register(o) | |
| 243 | + | } | |
| 244 | + | ||
| 245 | + | // wireEnv is one client connection against a fake compositor on a socketpair. | |
| 246 | + | type wireEnv struct { | |
| 247 | + | t *testing.T | |
| 248 | + | d *wlturbo.Display | |
| 249 | + | p *net.UnixConn | |
| 250 | + | } | |
| 251 | + | ||
| 252 | + | func newWireEnv(t *testing.T) *wireEnv { | |
| 253 | + | t.Helper() | |
| 254 | + | c, p := pair(t) | |
| 255 | + | d, e := wlturbo.ConnectFromConn(c) | |
| 256 | + | noerr(t, e) | |
| 257 | + | t.Cleanup(func() { d.Close() }) | |
| 258 | + | request(t, p) // wl_display.get_registry | |
| 259 | + | return &wireEnv{t: t, d: d, p: p} | |
| 260 | + | } | |
| 261 | + | ||
| 262 | + | func (s *wireEnv) dispatch() { s.t.Helper(); noerr(s.t, s.d.Dispatch()) } | |
| 263 | + | ||
| 264 | + | // bind advertises and binds a global; see the package-level bind. | |
| 265 | + | func (s *wireEnv) bind(name uint32, iface string, announced, supported uint32, proxy wlturbo.Proxy) { | |
| 266 | + | s.t.Helper() | |
| 267 | + | bind(s.t, s.d, s.p, name, iface, announced, supported, proxy) | |
| 268 | + | } | |
| 269 | + | ||
| 270 | + | // event sends one server event and dispatches it on the client. | |
| 271 | + | func (s *wireEnv) event(id uint32, op uint16, body ...byte) { | |
| 272 | + | s.t.Helper() | |
| 273 | + | s.eventFD(id, op, body) | |
| 274 | + | } | |
| 275 | + | ||
| 276 | + | // eventFD is event for an event that carries descriptors (SCM_RIGHTS). | |
| 277 | + | func (s *wireEnv) eventFD(id uint32, op uint16, body []byte, fd ...int) { | |
| 278 | + | s.t.Helper() | |
| 279 | + | send(s.t, s.p, payload(id, op, body...), fd...) | |
| 280 | + | s.dispatch() | |
| 281 | + | } | |
| 282 | + | ||
| 283 | + | // req reads the next client request and checks its object and opcode. | |
| 284 | + | func (s *wireEnv) req(id uint32, op uint16) []byte { | |
| 285 | + | s.t.Helper() | |
| 286 | + | gid, gop, b := request(s.t, s.p) | |
| 287 | + | if gid != id || gop != op { | |
| 288 | + | s.t.Fatalf("request object=%d op=%d, want object=%d op=%d (body %x)", gid, gop, id, op, b) | |
| 289 | + | } | |
| 290 | + | return b | |
| 291 | + | } | |
| 292 | + | ||
| 293 | + | // reqFD is req for a request that carries exactly one descriptor. | |
| 294 | + | func (s *wireEnv) reqFD(id uint32, op uint16) ([]byte, int) { | |
| 295 | + | s.t.Helper() | |
| 296 | + | return requestWithFD(s.t, s.p, id, op) | |
| 297 | + | } | |
| 298 | + | ||
| 299 | + | // noRequest fails if the client wrote anything. | |
| 300 | + | func (s *wireEnv) noRequest() { s.t.Helper(); requireNoWrite(s.t, s.p) } | |
| 301 | + | ||
| 302 | + | func (s *wireEnv) surface() *wayland.Surface { | |
| 303 | + | o := wayland.NewSurface(s.d.Context()) | |
| 304 | + | register(s.d, o) | |
| 305 | + | return o | |
| 306 | + | } | |
| 307 | + | func (s *wireEnv) seat() *wayland.Seat { | |
| 308 | + | o := wayland.NewSeat(s.d.Context()) | |
| 309 | + | register(s.d, o) | |
| 310 | + | return o | |
| 311 | + | } | |
| 312 | + | func (s *wireEnv) output() *wayland.Output { | |
| 313 | + | o := wayland.NewOutput(s.d.Context()) | |
| 314 | + | register(s.d, o) | |
| 315 | + | return o | |
| 316 | + | } | |
| 317 | + | func (s *wireEnv) pointer() *wayland.Pointer { | |
| 318 | + | o := wayland.NewPointer(s.d.Context()) | |
| 319 | + | register(s.d, o) | |
| 320 | + | return o | |
| 321 | + | } | |
| 322 | + | func (s *wireEnv) region() *wayland.Region { | |
| 323 | + | o := wayland.NewRegion(s.d.Context()) | |
| 324 | + | register(s.d, o) | |
| 325 | + | return o | |
| 326 | + | } | |
| 327 | + | func (s *wireEnv) buffer() *wayland.Buffer { | |
| 328 | + | o := wayland.NewBuffer(s.d.Context()) | |
| 329 | + | register(s.d, o) | |
| 330 | + | return o | |
| 331 | + | } | |
| 332 | + | ||
| 333 | + | func TestExtensionsOverSocketpair(t *testing.T) { | |
| 334 | + | c, p := pair(t) | |
| 335 | + | d, e := wlturbo.ConnectFromConn(c) | |
| 336 | + | noerr(t, e) | |
| 337 | + | defer d.Close() | |
| 338 | + | request(t, p) | |
| 339 | + | // A registry announcement is the only input to optional-global discovery. | |
| 340 | + | send(t, p, payload(d.Registry().ID(), 0, append(msg(0, 0, 11)[8:12], append(str(fractionalscale.WpFractionalScaleManagerInterface), msg(0, 0, 1)[8:12]...)...)...)) | |
| 341 | + | noerr(t, d.Dispatch()) | |
| 342 | + | if g, ok := d.Registry().FindGlobal(fractionalscale.WpFractionalScaleManagerInterface); !ok || g.Version != 1 { | |
| 343 | + | t.Fatal("announced fractional scale missing", g, ok) | |
| 344 | + | } | |
| 345 | + | if _, ok := d.Registry().FindGlobal(textinput.TextInputManagerV3Interface); ok { | |
| 346 | + | t.Fatal("absent text input") | |
| 347 | + | } | |
| 348 | + | // Remove the discovery-only announcement before the bind matrix assigns | |
| 349 | + | // its own global name to this interface. | |
| 350 | + | send(t, p, msg(d.Registry().ID(), 1, 11)) | |
| 351 | + | noerr(t, d.Dispatch()) | |
| 352 | + | surface := wayland.NewSurface(d.Context()) | |
| 353 | + | surface.SetID(d.AllocateID()) | |
| 354 | + | d.Context().Register(surface) | |
| 355 | + | seat := wayland.NewSeat(d.Context()) | |
| 356 | + | seat.SetID(d.AllocateID()) | |
| 357 | + | d.Context().Register(seat) | |
| 358 | + | wm := xdgshell.NewXdgWmBase(d.Context()) | |
| 359 | + | bind(t, d, p, 1, xdgshell.XdgWmBaseInterface, 6, 7, wm) | |
| 360 | + | xs, e := wm.GetXdgSurface(surface) | |
| 361 | + | noerr(t, e) | |
| 362 | + | request(t, p) | |
| 363 | + | top, e := xs.GetToplevel() | |
| 364 | + | noerr(t, e) | |
| 365 | + | request(t, p) | |
| 366 | + | var sequence []string | |
| 367 | + | top.OnConfigure(func(w, h int32, states []byte) { | |
| 368 | + | if w != 800 || h != 600 { | |
| 369 | + | t.Fatalf("size %d,%d", w, h) | |
| 370 | + | } | |
| 371 | + | sequence = append(sequence, "top") | |
| 372 | + | }) | |
| 373 | + | xs.OnConfigure(func(serial uint32) { sequence = append(sequence, "surface"); noerr(t, xs.AckConfigure(serial)) }) | |
| 374 | + | send(t, p, payload(top.ID(), 0, append(msg(0, 0, 800, 600)[8:], arr(nil)...)...)) | |
| 375 | + | noerr(t, d.Dispatch()) | |
| 376 | + | send(t, p, msg(xs.ID(), 0, 9)) | |
| 377 | + | noerr(t, d.Dispatch()) | |
| 378 | + | _, op, b := request(t, p) | |
| 379 | + | if op != 4 || binary.NativeEndian.Uint32(b) != 9 || strings.Join(sequence, ",") != "top,surface" { | |
| 380 | + | t.Fatalf("xdg %d %x %v", op, b, sequence) | |
| 381 | + | } | |
| 382 | + | noerr(t, top.Destroy()) | |
| 383 | + | request(t, p) | |
| 384 | + | noerr(t, xs.Destroy()) | |
| 385 | + | request(t, p) | |
| 386 | + | noerr(t, wm.Destroy()) | |
| 387 | + | request(t, p) | |
| 388 | + | dm := linuxdmabuf.NewLinuxDmabuf(d.Context()) | |
| 389 | + | bind(t, d, p, 2, linuxdmabuf.LinuxDmabufInterface, 6, 4, dm) | |
| 390 | + | fb, e := dm.GetDefaultFeedback() | |
| 391 | + | noerr(t, e) | |
| 392 | + | request(t, p) | |
| 393 | + | table, e := os.CreateTemp(t.TempDir(), "table") | |
| 394 | + | noerr(t, e) | |
| 395 | + | var bytes [32]byte | |
| 396 | + | binary.NativeEndian.PutUint32(bytes[:], 0x34325258) | |
| 397 | + | binary.NativeEndian.PutUint64(bytes[8:], 19) | |
| 398 | + | binary.NativeEndian.PutUint32(bytes[16:], 0x34325241) | |
| 399 | + | binary.NativeEndian.PutUint64(bytes[24:], 42) | |
| 400 | + | _, e = table.Write(bytes[:]) | |
| 401 | + | noerr(t, e) | |
| 402 | + | defer table.Close() | |
| 403 | + | var entries []linuxdmabuf.FormatEntry | |
| 404 | + | var indices []uint16 | |
| 405 | + | var feedback []string | |
| 406 | + | fb.OnMainDevice(func(dev []byte) { | |
| 407 | + | if len(dev) != 8 { | |
| 408 | + | t.Fatalf("device %x", dev) | |
| 409 | + | } | |
| 410 | + | feedback = append(feedback, "main") | |
| 411 | + | }) | |
| 412 | + | fb.OnFormatTable(func(fd *wlturbo.OwnedFD, size uint32) { | |
| 413 | + | entries, e = linuxdmabuf.ReadFormatTable(fd, size) | |
| 414 | + | noerr(t, e) | |
| 415 | + | feedback = append(feedback, "table") | |
| 416 | + | }) | |
| 417 | + | fb.OnTrancheTargetDevice(func(dev []byte) { feedback = append(feedback, "target") }) | |
| 418 | + | fb.OnTrancheFormats(func(data []byte) { | |
| 419 | + | indices, e = linuxdmabuf.TrancheIndices(data, len(entries)) | |
| 420 | + | noerr(t, e) | |
| 421 | + | feedback = append(feedback, "formats") | |
| 422 | + | }) | |
| 423 | + | fb.OnTrancheFlags(func(flags uint32) { | |
| 424 | + | if flags != 1 { | |
| 425 | + | t.Fatal(flags) | |
| 426 | + | } | |
| 427 | + | feedback = append(feedback, "flags") | |
| 428 | + | }) | |
| 429 | + | fb.OnTrancheDone(func() { feedback = append(feedback, "tranche") }) | |
| 430 | + | fb.OnDone(func() { feedback = append(feedback, "done") }) | |
| 431 | + | send(t, p, payload(fb.ID(), 2, arr(make([]byte, 8))...)) | |
| 432 | + | noerr(t, d.Dispatch()) | |
| 433 | + | send(t, p, msg(fb.ID(), 1, 32), int(table.Fd())) | |
| 434 | + | noerr(t, d.Dispatch()) | |
| 435 | + | send(t, p, payload(fb.ID(), 4, arr(make([]byte, 8))...)) | |
| 436 | + | noerr(t, d.Dispatch()) | |
| 437 | + | send(t, p, payload(fb.ID(), 5, arr([]byte{0, 0, 1, 0})...)) | |
| 438 | + | noerr(t, d.Dispatch()) | |
| 439 | + | send(t, p, msg(fb.ID(), 6, 1)) | |
| 440 | + | noerr(t, d.Dispatch()) | |
| 441 | + | send(t, p, msg(fb.ID(), 3)) | |
| 442 | + | noerr(t, d.Dispatch()) | |
| 443 | + | send(t, p, msg(fb.ID(), 0)) | |
| 444 | + | noerr(t, d.Dispatch()) | |
| 445 | + | if len(entries) != 2 || entries[1].Modifier != 42 || len(indices) != 2 || indices[1] != 1 || strings.Join(feedback, ",") != "main,table,target,formats,flags,tranche,done" { | |
| 446 | + | t.Fatalf("feedback %v %v %v", entries, indices, feedback) | |
| 447 | + | } | |
| 448 | + | noerr(t, fb.Destroy()) | |
| 449 | + | request(t, p) | |
| 450 | + | params, e := dm.CreateParams() | |
| 451 | + | noerr(t, e) | |
| 452 | + | request(t, p) | |
| 453 | + | f, e := os.Open("/dev/null") | |
| 454 | + | noerr(t, e) | |
| 455 | + | noerr(t, params.Add(int(f.Fd()), 0, 0, 4, 0, 0)) | |
| 456 | + | request(t, p) | |
| 457 | + | if _, e := unix.FcntlInt(f.Fd(), unix.F_GETFD, 0); e == nil { | |
| 458 | + | t.Fatal("sent fd not closed") | |
| 459 | + | } | |
| 460 | + | f.Close() | |
| 461 | + | var buffer *wayland.Buffer | |
| 462 | + | params.OnCreated(func(b *wayland.Buffer) { buffer = b }) | |
| 463 | + | params.OnFailed(func() { sequence = append(sequence, "failed") }) | |
| 464 | + | noerr(t, params.Create(1, 1, 0x34325258, 0)) | |
| 465 | + | request(t, p) | |
| 466 | + | send(t, p, msg(params.ID(), 0, 999)) | |
| 467 | + | noerr(t, d.Dispatch()) | |
| 468 | + | if buffer == nil || buffer.ID() != 999 { | |
| 469 | + | t.Fatal("typed buffer missing") | |
| 470 | + | } | |
| 471 | + | noerr(t, buffer.Destroy()) | |
| 472 | + | request(t, p) | |
| 473 | + | noerr(t, params.Destroy()) | |
| 474 | + | request(t, p) | |
| 475 | + | failedParams, e := dm.CreateParams() | |
| 476 | + | noerr(t, e) | |
| 477 | + | request(t, p) | |
| 478 | + | failedParams.OnFailed(func() { sequence = append(sequence, "failed") }) | |
| 479 | + | noerr(t, failedParams.Create(1, 1, 0x34325258, 0)) | |
| 480 | + | request(t, p) | |
| 481 | + | send(t, p, msg(failedParams.ID(), 1)) | |
| 482 | + | noerr(t, d.Dispatch()) | |
| 483 | + | if sequence[len(sequence)-1] != "failed" { | |
| 484 | + | t.Fatal(sequence) | |
| 485 | + | } | |
| 486 | + | noerr(t, failedParams.Destroy()) | |
| 487 | + | request(t, p) | |
| 488 | + | immedParams, e := dm.CreateParams() | |
| 489 | + | noerr(t, e) | |
| 490 | + | request(t, p) | |
| 491 | + | immediate, e := immedParams.CreateImmed(1, 1, 0x34325258, 0) | |
| 492 | + | noerr(t, e) | |
| 493 | + | request(t, p) | |
| 494 | + | noerr(t, immediate.Destroy()) | |
| 495 | + | request(t, p) | |
| 496 | + | noerr(t, immedParams.Destroy()) | |
| 497 | + | request(t, p) | |
| 498 | + | noerr(t, dm.Destroy()) | |
| 499 | + | request(t, p) | |
| 500 | + | sync := drmsyncobj.NewWpLinuxDrmSyncobjManager(d.Context()) | |
| 501 | + | bind(t, d, p, 3, drmsyncobj.WpLinuxDrmSyncobjManagerInterface, 1, 1, sync) | |
| 502 | + | ss, e := sync.GetSurface(surface) | |
| 503 | + | noerr(t, e) | |
| 504 | + | request(t, p) | |
| 505 | + | f, e = os.Open("/dev/null") | |
| 506 | + | noerr(t, e) | |
| 507 | + | tl, e := sync.ImportTimeline(int(f.Fd())) | |
| 508 | + | noerr(t, e) | |
| 509 | + | request(t, p) | |
| 510 | + | if _, e := unix.FcntlInt(f.Fd(), unix.F_GETFD, 0); e == nil { | |
| 511 | + | t.Fatal("timeline fd not closed") | |
| 512 | + | } | |
| 513 | + | f.Close() | |
| 514 | + | noerr(t, ss.SetAcquirePoint(tl, 0x123, 0x456)) | |
| 515 | + | _, op, b = request(t, p) | |
| 516 | + | if op != 1 || binary.NativeEndian.Uint32(b[4:]) != 0x123 || binary.NativeEndian.Uint32(b[8:]) != 0x456 { | |
| 517 | + | t.Fatalf("acquire %d %x", op, b) | |
| 518 | + | } | |
| 519 | + | noerr(t, ss.SetReleasePoint(tl, 0x789, 0xabc)) | |
| 520 | + | _, op, b = request(t, p) | |
| 521 | + | if op != 2 || binary.NativeEndian.Uint32(b[4:]) != 0x789 { | |
| 522 | + | t.Fatalf("release %d %x", op, b) | |
| 523 | + | } | |
| 524 | + | noerr(t, ss.Destroy()) | |
| 525 | + | request(t, p) | |
| 526 | + | noerr(t, tl.Destroy()) | |
| 527 | + | request(t, p) | |
| 528 | + | noerr(t, sync.Destroy()) | |
| 529 | + | request(t, p) | |
| 530 | + | vp := viewporter.NewWpViewporter(d.Context()) | |
| 531 | + | bind(t, d, p, 4, viewporter.WpViewporterInterface, 1, 1, vp) | |
| 532 | + | view, e := vp.GetViewport(surface) | |
| 533 | + | noerr(t, e) | |
| 534 | + | request(t, p) | |
| 535 | + | noerr(t, view.Destroy()) | |
| 536 | + | request(t, p) | |
| 537 | + | noerr(t, vp.Destroy()) | |
| 538 | + | request(t, p) | |
| 539 | + | fs := fractionalscale.NewWpFractionalScaleManager(d.Context()) | |
| 540 | + | bind(t, d, p, 5, fractionalscale.WpFractionalScaleManagerInterface, 1, 1, fs) | |
| 541 | + | scale, e := fs.GetFractionalScale(surface) | |
| 542 | + | noerr(t, e) | |
| 543 | + | request(t, p) | |
| 544 | + | var preferred uint32 | |
| 545 | + | scale.OnPreferredScale(func(v uint32) { preferred = v }) | |
| 546 | + | send(t, p, msg(scale.ID(), 0, 150)) | |
| 547 | + | noerr(t, d.Dispatch()) | |
| 548 | + | if preferred != 150 { | |
| 549 | + | t.Fatal(preferred) | |
| 550 | + | } | |
| 551 | + | noerr(t, scale.Destroy()) | |
| 552 | + | request(t, p) | |
| 553 | + | noerr(t, fs.Destroy()) | |
| 554 | + | request(t, p) | |
| 555 | + | ti := textinput.NewTextInputManagerV3(d.Context()) | |
| 556 | + | bind(t, d, p, 6, textinput.TextInputManagerV3Interface, 2, 1, ti) | |
| 557 | + | input, e := ti.GetTextInput(seat) | |
| 558 | + | noerr(t, e) | |
| 559 | + | request(t, p) | |
| 560 | + | noerr(t, input.Enable()) | |
| 561 | + | request(t, p) | |
| 562 | + | noerr(t, input.SetSurroundingText("hello", 5, 5)) | |
| 563 | + | request(t, p) | |
| 564 | + | noerr(t, input.Commit()) | |
| 565 | + | request(t, p) | |
| 566 | + | var events []string | |
| 567 | + | input.OnPreeditString(func(s string, _, _ int32) { events = append(events, "preedit:"+s) }) | |
| 568 | + | input.OnCommitString(func(s string) { events = append(events, "commit:"+s) }) | |
| 569 | + | input.OnDeleteSurroundingText(func(_, _ uint32) { events = append(events, "delete") }) | |
| 570 | + | input.OnDone(func(uint32) { events = append(events, "done") }) | |
| 571 | + | send(t, p, payload(input.ID(), 2, append(str("é"), msg(0, 0, 0, 0)[8:]...)...)) | |
| 572 | + | noerr(t, d.Dispatch()) | |
| 573 | + | send(t, p, payload(input.ID(), 3, str("hi")...)) | |
| 574 | + | noerr(t, d.Dispatch()) | |
| 575 | + | send(t, p, msg(input.ID(), 4, 1, 2)) | |
| 576 | + | noerr(t, d.Dispatch()) | |
| 577 | + | send(t, p, msg(input.ID(), 5, 1)) | |
| 578 | + | noerr(t, d.Dispatch()) | |
| 579 | + | if strings.Join(events, ",") != "preedit:é,commit:hi,delete,done" { | |
| 580 | + | t.Fatal(events) | |
| 581 | + | } | |
| 582 | + | noerr(t, input.Disable()) | |
| 583 | + | request(t, p) | |
| 584 | + | noerr(t, input.Commit()) | |
| 585 | + | request(t, p) | |
| 586 | + | noerr(t, input.Destroy()) | |
| 587 | + | request(t, p) | |
| 588 | + | noerr(t, ti.Destroy()) | |
| 589 | + | request(t, p) | |
| 590 | + | // Core data-device remains in client/wayland; verify its typed child and | |
| 591 | + | // both directions of clipboard descriptor ownership. | |
| 592 | + | mgr := wayland.NewDataDeviceManager(d.Context()) | |
| 593 | + | bind(t, d, p, 7, wayland.DataDeviceManagerInterface, 3, 4, mgr) | |
| 594 | + | device, e := mgr.GetDataDevice(seat) | |
| 595 | + | noerr(t, e) | |
| 596 | + | request(t, p) | |
| 597 | + | source, e := mgr.CreateDataSource() | |
| 598 | + | noerr(t, e) | |
| 599 | + | request(t, p) | |
| 600 | + | var offer *wayland.DataOffer | |
| 601 | + | device.OnDataOffer(func(o *wayland.DataOffer) { offer = o }) | |
| 602 | + | send(t, p, msg(device.ID(), 0, 998)) | |
| 603 | + | noerr(t, d.Dispatch()) | |
| 604 | + | if offer == nil || offer.ID() != 998 { | |
| 605 | + | t.Fatal("offer not typed") | |
| 606 | + | } | |
| 607 | + | read, write, e := os.Pipe() | |
| 608 | + | noerr(t, e) | |
| 609 | + | defer read.Close() | |
| 610 | + | noerr(t, offer.Receive("text/plain", int(write.Fd()))) | |
| 611 | + | request(t, p) | |
| 612 | + | if _, e := unix.FcntlInt(write.Fd(), unix.F_GETFD, 0); e == nil { | |
| 613 | + | t.Fatal("clipboard sent fd retained") | |
| 614 | + | } | |
| 615 | + | write.Close() | |
| 616 | + | source.OnSend(func(mime string, fd *wlturbo.OwnedFD) { | |
| 617 | + | if mime != "text/plain" { | |
| 618 | + | t.Fatal(mime) | |
| 619 | + | } | |
| 620 | + | n, e := fd.Take() | |
| 621 | + | noerr(t, e) | |
| 622 | + | unix.Close(n) | |
| 623 | + | }) | |
| 624 | + | received, e := os.Open("/dev/null") | |
| 625 | + | noerr(t, e) | |
| 626 | + | send(t, p, payload(source.ID(), 1, str("text/plain")...), int(received.Fd())) | |
| 627 | + | noerr(t, d.Dispatch()) | |
| 628 | + | received.Close() | |
| 629 | + | noerr(t, offer.Destroy()) | |
| 630 | + | request(t, p) | |
| 631 | + | noerr(t, source.Destroy()) | |
| 632 | + | request(t, p) | |
| 633 | + | noerr(t, device.Release()) | |
| 634 | + | request(t, p) | |
| 635 | + | // release is a version 4 request; the manager was negotiated at 3, so it | |
| 636 | + | // must be refused locally instead of reaching the compositor. | |
| 637 | + | if err := mgr.Release(); !errors.Is(err, wlturbo.ErrVersionTooLow) { | |
| 638 | + | t.Fatalf("release at v3 = %v, want ErrVersionTooLow", err) | |
| 639 | + | } | |
| 640 | + | // Cursor shape: get a device for a wl_pointer and set a shape at an | |
| 641 | + | // enter serial; check the exact wire arguments. | |
| 642 | + | pointer := wayland.NewPointer(d.Context()) | |
| 643 | + | pointer.SetID(d.AllocateID()) | |
| 644 | + | d.Context().Register(pointer) | |
| 645 | + | shapes := cursorshape.NewWpCursorShapeManager(d.Context()) | |
| 646 | + | bind(t, d, p, 8, cursorshape.WpCursorShapeManagerInterface, 2, 1, shapes) | |
| 647 | + | shape, e := shapes.GetPointer(pointer) | |
| 648 | + | noerr(t, e) | |
| 649 | + | if id, op, b := request(t, p); id != shapes.ID() || op != 1 || binary.NativeEndian.Uint32(b) != shape.ID() || binary.NativeEndian.Uint32(b[4:]) != pointer.ID() { | |
| 650 | + | t.Fatalf("get_pointer wire id=%d op=%d %x", id, op, b) | |
| 651 | + | } | |
| 652 | + | noerr(t, shape.SetShape(42, cursorshape.SHAPE_POINTER)) | |
| 653 | + | if id, op, b := request(t, p); id != shape.ID() || op != 1 || binary.NativeEndian.Uint32(b) != 42 || binary.NativeEndian.Uint32(b[4:]) != 4 { | |
| 654 | + | t.Fatalf("set_shape wire id=%d op=%d %x", id, op, b) | |
| 655 | + | } | |
| 656 | + | noerr(t, shape.Destroy()) | |
| 657 | + | request(t, p) | |
| 658 | + | noerr(t, shapes.Destroy()) | |
| 659 | + | request(t, p) | |
| 660 | + | ||
| 661 | + | } | |
| 662 | + | ||
| 663 | + | func TestLiveFeedback(t *testing.T) { | |
| 664 | + | if os.Getenv("WLTURBO_LIVE") != "1" { | |
| 665 | + | t.Skip("set WLTURBO_LIVE=1") | |
| 666 | + | } | |
| 667 | + | d, e := wlturbo.Connect("") | |
| 668 | + | noerr(t, e) | |
| 669 | + | defer d.Close() | |
| 670 | + | noerr(t, d.Roundtrip()) | |
| 671 | + | for _, iface := range []string{xdgshell.XdgWmBaseInterface, linuxdmabuf.LinuxDmabufInterface, drmsyncobj.WpLinuxDrmSyncobjManagerInterface, viewporter.WpViewporterInterface, fractionalscale.WpFractionalScaleManagerInterface, textinput.TextInputManagerV3Interface, cursorshape.WpCursorShapeManagerInterface} { | |
| 672 | + | g, ok := d.Registry().FindGlobal(iface) | |
| 673 | + | if !ok { | |
| 674 | + | t.Logf("%s absent", iface) | |
| 675 | + | continue | |
| 676 | + | } | |
| 677 | + | v := g.Version | |
| 678 | + | cap := uint32(1) | |
| 679 | + | if iface == xdgshell.XdgWmBaseInterface { | |
| 680 | + | cap = 7 | |
| 681 | + | } | |
| 682 | + | if iface == linuxdmabuf.LinuxDmabufInterface { | |
| 683 | + | cap = 4 | |
| 684 | + | } | |
| 685 | + | if v > cap { | |
| 686 | + | v = cap | |
| 687 | + | } | |
| 688 | + | t.Logf("%s negotiated=%d (server=%d)", iface, v, g.Version) | |
| 689 | + | if iface != linuxdmabuf.LinuxDmabufInterface { | |
| 690 | + | continue | |
| 691 | + | } | |
| 692 | + | if v < 4 { | |
| 693 | + | t.Fatal("dmabuf feedback requires v4") | |
| 694 | + | } | |
| 695 | + | dm := linuxdmabuf.NewLinuxDmabuf(d.Context()) | |
| 696 | + | negotiated, err := d.Registry().BindNegotiated(iface, 4, dm) | |
| 697 | + | noerr(t, err) | |
| 698 | + | if negotiated != v { | |
| 699 | + | t.Fatalf("dmabuf negotiated=%d want=%d", negotiated, v) | |
| 700 | + | } | |
| 701 | + | fb, e := dm.GetDefaultFeedback() | |
| 702 | + | noerr(t, e) | |
| 703 | + | done := false | |
| 704 | + | fb.OnMainDevice(func(b []byte) { t.Logf("main_device=%x", b) }) | |
| 705 | + | fb.OnFormatTable(func(fd *wlturbo.OwnedFD, size uint32) { | |
| 706 | + | entries, err := linuxdmabuf.ReadFormatTable(fd, size) | |
| 707 | + | if err != nil { | |
| 708 | + | t.Errorf("table: %v", err) | |
| 709 | + | } | |
| 710 | + | t.Logf("format-table entries=%d", len(entries)) | |
| 711 | + | }) | |
| 712 | + | fb.OnDone(func() { done = true }) | |
| 713 | + | for i := 0; i < 100 && !done; i++ { | |
| 714 | + | noerr(t, d.Dispatch()) | |
| 715 | + | } | |
| 716 | + | if !done { | |
| 717 | + | t.Fatal("no feedback done") | |
| 718 | + | } | |
| 719 | + | noerr(t, fb.Destroy()) | |
| 720 | + | noerr(t, dm.Destroy()) | |
| 721 | + | } | |
| 722 | + | } | |
A client/extforeigntoplevellist/extforeigntoplevellist_generated.go +356 -0
| @@ -0,0 +1,356 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: ext_foreign_toplevel_list_v1 | |
| 3 | + | // Source: ext-foreign-toplevel-list-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2018 Ilia Bozhinov | |
| 7 | + | // Copyright © 2020 Isaac Freund | |
| 8 | + | // Copyright © 2022 wb9688 | |
| 9 | + | // Copyright © 2023 i509VCB | |
| 10 | + | // | |
| 11 | + | // Permission to use, copy, modify, distribute, and sell this | |
| 12 | + | // software and its documentation for any purpose is hereby granted | |
| 13 | + | // without fee, provided that the above copyright notice appear in | |
| 14 | + | // all copies and that both that copyright notice and this permission | |
| 15 | + | // notice appear in supporting documentation, and that the name of | |
| 16 | + | // the copyright holders not be used in advertising or publicity | |
| 17 | + | // pertaining to distribution of the software without specific, | |
| 18 | + | // written prior permission. The copyright holders make no | |
| 19 | + | // representations about the suitability of this software for any | |
| 20 | + | // purpose. It is provided "as is" without express or implied | |
| 21 | + | // warranty. | |
| 22 | + | // | |
| 23 | + | // THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
| 24 | + | // SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| 25 | + | // FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| 26 | + | // SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 27 | + | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
| 28 | + | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
| 29 | + | // ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| 30 | + | // THIS SOFTWARE. | |
| 31 | + | ||
| 32 | + | package extforeigntoplevellist | |
| 33 | + | ||
| 34 | + | import ( | |
| 35 | + | "sync" | |
| 36 | + | ||
| 37 | + | "github.com/bnema/wlturbo/wl" | |
| 38 | + | ) | |
| 39 | + | ||
| 40 | + | // ExtForeignToplevelListInterface is the protocol interface name. | |
| 41 | + | const ExtForeignToplevelListInterface = "ext_foreign_toplevel_list_v1" | |
| 42 | + | ||
| 43 | + | // ExtForeignToplevelList is the generated binding for ext_foreign_toplevel_list_v1 version 1. | |
| 44 | + | type ExtForeignToplevelList struct { | |
| 45 | + | wl.BaseProxy | |
| 46 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 47 | + | // handlers while another goroutine dispatches events. | |
| 48 | + | handlersMu sync.Mutex | |
| 49 | + | onToplevel []func(toplevelObject *ExtForeignToplevelHandle) | |
| 50 | + | onFinished []func() | |
| 51 | + | } | |
| 52 | + | ||
| 53 | + | // NewExtForeignToplevelList returns an unbound ExtForeignToplevelList. | |
| 54 | + | func NewExtForeignToplevelList(ctx *wl.Context) *ExtForeignToplevelList { | |
| 55 | + | obj := &ExtForeignToplevelList{} | |
| 56 | + | obj.SetContext(ctx) | |
| 57 | + | ctx.Register(obj) | |
| 58 | + | return obj | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | // This request indicates that the client no longer wishes to receive events for new toplevels. The Wayland protocol is asynchronous, meaning the compositor may send further toplevel events until the stop request is processed. The client should wait for a ext_foreign_toplevel_list_v1.finished event before destroying this object. | |
| 62 | + | func (o *ExtForeignToplevelList) Stop() error { | |
| 63 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_foreign_toplevel_list_v1.stop"}); err != nil { | |
| 64 | + | return err | |
| 65 | + | } | |
| 66 | + | return nil | |
| 67 | + | } | |
| 68 | + | ||
| 69 | + | // This request should be called either when the client will no longer use the ext_foreign_toplevel_list_v1 or after the finished event has been received to allow destruction of the object. If a client wishes to destroy this object it should send a ext_foreign_toplevel_list_v1.stop request and wait for a ext_foreign_toplevel_list_v1.finished event, then destroy the handles and then this object. | |
| 70 | + | func (o *ExtForeignToplevelList) Destroy() error { | |
| 71 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_foreign_toplevel_list_v1.destroy", Destructor: true}); err != nil { | |
| 72 | + | return err | |
| 73 | + | } | |
| 74 | + | return nil | |
| 75 | + | } | |
| 76 | + | ||
| 77 | + | // OnToplevel registers a handler for the toplevel event. | |
| 78 | + | // | |
| 79 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 80 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 81 | + | func (o *ExtForeignToplevelList) OnToplevel(handler func(toplevelObject *ExtForeignToplevelHandle)) { | |
| 82 | + | if handler == nil { | |
| 83 | + | return | |
| 84 | + | } | |
| 85 | + | o.handlersMu.Lock() | |
| 86 | + | defer o.handlersMu.Unlock() | |
| 87 | + | o.onToplevel = append(o.onToplevel, handler) | |
| 88 | + | } | |
| 89 | + | ||
| 90 | + | // handlersForToplevel returns the handlers registered for toplevel, taken | |
| 91 | + | // under the lock so a handler may register another handler while events are | |
| 92 | + | // being dispatched. | |
| 93 | + | func (o *ExtForeignToplevelList) handlersForToplevel() []func(toplevelObject *ExtForeignToplevelHandle) { | |
| 94 | + | o.handlersMu.Lock() | |
| 95 | + | defer o.handlersMu.Unlock() | |
| 96 | + | return o.onToplevel | |
| 97 | + | } | |
| 98 | + | ||
| 99 | + | // OnFinished registers a handler for the finished event. | |
| 100 | + | // | |
| 101 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 102 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 103 | + | func (o *ExtForeignToplevelList) OnFinished(handler func()) { | |
| 104 | + | if handler == nil { | |
| 105 | + | return | |
| 106 | + | } | |
| 107 | + | o.handlersMu.Lock() | |
| 108 | + | defer o.handlersMu.Unlock() | |
| 109 | + | o.onFinished = append(o.onFinished, handler) | |
| 110 | + | } | |
| 111 | + | ||
| 112 | + | // handlersForFinished returns the handlers registered for finished, taken | |
| 113 | + | // under the lock so a handler may register another handler while events are | |
| 114 | + | // being dispatched. | |
| 115 | + | func (o *ExtForeignToplevelList) handlersForFinished() []func() { | |
| 116 | + | o.handlersMu.Lock() | |
| 117 | + | defer o.handlersMu.Unlock() | |
| 118 | + | return o.onFinished | |
| 119 | + | } | |
| 120 | + | ||
| 121 | + | // EventSignature returns the declared event argument types in wire order. | |
| 122 | + | func (o *ExtForeignToplevelList) EventSignature(opcode uint16) (string, bool) { | |
| 123 | + | switch opcode { | |
| 124 | + | case 0: | |
| 125 | + | return "new_id,", true | |
| 126 | + | case 1: | |
| 127 | + | return "", true | |
| 128 | + | default: | |
| 129 | + | return "", false | |
| 130 | + | } | |
| 131 | + | } | |
| 132 | + | ||
| 133 | + | // Dispatch decodes one event on ext_foreign_toplevel_list_v1 and calls the registered handlers. | |
| 134 | + | func (o *ExtForeignToplevelList) Dispatch(event *wl.Event) { | |
| 135 | + | switch event.Opcode { | |
| 136 | + | case 0: // toplevel | |
| 137 | + | toplevelID := event.Uint32() | |
| 138 | + | toplevelObject := &ExtForeignToplevelHandle{} | |
| 139 | + | toplevelObject.SetContext(o.Context()) | |
| 140 | + | toplevelObject.SetID(toplevelID) | |
| 141 | + | toplevelObject.SetVersion(o.Version()) | |
| 142 | + | o.Context().Register(toplevelObject) | |
| 143 | + | ||
| 144 | + | for i, handler := range o.handlersForToplevel() { | |
| 145 | + | _ = i | |
| 146 | + | handler(toplevelObject) | |
| 147 | + | } | |
| 148 | + | case 1: // finished | |
| 149 | + | ||
| 150 | + | for i, handler := range o.handlersForFinished() { | |
| 151 | + | _ = i | |
| 152 | + | handler() | |
| 153 | + | } | |
| 154 | + | default: | |
| 155 | + | } | |
| 156 | + | } | |
| 157 | + | ||
| 158 | + | // ExtForeignToplevelHandleInterface is the protocol interface name. | |
| 159 | + | const ExtForeignToplevelHandleInterface = "ext_foreign_toplevel_handle_v1" | |
| 160 | + | ||
| 161 | + | // ExtForeignToplevelHandle is the generated binding for ext_foreign_toplevel_handle_v1 version 1. | |
| 162 | + | type ExtForeignToplevelHandle struct { | |
| 163 | + | wl.BaseProxy | |
| 164 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 165 | + | // handlers while another goroutine dispatches events. | |
| 166 | + | handlersMu sync.Mutex | |
| 167 | + | onClosed []func() | |
| 168 | + | onDone []func() | |
| 169 | + | onTitle []func(title string) | |
| 170 | + | onAppId []func(appId string) | |
| 171 | + | onIdentifier []func(identifier string) | |
| 172 | + | } | |
| 173 | + | ||
| 174 | + | // NewExtForeignToplevelHandle returns an unbound ExtForeignToplevelHandle. | |
| 175 | + | func NewExtForeignToplevelHandle(ctx *wl.Context) *ExtForeignToplevelHandle { | |
| 176 | + | obj := &ExtForeignToplevelHandle{} | |
| 177 | + | obj.SetContext(ctx) | |
| 178 | + | ctx.Register(obj) | |
| 179 | + | return obj | |
| 180 | + | } | |
| 181 | + | ||
| 182 | + | // This request should be used when the client will no longer use the handle or after the closed event has been received to allow destruction of the object. When a handle is destroyed, a new handle may not be created by the server until the toplevel is unmapped and then remapped. Destroying a toplevel handle is not recommended unless the client is cleaning up child objects before destroying the ext_foreign_toplevel_list_v1 object, the toplevel was closed or the toplevel handle will not be used in the future. Other protocols which extend the ext_foreign_toplevel_handle_v1 interface should require destructors for extension interfaces be called before allowing the toplevel handle to be destroyed. | |
| 183 | + | func (o *ExtForeignToplevelHandle) Destroy() error { | |
| 184 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_foreign_toplevel_handle_v1.destroy", Destructor: true}); err != nil { | |
| 185 | + | return err | |
| 186 | + | } | |
| 187 | + | return nil | |
| 188 | + | } | |
| 189 | + | ||
| 190 | + | // OnClosed registers a handler for the closed event. | |
| 191 | + | // | |
| 192 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 193 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 194 | + | func (o *ExtForeignToplevelHandle) OnClosed(handler func()) { | |
| 195 | + | if handler == nil { | |
| 196 | + | return | |
| 197 | + | } | |
| 198 | + | o.handlersMu.Lock() | |
| 199 | + | defer o.handlersMu.Unlock() | |
| 200 | + | o.onClosed = append(o.onClosed, handler) | |
| 201 | + | } | |
| 202 | + | ||
| 203 | + | // handlersForClosed returns the handlers registered for closed, taken | |
| 204 | + | // under the lock so a handler may register another handler while events are | |
| 205 | + | // being dispatched. | |
| 206 | + | func (o *ExtForeignToplevelHandle) handlersForClosed() []func() { | |
| 207 | + | o.handlersMu.Lock() | |
| 208 | + | defer o.handlersMu.Unlock() | |
| 209 | + | return o.onClosed | |
| 210 | + | } | |
| 211 | + | ||
| 212 | + | // OnDone registers a handler for the done event. | |
| 213 | + | // | |
| 214 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 215 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 216 | + | func (o *ExtForeignToplevelHandle) OnDone(handler func()) { | |
| 217 | + | if handler == nil { | |
| 218 | + | return | |
| 219 | + | } | |
| 220 | + | o.handlersMu.Lock() | |
| 221 | + | defer o.handlersMu.Unlock() | |
| 222 | + | o.onDone = append(o.onDone, handler) | |
| 223 | + | } | |
| 224 | + | ||
| 225 | + | // handlersForDone returns the handlers registered for done, taken | |
| 226 | + | // under the lock so a handler may register another handler while events are | |
| 227 | + | // being dispatched. | |
| 228 | + | func (o *ExtForeignToplevelHandle) handlersForDone() []func() { | |
| 229 | + | o.handlersMu.Lock() | |
| 230 | + | defer o.handlersMu.Unlock() | |
| 231 | + | return o.onDone | |
| 232 | + | } | |
| 233 | + | ||
| 234 | + | // OnTitle registers a handler for the title event. | |
| 235 | + | // | |
| 236 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 237 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 238 | + | func (o *ExtForeignToplevelHandle) OnTitle(handler func(title string)) { | |
| 239 | + | if handler == nil { | |
| 240 | + | return | |
| 241 | + | } | |
| 242 | + | o.handlersMu.Lock() | |
| 243 | + | defer o.handlersMu.Unlock() | |
| 244 | + | o.onTitle = append(o.onTitle, handler) | |
| 245 | + | } | |
| 246 | + | ||
| 247 | + | // handlersForTitle returns the handlers registered for title, taken | |
| 248 | + | // under the lock so a handler may register another handler while events are | |
| 249 | + | // being dispatched. | |
| 250 | + | func (o *ExtForeignToplevelHandle) handlersForTitle() []func(title string) { | |
| 251 | + | o.handlersMu.Lock() | |
| 252 | + | defer o.handlersMu.Unlock() | |
| 253 | + | return o.onTitle | |
| 254 | + | } | |
| 255 | + | ||
| 256 | + | // OnAppId registers a handler for the app_id event. | |
| 257 | + | // | |
| 258 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 259 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 260 | + | func (o *ExtForeignToplevelHandle) OnAppId(handler func(appId string)) { | |
| 261 | + | if handler == nil { | |
| 262 | + | return | |
| 263 | + | } | |
| 264 | + | o.handlersMu.Lock() | |
| 265 | + | defer o.handlersMu.Unlock() | |
| 266 | + | o.onAppId = append(o.onAppId, handler) | |
| 267 | + | } | |
| 268 | + | ||
| 269 | + | // handlersForAppId returns the handlers registered for app_id, taken | |
| 270 | + | // under the lock so a handler may register another handler while events are | |
| 271 | + | // being dispatched. | |
| 272 | + | func (o *ExtForeignToplevelHandle) handlersForAppId() []func(appId string) { | |
| 273 | + | o.handlersMu.Lock() | |
| 274 | + | defer o.handlersMu.Unlock() | |
| 275 | + | return o.onAppId | |
| 276 | + | } | |
| 277 | + | ||
| 278 | + | // OnIdentifier registers a handler for the identifier event. | |
| 279 | + | // | |
| 280 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 281 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 282 | + | func (o *ExtForeignToplevelHandle) OnIdentifier(handler func(identifier string)) { | |
| 283 | + | if handler == nil { | |
| 284 | + | return | |
| 285 | + | } | |
| 286 | + | o.handlersMu.Lock() | |
| 287 | + | defer o.handlersMu.Unlock() | |
| 288 | + | o.onIdentifier = append(o.onIdentifier, handler) | |
| 289 | + | } | |
| 290 | + | ||
| 291 | + | // handlersForIdentifier returns the handlers registered for identifier, taken | |
| 292 | + | // under the lock so a handler may register another handler while events are | |
| 293 | + | // being dispatched. | |
| 294 | + | func (o *ExtForeignToplevelHandle) handlersForIdentifier() []func(identifier string) { | |
| 295 | + | o.handlersMu.Lock() | |
| 296 | + | defer o.handlersMu.Unlock() | |
| 297 | + | return o.onIdentifier | |
| 298 | + | } | |
| 299 | + | ||
| 300 | + | // EventSignature returns the declared event argument types in wire order. | |
| 301 | + | func (o *ExtForeignToplevelHandle) EventSignature(opcode uint16) (string, bool) { | |
| 302 | + | switch opcode { | |
| 303 | + | case 0: | |
| 304 | + | return "", true | |
| 305 | + | case 1: | |
| 306 | + | return "", true | |
| 307 | + | case 2: | |
| 308 | + | return "string,", true | |
| 309 | + | case 3: | |
| 310 | + | return "string,", true | |
| 311 | + | case 4: | |
| 312 | + | return "string,", true | |
| 313 | + | default: | |
| 314 | + | return "", false | |
| 315 | + | } | |
| 316 | + | } | |
| 317 | + | ||
| 318 | + | // Dispatch decodes one event on ext_foreign_toplevel_handle_v1 and calls the registered handlers. | |
| 319 | + | func (o *ExtForeignToplevelHandle) Dispatch(event *wl.Event) { | |
| 320 | + | switch event.Opcode { | |
| 321 | + | case 0: // closed | |
| 322 | + | ||
| 323 | + | for i, handler := range o.handlersForClosed() { | |
| 324 | + | _ = i | |
| 325 | + | handler() | |
| 326 | + | } | |
| 327 | + | case 1: // done | |
| 328 | + | ||
| 329 | + | for i, handler := range o.handlersForDone() { | |
| 330 | + | _ = i | |
| 331 | + | handler() | |
| 332 | + | } | |
| 333 | + | case 2: // title | |
| 334 | + | title := event.String() | |
| 335 | + | ||
| 336 | + | for i, handler := range o.handlersForTitle() { | |
| 337 | + | _ = i | |
| 338 | + | handler(title) | |
| 339 | + | } | |
| 340 | + | case 3: // app_id | |
| 341 | + | appId := event.String() | |
| 342 | + | ||
| 343 | + | for i, handler := range o.handlersForAppId() { | |
| 344 | + | _ = i | |
| 345 | + | handler(appId) | |
| 346 | + | } | |
| 347 | + | case 4: // identifier | |
| 348 | + | identifier := event.String() | |
| 349 | + | ||
| 350 | + | for i, handler := range o.handlersForIdentifier() { | |
| 351 | + | _ = i | |
| 352 | + | handler(identifier) | |
| 353 | + | } | |
| 354 | + | default: | |
| 355 | + | } | |
| 356 | + | } | |
A client/extidlenotify/extidlenotify_generated.go +206 -0
| @@ -0,0 +1,206 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: ext_idle_notify_v1 | |
| 3 | + | // Source: ext-idle-notify-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2015 Martin Gräßlin | |
| 7 | + | // Copyright © 2022 Simon Ser | |
| 8 | + | // | |
| 9 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 10 | + | // copy of this software and associated documentation files (the "Software"), | |
| 11 | + | // to deal in the Software without restriction, including without limitation | |
| 12 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 13 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 14 | + | // Software is furnished to do so, subject to the following conditions: | |
| 15 | + | // | |
| 16 | + | // The above copyright notice and this permission notice (including the next | |
| 17 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 18 | + | // Software. | |
| 19 | + | // | |
| 20 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 21 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 22 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 23 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 24 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 25 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 26 | + | // DEALINGS IN THE SOFTWARE. | |
| 27 | + | ||
| 28 | + | package extidlenotify | |
| 29 | + | ||
| 30 | + | import ( | |
| 31 | + | "sync" | |
| 32 | + | ||
| 33 | + | cross_wl_seat "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 34 | + | "github.com/bnema/wlturbo/wl" | |
| 35 | + | ) | |
| 36 | + | ||
| 37 | + | // ExtIdleNotifierInterface is the protocol interface name. | |
| 38 | + | const ExtIdleNotifierInterface = "ext_idle_notifier_v1" | |
| 39 | + | ||
| 40 | + | // ExtIdleNotifier is the generated binding for ext_idle_notifier_v1 version 2. | |
| 41 | + | type ExtIdleNotifier struct { | |
| 42 | + | wl.BaseProxy | |
| 43 | + | } | |
| 44 | + | ||
| 45 | + | // NewExtIdleNotifier returns an unbound ExtIdleNotifier. | |
| 46 | + | func NewExtIdleNotifier(ctx *wl.Context) *ExtIdleNotifier { | |
| 47 | + | obj := &ExtIdleNotifier{} | |
| 48 | + | obj.SetContext(ctx) | |
| 49 | + | ctx.Register(obj) | |
| 50 | + | return obj | |
| 51 | + | } | |
| 52 | + | ||
| 53 | + | // Destroy the manager object. All objects created via this interface remain valid. | |
| 54 | + | func (o *ExtIdleNotifier) Destroy() error { | |
| 55 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_idle_notifier_v1.destroy", Destructor: true}); err != nil { | |
| 56 | + | return err | |
| 57 | + | } | |
| 58 | + | return nil | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | // Create a new idle notification object. The notification object has a minimum timeout duration and is tied to a seat. The client will be notified if the seat is inactive for at least the provided timeout. See ext_idle_notification_v1 for more details. A zero timeout is valid and means the client wants to be notified as soon as possible when the seat is inactive. | |
| 62 | + | func (o *ExtIdleNotifier) GetIdleNotification(timeout uint32, seat *cross_wl_seat.Seat) (*ExtIdleNotification, error) { | |
| 63 | + | var arg2 wl.Object | |
| 64 | + | if seat != nil { | |
| 65 | + | arg2 = seat | |
| 66 | + | } | |
| 67 | + | child := &ExtIdleNotification{} | |
| 68 | + | child.SetContext(o.Context()) | |
| 69 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_idle_notifier_v1.get_idle_notification", Child: child}, wl.ArgObject(child), wl.ArgUint(timeout), wl.ArgObject(arg2)); err != nil { | |
| 70 | + | return nil, err | |
| 71 | + | } | |
| 72 | + | return child, nil | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | // Create a new idle notification object to track input from the user, such as keyboard and mouse movement. Because this object is meant to track user input alone, it ignores idle inhibitors. The notification object has a minimum timeout duration and is tied to a seat. The client will be notified if the seat is inactive for at least the provided timeout. See ext_idle_notification_v1 for more details. A zero timeout is valid and means the client wants to be notified as soon as possible when the seat is inactive. | |
| 76 | + | func (o *ExtIdleNotifier) GetInputIdleNotification(timeout uint32, seat *cross_wl_seat.Seat) (*ExtIdleNotification, error) { | |
| 77 | + | var arg2 wl.Object | |
| 78 | + | if seat != nil { | |
| 79 | + | arg2 = seat | |
| 80 | + | } | |
| 81 | + | child := &ExtIdleNotification{} | |
| 82 | + | child.SetContext(o.Context()) | |
| 83 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "ext_idle_notifier_v1.get_input_idle_notification", Since: 2, Child: child}, wl.ArgObject(child), wl.ArgUint(timeout), wl.ArgObject(arg2)); err != nil { | |
| 84 | + | return nil, err | |
| 85 | + | } | |
| 86 | + | return child, nil | |
| 87 | + | } | |
| 88 | + | ||
| 89 | + | // EventSignature returns the declared event argument types in wire order. | |
| 90 | + | func (o *ExtIdleNotifier) EventSignature(opcode uint16) (string, bool) { | |
| 91 | + | switch opcode { | |
| 92 | + | default: | |
| 93 | + | return "", false | |
| 94 | + | } | |
| 95 | + | } | |
| 96 | + | ||
| 97 | + | // Dispatch decodes one event on ext_idle_notifier_v1 and calls the registered handlers. | |
| 98 | + | func (o *ExtIdleNotifier) Dispatch(event *wl.Event) { | |
| 99 | + | switch event.Opcode { | |
| 100 | + | default: | |
| 101 | + | } | |
| 102 | + | } | |
| 103 | + | ||
| 104 | + | // ExtIdleNotificationInterface is the protocol interface name. | |
| 105 | + | const ExtIdleNotificationInterface = "ext_idle_notification_v1" | |
| 106 | + | ||
| 107 | + | // ExtIdleNotification is the generated binding for ext_idle_notification_v1 version 2. | |
| 108 | + | type ExtIdleNotification struct { | |
| 109 | + | wl.BaseProxy | |
| 110 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 111 | + | // handlers while another goroutine dispatches events. | |
| 112 | + | handlersMu sync.Mutex | |
| 113 | + | onIdled []func() | |
| 114 | + | onResumed []func() | |
| 115 | + | } | |
| 116 | + | ||
| 117 | + | // NewExtIdleNotification returns an unbound ExtIdleNotification. | |
| 118 | + | func NewExtIdleNotification(ctx *wl.Context) *ExtIdleNotification { | |
| 119 | + | obj := &ExtIdleNotification{} | |
| 120 | + | obj.SetContext(ctx) | |
| 121 | + | ctx.Register(obj) | |
| 122 | + | return obj | |
| 123 | + | } | |
| 124 | + | ||
| 125 | + | // Destroy the notification object. | |
| 126 | + | func (o *ExtIdleNotification) Destroy() error { | |
| 127 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_idle_notification_v1.destroy", Destructor: true}); err != nil { | |
| 128 | + | return err | |
| 129 | + | } | |
| 130 | + | return nil | |
| 131 | + | } | |
| 132 | + | ||
| 133 | + | // OnIdled registers a handler for the idled event. | |
| 134 | + | // | |
| 135 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 136 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 137 | + | func (o *ExtIdleNotification) OnIdled(handler func()) { | |
| 138 | + | if handler == nil { | |
| 139 | + | return | |
| 140 | + | } | |
| 141 | + | o.handlersMu.Lock() | |
| 142 | + | defer o.handlersMu.Unlock() | |
| 143 | + | o.onIdled = append(o.onIdled, handler) | |
| 144 | + | } | |
| 145 | + | ||
| 146 | + | // handlersForIdled returns the handlers registered for idled, taken | |
| 147 | + | // under the lock so a handler may register another handler while events are | |
| 148 | + | // being dispatched. | |
| 149 | + | func (o *ExtIdleNotification) handlersForIdled() []func() { | |
| 150 | + | o.handlersMu.Lock() | |
| 151 | + | defer o.handlersMu.Unlock() | |
| 152 | + | return o.onIdled | |
| 153 | + | } | |
| 154 | + | ||
| 155 | + | // OnResumed registers a handler for the resumed event. | |
| 156 | + | // | |
| 157 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 158 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 159 | + | func (o *ExtIdleNotification) OnResumed(handler func()) { | |
| 160 | + | if handler == nil { | |
| 161 | + | return | |
| 162 | + | } | |
| 163 | + | o.handlersMu.Lock() | |
| 164 | + | defer o.handlersMu.Unlock() | |
| 165 | + | o.onResumed = append(o.onResumed, handler) | |
| 166 | + | } | |
| 167 | + | ||
| 168 | + | // handlersForResumed returns the handlers registered for resumed, taken | |
| 169 | + | // under the lock so a handler may register another handler while events are | |
| 170 | + | // being dispatched. | |
| 171 | + | func (o *ExtIdleNotification) handlersForResumed() []func() { | |
| 172 | + | o.handlersMu.Lock() | |
| 173 | + | defer o.handlersMu.Unlock() | |
| 174 | + | return o.onResumed | |
| 175 | + | } | |
| 176 | + | ||
| 177 | + | // EventSignature returns the declared event argument types in wire order. | |
| 178 | + | func (o *ExtIdleNotification) EventSignature(opcode uint16) (string, bool) { | |
| 179 | + | switch opcode { | |
| 180 | + | case 0: | |
| 181 | + | return "", true | |
| 182 | + | case 1: | |
| 183 | + | return "", true | |
| 184 | + | default: | |
| 185 | + | return "", false | |
| 186 | + | } | |
| 187 | + | } | |
| 188 | + | ||
| 189 | + | // Dispatch decodes one event on ext_idle_notification_v1 and calls the registered handlers. | |
| 190 | + | func (o *ExtIdleNotification) Dispatch(event *wl.Event) { | |
| 191 | + | switch event.Opcode { | |
| 192 | + | case 0: // idled | |
| 193 | + | ||
| 194 | + | for i, handler := range o.handlersForIdled() { | |
| 195 | + | _ = i | |
| 196 | + | handler() | |
| 197 | + | } | |
| 198 | + | case 1: // resumed | |
| 199 | + | ||
| 200 | + | for i, handler := range o.handlersForResumed() { | |
| 201 | + | _ = i | |
| 202 | + | handler() | |
| 203 | + | } | |
| 204 | + | default: | |
| 205 | + | } | |
| 206 | + | } | |
A client/extimagecapturesource/extimagecapturesource_generated.go +179 -0
| @@ -0,0 +1,179 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: ext_image_capture_source_v1 | |
| 3 | + | // Source: ext-image-capture-source-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2022 Andri Yngvason | |
| 7 | + | // Copyright © 2024 Simon Ser | |
| 8 | + | // | |
| 9 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 10 | + | // copy of this software and associated documentation files (the "Software"), | |
| 11 | + | // to deal in the Software without restriction, including without limitation | |
| 12 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 13 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 14 | + | // Software is furnished to do so, subject to the following conditions: | |
| 15 | + | // | |
| 16 | + | // The above copyright notice and this permission notice (including the next | |
| 17 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 18 | + | // Software. | |
| 19 | + | // | |
| 20 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 21 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 22 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 23 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 24 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 25 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 26 | + | // DEALINGS IN THE SOFTWARE. | |
| 27 | + | ||
| 28 | + | package extimagecapturesource | |
| 29 | + | ||
| 30 | + | import ( | |
| 31 | + | cross_ext_foreign_toplevel_handle_v1 "github.com/bnema/go-wayland-bindings/client/extforeigntoplevellist" | |
| 32 | + | cross_wl_output "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 33 | + | "github.com/bnema/wlturbo/wl" | |
| 34 | + | ) | |
| 35 | + | ||
| 36 | + | // ExtImageCaptureSourceInterface is the protocol interface name. | |
| 37 | + | const ExtImageCaptureSourceInterface = "ext_image_capture_source_v1" | |
| 38 | + | ||
| 39 | + | // ExtImageCaptureSource is the generated binding for ext_image_capture_source_v1 version 1. | |
| 40 | + | type ExtImageCaptureSource struct { | |
| 41 | + | wl.BaseProxy | |
| 42 | + | } | |
| 43 | + | ||
| 44 | + | // NewExtImageCaptureSource returns an unbound ExtImageCaptureSource. | |
| 45 | + | func NewExtImageCaptureSource(ctx *wl.Context) *ExtImageCaptureSource { | |
| 46 | + | obj := &ExtImageCaptureSource{} | |
| 47 | + | obj.SetContext(ctx) | |
| 48 | + | ctx.Register(obj) | |
| 49 | + | return obj | |
| 50 | + | } | |
| 51 | + | ||
| 52 | + | // Destroys the image capture source. This request may be sent at any time by the client. | |
| 53 | + | func (o *ExtImageCaptureSource) Destroy() error { | |
| 54 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_image_capture_source_v1.destroy", Destructor: true}); err != nil { | |
| 55 | + | return err | |
| 56 | + | } | |
| 57 | + | return nil | |
| 58 | + | } | |
| 59 | + | ||
| 60 | + | // EventSignature returns the declared event argument types in wire order. | |
| 61 | + | func (o *ExtImageCaptureSource) EventSignature(opcode uint16) (string, bool) { | |
| 62 | + | switch opcode { | |
| 63 | + | default: | |
| 64 | + | return "", false | |
| 65 | + | } | |
| 66 | + | } | |
| 67 | + | ||
| 68 | + | // Dispatch decodes one event on ext_image_capture_source_v1 and calls the registered handlers. | |
| 69 | + | func (o *ExtImageCaptureSource) Dispatch(event *wl.Event) { | |
| 70 | + | switch event.Opcode { | |
| 71 | + | default: | |
| 72 | + | } | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | // ExtOutputImageCaptureSourceManagerInterface is the protocol interface name. | |
| 76 | + | const ExtOutputImageCaptureSourceManagerInterface = "ext_output_image_capture_source_manager_v1" | |
| 77 | + | ||
| 78 | + | // ExtOutputImageCaptureSourceManager is the generated binding for ext_output_image_capture_source_manager_v1 version 1. | |
| 79 | + | type ExtOutputImageCaptureSourceManager struct { | |
| 80 | + | wl.BaseProxy | |
| 81 | + | } | |
| 82 | + | ||
| 83 | + | // NewExtOutputImageCaptureSourceManager returns an unbound ExtOutputImageCaptureSourceManager. | |
| 84 | + | func NewExtOutputImageCaptureSourceManager(ctx *wl.Context) *ExtOutputImageCaptureSourceManager { | |
| 85 | + | obj := &ExtOutputImageCaptureSourceManager{} | |
| 86 | + | obj.SetContext(ctx) | |
| 87 | + | ctx.Register(obj) | |
| 88 | + | return obj | |
| 89 | + | } | |
| 90 | + | ||
| 91 | + | // Creates a source object for an output. Images captured from this source will show the same content as the output. Some elements may be omitted, such as cursors and overlays that have been marked as transparent to capturing. | |
| 92 | + | func (o *ExtOutputImageCaptureSourceManager) CreateSource(output *cross_wl_output.Output) (*ExtImageCaptureSource, error) { | |
| 93 | + | var arg1 wl.Object | |
| 94 | + | if output != nil { | |
| 95 | + | arg1 = output | |
| 96 | + | } | |
| 97 | + | child := &ExtImageCaptureSource{} | |
| 98 | + | child.SetContext(o.Context()) | |
| 99 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_output_image_capture_source_manager_v1.create_source", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 100 | + | return nil, err | |
| 101 | + | } | |
| 102 | + | return child, nil | |
| 103 | + | } | |
| 104 | + | ||
| 105 | + | // Destroys the manager. This request may be sent at any time by the client and objects created by the manager will remain valid after its destruction. | |
| 106 | + | func (o *ExtOutputImageCaptureSourceManager) Destroy() error { | |
| 107 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_output_image_capture_source_manager_v1.destroy", Destructor: true}); err != nil { | |
| 108 | + | return err | |
| 109 | + | } | |
| 110 | + | return nil | |
| 111 | + | } | |
| 112 | + | ||
| 113 | + | // EventSignature returns the declared event argument types in wire order. | |
| 114 | + | func (o *ExtOutputImageCaptureSourceManager) EventSignature(opcode uint16) (string, bool) { | |
| 115 | + | switch opcode { | |
| 116 | + | default: | |
| 117 | + | return "", false | |
| 118 | + | } | |
| 119 | + | } | |
| 120 | + | ||
| 121 | + | // Dispatch decodes one event on ext_output_image_capture_source_manager_v1 and calls the registered handlers. | |
| 122 | + | func (o *ExtOutputImageCaptureSourceManager) Dispatch(event *wl.Event) { | |
| 123 | + | switch event.Opcode { | |
| 124 | + | default: | |
| 125 | + | } | |
| 126 | + | } | |
| 127 | + | ||
| 128 | + | // ExtForeignToplevelImageCaptureSourceManagerInterface is the protocol interface name. | |
| 129 | + | const ExtForeignToplevelImageCaptureSourceManagerInterface = "ext_foreign_toplevel_image_capture_source_manager_v1" | |
| 130 | + | ||
| 131 | + | // ExtForeignToplevelImageCaptureSourceManager is the generated binding for ext_foreign_toplevel_image_capture_source_manager_v1 version 1. | |
| 132 | + | type ExtForeignToplevelImageCaptureSourceManager struct { | |
| 133 | + | wl.BaseProxy | |
| 134 | + | } | |
| 135 | + | ||
| 136 | + | // NewExtForeignToplevelImageCaptureSourceManager returns an unbound ExtForeignToplevelImageCaptureSourceManager. | |
| 137 | + | func NewExtForeignToplevelImageCaptureSourceManager(ctx *wl.Context) *ExtForeignToplevelImageCaptureSourceManager { | |
| 138 | + | obj := &ExtForeignToplevelImageCaptureSourceManager{} | |
| 139 | + | obj.SetContext(ctx) | |
| 140 | + | ctx.Register(obj) | |
| 141 | + | return obj | |
| 142 | + | } | |
| 143 | + | ||
| 144 | + | // Creates a source object for a foreign toplevel handle. Images captured from this source will show the same content as the toplevel. | |
| 145 | + | func (o *ExtForeignToplevelImageCaptureSourceManager) CreateSource(toplevelHandle *cross_ext_foreign_toplevel_handle_v1.ExtForeignToplevelHandle) (*ExtImageCaptureSource, error) { | |
| 146 | + | var arg1 wl.Object | |
| 147 | + | if toplevelHandle != nil { | |
| 148 | + | arg1 = toplevelHandle | |
| 149 | + | } | |
| 150 | + | child := &ExtImageCaptureSource{} | |
| 151 | + | child.SetContext(o.Context()) | |
| 152 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_foreign_toplevel_image_capture_source_manager_v1.create_source", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 153 | + | return nil, err | |
| 154 | + | } | |
| 155 | + | return child, nil | |
| 156 | + | } | |
| 157 | + | ||
| 158 | + | // Destroys the manager. This request may be sent at any time by the client and objects created by the manager will remain valid after its destruction. | |
| 159 | + | func (o *ExtForeignToplevelImageCaptureSourceManager) Destroy() error { | |
| 160 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_foreign_toplevel_image_capture_source_manager_v1.destroy", Destructor: true}); err != nil { | |
| 161 | + | return err | |
| 162 | + | } | |
| 163 | + | return nil | |
| 164 | + | } | |
| 165 | + | ||
| 166 | + | // EventSignature returns the declared event argument types in wire order. | |
| 167 | + | func (o *ExtForeignToplevelImageCaptureSourceManager) EventSignature(opcode uint16) (string, bool) { | |
| 168 | + | switch opcode { | |
| 169 | + | default: | |
| 170 | + | return "", false | |
| 171 | + | } | |
| 172 | + | } | |
| 173 | + | ||
| 174 | + | // Dispatch decodes one event on ext_foreign_toplevel_image_capture_source_manager_v1 and calls the registered handlers. | |
| 175 | + | func (o *ExtForeignToplevelImageCaptureSourceManager) Dispatch(event *wl.Event) { | |
| 176 | + | switch event.Opcode { | |
| 177 | + | default: | |
| 178 | + | } | |
| 179 | + | } | |
A client/extimagecopycapture/extimagecopycapture_generated.go +796 -0
| @@ -0,0 +1,796 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: ext_image_copy_capture_v1 | |
| 3 | + | // Source: ext-image-copy-capture-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2021-2023 Andri Yngvason | |
| 7 | + | // Copyright © 2024 Simon Ser | |
| 8 | + | // | |
| 9 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 10 | + | // copy of this software and associated documentation files (the "Software"), | |
| 11 | + | // to deal in the Software without restriction, including without limitation | |
| 12 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 13 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 14 | + | // Software is furnished to do so, subject to the following conditions: | |
| 15 | + | // | |
| 16 | + | // The above copyright notice and this permission notice (including the next | |
| 17 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 18 | + | // Software. | |
| 19 | + | // | |
| 20 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 21 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 22 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 23 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 24 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 25 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 26 | + | // DEALINGS IN THE SOFTWARE. | |
| 27 | + | ||
| 28 | + | package extimagecopycapture | |
| 29 | + | ||
| 30 | + | import ( | |
| 31 | + | "sync" | |
| 32 | + | ||
| 33 | + | cross_ext_image_capture_source_v1 "github.com/bnema/go-wayland-bindings/client/extimagecapturesource" | |
| 34 | + | cross_wl_buffer "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 35 | + | cross_wl_pointer "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 36 | + | "github.com/bnema/wlturbo/wl" | |
| 37 | + | ) | |
| 38 | + | ||
| 39 | + | // ERROR_INVALID_OPTION is the error invalid_option value. | |
| 40 | + | const ERROR_INVALID_OPTION = 1 | |
| 41 | + | ||
| 42 | + | // OPTIONS_PAINT_CURSORS is the options paint_cursors value. | |
| 43 | + | const OPTIONS_PAINT_CURSORS = 1 | |
| 44 | + | ||
| 45 | + | // ERROR_DUPLICATE_FRAME is the error duplicate_frame value. | |
| 46 | + | const ERROR_DUPLICATE_FRAME = 1 | |
| 47 | + | ||
| 48 | + | // ERROR_NO_BUFFER is the error no_buffer value. | |
| 49 | + | const ERROR_NO_BUFFER = 1 | |
| 50 | + | ||
| 51 | + | // ERROR_INVALID_BUFFER_DAMAGE is the error invalid_buffer_damage value. | |
| 52 | + | const ERROR_INVALID_BUFFER_DAMAGE = 2 | |
| 53 | + | ||
| 54 | + | // ERROR_ALREADY_CAPTURED is the error already_captured value. | |
| 55 | + | const ERROR_ALREADY_CAPTURED = 3 | |
| 56 | + | ||
| 57 | + | // FAILURE_REASON_UNKNOWN is the failure_reason unknown value. | |
| 58 | + | const FAILURE_REASON_UNKNOWN = 0 | |
| 59 | + | ||
| 60 | + | // FAILURE_REASON_BUFFER_CONSTRAINTS is the failure_reason buffer_constraints value. | |
| 61 | + | const FAILURE_REASON_BUFFER_CONSTRAINTS = 1 | |
| 62 | + | ||
| 63 | + | // FAILURE_REASON_STOPPED is the failure_reason stopped value. | |
| 64 | + | const FAILURE_REASON_STOPPED = 2 | |
| 65 | + | ||
| 66 | + | // ERROR_DUPLICATE_SESSION is the error duplicate_session value. | |
| 67 | + | const ERROR_DUPLICATE_SESSION = 1 | |
| 68 | + | ||
| 69 | + | // ExtImageCopyCaptureManagerInterface is the protocol interface name. | |
| 70 | + | const ExtImageCopyCaptureManagerInterface = "ext_image_copy_capture_manager_v1" | |
| 71 | + | ||
| 72 | + | // ExtImageCopyCaptureManager is the generated binding for ext_image_copy_capture_manager_v1 version 1. | |
| 73 | + | type ExtImageCopyCaptureManager struct { | |
| 74 | + | wl.BaseProxy | |
| 75 | + | } | |
| 76 | + | ||
| 77 | + | // NewExtImageCopyCaptureManager returns an unbound ExtImageCopyCaptureManager. | |
| 78 | + | func NewExtImageCopyCaptureManager(ctx *wl.Context) *ExtImageCopyCaptureManager { | |
| 79 | + | obj := &ExtImageCopyCaptureManager{} | |
| 80 | + | obj.SetContext(ctx) | |
| 81 | + | ctx.Register(obj) | |
| 82 | + | return obj | |
| 83 | + | } | |
| 84 | + | ||
| 85 | + | // Create a capturing session for an image capture source. If the paint_cursors option is set, cursors shall be composited onto the captured frame. The cursor must not be composited onto the frame if this flag is not set. If the options bitfield is invalid, the invalid_option protocol error is sent. | |
| 86 | + | func (o *ExtImageCopyCaptureManager) CreateSession(source *cross_ext_image_capture_source_v1.ExtImageCaptureSource, options uint32) (*ExtImageCopyCaptureSession, error) { | |
| 87 | + | var arg1 wl.Object | |
| 88 | + | if source != nil { | |
| 89 | + | arg1 = source | |
| 90 | + | } | |
| 91 | + | child := &ExtImageCopyCaptureSession{} | |
| 92 | + | child.SetContext(o.Context()) | |
| 93 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_image_copy_capture_manager_v1.create_session", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1), wl.ArgUint(options)); err != nil { | |
| 94 | + | return nil, err | |
| 95 | + | } | |
| 96 | + | return child, nil | |
| 97 | + | } | |
| 98 | + | ||
| 99 | + | // Create a cursor capturing session for the pointer of an image capture source. | |
| 100 | + | func (o *ExtImageCopyCaptureManager) CreatePointerCursorSession(source *cross_ext_image_capture_source_v1.ExtImageCaptureSource, pointer *cross_wl_pointer.Pointer) (*ExtImageCopyCaptureCursorSession, error) { | |
| 101 | + | var arg1 wl.Object | |
| 102 | + | if source != nil { | |
| 103 | + | arg1 = source | |
| 104 | + | } | |
| 105 | + | var arg2 wl.Object | |
| 106 | + | if pointer != nil { | |
| 107 | + | arg2 = pointer | |
| 108 | + | } | |
| 109 | + | child := &ExtImageCopyCaptureCursorSession{} | |
| 110 | + | child.SetContext(o.Context()) | |
| 111 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_image_copy_capture_manager_v1.create_pointer_cursor_session", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1), wl.ArgObject(arg2)); err != nil { | |
| 112 | + | return nil, err | |
| 113 | + | } | |
| 114 | + | return child, nil | |
| 115 | + | } | |
| 116 | + | ||
| 117 | + | // Destroy the manager object. Other objects created via this interface are unaffected. | |
| 118 | + | func (o *ExtImageCopyCaptureManager) Destroy() error { | |
| 119 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "ext_image_copy_capture_manager_v1.destroy", Destructor: true}); err != nil { | |
| 120 | + | return err | |
| 121 | + | } | |
| 122 | + | return nil | |
| 123 | + | } | |
| 124 | + | ||
| 125 | + | // EventSignature returns the declared event argument types in wire order. | |
| 126 | + | func (o *ExtImageCopyCaptureManager) EventSignature(opcode uint16) (string, bool) { | |
| 127 | + | switch opcode { | |
| 128 | + | default: | |
| 129 | + | return "", false | |
| 130 | + | } | |
| 131 | + | } | |
| 132 | + | ||
| 133 | + | // Dispatch decodes one event on ext_image_copy_capture_manager_v1 and calls the registered handlers. | |
| 134 | + | func (o *ExtImageCopyCaptureManager) Dispatch(event *wl.Event) { | |
| 135 | + | switch event.Opcode { | |
| 136 | + | default: | |
| 137 | + | } | |
| 138 | + | } | |
| 139 | + | ||
| 140 | + | // ExtImageCopyCaptureSessionInterface is the protocol interface name. | |
| 141 | + | const ExtImageCopyCaptureSessionInterface = "ext_image_copy_capture_session_v1" | |
| 142 | + | ||
| 143 | + | // ExtImageCopyCaptureSession is the generated binding for ext_image_copy_capture_session_v1 version 1. | |
| 144 | + | type ExtImageCopyCaptureSession struct { | |
| 145 | + | wl.BaseProxy | |
| 146 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 147 | + | // handlers while another goroutine dispatches events. | |
| 148 | + | handlersMu sync.Mutex | |
| 149 | + | onBufferSize []func(width uint32, height uint32) | |
| 150 | + | onShmFormat []func(format uint32) | |
| 151 | + | onDmabufDevice []func(device []byte) | |
| 152 | + | onDmabufFormat []func(format uint32, modifiers []byte) | |
| 153 | + | onDone []func() | |
| 154 | + | onStopped []func() | |
| 155 | + | } | |
| 156 | + | ||
| 157 | + | // NewExtImageCopyCaptureSession returns an unbound ExtImageCopyCaptureSession. | |
| 158 | + | func NewExtImageCopyCaptureSession(ctx *wl.Context) *ExtImageCopyCaptureSession { | |
| 159 | + | obj := &ExtImageCopyCaptureSession{} | |
| 160 | + | obj.SetContext(ctx) | |
| 161 | + | ctx.Register(obj) | |
| 162 | + | return obj | |
| 163 | + | } | |
| 164 | + | ||
| 165 | + | // Create a capture frame for this session. At most one frame object can exist for a given session at any time. If a client sends a create_frame request before a previous frame object has been destroyed, the duplicate_frame protocol error is raised. | |
| 166 | + | func (o *ExtImageCopyCaptureSession) CreateFrame() (*ExtImageCopyCaptureFrame, error) { | |
| 167 | + | child := &ExtImageCopyCaptureFrame{} | |
| 168 | + | child.SetContext(o.Context()) | |
| 169 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_image_copy_capture_session_v1.create_frame", Child: child}, wl.ArgObject(child)); err != nil { | |
| 170 | + | return nil, err | |
| 171 | + | } | |
| 172 | + | return child, nil | |
| 173 | + | } | |
| 174 | + | ||
| 175 | + | // Destroys the session. This request can be sent at any time by the client. This request doesn't affect ext_image_copy_capture_frame_v1 objects created by this object. | |
| 176 | + | func (o *ExtImageCopyCaptureSession) Destroy() error { | |
| 177 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_image_copy_capture_session_v1.destroy", Destructor: true}); err != nil { | |
| 178 | + | return err | |
| 179 | + | } | |
| 180 | + | return nil | |
| 181 | + | } | |
| 182 | + | ||
| 183 | + | // OnBufferSize registers a handler for the buffer_size event. | |
| 184 | + | // | |
| 185 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 186 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 187 | + | func (o *ExtImageCopyCaptureSession) OnBufferSize(handler func(width uint32, height uint32)) { | |
| 188 | + | if handler == nil { | |
| 189 | + | return | |
| 190 | + | } | |
| 191 | + | o.handlersMu.Lock() | |
| 192 | + | defer o.handlersMu.Unlock() | |
| 193 | + | o.onBufferSize = append(o.onBufferSize, handler) | |
| 194 | + | } | |
| 195 | + | ||
| 196 | + | // handlersForBufferSize returns the handlers registered for buffer_size, taken | |
| 197 | + | // under the lock so a handler may register another handler while events are | |
| 198 | + | // being dispatched. | |
| 199 | + | func (o *ExtImageCopyCaptureSession) handlersForBufferSize() []func(width uint32, height uint32) { | |
| 200 | + | o.handlersMu.Lock() | |
| 201 | + | defer o.handlersMu.Unlock() | |
| 202 | + | return o.onBufferSize | |
| 203 | + | } | |
| 204 | + | ||
| 205 | + | // OnShmFormat registers a handler for the shm_format event. | |
| 206 | + | // | |
| 207 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 208 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 209 | + | func (o *ExtImageCopyCaptureSession) OnShmFormat(handler func(format uint32)) { | |
| 210 | + | if handler == nil { | |
| 211 | + | return | |
| 212 | + | } | |
| 213 | + | o.handlersMu.Lock() | |
| 214 | + | defer o.handlersMu.Unlock() | |
| 215 | + | o.onShmFormat = append(o.onShmFormat, handler) | |
| 216 | + | } | |
| 217 | + | ||
| 218 | + | // handlersForShmFormat returns the handlers registered for shm_format, taken | |
| 219 | + | // under the lock so a handler may register another handler while events are | |
| 220 | + | // being dispatched. | |
| 221 | + | func (o *ExtImageCopyCaptureSession) handlersForShmFormat() []func(format uint32) { | |
| 222 | + | o.handlersMu.Lock() | |
| 223 | + | defer o.handlersMu.Unlock() | |
| 224 | + | return o.onShmFormat | |
| 225 | + | } | |
| 226 | + | ||
| 227 | + | // OnDmabufDevice registers a handler for the dmabuf_device event. | |
| 228 | + | // | |
| 229 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 230 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 231 | + | func (o *ExtImageCopyCaptureSession) OnDmabufDevice(handler func(device []byte)) { | |
| 232 | + | if handler == nil { | |
| 233 | + | return | |
| 234 | + | } | |
| 235 | + | o.handlersMu.Lock() | |
| 236 | + | defer o.handlersMu.Unlock() | |
| 237 | + | o.onDmabufDevice = append(o.onDmabufDevice, handler) | |
| 238 | + | } | |
| 239 | + | ||
| 240 | + | // handlersForDmabufDevice returns the handlers registered for dmabuf_device, taken | |
| 241 | + | // under the lock so a handler may register another handler while events are | |
| 242 | + | // being dispatched. | |
| 243 | + | func (o *ExtImageCopyCaptureSession) handlersForDmabufDevice() []func(device []byte) { | |
| 244 | + | o.handlersMu.Lock() | |
| 245 | + | defer o.handlersMu.Unlock() | |
| 246 | + | return o.onDmabufDevice | |
| 247 | + | } | |
| 248 | + | ||
| 249 | + | // OnDmabufFormat registers a handler for the dmabuf_format event. | |
| 250 | + | // | |
| 251 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 252 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 253 | + | func (o *ExtImageCopyCaptureSession) OnDmabufFormat(handler func(format uint32, modifiers []byte)) { | |
| 254 | + | if handler == nil { | |
| 255 | + | return | |
| 256 | + | } | |
| 257 | + | o.handlersMu.Lock() | |
| 258 | + | defer o.handlersMu.Unlock() | |
| 259 | + | o.onDmabufFormat = append(o.onDmabufFormat, handler) | |
| 260 | + | } | |
| 261 | + | ||
| 262 | + | // handlersForDmabufFormat returns the handlers registered for dmabuf_format, taken | |
| 263 | + | // under the lock so a handler may register another handler while events are | |
| 264 | + | // being dispatched. | |
| 265 | + | func (o *ExtImageCopyCaptureSession) handlersForDmabufFormat() []func(format uint32, modifiers []byte) { | |
| 266 | + | o.handlersMu.Lock() | |
| 267 | + | defer o.handlersMu.Unlock() | |
| 268 | + | return o.onDmabufFormat | |
| 269 | + | } | |
| 270 | + | ||
| 271 | + | // OnDone registers a handler for the done event. | |
| 272 | + | // | |
| 273 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 274 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 275 | + | func (o *ExtImageCopyCaptureSession) OnDone(handler func()) { | |
| 276 | + | if handler == nil { | |
| 277 | + | return | |
| 278 | + | } | |
| 279 | + | o.handlersMu.Lock() | |
| 280 | + | defer o.handlersMu.Unlock() | |
| 281 | + | o.onDone = append(o.onDone, handler) | |
| 282 | + | } | |
| 283 | + | ||
| 284 | + | // handlersForDone returns the handlers registered for done, taken | |
| 285 | + | // under the lock so a handler may register another handler while events are | |
| 286 | + | // being dispatched. | |
| 287 | + | func (o *ExtImageCopyCaptureSession) handlersForDone() []func() { | |
| 288 | + | o.handlersMu.Lock() | |
| 289 | + | defer o.handlersMu.Unlock() | |
| 290 | + | return o.onDone | |
| 291 | + | } | |
| 292 | + | ||
| 293 | + | // OnStopped registers a handler for the stopped event. | |
| 294 | + | // | |
| 295 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 296 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 297 | + | func (o *ExtImageCopyCaptureSession) OnStopped(handler func()) { | |
| 298 | + | if handler == nil { | |
| 299 | + | return | |
| 300 | + | } | |
| 301 | + | o.handlersMu.Lock() | |
| 302 | + | defer o.handlersMu.Unlock() | |
| 303 | + | o.onStopped = append(o.onStopped, handler) | |
| 304 | + | } | |
| 305 | + | ||
| 306 | + | // handlersForStopped returns the handlers registered for stopped, taken | |
| 307 | + | // under the lock so a handler may register another handler while events are | |
| 308 | + | // being dispatched. | |
| 309 | + | func (o *ExtImageCopyCaptureSession) handlersForStopped() []func() { | |
| 310 | + | o.handlersMu.Lock() | |
| 311 | + | defer o.handlersMu.Unlock() | |
| 312 | + | return o.onStopped | |
| 313 | + | } | |
| 314 | + | ||
| 315 | + | // EventSignature returns the declared event argument types in wire order. | |
| 316 | + | func (o *ExtImageCopyCaptureSession) EventSignature(opcode uint16) (string, bool) { | |
| 317 | + | switch opcode { | |
| 318 | + | case 0: | |
| 319 | + | return "uint,uint,", true | |
| 320 | + | case 1: | |
| 321 | + | return "uint,", true | |
| 322 | + | case 2: | |
| 323 | + | return "array,", true | |
| 324 | + | case 3: | |
| 325 | + | return "uint,array,", true | |
| 326 | + | case 4: | |
| 327 | + | return "", true | |
| 328 | + | case 5: | |
| 329 | + | return "", true | |
| 330 | + | default: | |
| 331 | + | return "", false | |
| 332 | + | } | |
| 333 | + | } | |
| 334 | + | ||
| 335 | + | // Dispatch decodes one event on ext_image_copy_capture_session_v1 and calls the registered handlers. | |
| 336 | + | func (o *ExtImageCopyCaptureSession) Dispatch(event *wl.Event) { | |
| 337 | + | switch event.Opcode { | |
| 338 | + | case 0: // buffer_size | |
| 339 | + | width := event.Uint32() | |
| 340 | + | height := event.Uint32() | |
| 341 | + | ||
| 342 | + | for i, handler := range o.handlersForBufferSize() { | |
| 343 | + | _ = i | |
| 344 | + | handler(width, height) | |
| 345 | + | } | |
| 346 | + | case 1: // shm_format | |
| 347 | + | format := event.Uint32() | |
| 348 | + | ||
| 349 | + | for i, handler := range o.handlersForShmFormat() { | |
| 350 | + | _ = i | |
| 351 | + | handler(format) | |
| 352 | + | } | |
| 353 | + | case 2: // dmabuf_device | |
| 354 | + | device := event.Array() | |
| 355 | + | ||
| 356 | + | for i, handler := range o.handlersForDmabufDevice() { | |
| 357 | + | _ = i | |
| 358 | + | handler(device) | |
| 359 | + | } | |
| 360 | + | case 3: // dmabuf_format | |
| 361 | + | format := event.Uint32() | |
| 362 | + | modifiers := event.Array() | |
| 363 | + | ||
| 364 | + | for i, handler := range o.handlersForDmabufFormat() { | |
| 365 | + | _ = i | |
| 366 | + | handler(format, modifiers) | |
| 367 | + | } | |
| 368 | + | case 4: // done | |
| 369 | + | ||
| 370 | + | for i, handler := range o.handlersForDone() { | |
| 371 | + | _ = i | |
| 372 | + | handler() | |
| 373 | + | } | |
| 374 | + | case 5: // stopped | |
| 375 | + | ||
| 376 | + | for i, handler := range o.handlersForStopped() { | |
| 377 | + | _ = i | |
| 378 | + | handler() | |
| 379 | + | } | |
| 380 | + | default: | |
| 381 | + | } | |
| 382 | + | } | |
| 383 | + | ||
| 384 | + | // ExtImageCopyCaptureFrameInterface is the protocol interface name. | |
| 385 | + | const ExtImageCopyCaptureFrameInterface = "ext_image_copy_capture_frame_v1" | |
| 386 | + | ||
| 387 | + | // ExtImageCopyCaptureFrame is the generated binding for ext_image_copy_capture_frame_v1 version 1. | |
| 388 | + | type ExtImageCopyCaptureFrame struct { | |
| 389 | + | wl.BaseProxy | |
| 390 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 391 | + | // handlers while another goroutine dispatches events. | |
| 392 | + | handlersMu sync.Mutex | |
| 393 | + | onTransform []func(transform uint32) | |
| 394 | + | onDamage []func(x int32, y int32, width int32, height int32) | |
| 395 | + | onPresentationTime []func(tvSecHi uint32, tvSecLo uint32, tvNsec uint32) | |
| 396 | + | onReady []func() | |
| 397 | + | onFailed []func(reason uint32) | |
| 398 | + | } | |
| 399 | + | ||
| 400 | + | // NewExtImageCopyCaptureFrame returns an unbound ExtImageCopyCaptureFrame. | |
| 401 | + | func NewExtImageCopyCaptureFrame(ctx *wl.Context) *ExtImageCopyCaptureFrame { | |
| 402 | + | obj := &ExtImageCopyCaptureFrame{} | |
| 403 | + | obj.SetContext(ctx) | |
| 404 | + | ctx.Register(obj) | |
| 405 | + | return obj | |
| 406 | + | } | |
| 407 | + | ||
| 408 | + | // Destroys the frame. This request can be sent at any time by the client. | |
| 409 | + | func (o *ExtImageCopyCaptureFrame) Destroy() error { | |
| 410 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_image_copy_capture_frame_v1.destroy", Destructor: true}); err != nil { | |
| 411 | + | return err | |
| 412 | + | } | |
| 413 | + | return nil | |
| 414 | + | } | |
| 415 | + | ||
| 416 | + | // Attach a buffer to the session. The wl_buffer.release request is unused. The new buffer replaces any previously attached buffer. This request must not be sent after capture, or else the already_captured protocol error is raised. | |
| 417 | + | func (o *ExtImageCopyCaptureFrame) AttachBuffer(buffer *cross_wl_buffer.Buffer) error { | |
| 418 | + | var arg0 wl.Object | |
| 419 | + | if buffer != nil { | |
| 420 | + | arg0 = buffer | |
| 421 | + | } | |
| 422 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_image_copy_capture_frame_v1.attach_buffer"}, wl.ArgObject(arg0)); err != nil { | |
| 423 | + | return err | |
| 424 | + | } | |
| 425 | + | return nil | |
| 426 | + | } | |
| 427 | + | ||
| 428 | + | // Apply damage to the buffer which is to be captured next. This request may be sent multiple times to describe a region. The client indicates the accumulated damage since this wl_buffer was last captured. During capture, the compositor will update the buffer with at least the union of the region passed by the client and the region advertised by ext_image_copy_capture_frame_v1.damage. When a wl_buffer is captured for the first time, or when the client doesn't track damage, the client must damage the whole buffer. This is for optimisation purposes. The compositor may use this information to reduce copying. These coordinates originate from the upper left corner of the buffer. If x or y are strictly negative, or if width or height are negative or zero, the invalid_buffer_damage protocol error is raised. This request must not be sent after capture, or else the already_captured protocol error is raised. | |
| 429 | + | func (o *ExtImageCopyCaptureFrame) DamageBuffer(x int32, y int32, width int32, height int32) error { | |
| 430 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "ext_image_copy_capture_frame_v1.damage_buffer"}, wl.ArgInt(x), wl.ArgInt(y), wl.ArgInt(width), wl.ArgInt(height)); err != nil { | |
| 431 | + | return err | |
| 432 | + | } | |
| 433 | + | return nil | |
| 434 | + | } | |
| 435 | + | ||
| 436 | + | // Capture a frame. Unless this is the first successful captured frame performed in this session, the compositor may wait an indefinite amount of time for the source content to change before performing the copy. This request may only be sent once, or else the already_captured protocol error is raised. A buffer must be attached before this request is sent, or else the no_buffer protocol error is raised. | |
| 437 | + | func (o *ExtImageCopyCaptureFrame) Capture() error { | |
| 438 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "ext_image_copy_capture_frame_v1.capture"}); err != nil { | |
| 439 | + | return err | |
| 440 | + | } | |
| 441 | + | return nil | |
| 442 | + | } | |
| 443 | + | ||
| 444 | + | // OnTransform registers a handler for the transform event. | |
| 445 | + | // | |
| 446 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 447 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 448 | + | func (o *ExtImageCopyCaptureFrame) OnTransform(handler func(transform uint32)) { | |
| 449 | + | if handler == nil { | |
| 450 | + | return | |
| 451 | + | } | |
| 452 | + | o.handlersMu.Lock() | |
| 453 | + | defer o.handlersMu.Unlock() | |
| 454 | + | o.onTransform = append(o.onTransform, handler) | |
| 455 | + | } | |
| 456 | + | ||
| 457 | + | // handlersForTransform returns the handlers registered for transform, taken | |
| 458 | + | // under the lock so a handler may register another handler while events are | |
| 459 | + | // being dispatched. | |
| 460 | + | func (o *ExtImageCopyCaptureFrame) handlersForTransform() []func(transform uint32) { | |
| 461 | + | o.handlersMu.Lock() | |
| 462 | + | defer o.handlersMu.Unlock() | |
| 463 | + | return o.onTransform | |
| 464 | + | } | |
| 465 | + | ||
| 466 | + | // OnDamage registers a handler for the damage event. | |
| 467 | + | // | |
| 468 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 469 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 470 | + | func (o *ExtImageCopyCaptureFrame) OnDamage(handler func(x int32, y int32, width int32, height int32)) { | |
| 471 | + | if handler == nil { | |
| 472 | + | return | |
| 473 | + | } | |
| 474 | + | o.handlersMu.Lock() | |
| 475 | + | defer o.handlersMu.Unlock() | |
| 476 | + | o.onDamage = append(o.onDamage, handler) | |
| 477 | + | } | |
| 478 | + | ||
| 479 | + | // handlersForDamage returns the handlers registered for damage, taken | |
| 480 | + | // under the lock so a handler may register another handler while events are | |
| 481 | + | // being dispatched. | |
| 482 | + | func (o *ExtImageCopyCaptureFrame) handlersForDamage() []func(x int32, y int32, width int32, height int32) { | |
| 483 | + | o.handlersMu.Lock() | |
| 484 | + | defer o.handlersMu.Unlock() | |
| 485 | + | return o.onDamage | |
| 486 | + | } | |
| 487 | + | ||
| 488 | + | // OnPresentationTime registers a handler for the presentation_time event. | |
| 489 | + | // | |
| 490 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 491 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 492 | + | func (o *ExtImageCopyCaptureFrame) OnPresentationTime(handler func(tvSecHi uint32, tvSecLo uint32, tvNsec uint32)) { | |
| 493 | + | if handler == nil { | |
| 494 | + | return | |
| 495 | + | } | |
| 496 | + | o.handlersMu.Lock() | |
| 497 | + | defer o.handlersMu.Unlock() | |
| 498 | + | o.onPresentationTime = append(o.onPresentationTime, handler) | |
| 499 | + | } | |
| 500 | + | ||
| 501 | + | // handlersForPresentationTime returns the handlers registered for presentation_time, taken | |
| 502 | + | // under the lock so a handler may register another handler while events are | |
| 503 | + | // being dispatched. | |
| 504 | + | func (o *ExtImageCopyCaptureFrame) handlersForPresentationTime() []func(tvSecHi uint32, tvSecLo uint32, tvNsec uint32) { | |
| 505 | + | o.handlersMu.Lock() | |
| 506 | + | defer o.handlersMu.Unlock() | |
| 507 | + | return o.onPresentationTime | |
| 508 | + | } | |
| 509 | + | ||
| 510 | + | // OnReady registers a handler for the ready event. | |
| 511 | + | // | |
| 512 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 513 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 514 | + | func (o *ExtImageCopyCaptureFrame) OnReady(handler func()) { | |
| 515 | + | if handler == nil { | |
| 516 | + | return | |
| 517 | + | } | |
| 518 | + | o.handlersMu.Lock() | |
| 519 | + | defer o.handlersMu.Unlock() | |
| 520 | + | o.onReady = append(o.onReady, handler) | |
| 521 | + | } | |
| 522 | + | ||
| 523 | + | // handlersForReady returns the handlers registered for ready, taken | |
| 524 | + | // under the lock so a handler may register another handler while events are | |
| 525 | + | // being dispatched. | |
| 526 | + | func (o *ExtImageCopyCaptureFrame) handlersForReady() []func() { | |
| 527 | + | o.handlersMu.Lock() | |
| 528 | + | defer o.handlersMu.Unlock() | |
| 529 | + | return o.onReady | |
| 530 | + | } | |
| 531 | + | ||
| 532 | + | // OnFailed registers a handler for the failed event. | |
| 533 | + | // | |
| 534 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 535 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 536 | + | func (o *ExtImageCopyCaptureFrame) OnFailed(handler func(reason uint32)) { | |
| 537 | + | if handler == nil { | |
| 538 | + | return | |
| 539 | + | } | |
| 540 | + | o.handlersMu.Lock() | |
| 541 | + | defer o.handlersMu.Unlock() | |
| 542 | + | o.onFailed = append(o.onFailed, handler) | |
| 543 | + | } | |
| 544 | + | ||
| 545 | + | // handlersForFailed returns the handlers registered for failed, taken | |
| 546 | + | // under the lock so a handler may register another handler while events are | |
| 547 | + | // being dispatched. | |
| 548 | + | func (o *ExtImageCopyCaptureFrame) handlersForFailed() []func(reason uint32) { | |
| 549 | + | o.handlersMu.Lock() | |
| 550 | + | defer o.handlersMu.Unlock() | |
| 551 | + | return o.onFailed | |
| 552 | + | } | |
| 553 | + | ||
| 554 | + | // EventSignature returns the declared event argument types in wire order. | |
| 555 | + | func (o *ExtImageCopyCaptureFrame) EventSignature(opcode uint16) (string, bool) { | |
| 556 | + | switch opcode { | |
| 557 | + | case 0: | |
| 558 | + | return "uint,", true | |
| 559 | + | case 1: | |
| 560 | + | return "int,int,int,int,", true | |
| 561 | + | case 2: | |
| 562 | + | return "uint,uint,uint,", true | |
| 563 | + | case 3: | |
| 564 | + | return "", true | |
| 565 | + | case 4: | |
| 566 | + | return "uint,", true | |
| 567 | + | default: | |
| 568 | + | return "", false | |
| 569 | + | } | |
| 570 | + | } | |
| 571 | + | ||
| 572 | + | // Dispatch decodes one event on ext_image_copy_capture_frame_v1 and calls the registered handlers. | |
| 573 | + | func (o *ExtImageCopyCaptureFrame) Dispatch(event *wl.Event) { | |
| 574 | + | switch event.Opcode { | |
| 575 | + | case 0: // transform | |
| 576 | + | transform := event.Uint32() | |
| 577 | + | ||
| 578 | + | for i, handler := range o.handlersForTransform() { | |
| 579 | + | _ = i | |
| 580 | + | handler(transform) | |
| 581 | + | } | |
| 582 | + | case 1: // damage | |
| 583 | + | x := event.Int32() | |
| 584 | + | y := event.Int32() | |
| 585 | + | width := event.Int32() | |
| 586 | + | height := event.Int32() | |
| 587 | + | ||
| 588 | + | for i, handler := range o.handlersForDamage() { | |
| 589 | + | _ = i | |
| 590 | + | handler(x, y, width, height) | |
| 591 | + | } | |
| 592 | + | case 2: // presentation_time | |
| 593 | + | tvSecHi := event.Uint32() | |
| 594 | + | tvSecLo := event.Uint32() | |
| 595 | + | tvNsec := event.Uint32() | |
| 596 | + | ||
| 597 | + | for i, handler := range o.handlersForPresentationTime() { | |
| 598 | + | _ = i | |
| 599 | + | handler(tvSecHi, tvSecLo, tvNsec) | |
| 600 | + | } | |
| 601 | + | case 3: // ready | |
| 602 | + | ||
| 603 | + | for i, handler := range o.handlersForReady() { | |
| 604 | + | _ = i | |
| 605 | + | handler() | |
| 606 | + | } | |
| 607 | + | case 4: // failed | |
| 608 | + | reason := event.Uint32() | |
| 609 | + | ||
| 610 | + | for i, handler := range o.handlersForFailed() { | |
| 611 | + | _ = i | |
| 612 | + | handler(reason) | |
| 613 | + | } | |
| 614 | + | default: | |
| 615 | + | } | |
| 616 | + | } | |
| 617 | + | ||
| 618 | + | // ExtImageCopyCaptureCursorSessionInterface is the protocol interface name. | |
| 619 | + | const ExtImageCopyCaptureCursorSessionInterface = "ext_image_copy_capture_cursor_session_v1" | |
| 620 | + | ||
| 621 | + | // ExtImageCopyCaptureCursorSession is the generated binding for ext_image_copy_capture_cursor_session_v1 version 1. | |
| 622 | + | type ExtImageCopyCaptureCursorSession struct { | |
| 623 | + | wl.BaseProxy | |
| 624 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 625 | + | // handlers while another goroutine dispatches events. | |
| 626 | + | handlersMu sync.Mutex | |
| 627 | + | onEnter []func() | |
| 628 | + | onLeave []func() | |
| 629 | + | onPosition []func(x int32, y int32) | |
| 630 | + | onHotspot []func(x int32, y int32) | |
| 631 | + | } | |
| 632 | + | ||
| 633 | + | // NewExtImageCopyCaptureCursorSession returns an unbound ExtImageCopyCaptureCursorSession. | |
| 634 | + | func NewExtImageCopyCaptureCursorSession(ctx *wl.Context) *ExtImageCopyCaptureCursorSession { | |
| 635 | + | obj := &ExtImageCopyCaptureCursorSession{} | |
| 636 | + | obj.SetContext(ctx) | |
| 637 | + | ctx.Register(obj) | |
| 638 | + | return obj | |
| 639 | + | } | |
| 640 | + | ||
| 641 | + | // Destroys the session. This request can be sent at any time by the client. This request doesn't affect ext_image_copy_capture_frame_v1 objects created by this object. | |
| 642 | + | func (o *ExtImageCopyCaptureCursorSession) Destroy() error { | |
| 643 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_image_copy_capture_cursor_session_v1.destroy", Destructor: true}); err != nil { | |
| 644 | + | return err | |
| 645 | + | } | |
| 646 | + | return nil | |
| 647 | + | } | |
| 648 | + | ||
| 649 | + | // Gets the image copy capture session for this cursor session. The session will produce frames of the cursor image. The compositor may pause the session when the cursor leaves the captured area. This request must not be sent more than once, or else the duplicate_session protocol error is raised. | |
| 650 | + | func (o *ExtImageCopyCaptureCursorSession) GetCaptureSession() (*ExtImageCopyCaptureSession, error) { | |
| 651 | + | child := &ExtImageCopyCaptureSession{} | |
| 652 | + | child.SetContext(o.Context()) | |
| 653 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_image_copy_capture_cursor_session_v1.get_capture_session", Child: child}, wl.ArgObject(child)); err != nil { | |
| 654 | + | return nil, err | |
| 655 | + | } | |
| 656 | + | return child, nil | |
| 657 | + | } | |
| 658 | + | ||
| 659 | + | // OnEnter registers a handler for the enter event. | |
| 660 | + | // | |
| 661 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 662 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 663 | + | func (o *ExtImageCopyCaptureCursorSession) OnEnter(handler func()) { | |
| 664 | + | if handler == nil { | |
| 665 | + | return | |
| 666 | + | } | |
| 667 | + | o.handlersMu.Lock() | |
| 668 | + | defer o.handlersMu.Unlock() | |
| 669 | + | o.onEnter = append(o.onEnter, handler) | |
| 670 | + | } | |
| 671 | + | ||
| 672 | + | // handlersForEnter returns the handlers registered for enter, taken | |
| 673 | + | // under the lock so a handler may register another handler while events are | |
| 674 | + | // being dispatched. | |
| 675 | + | func (o *ExtImageCopyCaptureCursorSession) handlersForEnter() []func() { | |
| 676 | + | o.handlersMu.Lock() | |
| 677 | + | defer o.handlersMu.Unlock() | |
| 678 | + | return o.onEnter | |
| 679 | + | } | |
| 680 | + | ||
| 681 | + | // OnLeave registers a handler for the leave event. | |
| 682 | + | // | |
| 683 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 684 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 685 | + | func (o *ExtImageCopyCaptureCursorSession) OnLeave(handler func()) { | |
| 686 | + | if handler == nil { | |
| 687 | + | return | |
| 688 | + | } | |
| 689 | + | o.handlersMu.Lock() | |
| 690 | + | defer o.handlersMu.Unlock() | |
| 691 | + | o.onLeave = append(o.onLeave, handler) | |
| 692 | + | } | |
| 693 | + | ||
| 694 | + | // handlersForLeave returns the handlers registered for leave, taken | |
| 695 | + | // under the lock so a handler may register another handler while events are | |
| 696 | + | // being dispatched. | |
| 697 | + | func (o *ExtImageCopyCaptureCursorSession) handlersForLeave() []func() { | |
| 698 | + | o.handlersMu.Lock() | |
| 699 | + | defer o.handlersMu.Unlock() | |
| 700 | + | return o.onLeave | |
| 701 | + | } | |
| 702 | + | ||
| 703 | + | // OnPosition registers a handler for the position event. | |
| 704 | + | // | |
| 705 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 706 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 707 | + | func (o *ExtImageCopyCaptureCursorSession) OnPosition(handler func(x int32, y int32)) { | |
| 708 | + | if handler == nil { | |
| 709 | + | return | |
| 710 | + | } | |
| 711 | + | o.handlersMu.Lock() | |
| 712 | + | defer o.handlersMu.Unlock() | |
| 713 | + | o.onPosition = append(o.onPosition, handler) | |
| 714 | + | } | |
| 715 | + | ||
| 716 | + | // handlersForPosition returns the handlers registered for position, taken | |
| 717 | + | // under the lock so a handler may register another handler while events are | |
| 718 | + | // being dispatched. | |
| 719 | + | func (o *ExtImageCopyCaptureCursorSession) handlersForPosition() []func(x int32, y int32) { | |
| 720 | + | o.handlersMu.Lock() | |
| 721 | + | defer o.handlersMu.Unlock() | |
| 722 | + | return o.onPosition | |
| 723 | + | } | |
| 724 | + | ||
| 725 | + | // OnHotspot registers a handler for the hotspot event. | |
| 726 | + | // | |
| 727 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 728 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 729 | + | func (o *ExtImageCopyCaptureCursorSession) OnHotspot(handler func(x int32, y int32)) { | |
| 730 | + | if handler == nil { | |
| 731 | + | return | |
| 732 | + | } | |
| 733 | + | o.handlersMu.Lock() | |
| 734 | + | defer o.handlersMu.Unlock() | |
| 735 | + | o.onHotspot = append(o.onHotspot, handler) | |
| 736 | + | } | |
| 737 | + | ||
| 738 | + | // handlersForHotspot returns the handlers registered for hotspot, taken | |
| 739 | + | // under the lock so a handler may register another handler while events are | |
| 740 | + | // being dispatched. | |
| 741 | + | func (o *ExtImageCopyCaptureCursorSession) handlersForHotspot() []func(x int32, y int32) { | |
| 742 | + | o.handlersMu.Lock() | |
| 743 | + | defer o.handlersMu.Unlock() | |
| 744 | + | return o.onHotspot | |
| 745 | + | } | |
| 746 | + | ||
| 747 | + | // EventSignature returns the declared event argument types in wire order. | |
| 748 | + | func (o *ExtImageCopyCaptureCursorSession) EventSignature(opcode uint16) (string, bool) { | |
| 749 | + | switch opcode { | |
| 750 | + | case 0: | |
| 751 | + | return "", true | |
| 752 | + | case 1: | |
| 753 | + | return "", true | |
| 754 | + | case 2: | |
| 755 | + | return "int,int,", true | |
| 756 | + | case 3: | |
| 757 | + | return "int,int,", true | |
| 758 | + | default: | |
| 759 | + | return "", false | |
| 760 | + | } | |
| 761 | + | } | |
| 762 | + | ||
| 763 | + | // Dispatch decodes one event on ext_image_copy_capture_cursor_session_v1 and calls the registered handlers. | |
| 764 | + | func (o *ExtImageCopyCaptureCursorSession) Dispatch(event *wl.Event) { | |
| 765 | + | switch event.Opcode { | |
| 766 | + | case 0: // enter | |
| 767 | + | ||
| 768 | + | for i, handler := range o.handlersForEnter() { | |
| 769 | + | _ = i | |
| 770 | + | handler() | |
| 771 | + | } | |
| 772 | + | case 1: // leave | |
| 773 | + | ||
| 774 | + | for i, handler := range o.handlersForLeave() { | |
| 775 | + | _ = i | |
| 776 | + | handler() | |
| 777 | + | } | |
| 778 | + | case 2: // position | |
| 779 | + | x := event.Int32() | |
| 780 | + | y := event.Int32() | |
| 781 | + | ||
| 782 | + | for i, handler := range o.handlersForPosition() { | |
| 783 | + | _ = i | |
| 784 | + | handler(x, y) | |
| 785 | + | } | |
| 786 | + | case 3: // hotspot | |
| 787 | + | x := event.Int32() | |
| 788 | + | y := event.Int32() | |
| 789 | + | ||
| 790 | + | for i, handler := range o.handlersForHotspot() { | |
| 791 | + | _ = i | |
| 792 | + | handler(x, y) | |
| 793 | + | } | |
| 794 | + | default: | |
| 795 | + | } | |
| 796 | + | } | |
A client/extsessionlock/extsessionlock_generated.go +324 -0
| @@ -0,0 +1,324 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: ext_session_lock_v1 | |
| 3 | + | // Source: ext-session-lock-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright 2021 Isaac Freund | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice shall be included in | |
| 16 | + | // all copies or substantial portions of the Software. | |
| 17 | + | // | |
| 18 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 21 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 23 | + | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 24 | + | // THE SOFTWARE. | |
| 25 | + | ||
| 26 | + | package extsessionlock | |
| 27 | + | ||
| 28 | + | import ( | |
| 29 | + | "sync" | |
| 30 | + | ||
| 31 | + | cross_wl_output "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 32 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 33 | + | "github.com/bnema/wlturbo/wl" | |
| 34 | + | ) | |
| 35 | + | ||
| 36 | + | // ERROR_INVALID_DESTROY is the error invalid_destroy value. | |
| 37 | + | const ERROR_INVALID_DESTROY = 0 | |
| 38 | + | ||
| 39 | + | // ERROR_INVALID_UNLOCK is the error invalid_unlock value. | |
| 40 | + | const ERROR_INVALID_UNLOCK = 1 | |
| 41 | + | ||
| 42 | + | // ERROR_ROLE is the error role value. | |
| 43 | + | const ERROR_ROLE = 2 | |
| 44 | + | ||
| 45 | + | // ERROR_DUPLICATE_OUTPUT is the error duplicate_output value. | |
| 46 | + | const ERROR_DUPLICATE_OUTPUT = 3 | |
| 47 | + | ||
| 48 | + | // ERROR_ALREADY_CONSTRUCTED is the error already_constructed value. | |
| 49 | + | const ERROR_ALREADY_CONSTRUCTED = 4 | |
| 50 | + | ||
| 51 | + | // ERROR_COMMIT_BEFORE_FIRST_ACK is the error commit_before_first_ack value. | |
| 52 | + | const ERROR_COMMIT_BEFORE_FIRST_ACK = 0 | |
| 53 | + | ||
| 54 | + | // ERROR_NULL_BUFFER is the error null_buffer value. | |
| 55 | + | const ERROR_NULL_BUFFER = 1 | |
| 56 | + | ||
| 57 | + | // ERROR_DIMENSIONS_MISMATCH is the error dimensions_mismatch value. | |
| 58 | + | const ERROR_DIMENSIONS_MISMATCH = 2 | |
| 59 | + | ||
| 60 | + | // ERROR_INVALID_SERIAL is the error invalid_serial value. | |
| 61 | + | const ERROR_INVALID_SERIAL = 3 | |
| 62 | + | ||
| 63 | + | // ExtSessionLockManagerInterface is the protocol interface name. | |
| 64 | + | const ExtSessionLockManagerInterface = "ext_session_lock_manager_v1" | |
| 65 | + | ||
| 66 | + | // ExtSessionLockManager is the generated binding for ext_session_lock_manager_v1 version 1. | |
| 67 | + | type ExtSessionLockManager struct { | |
| 68 | + | wl.BaseProxy | |
| 69 | + | } | |
| 70 | + | ||
| 71 | + | // NewExtSessionLockManager returns an unbound ExtSessionLockManager. | |
| 72 | + | func NewExtSessionLockManager(ctx *wl.Context) *ExtSessionLockManager { | |
| 73 | + | obj := &ExtSessionLockManager{} | |
| 74 | + | obj.SetContext(ctx) | |
| 75 | + | ctx.Register(obj) | |
| 76 | + | return obj | |
| 77 | + | } | |
| 78 | + | ||
| 79 | + | // This informs the compositor that the session lock manager object will no longer be used. Existing objects created through this interface remain valid. | |
| 80 | + | func (o *ExtSessionLockManager) Destroy() error { | |
| 81 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_session_lock_manager_v1.destroy", Destructor: true}); err != nil { | |
| 82 | + | return err | |
| 83 | + | } | |
| 84 | + | return nil | |
| 85 | + | } | |
| 86 | + | ||
| 87 | + | // This request creates a session lock and asks the compositor to lock the session. The compositor will send either the ext_session_lock_v1.locked or ext_session_lock_v1.finished event on the created object in response to this request. | |
| 88 | + | func (o *ExtSessionLockManager) Lock() (*ExtSessionLock, error) { | |
| 89 | + | child := &ExtSessionLock{} | |
| 90 | + | child.SetContext(o.Context()) | |
| 91 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_session_lock_manager_v1.lock", Child: child}, wl.ArgObject(child)); err != nil { | |
| 92 | + | return nil, err | |
| 93 | + | } | |
| 94 | + | return child, nil | |
| 95 | + | } | |
| 96 | + | ||
| 97 | + | // EventSignature returns the declared event argument types in wire order. | |
| 98 | + | func (o *ExtSessionLockManager) EventSignature(opcode uint16) (string, bool) { | |
| 99 | + | switch opcode { | |
| 100 | + | default: | |
| 101 | + | return "", false | |
| 102 | + | } | |
| 103 | + | } | |
| 104 | + | ||
| 105 | + | // Dispatch decodes one event on ext_session_lock_manager_v1 and calls the registered handlers. | |
| 106 | + | func (o *ExtSessionLockManager) Dispatch(event *wl.Event) { | |
| 107 | + | switch event.Opcode { | |
| 108 | + | default: | |
| 109 | + | } | |
| 110 | + | } | |
| 111 | + | ||
| 112 | + | // ExtSessionLockInterface is the protocol interface name. | |
| 113 | + | const ExtSessionLockInterface = "ext_session_lock_v1" | |
| 114 | + | ||
| 115 | + | // ExtSessionLock is the generated binding for ext_session_lock_v1 version 1. | |
| 116 | + | type ExtSessionLock struct { | |
| 117 | + | wl.BaseProxy | |
| 118 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 119 | + | // handlers while another goroutine dispatches events. | |
| 120 | + | handlersMu sync.Mutex | |
| 121 | + | onLocked []func() | |
| 122 | + | onFinished []func() | |
| 123 | + | } | |
| 124 | + | ||
| 125 | + | // NewExtSessionLock returns an unbound ExtSessionLock. | |
| 126 | + | func NewExtSessionLock(ctx *wl.Context) *ExtSessionLock { | |
| 127 | + | obj := &ExtSessionLock{} | |
| 128 | + | obj.SetContext(ctx) | |
| 129 | + | ctx.Register(obj) | |
| 130 | + | return obj | |
| 131 | + | } | |
| 132 | + | ||
| 133 | + | // This informs the compositor that the lock object will no longer be used. Existing objects created through this interface remain valid. After this request is made, lock surfaces created through this object should be destroyed by the client as they will no longer be used by the compositor. It is a protocol error to make this request if the locked event was sent, the unlock_and_destroy request must be used instead. | |
| 134 | + | func (o *ExtSessionLock) Destroy() error { | |
| 135 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_session_lock_v1.destroy", Destructor: true}); err != nil { | |
| 136 | + | return err | |
| 137 | + | } | |
| 138 | + | return nil | |
| 139 | + | } | |
| 140 | + | ||
| 141 | + | // The client is expected to create lock surfaces for all outputs currently present and any new outputs as they are advertised. These won't be displayed by the compositor unless the lock is successful and the locked event is sent. Providing a wl_surface which already has a role or already has a buffer attached or committed is a protocol error, as is attaching/committing a buffer before the first ext_session_lock_surface_v1.configure event. Attempting to create more than one lock surface for a given output is a duplicate_output protocol error. | |
| 142 | + | func (o *ExtSessionLock) GetLockSurface(surface *cross_wl_surface.Surface, output *cross_wl_output.Output) (*ExtSessionLockSurface, error) { | |
| 143 | + | var arg1 wl.Object | |
| 144 | + | if surface != nil { | |
| 145 | + | arg1 = surface | |
| 146 | + | } | |
| 147 | + | var arg2 wl.Object | |
| 148 | + | if output != nil { | |
| 149 | + | arg2 = output | |
| 150 | + | } | |
| 151 | + | child := &ExtSessionLockSurface{} | |
| 152 | + | child.SetContext(o.Context()) | |
| 153 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_session_lock_v1.get_lock_surface", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1), wl.ArgObject(arg2)); err != nil { | |
| 154 | + | return nil, err | |
| 155 | + | } | |
| 156 | + | return child, nil | |
| 157 | + | } | |
| 158 | + | ||
| 159 | + | // This request indicates that the session should be unlocked, for example because the user has entered their password and it has been verified by the client. This request also informs the compositor that the lock object will no longer be used and should be destroyed. Existing objects created through this interface remain valid. After this request is made, lock surfaces created through this object should be destroyed by the client as they will no longer be used by the compositor. It is a protocol error to make this request if the locked event has not been sent. In that case, the lock object must be destroyed using the destroy request. Note that a correct client that wishes to exit directly after unlocking the session must use the wl_display.sync request to ensure the server receives and processes the unlock_and_destroy request. Otherwise there is no guarantee that the server has unlocked the session due to the asynchronous nature of the Wayland protocol. For example, the server might terminate the client with a protocol error before it processes the unlock_and_destroy request. | |
| 160 | + | func (o *ExtSessionLock) UnlockAndDestroy() error { | |
| 161 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "ext_session_lock_v1.unlock_and_destroy", Destructor: true}); err != nil { | |
| 162 | + | return err | |
| 163 | + | } | |
| 164 | + | return nil | |
| 165 | + | } | |
| 166 | + | ||
| 167 | + | // OnLocked registers a handler for the locked event. | |
| 168 | + | // | |
| 169 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 170 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 171 | + | func (o *ExtSessionLock) OnLocked(handler func()) { | |
| 172 | + | if handler == nil { | |
| 173 | + | return | |
| 174 | + | } | |
| 175 | + | o.handlersMu.Lock() | |
| 176 | + | defer o.handlersMu.Unlock() | |
| 177 | + | o.onLocked = append(o.onLocked, handler) | |
| 178 | + | } | |
| 179 | + | ||
| 180 | + | // handlersForLocked returns the handlers registered for locked, taken | |
| 181 | + | // under the lock so a handler may register another handler while events are | |
| 182 | + | // being dispatched. | |
| 183 | + | func (o *ExtSessionLock) handlersForLocked() []func() { | |
| 184 | + | o.handlersMu.Lock() | |
| 185 | + | defer o.handlersMu.Unlock() | |
| 186 | + | return o.onLocked | |
| 187 | + | } | |
| 188 | + | ||
| 189 | + | // OnFinished registers a handler for the finished event. | |
| 190 | + | // | |
| 191 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 192 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 193 | + | func (o *ExtSessionLock) OnFinished(handler func()) { | |
| 194 | + | if handler == nil { | |
| 195 | + | return | |
| 196 | + | } | |
| 197 | + | o.handlersMu.Lock() | |
| 198 | + | defer o.handlersMu.Unlock() | |
| 199 | + | o.onFinished = append(o.onFinished, handler) | |
| 200 | + | } | |
| 201 | + | ||
| 202 | + | // handlersForFinished returns the handlers registered for finished, taken | |
| 203 | + | // under the lock so a handler may register another handler while events are | |
| 204 | + | // being dispatched. | |
| 205 | + | func (o *ExtSessionLock) handlersForFinished() []func() { | |
| 206 | + | o.handlersMu.Lock() | |
| 207 | + | defer o.handlersMu.Unlock() | |
| 208 | + | return o.onFinished | |
| 209 | + | } | |
| 210 | + | ||
| 211 | + | // EventSignature returns the declared event argument types in wire order. | |
| 212 | + | func (o *ExtSessionLock) EventSignature(opcode uint16) (string, bool) { | |
| 213 | + | switch opcode { | |
| 214 | + | case 0: | |
| 215 | + | return "", true | |
| 216 | + | case 1: | |
| 217 | + | return "", true | |
| 218 | + | default: | |
| 219 | + | return "", false | |
| 220 | + | } | |
| 221 | + | } | |
| 222 | + | ||
| 223 | + | // Dispatch decodes one event on ext_session_lock_v1 and calls the registered handlers. | |
| 224 | + | func (o *ExtSessionLock) Dispatch(event *wl.Event) { | |
| 225 | + | switch event.Opcode { | |
| 226 | + | case 0: // locked | |
| 227 | + | ||
| 228 | + | for i, handler := range o.handlersForLocked() { | |
| 229 | + | _ = i | |
| 230 | + | handler() | |
| 231 | + | } | |
| 232 | + | case 1: // finished | |
| 233 | + | ||
| 234 | + | for i, handler := range o.handlersForFinished() { | |
| 235 | + | _ = i | |
| 236 | + | handler() | |
| 237 | + | } | |
| 238 | + | default: | |
| 239 | + | } | |
| 240 | + | } | |
| 241 | + | ||
| 242 | + | // ExtSessionLockSurfaceInterface is the protocol interface name. | |
| 243 | + | const ExtSessionLockSurfaceInterface = "ext_session_lock_surface_v1" | |
| 244 | + | ||
| 245 | + | // ExtSessionLockSurface is the generated binding for ext_session_lock_surface_v1 version 1. | |
| 246 | + | type ExtSessionLockSurface struct { | |
| 247 | + | wl.BaseProxy | |
| 248 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 249 | + | // handlers while another goroutine dispatches events. | |
| 250 | + | handlersMu sync.Mutex | |
| 251 | + | onConfigure []func(serial uint32, width uint32, height uint32) | |
| 252 | + | } | |
| 253 | + | ||
| 254 | + | // NewExtSessionLockSurface returns an unbound ExtSessionLockSurface. | |
| 255 | + | func NewExtSessionLockSurface(ctx *wl.Context) *ExtSessionLockSurface { | |
| 256 | + | obj := &ExtSessionLockSurface{} | |
| 257 | + | obj.SetContext(ctx) | |
| 258 | + | ctx.Register(obj) | |
| 259 | + | return obj | |
| 260 | + | } | |
| 261 | + | ||
| 262 | + | // This informs the compositor that the lock surface object will no longer be used. It is recommended for a lock client to destroy lock surfaces if their corresponding wl_output global is removed. If a lock surface on an active output is destroyed before the ext_session_lock_v1.unlock_and_destroy event is sent, the compositor must fall back to rendering a solid color. | |
| 263 | + | func (o *ExtSessionLockSurface) Destroy() error { | |
| 264 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_session_lock_surface_v1.destroy", Destructor: true}); err != nil { | |
| 265 | + | return err | |
| 266 | + | } | |
| 267 | + | return nil | |
| 268 | + | } | |
| 269 | + | ||
| 270 | + | // When a configure event is received, if a client commits the surface in response to the configure event, then the client must make an ack_configure request sometime before the commit request, passing along the serial of the configure event. If the client receives multiple configure events before it can respond to one, it only has to ack the last configure event. A client is not required to commit immediately after sending an ack_configure request - it may even ack_configure several times before its next surface commit. A client may send multiple ack_configure requests before committing, but only the last request sent before a commit indicates which configure event the client really is responding to. Sending an ack_configure request consumes the configure event referenced by the given serial, as well as all older configure events sent on this object. It is a protocol error to issue multiple ack_configure requests referencing the same configure event or to issue an ack_configure request referencing a configure event older than the last configure event acked for a given lock surface. | |
| 271 | + | func (o *ExtSessionLockSurface) AckConfigure(serial uint32) error { | |
| 272 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_session_lock_surface_v1.ack_configure"}, wl.ArgUint(serial)); err != nil { | |
| 273 | + | return err | |
| 274 | + | } | |
| 275 | + | return nil | |
| 276 | + | } | |
| 277 | + | ||
| 278 | + | // OnConfigure registers a handler for the configure event. | |
| 279 | + | // | |
| 280 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 281 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 282 | + | func (o *ExtSessionLockSurface) OnConfigure(handler func(serial uint32, width uint32, height uint32)) { | |
| 283 | + | if handler == nil { | |
| 284 | + | return | |
| 285 | + | } | |
| 286 | + | o.handlersMu.Lock() | |
| 287 | + | defer o.handlersMu.Unlock() | |
| 288 | + | o.onConfigure = append(o.onConfigure, handler) | |
| 289 | + | } | |
| 290 | + | ||
| 291 | + | // handlersForConfigure returns the handlers registered for configure, taken | |
| 292 | + | // under the lock so a handler may register another handler while events are | |
| 293 | + | // being dispatched. | |
| 294 | + | func (o *ExtSessionLockSurface) handlersForConfigure() []func(serial uint32, width uint32, height uint32) { | |
| 295 | + | o.handlersMu.Lock() | |
| 296 | + | defer o.handlersMu.Unlock() | |
| 297 | + | return o.onConfigure | |
| 298 | + | } | |
| 299 | + | ||
| 300 | + | // EventSignature returns the declared event argument types in wire order. | |
| 301 | + | func (o *ExtSessionLockSurface) EventSignature(opcode uint16) (string, bool) { | |
| 302 | + | switch opcode { | |
| 303 | + | case 0: | |
| 304 | + | return "uint,uint,uint,", true | |
| 305 | + | default: | |
| 306 | + | return "", false | |
| 307 | + | } | |
| 308 | + | } | |
| 309 | + | ||
| 310 | + | // Dispatch decodes one event on ext_session_lock_surface_v1 and calls the registered handlers. | |
| 311 | + | func (o *ExtSessionLockSurface) Dispatch(event *wl.Event) { | |
| 312 | + | switch event.Opcode { | |
| 313 | + | case 0: // configure | |
| 314 | + | serial := event.Uint32() | |
| 315 | + | width := event.Uint32() | |
| 316 | + | height := event.Uint32() | |
| 317 | + | ||
| 318 | + | for i, handler := range o.handlersForConfigure() { | |
| 319 | + | _ = i | |
| 320 | + | handler(serial, width, height) | |
| 321 | + | } | |
| 322 | + | default: | |
| 323 | + | } | |
| 324 | + | } | |
A client/exttransientseat/exttransientseat_generated.go +187 -0
| @@ -0,0 +1,187 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: ext_transient_seat_v1 | |
| 3 | + | // Source: ext-transient-seat-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2020 - 2023 Andri Yngvason | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package exttransientseat | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | "sync" | |
| 31 | + | ||
| 32 | + | "github.com/bnema/wlturbo/wl" | |
| 33 | + | ) | |
| 34 | + | ||
| 35 | + | // ExtTransientSeatManagerInterface is the protocol interface name. | |
| 36 | + | const ExtTransientSeatManagerInterface = "ext_transient_seat_manager_v1" | |
| 37 | + | ||
| 38 | + | // ExtTransientSeatManager is the generated binding for ext_transient_seat_manager_v1 version 1. | |
| 39 | + | type ExtTransientSeatManager struct { | |
| 40 | + | wl.BaseProxy | |
| 41 | + | } | |
| 42 | + | ||
| 43 | + | // NewExtTransientSeatManager returns an unbound ExtTransientSeatManager. | |
| 44 | + | func NewExtTransientSeatManager(ctx *wl.Context) *ExtTransientSeatManager { | |
| 45 | + | obj := &ExtTransientSeatManager{} | |
| 46 | + | obj.SetContext(ctx) | |
| 47 | + | ctx.Register(obj) | |
| 48 | + | return obj | |
| 49 | + | } | |
| 50 | + | ||
| 51 | + | // Create a new seat that is removed when the client side transient seat object is destroyed. The actual seat may be removed sooner, in which case the transient seat object shall become inert. | |
| 52 | + | func (o *ExtTransientSeatManager) Create() (*ExtTransientSeat, error) { | |
| 53 | + | child := &ExtTransientSeat{} | |
| 54 | + | child.SetContext(o.Context()) | |
| 55 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_transient_seat_manager_v1.create", Child: child}, wl.ArgObject(child)); err != nil { | |
| 56 | + | return nil, err | |
| 57 | + | } | |
| 58 | + | return child, nil | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | // Destroy the manager. All objects created by the manager will remain valid until they are destroyed themselves. | |
| 62 | + | func (o *ExtTransientSeatManager) Destroy() error { | |
| 63 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_transient_seat_manager_v1.destroy", Destructor: true}); err != nil { | |
| 64 | + | return err | |
| 65 | + | } | |
| 66 | + | return nil | |
| 67 | + | } | |
| 68 | + | ||
| 69 | + | // EventSignature returns the declared event argument types in wire order. | |
| 70 | + | func (o *ExtTransientSeatManager) EventSignature(opcode uint16) (string, bool) { | |
| 71 | + | switch opcode { | |
| 72 | + | default: | |
| 73 | + | return "", false | |
| 74 | + | } | |
| 75 | + | } | |
| 76 | + | ||
| 77 | + | // Dispatch decodes one event on ext_transient_seat_manager_v1 and calls the registered handlers. | |
| 78 | + | func (o *ExtTransientSeatManager) Dispatch(event *wl.Event) { | |
| 79 | + | switch event.Opcode { | |
| 80 | + | default: | |
| 81 | + | } | |
| 82 | + | } | |
| 83 | + | ||
| 84 | + | // ExtTransientSeatInterface is the protocol interface name. | |
| 85 | + | const ExtTransientSeatInterface = "ext_transient_seat_v1" | |
| 86 | + | ||
| 87 | + | // ExtTransientSeat is the generated binding for ext_transient_seat_v1 version 1. | |
| 88 | + | type ExtTransientSeat struct { | |
| 89 | + | wl.BaseProxy | |
| 90 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 91 | + | // handlers while another goroutine dispatches events. | |
| 92 | + | handlersMu sync.Mutex | |
| 93 | + | onReady []func(globalName uint32) | |
| 94 | + | onDenied []func() | |
| 95 | + | } | |
| 96 | + | ||
| 97 | + | // NewExtTransientSeat returns an unbound ExtTransientSeat. | |
| 98 | + | func NewExtTransientSeat(ctx *wl.Context) *ExtTransientSeat { | |
| 99 | + | obj := &ExtTransientSeat{} | |
| 100 | + | obj.SetContext(ctx) | |
| 101 | + | ctx.Register(obj) | |
| 102 | + | return obj | |
| 103 | + | } | |
| 104 | + | ||
| 105 | + | // When the transient seat object is destroyed by the client, the associated seat created by the compositor is also destroyed. | |
| 106 | + | func (o *ExtTransientSeat) Destroy() error { | |
| 107 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_transient_seat_v1.destroy", Destructor: true}); err != nil { | |
| 108 | + | return err | |
| 109 | + | } | |
| 110 | + | return nil | |
| 111 | + | } | |
| 112 | + | ||
| 113 | + | // OnReady registers a handler for the ready event. | |
| 114 | + | // | |
| 115 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 116 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 117 | + | func (o *ExtTransientSeat) OnReady(handler func(globalName uint32)) { | |
| 118 | + | if handler == nil { | |
| 119 | + | return | |
| 120 | + | } | |
| 121 | + | o.handlersMu.Lock() | |
| 122 | + | defer o.handlersMu.Unlock() | |
| 123 | + | o.onReady = append(o.onReady, handler) | |
| 124 | + | } | |
| 125 | + | ||
| 126 | + | // handlersForReady returns the handlers registered for ready, taken | |
| 127 | + | // under the lock so a handler may register another handler while events are | |
| 128 | + | // being dispatched. | |
| 129 | + | func (o *ExtTransientSeat) handlersForReady() []func(globalName uint32) { | |
| 130 | + | o.handlersMu.Lock() | |
| 131 | + | defer o.handlersMu.Unlock() | |
| 132 | + | return o.onReady | |
| 133 | + | } | |
| 134 | + | ||
| 135 | + | // OnDenied registers a handler for the denied event. | |
| 136 | + | // | |
| 137 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 138 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 139 | + | func (o *ExtTransientSeat) OnDenied(handler func()) { | |
| 140 | + | if handler == nil { | |
| 141 | + | return | |
| 142 | + | } | |
| 143 | + | o.handlersMu.Lock() | |
| 144 | + | defer o.handlersMu.Unlock() | |
| 145 | + | o.onDenied = append(o.onDenied, handler) | |
| 146 | + | } | |
| 147 | + | ||
| 148 | + | // handlersForDenied returns the handlers registered for denied, taken | |
| 149 | + | // under the lock so a handler may register another handler while events are | |
| 150 | + | // being dispatched. | |
| 151 | + | func (o *ExtTransientSeat) handlersForDenied() []func() { | |
| 152 | + | o.handlersMu.Lock() | |
| 153 | + | defer o.handlersMu.Unlock() | |
| 154 | + | return o.onDenied | |
| 155 | + | } | |
| 156 | + | ||
| 157 | + | // EventSignature returns the declared event argument types in wire order. | |
| 158 | + | func (o *ExtTransientSeat) EventSignature(opcode uint16) (string, bool) { | |
| 159 | + | switch opcode { | |
| 160 | + | case 0: | |
| 161 | + | return "uint,", true | |
| 162 | + | case 1: | |
| 163 | + | return "", true | |
| 164 | + | default: | |
| 165 | + | return "", false | |
| 166 | + | } | |
| 167 | + | } | |
| 168 | + | ||
| 169 | + | // Dispatch decodes one event on ext_transient_seat_v1 and calls the registered handlers. | |
| 170 | + | func (o *ExtTransientSeat) Dispatch(event *wl.Event) { | |
| 171 | + | switch event.Opcode { | |
| 172 | + | case 0: // ready | |
| 173 | + | globalName := event.Uint32() | |
| 174 | + | ||
| 175 | + | for i, handler := range o.handlersForReady() { | |
| 176 | + | _ = i | |
| 177 | + | handler(globalName) | |
| 178 | + | } | |
| 179 | + | case 1: // denied | |
| 180 | + | ||
| 181 | + | for i, handler := range o.handlersForDenied() { | |
| 182 | + | _ = i | |
| 183 | + | handler() | |
| 184 | + | } | |
| 185 | + | default: | |
| 186 | + | } | |
| 187 | + | } | |
A client/extworkspace/extworkspace_generated.go +758 -0
| @@ -0,0 +1,758 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: ext_workspace_v1 | |
| 3 | + | // Source: ext-workspace-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2019 Christopher Billington | |
| 7 | + | // Copyright © 2020 Ilia Bozhinov | |
| 8 | + | // Copyright © 2022 Victoria Brekenfeld | |
| 9 | + | // | |
| 10 | + | // Permission to use, copy, modify, distribute, and sell this | |
| 11 | + | // software and its documentation for any purpose is hereby granted | |
| 12 | + | // without fee, provided that the above copyright notice appear in | |
| 13 | + | // all copies and that both that copyright notice and this permission | |
| 14 | + | // notice appear in supporting documentation, and that the name of | |
| 15 | + | // the copyright holders not be used in advertising or publicity | |
| 16 | + | // pertaining to distribution of the software without specific, | |
| 17 | + | // written prior permission. The copyright holders make no | |
| 18 | + | // representations about the suitability of this software for any | |
| 19 | + | // purpose. It is provided "as is" without express or implied | |
| 20 | + | // warranty. | |
| 21 | + | // | |
| 22 | + | // THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
| 23 | + | // SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| 24 | + | // FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| 25 | + | // SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 26 | + | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
| 27 | + | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
| 28 | + | // ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| 29 | + | // THIS SOFTWARE. | |
| 30 | + | ||
| 31 | + | package extworkspace | |
| 32 | + | ||
| 33 | + | import ( | |
| 34 | + | "sync" | |
| 35 | + | ||
| 36 | + | "github.com/bnema/wlturbo/wl" | |
| 37 | + | ) | |
| 38 | + | ||
| 39 | + | // GROUP_CAPABILITIES_CREATE_WORKSPACE is the group_capabilities create_workspace value. | |
| 40 | + | const GROUP_CAPABILITIES_CREATE_WORKSPACE = 1 | |
| 41 | + | ||
| 42 | + | // STATE_ACTIVE is the state active value. | |
| 43 | + | const STATE_ACTIVE = 1 | |
| 44 | + | ||
| 45 | + | // STATE_URGENT is the state urgent value. | |
| 46 | + | const STATE_URGENT = 2 | |
| 47 | + | ||
| 48 | + | // STATE_HIDDEN is the state hidden value. | |
| 49 | + | const STATE_HIDDEN = 4 | |
| 50 | + | ||
| 51 | + | // WORKSPACE_CAPABILITIES_ACTIVATE is the workspace_capabilities activate value. | |
| 52 | + | const WORKSPACE_CAPABILITIES_ACTIVATE = 1 | |
| 53 | + | ||
| 54 | + | // WORKSPACE_CAPABILITIES_DEACTIVATE is the workspace_capabilities deactivate value. | |
| 55 | + | const WORKSPACE_CAPABILITIES_DEACTIVATE = 2 | |
| 56 | + | ||
| 57 | + | // WORKSPACE_CAPABILITIES_REMOVE is the workspace_capabilities remove value. | |
| 58 | + | const WORKSPACE_CAPABILITIES_REMOVE = 4 | |
| 59 | + | ||
| 60 | + | // WORKSPACE_CAPABILITIES_ASSIGN is the workspace_capabilities assign value. | |
| 61 | + | const WORKSPACE_CAPABILITIES_ASSIGN = 8 | |
| 62 | + | ||
| 63 | + | // ExtWorkspaceManagerInterface is the protocol interface name. | |
| 64 | + | const ExtWorkspaceManagerInterface = "ext_workspace_manager_v1" | |
| 65 | + | ||
| 66 | + | // ExtWorkspaceManager is the generated binding for ext_workspace_manager_v1 version 1. | |
| 67 | + | type ExtWorkspaceManager struct { | |
| 68 | + | wl.BaseProxy | |
| 69 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 70 | + | // handlers while another goroutine dispatches events. | |
| 71 | + | handlersMu sync.Mutex | |
| 72 | + | onWorkspaceGroup []func(workspaceGroupObject *ExtWorkspaceGroupHandle) | |
| 73 | + | onWorkspace []func(workspaceObject *ExtWorkspaceHandle) | |
| 74 | + | onDone []func() | |
| 75 | + | onFinished []func() | |
| 76 | + | } | |
| 77 | + | ||
| 78 | + | // NewExtWorkspaceManager returns an unbound ExtWorkspaceManager. | |
| 79 | + | func NewExtWorkspaceManager(ctx *wl.Context) *ExtWorkspaceManager { | |
| 80 | + | obj := &ExtWorkspaceManager{} | |
| 81 | + | obj.SetContext(ctx) | |
| 82 | + | ctx.Register(obj) | |
| 83 | + | return obj | |
| 84 | + | } | |
| 85 | + | ||
| 86 | + | // The client must send this request after it has finished sending other requests. The compositor must process a series of requests preceding a commit request atomically. This allows changes to the workspace properties to be seen as atomic, even if they happen via multiple events, and even if they involve multiple ext_workspace_handle_v1 objects, for example, deactivating one workspace and activating another. | |
| 87 | + | func (o *ExtWorkspaceManager) Commit() error { | |
| 88 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_workspace_manager_v1.commit"}); err != nil { | |
| 89 | + | return err | |
| 90 | + | } | |
| 91 | + | return nil | |
| 92 | + | } | |
| 93 | + | ||
| 94 | + | // Indicates the client no longer wishes to receive events for new workspace groups. However the compositor may emit further workspace events, until the finished event is emitted. The compositor is expected to send the finished event eventually once the stop request has been processed. The client must not send any requests after this one, doing so will raise a wl_display invalid_object error. | |
| 95 | + | func (o *ExtWorkspaceManager) Stop() error { | |
| 96 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_workspace_manager_v1.stop"}); err != nil { | |
| 97 | + | return err | |
| 98 | + | } | |
| 99 | + | return nil | |
| 100 | + | } | |
| 101 | + | ||
| 102 | + | // OnWorkspaceGroup registers a handler for the workspace_group event. | |
| 103 | + | // | |
| 104 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 105 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 106 | + | func (o *ExtWorkspaceManager) OnWorkspaceGroup(handler func(workspaceGroupObject *ExtWorkspaceGroupHandle)) { | |
| 107 | + | if handler == nil { | |
| 108 | + | return | |
| 109 | + | } | |
| 110 | + | o.handlersMu.Lock() | |
| 111 | + | defer o.handlersMu.Unlock() | |
| 112 | + | o.onWorkspaceGroup = append(o.onWorkspaceGroup, handler) | |
| 113 | + | } | |
| 114 | + | ||
| 115 | + | // handlersForWorkspaceGroup returns the handlers registered for workspace_group, taken | |
| 116 | + | // under the lock so a handler may register another handler while events are | |
| 117 | + | // being dispatched. | |
| 118 | + | func (o *ExtWorkspaceManager) handlersForWorkspaceGroup() []func(workspaceGroupObject *ExtWorkspaceGroupHandle) { | |
| 119 | + | o.handlersMu.Lock() | |
| 120 | + | defer o.handlersMu.Unlock() | |
| 121 | + | return o.onWorkspaceGroup | |
| 122 | + | } | |
| 123 | + | ||
| 124 | + | // OnWorkspace registers a handler for the workspace event. | |
| 125 | + | // | |
| 126 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 127 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 128 | + | func (o *ExtWorkspaceManager) OnWorkspace(handler func(workspaceObject *ExtWorkspaceHandle)) { | |
| 129 | + | if handler == nil { | |
| 130 | + | return | |
| 131 | + | } | |
| 132 | + | o.handlersMu.Lock() | |
| 133 | + | defer o.handlersMu.Unlock() | |
| 134 | + | o.onWorkspace = append(o.onWorkspace, handler) | |
| 135 | + | } | |
| 136 | + | ||
| 137 | + | // handlersForWorkspace returns the handlers registered for workspace, taken | |
| 138 | + | // under the lock so a handler may register another handler while events are | |
| 139 | + | // being dispatched. | |
| 140 | + | func (o *ExtWorkspaceManager) handlersForWorkspace() []func(workspaceObject *ExtWorkspaceHandle) { | |
| 141 | + | o.handlersMu.Lock() | |
| 142 | + | defer o.handlersMu.Unlock() | |
| 143 | + | return o.onWorkspace | |
| 144 | + | } | |
| 145 | + | ||
| 146 | + | // OnDone registers a handler for the done event. | |
| 147 | + | // | |
| 148 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 149 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 150 | + | func (o *ExtWorkspaceManager) OnDone(handler func()) { | |
| 151 | + | if handler == nil { | |
| 152 | + | return | |
| 153 | + | } | |
| 154 | + | o.handlersMu.Lock() | |
| 155 | + | defer o.handlersMu.Unlock() | |
| 156 | + | o.onDone = append(o.onDone, handler) | |
| 157 | + | } | |
| 158 | + | ||
| 159 | + | // handlersForDone returns the handlers registered for done, taken | |
| 160 | + | // under the lock so a handler may register another handler while events are | |
| 161 | + | // being dispatched. | |
| 162 | + | func (o *ExtWorkspaceManager) handlersForDone() []func() { | |
| 163 | + | o.handlersMu.Lock() | |
| 164 | + | defer o.handlersMu.Unlock() | |
| 165 | + | return o.onDone | |
| 166 | + | } | |
| 167 | + | ||
| 168 | + | // OnFinished registers a handler for the finished event. | |
| 169 | + | // | |
| 170 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 171 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 172 | + | func (o *ExtWorkspaceManager) OnFinished(handler func()) { | |
| 173 | + | if handler == nil { | |
| 174 | + | return | |
| 175 | + | } | |
| 176 | + | o.handlersMu.Lock() | |
| 177 | + | defer o.handlersMu.Unlock() | |
| 178 | + | o.onFinished = append(o.onFinished, handler) | |
| 179 | + | } | |
| 180 | + | ||
| 181 | + | // handlersForFinished returns the handlers registered for finished, taken | |
| 182 | + | // under the lock so a handler may register another handler while events are | |
| 183 | + | // being dispatched. | |
| 184 | + | func (o *ExtWorkspaceManager) handlersForFinished() []func() { | |
| 185 | + | o.handlersMu.Lock() | |
| 186 | + | defer o.handlersMu.Unlock() | |
| 187 | + | return o.onFinished | |
| 188 | + | } | |
| 189 | + | ||
| 190 | + | // EventSignature returns the declared event argument types in wire order. | |
| 191 | + | func (o *ExtWorkspaceManager) EventSignature(opcode uint16) (string, bool) { | |
| 192 | + | switch opcode { | |
| 193 | + | case 0: | |
| 194 | + | return "new_id,", true | |
| 195 | + | case 1: | |
| 196 | + | return "new_id,", true | |
| 197 | + | case 2: | |
| 198 | + | return "", true | |
| 199 | + | case 3: | |
| 200 | + | return "", true | |
| 201 | + | default: | |
| 202 | + | return "", false | |
| 203 | + | } | |
| 204 | + | } | |
| 205 | + | ||
| 206 | + | // Dispatch decodes one event on ext_workspace_manager_v1 and calls the registered handlers. | |
| 207 | + | func (o *ExtWorkspaceManager) Dispatch(event *wl.Event) { | |
| 208 | + | switch event.Opcode { | |
| 209 | + | case 0: // workspace_group | |
| 210 | + | workspaceGroupID := event.Uint32() | |
| 211 | + | workspaceGroupObject := &ExtWorkspaceGroupHandle{} | |
| 212 | + | workspaceGroupObject.SetContext(o.Context()) | |
| 213 | + | workspaceGroupObject.SetID(workspaceGroupID) | |
| 214 | + | workspaceGroupObject.SetVersion(o.Version()) | |
| 215 | + | o.Context().Register(workspaceGroupObject) | |
| 216 | + | ||
| 217 | + | for i, handler := range o.handlersForWorkspaceGroup() { | |
| 218 | + | _ = i | |
| 219 | + | handler(workspaceGroupObject) | |
| 220 | + | } | |
| 221 | + | case 1: // workspace | |
| 222 | + | workspaceID := event.Uint32() | |
| 223 | + | workspaceObject := &ExtWorkspaceHandle{} | |
| 224 | + | workspaceObject.SetContext(o.Context()) | |
| 225 | + | workspaceObject.SetID(workspaceID) | |
| 226 | + | workspaceObject.SetVersion(o.Version()) | |
| 227 | + | o.Context().Register(workspaceObject) | |
| 228 | + | ||
| 229 | + | for i, handler := range o.handlersForWorkspace() { | |
| 230 | + | _ = i | |
| 231 | + | handler(workspaceObject) | |
| 232 | + | } | |
| 233 | + | case 2: // done | |
| 234 | + | ||
| 235 | + | for i, handler := range o.handlersForDone() { | |
| 236 | + | _ = i | |
| 237 | + | handler() | |
| 238 | + | } | |
| 239 | + | case 3: // finished | |
| 240 | + | ||
| 241 | + | for i, handler := range o.handlersForFinished() { | |
| 242 | + | _ = i | |
| 243 | + | handler() | |
| 244 | + | } | |
| 245 | + | o.Context().Unregister(o) | |
| 246 | + | default: | |
| 247 | + | } | |
| 248 | + | } | |
| 249 | + | ||
| 250 | + | // ExtWorkspaceGroupHandleInterface is the protocol interface name. | |
| 251 | + | const ExtWorkspaceGroupHandleInterface = "ext_workspace_group_handle_v1" | |
| 252 | + | ||
| 253 | + | // ExtWorkspaceGroupHandle is the generated binding for ext_workspace_group_handle_v1 version 1. | |
| 254 | + | type ExtWorkspaceGroupHandle struct { | |
| 255 | + | wl.BaseProxy | |
| 256 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 257 | + | // handlers while another goroutine dispatches events. | |
| 258 | + | handlersMu sync.Mutex | |
| 259 | + | onCapabilities []func(capabilities uint32) | |
| 260 | + | onOutputEnter []func(outputID uint32) | |
| 261 | + | onOutputLeave []func(outputID uint32) | |
| 262 | + | onWorkspaceEnter []func(workspaceID uint32) | |
| 263 | + | onWorkspaceLeave []func(workspaceID uint32) | |
| 264 | + | onRemoved []func() | |
| 265 | + | } | |
| 266 | + | ||
| 267 | + | // NewExtWorkspaceGroupHandle returns an unbound ExtWorkspaceGroupHandle. | |
| 268 | + | func NewExtWorkspaceGroupHandle(ctx *wl.Context) *ExtWorkspaceGroupHandle { | |
| 269 | + | obj := &ExtWorkspaceGroupHandle{} | |
| 270 | + | obj.SetContext(ctx) | |
| 271 | + | ctx.Register(obj) | |
| 272 | + | return obj | |
| 273 | + | } | |
| 274 | + | ||
| 275 | + | // Request that the compositor create a new workspace with the given name and assign it to this group. There is no guarantee that the compositor will create a new workspace, or that the created workspace will have the provided name. | |
| 276 | + | func (o *ExtWorkspaceGroupHandle) CreateWorkspace(workspace string) error { | |
| 277 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_workspace_group_handle_v1.create_workspace"}, wl.ArgString(workspace)); err != nil { | |
| 278 | + | return err | |
| 279 | + | } | |
| 280 | + | return nil | |
| 281 | + | } | |
| 282 | + | ||
| 283 | + | // Destroys the ext_workspace_group_handle_v1 object. This request should be send either when the client does not want to use the workspace group object any more or after the removed event to finalize the destruction of the object. | |
| 284 | + | func (o *ExtWorkspaceGroupHandle) Destroy() error { | |
| 285 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_workspace_group_handle_v1.destroy", Destructor: true}); err != nil { | |
| 286 | + | return err | |
| 287 | + | } | |
| 288 | + | return nil | |
| 289 | + | } | |
| 290 | + | ||
| 291 | + | // OnCapabilities registers a handler for the capabilities event. | |
| 292 | + | // | |
| 293 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 294 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 295 | + | func (o *ExtWorkspaceGroupHandle) OnCapabilities(handler func(capabilities uint32)) { | |
| 296 | + | if handler == nil { | |
| 297 | + | return | |
| 298 | + | } | |
| 299 | + | o.handlersMu.Lock() | |
| 300 | + | defer o.handlersMu.Unlock() | |
| 301 | + | o.onCapabilities = append(o.onCapabilities, handler) | |
| 302 | + | } | |
| 303 | + | ||
| 304 | + | // handlersForCapabilities returns the handlers registered for capabilities, taken | |
| 305 | + | // under the lock so a handler may register another handler while events are | |
| 306 | + | // being dispatched. | |
| 307 | + | func (o *ExtWorkspaceGroupHandle) handlersForCapabilities() []func(capabilities uint32) { | |
| 308 | + | o.handlersMu.Lock() | |
| 309 | + | defer o.handlersMu.Unlock() | |
| 310 | + | return o.onCapabilities | |
| 311 | + | } | |
| 312 | + | ||
| 313 | + | // OnOutputEnter registers a handler for the output_enter event. | |
| 314 | + | // | |
| 315 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 316 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 317 | + | func (o *ExtWorkspaceGroupHandle) OnOutputEnter(handler func(outputID uint32)) { | |
| 318 | + | if handler == nil { | |
| 319 | + | return | |
| 320 | + | } | |
| 321 | + | o.handlersMu.Lock() | |
| 322 | + | defer o.handlersMu.Unlock() | |
| 323 | + | o.onOutputEnter = append(o.onOutputEnter, handler) | |
| 324 | + | } | |
| 325 | + | ||
| 326 | + | // handlersForOutputEnter returns the handlers registered for output_enter, taken | |
| 327 | + | // under the lock so a handler may register another handler while events are | |
| 328 | + | // being dispatched. | |
| 329 | + | func (o *ExtWorkspaceGroupHandle) handlersForOutputEnter() []func(outputID uint32) { | |
| 330 | + | o.handlersMu.Lock() | |
| 331 | + | defer o.handlersMu.Unlock() | |
| 332 | + | return o.onOutputEnter | |
| 333 | + | } | |
| 334 | + | ||
| 335 | + | // OnOutputLeave registers a handler for the output_leave event. | |
| 336 | + | // | |
| 337 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 338 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 339 | + | func (o *ExtWorkspaceGroupHandle) OnOutputLeave(handler func(outputID uint32)) { | |
| 340 | + | if handler == nil { | |
| 341 | + | return | |
| 342 | + | } | |
| 343 | + | o.handlersMu.Lock() | |
| 344 | + | defer o.handlersMu.Unlock() | |
| 345 | + | o.onOutputLeave = append(o.onOutputLeave, handler) | |
| 346 | + | } | |
| 347 | + | ||
| 348 | + | // handlersForOutputLeave returns the handlers registered for output_leave, taken | |
| 349 | + | // under the lock so a handler may register another handler while events are | |
| 350 | + | // being dispatched. | |
| 351 | + | func (o *ExtWorkspaceGroupHandle) handlersForOutputLeave() []func(outputID uint32) { | |
| 352 | + | o.handlersMu.Lock() | |
| 353 | + | defer o.handlersMu.Unlock() | |
| 354 | + | return o.onOutputLeave | |
| 355 | + | } | |
| 356 | + | ||
| 357 | + | // OnWorkspaceEnter registers a handler for the workspace_enter event. | |
| 358 | + | // | |
| 359 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 360 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 361 | + | func (o *ExtWorkspaceGroupHandle) OnWorkspaceEnter(handler func(workspaceID uint32)) { | |
| 362 | + | if handler == nil { | |
| 363 | + | return | |
| 364 | + | } | |
| 365 | + | o.handlersMu.Lock() | |
| 366 | + | defer o.handlersMu.Unlock() | |
| 367 | + | o.onWorkspaceEnter = append(o.onWorkspaceEnter, handler) | |
| 368 | + | } | |
| 369 | + | ||
| 370 | + | // handlersForWorkspaceEnter returns the handlers registered for workspace_enter, taken | |
| 371 | + | // under the lock so a handler may register another handler while events are | |
| 372 | + | // being dispatched. | |
| 373 | + | func (o *ExtWorkspaceGroupHandle) handlersForWorkspaceEnter() []func(workspaceID uint32) { | |
| 374 | + | o.handlersMu.Lock() | |
| 375 | + | defer o.handlersMu.Unlock() | |
| 376 | + | return o.onWorkspaceEnter | |
| 377 | + | } | |
| 378 | + | ||
| 379 | + | // OnWorkspaceLeave registers a handler for the workspace_leave event. | |
| 380 | + | // | |
| 381 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 382 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 383 | + | func (o *ExtWorkspaceGroupHandle) OnWorkspaceLeave(handler func(workspaceID uint32)) { | |
| 384 | + | if handler == nil { | |
| 385 | + | return | |
| 386 | + | } | |
| 387 | + | o.handlersMu.Lock() | |
| 388 | + | defer o.handlersMu.Unlock() | |
| 389 | + | o.onWorkspaceLeave = append(o.onWorkspaceLeave, handler) | |
| 390 | + | } | |
| 391 | + | ||
| 392 | + | // handlersForWorkspaceLeave returns the handlers registered for workspace_leave, taken | |
| 393 | + | // under the lock so a handler may register another handler while events are | |
| 394 | + | // being dispatched. | |
| 395 | + | func (o *ExtWorkspaceGroupHandle) handlersForWorkspaceLeave() []func(workspaceID uint32) { | |
| 396 | + | o.handlersMu.Lock() | |
| 397 | + | defer o.handlersMu.Unlock() | |
| 398 | + | return o.onWorkspaceLeave | |
| 399 | + | } | |
| 400 | + | ||
| 401 | + | // OnRemoved registers a handler for the removed event. | |
| 402 | + | // | |
| 403 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 404 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 405 | + | func (o *ExtWorkspaceGroupHandle) OnRemoved(handler func()) { | |
| 406 | + | if handler == nil { | |
| 407 | + | return | |
| 408 | + | } | |
| 409 | + | o.handlersMu.Lock() | |
| 410 | + | defer o.handlersMu.Unlock() | |
| 411 | + | o.onRemoved = append(o.onRemoved, handler) | |
| 412 | + | } | |
| 413 | + | ||
| 414 | + | // handlersForRemoved returns the handlers registered for removed, taken | |
| 415 | + | // under the lock so a handler may register another handler while events are | |
| 416 | + | // being dispatched. | |
| 417 | + | func (o *ExtWorkspaceGroupHandle) handlersForRemoved() []func() { | |
| 418 | + | o.handlersMu.Lock() | |
| 419 | + | defer o.handlersMu.Unlock() | |
| 420 | + | return o.onRemoved | |
| 421 | + | } | |
| 422 | + | ||
| 423 | + | // EventSignature returns the declared event argument types in wire order. | |
| 424 | + | func (o *ExtWorkspaceGroupHandle) EventSignature(opcode uint16) (string, bool) { | |
| 425 | + | switch opcode { | |
| 426 | + | case 0: | |
| 427 | + | return "uint,", true | |
| 428 | + | case 1: | |
| 429 | + | return "object,", true | |
| 430 | + | case 2: | |
| 431 | + | return "object,", true | |
| 432 | + | case 3: | |
| 433 | + | return "object,", true | |
| 434 | + | case 4: | |
| 435 | + | return "object,", true | |
| 436 | + | case 5: | |
| 437 | + | return "", true | |
| 438 | + | default: | |
| 439 | + | return "", false | |
| 440 | + | } | |
| 441 | + | } | |
| 442 | + | ||
| 443 | + | // Dispatch decodes one event on ext_workspace_group_handle_v1 and calls the registered handlers. | |
| 444 | + | func (o *ExtWorkspaceGroupHandle) Dispatch(event *wl.Event) { | |
| 445 | + | switch event.Opcode { | |
| 446 | + | case 0: // capabilities | |
| 447 | + | capabilities := event.Uint32() | |
| 448 | + | ||
| 449 | + | for i, handler := range o.handlersForCapabilities() { | |
| 450 | + | _ = i | |
| 451 | + | handler(capabilities) | |
| 452 | + | } | |
| 453 | + | case 1: // output_enter | |
| 454 | + | outputID := event.Uint32() | |
| 455 | + | ||
| 456 | + | for i, handler := range o.handlersForOutputEnter() { | |
| 457 | + | _ = i | |
| 458 | + | handler(outputID) | |
| 459 | + | } | |
| 460 | + | case 2: // output_leave | |
| 461 | + | outputID := event.Uint32() | |
| 462 | + | ||
| 463 | + | for i, handler := range o.handlersForOutputLeave() { | |
| 464 | + | _ = i | |
| 465 | + | handler(outputID) | |
| 466 | + | } | |
| 467 | + | case 3: // workspace_enter | |
| 468 | + | workspaceID := event.Uint32() | |
| 469 | + | ||
| 470 | + | for i, handler := range o.handlersForWorkspaceEnter() { | |
| 471 | + | _ = i | |
| 472 | + | handler(workspaceID) | |
| 473 | + | } | |
| 474 | + | case 4: // workspace_leave | |
| 475 | + | workspaceID := event.Uint32() | |
| 476 | + | ||
| 477 | + | for i, handler := range o.handlersForWorkspaceLeave() { | |
| 478 | + | _ = i | |
| 479 | + | handler(workspaceID) | |
| 480 | + | } | |
| 481 | + | case 5: // removed | |
| 482 | + | ||
| 483 | + | for i, handler := range o.handlersForRemoved() { | |
| 484 | + | _ = i | |
| 485 | + | handler() | |
| 486 | + | } | |
| 487 | + | default: | |
| 488 | + | } | |
| 489 | + | } | |
| 490 | + | ||
| 491 | + | // ExtWorkspaceHandleInterface is the protocol interface name. | |
| 492 | + | const ExtWorkspaceHandleInterface = "ext_workspace_handle_v1" | |
| 493 | + | ||
| 494 | + | // ExtWorkspaceHandle is the generated binding for ext_workspace_handle_v1 version 1. | |
| 495 | + | type ExtWorkspaceHandle struct { | |
| 496 | + | wl.BaseProxy | |
| 497 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 498 | + | // handlers while another goroutine dispatches events. | |
| 499 | + | handlersMu sync.Mutex | |
| 500 | + | onId []func(id string) | |
| 501 | + | onName []func(name string) | |
| 502 | + | onCoordinates []func(coordinates []byte) | |
| 503 | + | onState []func(state uint32) | |
| 504 | + | onCapabilities []func(capabilities uint32) | |
| 505 | + | onRemoved []func() | |
| 506 | + | } | |
| 507 | + | ||
| 508 | + | // NewExtWorkspaceHandle returns an unbound ExtWorkspaceHandle. | |
| 509 | + | func NewExtWorkspaceHandle(ctx *wl.Context) *ExtWorkspaceHandle { | |
| 510 | + | obj := &ExtWorkspaceHandle{} | |
| 511 | + | obj.SetContext(ctx) | |
| 512 | + | ctx.Register(obj) | |
| 513 | + | return obj | |
| 514 | + | } | |
| 515 | + | ||
| 516 | + | // Destroys the ext_workspace_handle_v1 object. This request should be made either when the client does not want to use the workspace object any more or after the remove event to finalize the destruction of the object. | |
| 517 | + | func (o *ExtWorkspaceHandle) Destroy() error { | |
| 518 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_workspace_handle_v1.destroy", Destructor: true}); err != nil { | |
| 519 | + | return err | |
| 520 | + | } | |
| 521 | + | return nil | |
| 522 | + | } | |
| 523 | + | ||
| 524 | + | // Request that this workspace be activated. There is no guarantee the workspace will be actually activated, and behaviour may be compositor-dependent. For example, activating a workspace may or may not deactivate all other workspaces in the same group. | |
| 525 | + | func (o *ExtWorkspaceHandle) Activate() error { | |
| 526 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_workspace_handle_v1.activate"}); err != nil { | |
| 527 | + | return err | |
| 528 | + | } | |
| 529 | + | return nil | |
| 530 | + | } | |
| 531 | + | ||
| 532 | + | // Request that this workspace be deactivated. There is no guarantee the workspace will be actually deactivated. | |
| 533 | + | func (o *ExtWorkspaceHandle) Deactivate() error { | |
| 534 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "ext_workspace_handle_v1.deactivate"}); err != nil { | |
| 535 | + | return err | |
| 536 | + | } | |
| 537 | + | return nil | |
| 538 | + | } | |
| 539 | + | ||
| 540 | + | // Requests that this workspace is assigned to the given workspace group. There is no guarantee the workspace will be assigned. | |
| 541 | + | func (o *ExtWorkspaceHandle) Assign(workspaceGroup *ExtWorkspaceGroupHandle) error { | |
| 542 | + | var arg0 wl.Object | |
| 543 | + | if workspaceGroup != nil { | |
| 544 | + | arg0 = workspaceGroup | |
| 545 | + | } | |
| 546 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "ext_workspace_handle_v1.assign"}, wl.ArgObject(arg0)); err != nil { | |
| 547 | + | return err | |
| 548 | + | } | |
| 549 | + | return nil | |
| 550 | + | } | |
| 551 | + | ||
| 552 | + | // Request that this workspace be removed. There is no guarantee the workspace will be actually removed. | |
| 553 | + | func (o *ExtWorkspaceHandle) Remove() error { | |
| 554 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 4, Name: "ext_workspace_handle_v1.remove"}); err != nil { | |
| 555 | + | return err | |
| 556 | + | } | |
| 557 | + | return nil | |
| 558 | + | } | |
| 559 | + | ||
| 560 | + | // OnId registers a handler for the id event. | |
| 561 | + | // | |
| 562 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 563 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 564 | + | func (o *ExtWorkspaceHandle) OnId(handler func(id string)) { | |
| 565 | + | if handler == nil { | |
| 566 | + | return | |
| 567 | + | } | |
| 568 | + | o.handlersMu.Lock() | |
| 569 | + | defer o.handlersMu.Unlock() | |
| 570 | + | o.onId = append(o.onId, handler) | |
| 571 | + | } | |
| 572 | + | ||
| 573 | + | // handlersForId returns the handlers registered for id, taken | |
| 574 | + | // under the lock so a handler may register another handler while events are | |
| 575 | + | // being dispatched. | |
| 576 | + | func (o *ExtWorkspaceHandle) handlersForId() []func(id string) { | |
| 577 | + | o.handlersMu.Lock() | |
| 578 | + | defer o.handlersMu.Unlock() | |
| 579 | + | return o.onId | |
| 580 | + | } | |
| 581 | + | ||
| 582 | + | // OnName registers a handler for the name event. | |
| 583 | + | // | |
| 584 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 585 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 586 | + | func (o *ExtWorkspaceHandle) OnName(handler func(name string)) { | |
| 587 | + | if handler == nil { | |
| 588 | + | return | |
| 589 | + | } | |
| 590 | + | o.handlersMu.Lock() | |
| 591 | + | defer o.handlersMu.Unlock() | |
| 592 | + | o.onName = append(o.onName, handler) | |
| 593 | + | } | |
| 594 | + | ||
| 595 | + | // handlersForName returns the handlers registered for name, taken | |
| 596 | + | // under the lock so a handler may register another handler while events are | |
| 597 | + | // being dispatched. | |
| 598 | + | func (o *ExtWorkspaceHandle) handlersForName() []func(name string) { | |
| 599 | + | o.handlersMu.Lock() | |
| 600 | + | defer o.handlersMu.Unlock() | |
| 601 | + | return o.onName | |
| 602 | + | } | |
| 603 | + | ||
| 604 | + | // OnCoordinates registers a handler for the coordinates event. | |
| 605 | + | // | |
| 606 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 607 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 608 | + | func (o *ExtWorkspaceHandle) OnCoordinates(handler func(coordinates []byte)) { | |
| 609 | + | if handler == nil { | |
| 610 | + | return | |
| 611 | + | } | |
| 612 | + | o.handlersMu.Lock() | |
| 613 | + | defer o.handlersMu.Unlock() | |
| 614 | + | o.onCoordinates = append(o.onCoordinates, handler) | |
| 615 | + | } | |
| 616 | + | ||
| 617 | + | // handlersForCoordinates returns the handlers registered for coordinates, taken | |
| 618 | + | // under the lock so a handler may register another handler while events are | |
| 619 | + | // being dispatched. | |
| 620 | + | func (o *ExtWorkspaceHandle) handlersForCoordinates() []func(coordinates []byte) { | |
| 621 | + | o.handlersMu.Lock() | |
| 622 | + | defer o.handlersMu.Unlock() | |
| 623 | + | return o.onCoordinates | |
| 624 | + | } | |
| 625 | + | ||
| 626 | + | // OnState registers a handler for the state event. | |
| 627 | + | // | |
| 628 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 629 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 630 | + | func (o *ExtWorkspaceHandle) OnState(handler func(state uint32)) { | |
| 631 | + | if handler == nil { | |
| 632 | + | return | |
| 633 | + | } | |
| 634 | + | o.handlersMu.Lock() | |
| 635 | + | defer o.handlersMu.Unlock() | |
| 636 | + | o.onState = append(o.onState, handler) | |
| 637 | + | } | |
| 638 | + | ||
| 639 | + | // handlersForState returns the handlers registered for state, taken | |
| 640 | + | // under the lock so a handler may register another handler while events are | |
| 641 | + | // being dispatched. | |
| 642 | + | func (o *ExtWorkspaceHandle) handlersForState() []func(state uint32) { | |
| 643 | + | o.handlersMu.Lock() | |
| 644 | + | defer o.handlersMu.Unlock() | |
| 645 | + | return o.onState | |
| 646 | + | } | |
| 647 | + | ||
| 648 | + | // OnCapabilities registers a handler for the capabilities event. | |
| 649 | + | // | |
| 650 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 651 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 652 | + | func (o *ExtWorkspaceHandle) OnCapabilities(handler func(capabilities uint32)) { | |
| 653 | + | if handler == nil { | |
| 654 | + | return | |
| 655 | + | } | |
| 656 | + | o.handlersMu.Lock() | |
| 657 | + | defer o.handlersMu.Unlock() | |
| 658 | + | o.onCapabilities = append(o.onCapabilities, handler) | |
| 659 | + | } | |
| 660 | + | ||
| 661 | + | // handlersForCapabilities returns the handlers registered for capabilities, taken | |
| 662 | + | // under the lock so a handler may register another handler while events are | |
| 663 | + | // being dispatched. | |
| 664 | + | func (o *ExtWorkspaceHandle) handlersForCapabilities() []func(capabilities uint32) { | |
| 665 | + | o.handlersMu.Lock() | |
| 666 | + | defer o.handlersMu.Unlock() | |
| 667 | + | return o.onCapabilities | |
| 668 | + | } | |
| 669 | + | ||
| 670 | + | // OnRemoved registers a handler for the removed event. | |
| 671 | + | // | |
| 672 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 673 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 674 | + | func (o *ExtWorkspaceHandle) OnRemoved(handler func()) { | |
| 675 | + | if handler == nil { | |
| 676 | + | return | |
| 677 | + | } | |
| 678 | + | o.handlersMu.Lock() | |
| 679 | + | defer o.handlersMu.Unlock() | |
| 680 | + | o.onRemoved = append(o.onRemoved, handler) | |
| 681 | + | } | |
| 682 | + | ||
| 683 | + | // handlersForRemoved returns the handlers registered for removed, taken | |
| 684 | + | // under the lock so a handler may register another handler while events are | |
| 685 | + | // being dispatched. | |
| 686 | + | func (o *ExtWorkspaceHandle) handlersForRemoved() []func() { | |
| 687 | + | o.handlersMu.Lock() | |
| 688 | + | defer o.handlersMu.Unlock() | |
| 689 | + | return o.onRemoved | |
| 690 | + | } | |
| 691 | + | ||
| 692 | + | // EventSignature returns the declared event argument types in wire order. | |
| 693 | + | func (o *ExtWorkspaceHandle) EventSignature(opcode uint16) (string, bool) { | |
| 694 | + | switch opcode { | |
| 695 | + | case 0: | |
| 696 | + | return "string,", true | |
| 697 | + | case 1: | |
| 698 | + | return "string,", true | |
| 699 | + | case 2: | |
| 700 | + | return "array,", true | |
| 701 | + | case 3: | |
| 702 | + | return "uint,", true | |
| 703 | + | case 4: | |
| 704 | + | return "uint,", true | |
| 705 | + | case 5: | |
| 706 | + | return "", true | |
| 707 | + | default: | |
| 708 | + | return "", false | |
| 709 | + | } | |
| 710 | + | } | |
| 711 | + | ||
| 712 | + | // Dispatch decodes one event on ext_workspace_handle_v1 and calls the registered handlers. | |
| 713 | + | func (o *ExtWorkspaceHandle) Dispatch(event *wl.Event) { | |
| 714 | + | switch event.Opcode { | |
| 715 | + | case 0: // id | |
| 716 | + | id := event.String() | |
| 717 | + | ||
| 718 | + | for i, handler := range o.handlersForId() { | |
| 719 | + | _ = i | |
| 720 | + | handler(id) | |
| 721 | + | } | |
| 722 | + | case 1: // name | |
| 723 | + | name := event.String() | |
| 724 | + | ||
| 725 | + | for i, handler := range o.handlersForName() { | |
| 726 | + | _ = i | |
| 727 | + | handler(name) | |
| 728 | + | } | |
| 729 | + | case 2: // coordinates | |
| 730 | + | coordinates := event.Array() | |
| 731 | + | ||
| 732 | + | for i, handler := range o.handlersForCoordinates() { | |
| 733 | + | _ = i | |
| 734 | + | handler(coordinates) | |
| 735 | + | } | |
| 736 | + | case 3: // state | |
| 737 | + | state := event.Uint32() | |
| 738 | + | ||
| 739 | + | for i, handler := range o.handlersForState() { | |
| 740 | + | _ = i | |
| 741 | + | handler(state) | |
| 742 | + | } | |
| 743 | + | case 4: // capabilities | |
| 744 | + | capabilities := event.Uint32() | |
| 745 | + | ||
| 746 | + | for i, handler := range o.handlersForCapabilities() { | |
| 747 | + | _ = i | |
| 748 | + | handler(capabilities) | |
| 749 | + | } | |
| 750 | + | case 5: // removed | |
| 751 | + | ||
| 752 | + | for i, handler := range o.handlersForRemoved() { | |
| 753 | + | _ = i | |
| 754 | + | handler() | |
| 755 | + | } | |
| 756 | + | default: | |
| 757 | + | } | |
| 758 | + | } | |
A client/fifo/fifo_generated.go +146 -0
| @@ -0,0 +1,146 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: fifo_v1 | |
| 3 | + | // Source: fifo-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2023 Valve Corporation | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package fifo | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 31 | + | "github.com/bnema/wlturbo/wl" | |
| 32 | + | ) | |
| 33 | + | ||
| 34 | + | // ERROR_ALREADY_EXISTS is the error already_exists value. | |
| 35 | + | const ERROR_ALREADY_EXISTS = 0 | |
| 36 | + | ||
| 37 | + | // ERROR_SURFACE_DESTROYED is the error surface_destroyed value. | |
| 38 | + | const ERROR_SURFACE_DESTROYED = 0 | |
| 39 | + | ||
| 40 | + | // WpFifoManagerInterface is the protocol interface name. | |
| 41 | + | const WpFifoManagerInterface = "wp_fifo_manager_v1" | |
| 42 | + | ||
| 43 | + | // WpFifoManager is the generated binding for wp_fifo_manager_v1 version 1. | |
| 44 | + | type WpFifoManager struct { | |
| 45 | + | wl.BaseProxy | |
| 46 | + | } | |
| 47 | + | ||
| 48 | + | // NewWpFifoManager returns an unbound WpFifoManager. | |
| 49 | + | func NewWpFifoManager(ctx *wl.Context) *WpFifoManager { | |
| 50 | + | obj := &WpFifoManager{} | |
| 51 | + | obj.SetContext(ctx) | |
| 52 | + | ctx.Register(obj) | |
| 53 | + | return obj | |
| 54 | + | } | |
| 55 | + | ||
| 56 | + | // Informs the server that the client will no longer be using this protocol object. Existing objects created by this object are not affected. | |
| 57 | + | func (o *WpFifoManager) Destroy() error { | |
| 58 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_fifo_manager_v1.destroy", Destructor: true}); err != nil { | |
| 59 | + | return err | |
| 60 | + | } | |
| 61 | + | return nil | |
| 62 | + | } | |
| 63 | + | ||
| 64 | + | // Establish a fifo object for a surface that may be used to add display refresh constraints to content updates. Only one such object may exist for a surface and attempting to create more than one will result in an already_exists protocol error. If a surface is acted on by multiple software components, general best practice is that only the component performing wl_surface.attach operations should use this protocol. | |
| 65 | + | func (o *WpFifoManager) GetFifo(surface *cross_wl_surface.Surface) (*WpFifo, error) { | |
| 66 | + | var arg1 wl.Object | |
| 67 | + | if surface != nil { | |
| 68 | + | arg1 = surface | |
| 69 | + | } | |
| 70 | + | child := &WpFifo{} | |
| 71 | + | child.SetContext(o.Context()) | |
| 72 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_fifo_manager_v1.get_fifo", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 73 | + | return nil, err | |
| 74 | + | } | |
| 75 | + | return child, nil | |
| 76 | + | } | |
| 77 | + | ||
| 78 | + | // EventSignature returns the declared event argument types in wire order. | |
| 79 | + | func (o *WpFifoManager) EventSignature(opcode uint16) (string, bool) { | |
| 80 | + | switch opcode { | |
| 81 | + | default: | |
| 82 | + | return "", false | |
| 83 | + | } | |
| 84 | + | } | |
| 85 | + | ||
| 86 | + | // Dispatch decodes one event on wp_fifo_manager_v1 and calls the registered handlers. | |
| 87 | + | func (o *WpFifoManager) Dispatch(event *wl.Event) { | |
| 88 | + | switch event.Opcode { | |
| 89 | + | default: | |
| 90 | + | } | |
| 91 | + | } | |
| 92 | + | ||
| 93 | + | // WpFifoInterface is the protocol interface name. | |
| 94 | + | const WpFifoInterface = "wp_fifo_v1" | |
| 95 | + | ||
| 96 | + | // WpFifo is the generated binding for wp_fifo_v1 version 1. | |
| 97 | + | type WpFifo struct { | |
| 98 | + | wl.BaseProxy | |
| 99 | + | } | |
| 100 | + | ||
| 101 | + | // NewWpFifo returns an unbound WpFifo. | |
| 102 | + | func NewWpFifo(ctx *wl.Context) *WpFifo { | |
| 103 | + | obj := &WpFifo{} | |
| 104 | + | obj.SetContext(ctx) | |
| 105 | + | ctx.Register(obj) | |
| 106 | + | return obj | |
| 107 | + | } | |
| 108 | + | ||
| 109 | + | // When the content update containing the "set_barrier" is applied, it sets a "fifo_barrier" condition on the surface associated with the fifo object. The condition is cleared immediately after the following latching deadline for non-tearing presentation. The compositor may clear the condition early if it must do so to ensure client forward progress assumptions. To wait for this condition to clear, use the "wait_barrier" request. "set_barrier" is double-buffered state, see wl_surface.commit. Requesting set_barrier after the fifo object's surface is destroyed will generate a "surface_destroyed" error. | |
| 110 | + | func (o *WpFifo) SetBarrier() error { | |
| 111 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_fifo_v1.set_barrier"}); err != nil { | |
| 112 | + | return err | |
| 113 | + | } | |
| 114 | + | return nil | |
| 115 | + | } | |
| 116 | + | ||
| 117 | + | // Indicate that this content update is not ready while a "fifo_barrier" condition is present on the surface. This means that when the content update containing "set_barrier" was made active at a latching deadline, it will be active for at least one refresh cycle. A content update which is allowed to tear might become active after a latching deadline if no content update became active at the deadline. The constraint must be ignored if the surface is a subsurface in synchronized mode. If the surface is not being updated by the compositor (off-screen, occluded) the compositor may ignore the constraint. Clients must use an additional mechanism such as frame callbacks or timestamps to ensure throttling occurs under all conditions. "wait_barrier" is double-buffered state, see wl_surface.commit. Requesting "wait_barrier" after the fifo object's surface is destroyed will generate a "surface_destroyed" error. | |
| 118 | + | func (o *WpFifo) WaitBarrier() error { | |
| 119 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_fifo_v1.wait_barrier"}); err != nil { | |
| 120 | + | return err | |
| 121 | + | } | |
| 122 | + | return nil | |
| 123 | + | } | |
| 124 | + | ||
| 125 | + | // Informs the server that the client will no longer be using this protocol object. Surface state changes previously made by this protocol are unaffected by this object's destruction. | |
| 126 | + | func (o *WpFifo) Destroy() error { | |
| 127 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wp_fifo_v1.destroy", Destructor: true}); err != nil { | |
| 128 | + | return err | |
| 129 | + | } | |
| 130 | + | return nil | |
| 131 | + | } | |
| 132 | + | ||
| 133 | + | // EventSignature returns the declared event argument types in wire order. | |
| 134 | + | func (o *WpFifo) EventSignature(opcode uint16) (string, bool) { | |
| 135 | + | switch opcode { | |
| 136 | + | default: | |
| 137 | + | return "", false | |
| 138 | + | } | |
| 139 | + | } | |
| 140 | + | ||
| 141 | + | // Dispatch decodes one event on wp_fifo_v1 and calls the registered handlers. | |
| 142 | + | func (o *WpFifo) Dispatch(event *wl.Event) { | |
| 143 | + | switch event.Opcode { | |
| 144 | + | default: | |
| 145 | + | } | |
| 146 | + | } | |
A client/format_table_test.go +71 -0
| @@ -0,0 +1,71 @@ | |||
| 1 | + | //go:build linux | |
| 2 | + | ||
| 3 | + | package client_test | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "errors" | |
| 7 | + | "github.com/bnema/go-wayland-bindings/client/linuxdmabuf" | |
| 8 | + | "github.com/bnema/wlturbo" | |
| 9 | + | "golang.org/x/sys/unix" | |
| 10 | + | "io" | |
| 11 | + | "os" | |
| 12 | + | "testing" | |
| 13 | + | ) | |
| 14 | + | ||
| 15 | + | // Exercise format_table through generated event dispatch so the received FD | |
| 16 | + | // has real transport ownership; verify closing by inspecting the taken FD. | |
| 17 | + | func TestMalformedFormatTables(t *testing.T) { | |
| 18 | + | for _, tc := range []struct { | |
| 19 | + | name string | |
| 20 | + | contents []byte | |
| 21 | + | size uint32 | |
| 22 | + | wantErr bool | |
| 23 | + | }{ | |
| 24 | + | {"unaligned", make([]byte, 16), 17, true}, | |
| 25 | + | {"truncated", make([]byte, 16), 32, true}, | |
| 26 | + | {"zero", nil, 0, false}, | |
| 27 | + | {"oversize", nil, (16 << 20) + 16, true}, | |
| 28 | + | } { | |
| 29 | + | t.Run(tc.name, func(t *testing.T) { | |
| 30 | + | c, p := pair(t) | |
| 31 | + | d, e := wlturbo.ConnectFromConn(c) | |
| 32 | + | noerr(t, e) | |
| 33 | + | defer d.Close() | |
| 34 | + | request(t, p) | |
| 35 | + | fb := linuxdmabuf.NewLinuxDmabufFeedback(d.Context()) | |
| 36 | + | fb.SetID(d.AllocateID()) | |
| 37 | + | d.Context().Register(fb) | |
| 38 | + | file, e := os.CreateTemp(t.TempDir(), "table") | |
| 39 | + | noerr(t, e) | |
| 40 | + | defer file.Close() | |
| 41 | + | _, e = file.Write(tc.contents) | |
| 42 | + | noerr(t, e) | |
| 43 | + | called := false | |
| 44 | + | fb.OnFormatTable(func(fd *wlturbo.OwnedFD, size uint32) { | |
| 45 | + | called = true | |
| 46 | + | entries, err := linuxdmabuf.ReadFormatTable(fd, size) | |
| 47 | + | if (err != nil) != tc.wantErr { | |
| 48 | + | t.Fatalf("size=%d entries=%v err=%v", size, entries, err) | |
| 49 | + | } | |
| 50 | + | if tc.name == "truncated" && !errors.Is(err, io.ErrUnexpectedEOF) { | |
| 51 | + | t.Fatalf("short read: %v", err) | |
| 52 | + | } | |
| 53 | + | // Take/Close must be idempotent, including after a failed size check. | |
| 54 | + | if _, err = fd.Take(); err == nil { | |
| 55 | + | t.Fatal("already consumed fd still takeable") | |
| 56 | + | } | |
| 57 | + | noerr(t, fd.Close()) | |
| 58 | + | noerr(t, fd.Close()) | |
| 59 | + | }) | |
| 60 | + | send(t, p, msg(fb.ID(), 1, tc.size), int(file.Fd())) | |
| 61 | + | noerr(t, d.Dispatch()) | |
| 62 | + | if !called { | |
| 63 | + | t.Fatal("no callback") | |
| 64 | + | } | |
| 65 | + | // The transport FD was a duplicate: caller's descriptor is still open. | |
| 66 | + | if _, e = unix.FcntlInt(file.Fd(), unix.F_GETFD, 0); e != nil { | |
| 67 | + | t.Fatalf("sender fd closed: %v", e) | |
| 68 | + | } | |
| 69 | + | }) | |
| 70 | + | } | |
| 71 | + | } | |
A client/fractionalscale/fractionalscale_generated.go +164 -0
| @@ -0,0 +1,164 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: fractional_scale_v1 | |
| 3 | + | // Source: fractional-scale-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2022 Kenny Levinsen | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package fractionalscale | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | "sync" | |
| 31 | + | ||
| 32 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 33 | + | "github.com/bnema/wlturbo/wl" | |
| 34 | + | ) | |
| 35 | + | ||
| 36 | + | // ERROR_FRACTIONAL_SCALE_EXISTS is the error fractional_scale_exists value. | |
| 37 | + | const ERROR_FRACTIONAL_SCALE_EXISTS = 0 | |
| 38 | + | ||
| 39 | + | // WpFractionalScaleManagerInterface is the protocol interface name. | |
| 40 | + | const WpFractionalScaleManagerInterface = "wp_fractional_scale_manager_v1" | |
| 41 | + | ||
| 42 | + | // WpFractionalScaleManager is the generated binding for wp_fractional_scale_manager_v1 version 1. | |
| 43 | + | type WpFractionalScaleManager struct { | |
| 44 | + | wl.BaseProxy | |
| 45 | + | } | |
| 46 | + | ||
| 47 | + | // NewWpFractionalScaleManager returns an unbound WpFractionalScaleManager. | |
| 48 | + | func NewWpFractionalScaleManager(ctx *wl.Context) *WpFractionalScaleManager { | |
| 49 | + | obj := &WpFractionalScaleManager{} | |
| 50 | + | obj.SetContext(ctx) | |
| 51 | + | ctx.Register(obj) | |
| 52 | + | return obj | |
| 53 | + | } | |
| 54 | + | ||
| 55 | + | // Informs the server that the client will not be using this protocol object anymore. This does not affect any other objects, wp_fractional_scale_v1 objects included. | |
| 56 | + | func (o *WpFractionalScaleManager) Destroy() error { | |
| 57 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_fractional_scale_manager_v1.destroy", Destructor: true}); err != nil { | |
| 58 | + | return err | |
| 59 | + | } | |
| 60 | + | return nil | |
| 61 | + | } | |
| 62 | + | ||
| 63 | + | // Create an add-on object for the the wl_surface to let the compositor request fractional scales. If the given wl_surface already has a wp_fractional_scale_v1 object associated, the fractional_scale_exists protocol error is raised. | |
| 64 | + | func (o *WpFractionalScaleManager) GetFractionalScale(surface *cross_wl_surface.Surface) (*WpFractionalScale, error) { | |
| 65 | + | var arg1 wl.Object | |
| 66 | + | if surface != nil { | |
| 67 | + | arg1 = surface | |
| 68 | + | } | |
| 69 | + | child := &WpFractionalScale{} | |
| 70 | + | child.SetContext(o.Context()) | |
| 71 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_fractional_scale_manager_v1.get_fractional_scale", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 72 | + | return nil, err | |
| 73 | + | } | |
| 74 | + | return child, nil | |
| 75 | + | } | |
| 76 | + | ||
| 77 | + | // EventSignature returns the declared event argument types in wire order. | |
| 78 | + | func (o *WpFractionalScaleManager) EventSignature(opcode uint16) (string, bool) { | |
| 79 | + | switch opcode { | |
| 80 | + | default: | |
| 81 | + | return "", false | |
| 82 | + | } | |
| 83 | + | } | |
| 84 | + | ||
| 85 | + | // Dispatch decodes one event on wp_fractional_scale_manager_v1 and calls the registered handlers. | |
| 86 | + | func (o *WpFractionalScaleManager) Dispatch(event *wl.Event) { | |
| 87 | + | switch event.Opcode { | |
| 88 | + | default: | |
| 89 | + | } | |
| 90 | + | } | |
| 91 | + | ||
| 92 | + | // WpFractionalScaleInterface is the protocol interface name. | |
| 93 | + | const WpFractionalScaleInterface = "wp_fractional_scale_v1" | |
| 94 | + | ||
| 95 | + | // WpFractionalScale is the generated binding for wp_fractional_scale_v1 version 1. | |
| 96 | + | type WpFractionalScale struct { | |
| 97 | + | wl.BaseProxy | |
| 98 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 99 | + | // handlers while another goroutine dispatches events. | |
| 100 | + | handlersMu sync.Mutex | |
| 101 | + | onPreferredScale []func(scale uint32) | |
| 102 | + | } | |
| 103 | + | ||
| 104 | + | // NewWpFractionalScale returns an unbound WpFractionalScale. | |
| 105 | + | func NewWpFractionalScale(ctx *wl.Context) *WpFractionalScale { | |
| 106 | + | obj := &WpFractionalScale{} | |
| 107 | + | obj.SetContext(ctx) | |
| 108 | + | ctx.Register(obj) | |
| 109 | + | return obj | |
| 110 | + | } | |
| 111 | + | ||
| 112 | + | // Destroy the fractional scale object. When this object is destroyed, preferred_scale events will no longer be sent. | |
| 113 | + | func (o *WpFractionalScale) Destroy() error { | |
| 114 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_fractional_scale_v1.destroy", Destructor: true}); err != nil { | |
| 115 | + | return err | |
| 116 | + | } | |
| 117 | + | return nil | |
| 118 | + | } | |
| 119 | + | ||
| 120 | + | // OnPreferredScale registers a handler for the preferred_scale event. | |
| 121 | + | // | |
| 122 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 123 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 124 | + | func (o *WpFractionalScale) OnPreferredScale(handler func(scale uint32)) { | |
| 125 | + | if handler == nil { | |
| 126 | + | return | |
| 127 | + | } | |
| 128 | + | o.handlersMu.Lock() | |
| 129 | + | defer o.handlersMu.Unlock() | |
| 130 | + | o.onPreferredScale = append(o.onPreferredScale, handler) | |
| 131 | + | } | |
| 132 | + | ||
| 133 | + | // handlersForPreferredScale returns the handlers registered for preferred_scale, taken | |
| 134 | + | // under the lock so a handler may register another handler while events are | |
| 135 | + | // being dispatched. | |
| 136 | + | func (o *WpFractionalScale) handlersForPreferredScale() []func(scale uint32) { | |
| 137 | + | o.handlersMu.Lock() | |
| 138 | + | defer o.handlersMu.Unlock() | |
| 139 | + | return o.onPreferredScale | |
| 140 | + | } | |
| 141 | + | ||
| 142 | + | // EventSignature returns the declared event argument types in wire order. | |
| 143 | + | func (o *WpFractionalScale) EventSignature(opcode uint16) (string, bool) { | |
| 144 | + | switch opcode { | |
| 145 | + | case 0: | |
| 146 | + | return "uint,", true | |
| 147 | + | default: | |
| 148 | + | return "", false | |
| 149 | + | } | |
| 150 | + | } | |
| 151 | + | ||
| 152 | + | // Dispatch decodes one event on wp_fractional_scale_v1 and calls the registered handlers. | |
| 153 | + | func (o *WpFractionalScale) Dispatch(event *wl.Event) { | |
| 154 | + | switch event.Opcode { | |
| 155 | + | case 0: // preferred_scale | |
| 156 | + | scale := event.Uint32() | |
| 157 | + | ||
| 158 | + | for i, handler := range o.handlersForPreferredScale() { | |
| 159 | + | _ = i | |
| 160 | + | handler(scale) | |
| 161 | + | } | |
| 162 | + | default: | |
| 163 | + | } | |
| 164 | + | } | |
A client/fullscreenshell/fullscreenshell_generated.go +302 -0
| @@ -0,0 +1,302 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: fullscreen_shell_unstable_v1 | |
| 3 | + | // Source: fullscreen-shell-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2016 Yong Bakos | |
| 7 | + | // Copyright © 2015 Jason Ekstrand | |
| 8 | + | // Copyright © 2015 Jonas Ådahl | |
| 9 | + | // | |
| 10 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 11 | + | // copy of this software and associated documentation files (the "Software"), | |
| 12 | + | // to deal in the Software without restriction, including without limitation | |
| 13 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 14 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 15 | + | // Software is furnished to do so, subject to the following conditions: | |
| 16 | + | // | |
| 17 | + | // The above copyright notice and this permission notice (including the next | |
| 18 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 19 | + | // Software. | |
| 20 | + | // | |
| 21 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 22 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 23 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 24 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 25 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 26 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 27 | + | // DEALINGS IN THE SOFTWARE. | |
| 28 | + | ||
| 29 | + | package fullscreenshell | |
| 30 | + | ||
| 31 | + | import ( | |
| 32 | + | "sync" | |
| 33 | + | ||
| 34 | + | cross_wl_output "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 35 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 36 | + | "github.com/bnema/wlturbo/wl" | |
| 37 | + | ) | |
| 38 | + | ||
| 39 | + | // CAPABILITY_ARBITRARY_MODES is the capability arbitrary_modes value. | |
| 40 | + | const CAPABILITY_ARBITRARY_MODES = 1 | |
| 41 | + | ||
| 42 | + | // CAPABILITY_CURSOR_PLANE is the capability cursor_plane value. | |
| 43 | + | const CAPABILITY_CURSOR_PLANE = 2 | |
| 44 | + | ||
| 45 | + | // PRESENT_METHOD_DEFAULT is the present_method default value. | |
| 46 | + | const PRESENT_METHOD_DEFAULT = 0 | |
| 47 | + | ||
| 48 | + | // PRESENT_METHOD_CENTER is the present_method center value. | |
| 49 | + | const PRESENT_METHOD_CENTER = 1 | |
| 50 | + | ||
| 51 | + | // PRESENT_METHOD_ZOOM is the present_method zoom value. | |
| 52 | + | const PRESENT_METHOD_ZOOM = 2 | |
| 53 | + | ||
| 54 | + | // PRESENT_METHOD_ZOOM_CROP is the present_method zoom_crop value. | |
| 55 | + | const PRESENT_METHOD_ZOOM_CROP = 3 | |
| 56 | + | ||
| 57 | + | // PRESENT_METHOD_STRETCH is the present_method stretch value. | |
| 58 | + | const PRESENT_METHOD_STRETCH = 4 | |
| 59 | + | ||
| 60 | + | // ERROR_INVALID_METHOD is the error invalid_method value. | |
| 61 | + | const ERROR_INVALID_METHOD = 0 | |
| 62 | + | ||
| 63 | + | // ERROR_ROLE is the error role value. | |
| 64 | + | const ERROR_ROLE = 1 | |
| 65 | + | ||
| 66 | + | // FullscreenShellInterface is the protocol interface name. | |
| 67 | + | const FullscreenShellInterface = "zwp_fullscreen_shell_v1" | |
| 68 | + | ||
| 69 | + | // FullscreenShell is the generated binding for zwp_fullscreen_shell_v1 version 1. | |
| 70 | + | type FullscreenShell struct { | |
| 71 | + | wl.BaseProxy | |
| 72 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 73 | + | // handlers while another goroutine dispatches events. | |
| 74 | + | handlersMu sync.Mutex | |
| 75 | + | onCapability []func(capability uint32) | |
| 76 | + | } | |
| 77 | + | ||
| 78 | + | // NewFullscreenShell returns an unbound FullscreenShell. | |
| 79 | + | func NewFullscreenShell(ctx *wl.Context) *FullscreenShell { | |
| 80 | + | obj := &FullscreenShell{} | |
| 81 | + | obj.SetContext(ctx) | |
| 82 | + | ctx.Register(obj) | |
| 83 | + | return obj | |
| 84 | + | } | |
| 85 | + | ||
| 86 | + | // Release the binding from the wl_fullscreen_shell interface. This destroys the server-side object and frees this binding. If the client binds to wl_fullscreen_shell multiple times, it may wish to free some of those bindings. | |
| 87 | + | func (o *FullscreenShell) Release() error { | |
| 88 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_fullscreen_shell_v1.release", Destructor: true}); err != nil { | |
| 89 | + | return err | |
| 90 | + | } | |
| 91 | + | return nil | |
| 92 | + | } | |
| 93 | + | ||
| 94 | + | // Present a surface on the given output. If the output is null, the compositor will present the surface on whatever display (or displays) it thinks best. In particular, this may replace any or all surfaces currently presented so it should not be used in combination with placing surfaces on specific outputs. The method parameter is a hint to the compositor for how the surface is to be presented. In particular, it tells the compositor how to handle a size mismatch between the presented surface and the output. The compositor is free to ignore this parameter. The "zoom", "zoom_crop", and "stretch" methods imply a scaling operation on the surface. This will override any kind of output scaling, so the buffer_scale property of the surface is effectively ignored. This request gives the surface the role of a fullscreen shell surface. If the surface already has another role, it raises a role protocol error. | |
| 95 | + | func (o *FullscreenShell) PresentSurface(surface *cross_wl_surface.Surface, method uint32, output *cross_wl_output.Output) error { | |
| 96 | + | var arg0 wl.Object | |
| 97 | + | if surface != nil { | |
| 98 | + | arg0 = surface | |
| 99 | + | } | |
| 100 | + | var arg2 wl.Object | |
| 101 | + | if output != nil { | |
| 102 | + | arg2 = output | |
| 103 | + | } | |
| 104 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_fullscreen_shell_v1.present_surface"}, wl.ArgObject(arg0), wl.ArgUint(method), wl.ArgObject(arg2)); err != nil { | |
| 105 | + | return err | |
| 106 | + | } | |
| 107 | + | return nil | |
| 108 | + | } | |
| 109 | + | ||
| 110 | + | // Presents a surface on the given output for a particular mode. If the current size of the output differs from that of the surface, the compositor will attempt to change the size of the output to match the surface. The result of the mode-switch operation will be returned via the provided wl_fullscreen_shell_mode_feedback object. If the current output mode matches the one requested or if the compositor successfully switches the mode to match the surface, then the mode_successful event will be sent and the output will contain the contents of the given surface. If the compositor cannot match the output size to the surface size, the mode_failed will be sent and the output will contain the contents of the previously presented surface (if any). If another surface is presented on the given output before either of these has a chance to happen, the present_cancelled event will be sent. Due to race conditions and other issues unknown to the client, no mode-switch operation is guaranteed to succeed. However, if the mode is one advertised by wl_output.mode or if the compositor advertises the ARBITRARY_MODES capability, then the client should expect that the mode-switch operation will usually succeed. If the size of the presented surface changes, the resulting output is undefined. The compositor may attempt to change the output mode to compensate. However, there is no guarantee that a suitable mode will be found and the client has no way to be notified of success or failure. The framerate parameter specifies the desired framerate for the output in mHz. The compositor is free to ignore this parameter. A value of 0 indicates that the client has no preference. If the value of wl_output.scale differs from wl_surface.buffer_scale, then the compositor may choose a mode that matches either the buffer size or the surface size. In either case, the surface will fill the output. This request gives the surface the role of a fullscreen shell surface. If the surface already has another role, it raises a role protocol error. | |
| 111 | + | func (o *FullscreenShell) PresentSurfaceForMode(surface *cross_wl_surface.Surface, output *cross_wl_output.Output, framerate int32) (*FullscreenShellModeFeedback, error) { | |
| 112 | + | var arg0 wl.Object | |
| 113 | + | if surface != nil { | |
| 114 | + | arg0 = surface | |
| 115 | + | } | |
| 116 | + | var arg1 wl.Object | |
| 117 | + | if output != nil { | |
| 118 | + | arg1 = output | |
| 119 | + | } | |
| 120 | + | child := &FullscreenShellModeFeedback{} | |
| 121 | + | child.SetContext(o.Context()) | |
| 122 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_fullscreen_shell_v1.present_surface_for_mode", Child: child}, wl.ArgObject(arg0), wl.ArgObject(arg1), wl.ArgInt(framerate), wl.ArgObject(child)); err != nil { | |
| 123 | + | return nil, err | |
| 124 | + | } | |
| 125 | + | return child, nil | |
| 126 | + | } | |
| 127 | + | ||
| 128 | + | // OnCapability registers a handler for the capability event. | |
| 129 | + | // | |
| 130 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 131 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 132 | + | func (o *FullscreenShell) OnCapability(handler func(capability uint32)) { | |
| 133 | + | if handler == nil { | |
| 134 | + | return | |
| 135 | + | } | |
| 136 | + | o.handlersMu.Lock() | |
| 137 | + | defer o.handlersMu.Unlock() | |
| 138 | + | o.onCapability = append(o.onCapability, handler) | |
| 139 | + | } | |
| 140 | + | ||
| 141 | + | // handlersForCapability returns the handlers registered for capability, taken | |
| 142 | + | // under the lock so a handler may register another handler while events are | |
| 143 | + | // being dispatched. | |
| 144 | + | func (o *FullscreenShell) handlersForCapability() []func(capability uint32) { | |
| 145 | + | o.handlersMu.Lock() | |
| 146 | + | defer o.handlersMu.Unlock() | |
| 147 | + | return o.onCapability | |
| 148 | + | } | |
| 149 | + | ||
| 150 | + | // EventSignature returns the declared event argument types in wire order. | |
| 151 | + | func (o *FullscreenShell) EventSignature(opcode uint16) (string, bool) { | |
| 152 | + | switch opcode { | |
| 153 | + | case 0: | |
| 154 | + | return "uint,", true | |
| 155 | + | default: | |
| 156 | + | return "", false | |
| 157 | + | } | |
| 158 | + | } | |
| 159 | + | ||
| 160 | + | // Dispatch decodes one event on zwp_fullscreen_shell_v1 and calls the registered handlers. | |
| 161 | + | func (o *FullscreenShell) Dispatch(event *wl.Event) { | |
| 162 | + | switch event.Opcode { | |
| 163 | + | case 0: // capability | |
| 164 | + | capability := event.Uint32() | |
| 165 | + | ||
| 166 | + | for i, handler := range o.handlersForCapability() { | |
| 167 | + | _ = i | |
| 168 | + | handler(capability) | |
| 169 | + | } | |
| 170 | + | default: | |
| 171 | + | } | |
| 172 | + | } | |
| 173 | + | ||
| 174 | + | // FullscreenShellModeFeedbackInterface is the protocol interface name. | |
| 175 | + | const FullscreenShellModeFeedbackInterface = "zwp_fullscreen_shell_mode_feedback_v1" | |
| 176 | + | ||
| 177 | + | // FullscreenShellModeFeedback is the generated binding for zwp_fullscreen_shell_mode_feedback_v1 version 1. | |
| 178 | + | type FullscreenShellModeFeedback struct { | |
| 179 | + | wl.BaseProxy | |
| 180 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 181 | + | // handlers while another goroutine dispatches events. | |
| 182 | + | handlersMu sync.Mutex | |
| 183 | + | onModeSuccessful []func() | |
| 184 | + | onModeFailed []func() | |
| 185 | + | onPresentCancelled []func() | |
| 186 | + | } | |
| 187 | + | ||
| 188 | + | // NewFullscreenShellModeFeedback returns an unbound FullscreenShellModeFeedback. | |
| 189 | + | func NewFullscreenShellModeFeedback(ctx *wl.Context) *FullscreenShellModeFeedback { | |
| 190 | + | obj := &FullscreenShellModeFeedback{} | |
| 191 | + | obj.SetContext(ctx) | |
| 192 | + | ctx.Register(obj) | |
| 193 | + | return obj | |
| 194 | + | } | |
| 195 | + | ||
| 196 | + | // OnModeSuccessful registers a handler for the mode_successful event. | |
| 197 | + | // | |
| 198 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 199 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 200 | + | func (o *FullscreenShellModeFeedback) OnModeSuccessful(handler func()) { | |
| 201 | + | if handler == nil { | |
| 202 | + | return | |
| 203 | + | } | |
| 204 | + | o.handlersMu.Lock() | |
| 205 | + | defer o.handlersMu.Unlock() | |
| 206 | + | o.onModeSuccessful = append(o.onModeSuccessful, handler) | |
| 207 | + | } | |
| 208 | + | ||
| 209 | + | // handlersForModeSuccessful returns the handlers registered for mode_successful, taken | |
| 210 | + | // under the lock so a handler may register another handler while events are | |
| 211 | + | // being dispatched. | |
| 212 | + | func (o *FullscreenShellModeFeedback) handlersForModeSuccessful() []func() { | |
| 213 | + | o.handlersMu.Lock() | |
| 214 | + | defer o.handlersMu.Unlock() | |
| 215 | + | return o.onModeSuccessful | |
| 216 | + | } | |
| 217 | + | ||
| 218 | + | // OnModeFailed registers a handler for the mode_failed event. | |
| 219 | + | // | |
| 220 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 221 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 222 | + | func (o *FullscreenShellModeFeedback) OnModeFailed(handler func()) { | |
| 223 | + | if handler == nil { | |
| 224 | + | return | |
| 225 | + | } | |
| 226 | + | o.handlersMu.Lock() | |
| 227 | + | defer o.handlersMu.Unlock() | |
| 228 | + | o.onModeFailed = append(o.onModeFailed, handler) | |
| 229 | + | } | |
| 230 | + | ||
| 231 | + | // handlersForModeFailed returns the handlers registered for mode_failed, taken | |
| 232 | + | // under the lock so a handler may register another handler while events are | |
| 233 | + | // being dispatched. | |
| 234 | + | func (o *FullscreenShellModeFeedback) handlersForModeFailed() []func() { | |
| 235 | + | o.handlersMu.Lock() | |
| 236 | + | defer o.handlersMu.Unlock() | |
| 237 | + | return o.onModeFailed | |
| 238 | + | } | |
| 239 | + | ||
| 240 | + | // OnPresentCancelled registers a handler for the present_cancelled event. | |
| 241 | + | // | |
| 242 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 243 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 244 | + | func (o *FullscreenShellModeFeedback) OnPresentCancelled(handler func()) { | |
| 245 | + | if handler == nil { | |
| 246 | + | return | |
| 247 | + | } | |
| 248 | + | o.handlersMu.Lock() | |
| 249 | + | defer o.handlersMu.Unlock() | |
| 250 | + | o.onPresentCancelled = append(o.onPresentCancelled, handler) | |
| 251 | + | } | |
| 252 | + | ||
| 253 | + | // handlersForPresentCancelled returns the handlers registered for present_cancelled, taken | |
| 254 | + | // under the lock so a handler may register another handler while events are | |
| 255 | + | // being dispatched. | |
| 256 | + | func (o *FullscreenShellModeFeedback) handlersForPresentCancelled() []func() { | |
| 257 | + | o.handlersMu.Lock() | |
| 258 | + | defer o.handlersMu.Unlock() | |
| 259 | + | return o.onPresentCancelled | |
| 260 | + | } | |
| 261 | + | ||
| 262 | + | // EventSignature returns the declared event argument types in wire order. | |
| 263 | + | func (o *FullscreenShellModeFeedback) EventSignature(opcode uint16) (string, bool) { | |
| 264 | + | switch opcode { | |
| 265 | + | case 0: | |
| 266 | + | return "", true | |
| 267 | + | case 1: | |
| 268 | + | return "", true | |
| 269 | + | case 2: | |
| 270 | + | return "", true | |
| 271 | + | default: | |
| 272 | + | return "", false | |
| 273 | + | } | |
| 274 | + | } | |
| 275 | + | ||
| 276 | + | // Dispatch decodes one event on zwp_fullscreen_shell_mode_feedback_v1 and calls the registered handlers. | |
| 277 | + | func (o *FullscreenShellModeFeedback) Dispatch(event *wl.Event) { | |
| 278 | + | switch event.Opcode { | |
| 279 | + | case 0: // mode_successful | |
| 280 | + | ||
| 281 | + | for i, handler := range o.handlersForModeSuccessful() { | |
| 282 | + | _ = i | |
| 283 | + | handler() | |
| 284 | + | } | |
| 285 | + | o.Context().Unregister(o) | |
| 286 | + | case 1: // mode_failed | |
| 287 | + | ||
| 288 | + | for i, handler := range o.handlersForModeFailed() { | |
| 289 | + | _ = i | |
| 290 | + | handler() | |
| 291 | + | } | |
| 292 | + | o.Context().Unregister(o) | |
| 293 | + | case 2: // present_cancelled | |
| 294 | + | ||
| 295 | + | for i, handler := range o.handlersForPresentCancelled() { | |
| 296 | + | _ = i | |
| 297 | + | handler() | |
| 298 | + | } | |
| 299 | + | o.Context().Unregister(o) | |
| 300 | + | default: | |
| 301 | + | } | |
| 302 | + | } | |
A client/headless_extensions_test.go +430 -0
| @@ -0,0 +1,430 @@ | |||
| 1 | + | //go:build linux | |
| 2 | + | ||
| 3 | + | package client_test | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "fmt" | |
| 7 | + | "sort" | |
| 8 | + | "testing" | |
| 9 | + | ||
| 10 | + | "github.com/bnema/go-wayland-bindings/client/alphamodifier" | |
| 11 | + | "github.com/bnema/go-wayland-bindings/client/colormanagement" | |
| 12 | + | "github.com/bnema/go-wayland-bindings/client/colorrepresentation" | |
| 13 | + | "github.com/bnema/go-wayland-bindings/client/committiming" | |
| 14 | + | "github.com/bnema/go-wayland-bindings/client/contenttype" | |
| 15 | + | "github.com/bnema/go-wayland-bindings/client/cursorshape" | |
| 16 | + | "github.com/bnema/go-wayland-bindings/client/drmlease" | |
| 17 | + | datacontrol "github.com/bnema/go-wayland-bindings/client/extdatacontrol" | |
| 18 | + | extforeigntoplevel "github.com/bnema/go-wayland-bindings/client/extforeigntoplevellist" | |
| 19 | + | idlenotify "github.com/bnema/go-wayland-bindings/client/extidlenotify" | |
| 20 | + | imagecapturesource "github.com/bnema/go-wayland-bindings/client/extimagecapturesource" | |
| 21 | + | imagecopycapture "github.com/bnema/go-wayland-bindings/client/extimagecopycapture" | |
| 22 | + | workspace "github.com/bnema/go-wayland-bindings/client/extworkspace" | |
| 23 | + | "github.com/bnema/go-wayland-bindings/client/fifo" | |
| 24 | + | "github.com/bnema/go-wayland-bindings/client/fractionalscale" | |
| 25 | + | "github.com/bnema/go-wayland-bindings/client/idleinhibit" | |
| 26 | + | "github.com/bnema/go-wayland-bindings/client/inputmethod" | |
| 27 | + | shortcutsinhibit "github.com/bnema/go-wayland-bindings/client/keyboardshortcutsinhibit" | |
| 28 | + | "github.com/bnema/go-wayland-bindings/client/linuxdmabuf" | |
| 29 | + | drmsyncobj "github.com/bnema/go-wayland-bindings/client/linuxdrmsyncobj" | |
| 30 | + | "github.com/bnema/go-wayland-bindings/client/pointerconstraints" | |
| 31 | + | "github.com/bnema/go-wayland-bindings/client/pointerwarp" | |
| 32 | + | presentation "github.com/bnema/go-wayland-bindings/client/presentationtime" | |
| 33 | + | "github.com/bnema/go-wayland-bindings/client/primaryselection" | |
| 34 | + | "github.com/bnema/go-wayland-bindings/client/relativepointer" | |
| 35 | + | kdeserverdecoration "github.com/bnema/go-wayland-bindings/client/serverdecoration" | |
| 36 | + | "github.com/bnema/go-wayland-bindings/client/tablet" | |
| 37 | + | "github.com/bnema/go-wayland-bindings/client/tearingcontrol" | |
| 38 | + | "github.com/bnema/go-wayland-bindings/client/textinput" | |
| 39 | + | "github.com/bnema/go-wayland-bindings/client/viewporter" | |
| 40 | + | "github.com/bnema/go-wayland-bindings/client/virtualkeyboard" | |
| 41 | + | "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 42 | + | foreigntoplevel "github.com/bnema/go-wayland-bindings/client/wlrforeigntoplevelmanagement" | |
| 43 | + | layershell "github.com/bnema/go-wayland-bindings/client/wlrlayershell" | |
| 44 | + | outputmanagement "github.com/bnema/go-wayland-bindings/client/wlroutputmanagement" | |
| 45 | + | outputpower "github.com/bnema/go-wayland-bindings/client/wlroutputpowermanagement" | |
| 46 | + | screencopy "github.com/bnema/go-wayland-bindings/client/wlrscreencopy" | |
| 47 | + | "github.com/bnema/go-wayland-bindings/client/xdgactivation" | |
| 48 | + | "github.com/bnema/go-wayland-bindings/client/xdgdecoration" | |
| 49 | + | "github.com/bnema/go-wayland-bindings/client/xdgoutput" | |
| 50 | + | "github.com/bnema/go-wayland-bindings/client/xdgshell" | |
| 51 | + | "github.com/bnema/wlturbo" | |
| 52 | + | "golang.org/x/sys/unix" | |
| 53 | + | ) | |
| 54 | + | ||
| 55 | + | // headlessBinding is one generated root object and the highest version its | |
| 56 | + | // package supports (the XML interface version). | |
| 57 | + | type headlessBinding struct { | |
| 58 | + | iface string | |
| 59 | + | supported uint32 | |
| 60 | + | make func(*wlturbo.Context) wlturbo.Proxy | |
| 61 | + | // optional marks globals that depend on GPU, DRM or input devices, or that | |
| 62 | + | // this NeferWL build does not advertise headless: absence is logged, not | |
| 63 | + | // a failure. Everything else must be announced. | |
| 64 | + | optional bool | |
| 65 | + | } | |
| 66 | + | ||
| 67 | + | func headlessBindings() []headlessBinding { | |
| 68 | + | return []headlessBinding{ | |
| 69 | + | {wayland.CompositorInterface, 7, func(c *wlturbo.Context) wlturbo.Proxy { return wayland.NewCompositor(c) }, false}, | |
| 70 | + | {wayland.SubcompositorInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return wayland.NewSubcompositor(c) }, false}, | |
| 71 | + | {wayland.ShmInterface, 3, func(c *wlturbo.Context) wlturbo.Proxy { return wayland.NewShm(c) }, false}, | |
| 72 | + | {wayland.SeatInterface, 11, func(c *wlturbo.Context) wlturbo.Proxy { return wayland.NewSeat(c) }, false}, | |
| 73 | + | {wayland.OutputInterface, 4, func(c *wlturbo.Context) wlturbo.Proxy { return wayland.NewOutput(c) }, false}, | |
| 74 | + | {wayland.DataDeviceManagerInterface, 4, func(c *wlturbo.Context) wlturbo.Proxy { return wayland.NewDataDeviceManager(c) }, false}, | |
| 75 | + | {xdgshell.XdgWmBaseInterface, 7, func(c *wlturbo.Context) wlturbo.Proxy { return xdgshell.NewXdgWmBase(c) }, false}, | |
| 76 | + | {linuxdmabuf.LinuxDmabufInterface, 6, func(c *wlturbo.Context) wlturbo.Proxy { return linuxdmabuf.NewLinuxDmabuf(c) }, true}, | |
| 77 | + | {drmsyncobj.WpLinuxDrmSyncobjManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return drmsyncobj.NewWpLinuxDrmSyncobjManager(c) }, true}, | |
| 78 | + | {viewporter.WpViewporterInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return viewporter.NewWpViewporter(c) }, false}, | |
| 79 | + | {fractionalscale.WpFractionalScaleManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return fractionalscale.NewWpFractionalScaleManager(c) }, false}, | |
| 80 | + | {cursorshape.WpCursorShapeManagerInterface, 2, func(c *wlturbo.Context) wlturbo.Proxy { return cursorshape.NewWpCursorShapeManager(c) }, false}, | |
| 81 | + | {tablet.TabletManagerInterface, 2, func(c *wlturbo.Context) wlturbo.Proxy { return tablet.NewTabletManager(c) }, true}, | |
| 82 | + | {textinput.TextInputManagerV3Interface, 2, func(c *wlturbo.Context) wlturbo.Proxy { return textinput.NewTextInputManagerV3(c) }, false}, | |
| 83 | + | {alphamodifier.WpAlphaModifierInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return alphamodifier.NewWpAlphaModifier(c) }, false}, | |
| 84 | + | {colormanagement.WpColorManagerInterface, 3, func(c *wlturbo.Context) wlturbo.Proxy { return colormanagement.NewWpColorManager(c) }, false}, | |
| 85 | + | {colorrepresentation.WpColorRepresentationManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return colorrepresentation.NewWpColorRepresentationManager(c) }, false}, | |
| 86 | + | {committiming.WpCommitTimingManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return committiming.NewWpCommitTimingManager(c) }, false}, | |
| 87 | + | {contenttype.WpContentTypeManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return contenttype.NewWpContentTypeManager(c) }, false}, | |
| 88 | + | {datacontrol.ExtDataControlManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return datacontrol.NewExtDataControlManager(c) }, false}, | |
| 89 | + | {drmlease.WpDrmLeaseDeviceInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return drmlease.NewWpDrmLeaseDevice(c) }, true}, | |
| 90 | + | {extforeigntoplevel.ExtForeignToplevelListInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return extforeigntoplevel.NewExtForeignToplevelList(c) }, true}, | |
| 91 | + | {fifo.WpFifoManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return fifo.NewWpFifoManager(c) }, false}, | |
| 92 | + | {foreigntoplevel.ForeignToplevelManagerInterface, 3, func(c *wlturbo.Context) wlturbo.Proxy { return foreigntoplevel.NewForeignToplevelManager(c) }, false}, | |
| 93 | + | {idleinhibit.IdleInhibitManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return idleinhibit.NewIdleInhibitManager(c) }, false}, | |
| 94 | + | {idlenotify.ExtIdleNotifierInterface, 2, func(c *wlturbo.Context) wlturbo.Proxy { return idlenotify.NewExtIdleNotifier(c) }, false}, | |
| 95 | + | {imagecapturesource.ExtOutputImageCaptureSourceManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { | |
| 96 | + | return imagecapturesource.NewExtOutputImageCaptureSourceManager(c) | |
| 97 | + | }, false}, | |
| 98 | + | {imagecapturesource.ExtForeignToplevelImageCaptureSourceManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { | |
| 99 | + | return imagecapturesource.NewExtForeignToplevelImageCaptureSourceManager(c) | |
| 100 | + | }, true}, | |
| 101 | + | {imagecopycapture.ExtImageCopyCaptureManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return imagecopycapture.NewExtImageCopyCaptureManager(c) }, false}, | |
| 102 | + | {inputmethod.InputMethodManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return inputmethod.NewInputMethodManager(c) }, false}, | |
| 103 | + | {kdeserverdecoration.OrgKdeKwinServerDecorationManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { | |
| 104 | + | return kdeserverdecoration.NewOrgKdeKwinServerDecorationManager(c) | |
| 105 | + | }, false}, | |
| 106 | + | {layershell.LayerShellInterface, 5, func(c *wlturbo.Context) wlturbo.Proxy { return layershell.NewLayerShell(c) }, false}, | |
| 107 | + | {outputmanagement.OutputManagerInterface, 4, func(c *wlturbo.Context) wlturbo.Proxy { return outputmanagement.NewOutputManager(c) }, false}, | |
| 108 | + | {outputpower.OutputPowerManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return outputpower.NewOutputPowerManager(c) }, false}, | |
| 109 | + | {pointerconstraints.PointerConstraintsInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return pointerconstraints.NewPointerConstraints(c) }, false}, | |
| 110 | + | {pointerwarp.WpPointerWarpInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return pointerwarp.NewWpPointerWarp(c) }, false}, | |
| 111 | + | {presentation.WpPresentationInterface, 2, func(c *wlturbo.Context) wlturbo.Proxy { return presentation.NewWpPresentation(c) }, false}, | |
| 112 | + | {primaryselection.PrimarySelectionDeviceManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return primaryselection.NewPrimarySelectionDeviceManager(c) }, false}, | |
| 113 | + | {relativepointer.RelativePointerManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return relativepointer.NewRelativePointerManager(c) }, false}, | |
| 114 | + | {screencopy.ScreencopyManagerInterface, 3, func(c *wlturbo.Context) wlturbo.Proxy { return screencopy.NewScreencopyManager(c) }, false}, | |
| 115 | + | {shortcutsinhibit.KeyboardShortcutsInhibitManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return shortcutsinhibit.NewKeyboardShortcutsInhibitManager(c) }, false}, | |
| 116 | + | {tearingcontrol.WpTearingControlManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return tearingcontrol.NewWpTearingControlManager(c) }, false}, | |
| 117 | + | {virtualkeyboard.VirtualKeyboardManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return virtualkeyboard.NewVirtualKeyboardManager(c) }, false}, | |
| 118 | + | {workspace.ExtWorkspaceManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return workspace.NewExtWorkspaceManager(c) }, false}, | |
| 119 | + | {xdgactivation.XdgActivationInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return xdgactivation.NewXdgActivation(c) }, false}, | |
| 120 | + | {xdgdecoration.ZxdgDecorationManagerInterface, 2, func(c *wlturbo.Context) wlturbo.Proxy { return xdgdecoration.NewZxdgDecorationManager(c) }, false}, | |
| 121 | + | {xdgoutput.ZxdgOutputManagerInterface, 3, func(c *wlturbo.Context) wlturbo.Proxy { return xdgoutput.NewZxdgOutputManager(c) }, false}, | |
| 122 | + | } | |
| 123 | + | } | |
| 124 | + | ||
| 125 | + | // waitGlobal blocks in Dispatch until iface is announced. wl_output is added | |
| 126 | + | // by the compositor after startup, so it can follow the first roundtrip. The | |
| 127 | + | // instance context ends a wait that never completes. | |
| 128 | + | func (h *headlessInstance) waitGlobal(t *testing.T, d *wlturbo.Display, iface string) { | |
| 129 | + | t.Helper() | |
| 130 | + | for { | |
| 131 | + | if _, ok := d.Registry().FindGlobal(iface); ok { | |
| 132 | + | return | |
| 133 | + | } | |
| 134 | + | if e := d.Dispatch(); e != nil { | |
| 135 | + | t.Fatalf("waiting for %s: %v (ctx %v)\n%s", iface, e, h.ctx.Err(), h.Log()) | |
| 136 | + | } | |
| 137 | + | } | |
| 138 | + | } | |
| 139 | + | ||
| 140 | + | // bindOne binds a global at its negotiated version and fails on any error. | |
| 141 | + | func (h *headlessInstance) bindOne(t *testing.T, d *wlturbo.Display, iface string, supported uint32, p wlturbo.Proxy) uint32 { | |
| 142 | + | t.Helper() | |
| 143 | + | v, e := d.Registry().BindNegotiated(iface, supported, p) | |
| 144 | + | if e != nil { | |
| 145 | + | t.Fatalf("bind %s: %v\n%s", iface, e, h.Log()) | |
| 146 | + | } | |
| 147 | + | return v | |
| 148 | + | } | |
| 149 | + | ||
| 150 | + | func TestHeadlessExtensions(t *testing.T) { | |
| 151 | + | h := startHeadless(t) | |
| 152 | + | ||
| 153 | + | t.Run("bind announced globals", func(t *testing.T) { | |
| 154 | + | d := h.connect(t) | |
| 155 | + | h.waitGlobal(t, d, wayland.OutputInterface) | |
| 156 | + | for _, b := range headlessBindings() { | |
| 157 | + | g, ok := d.Registry().FindGlobal(b.iface) | |
| 158 | + | if !ok { | |
| 159 | + | if b.optional { | |
| 160 | + | t.Logf("%s absent (optional: hardware, device or build dependent)", b.iface) | |
| 161 | + | } else { | |
| 162 | + | t.Errorf("%s not announced", b.iface) | |
| 163 | + | } | |
| 164 | + | continue | |
| 165 | + | } | |
| 166 | + | p := b.make(d.Context()) | |
| 167 | + | v, e := d.Registry().BindNegotiated(b.iface, b.supported, p) | |
| 168 | + | if e != nil { | |
| 169 | + | t.Errorf("bind %s: %v", b.iface, e) | |
| 170 | + | continue | |
| 171 | + | } | |
| 172 | + | want := min(g.Version, b.supported) | |
| 173 | + | if v != want || v == 0 { | |
| 174 | + | t.Errorf("%s negotiated %d, announced %d supported %d", b.iface, v, g.Version, b.supported) | |
| 175 | + | } | |
| 176 | + | if pv, ok := p.(interface{ Version() uint32 }); ok && pv.Version() != v { | |
| 177 | + | t.Errorf("%s proxy version %d, negotiated %d", b.iface, pv.Version(), v) | |
| 178 | + | } | |
| 179 | + | t.Logf("%s announced=%d supported=%d negotiated=%d", b.iface, g.Version, b.supported, v) | |
| 180 | + | } | |
| 181 | + | // Every bind request is validated by the compositor before this returns. | |
| 182 | + | h.sync(t, d, "bind all") | |
| 183 | + | // Report announced globals that no generated package covers. | |
| 184 | + | known := map[string]bool{"wl_fixes": true} | |
| 185 | + | for _, b := range headlessBindings() { | |
| 186 | + | known[b.iface] = true | |
| 187 | + | } | |
| 188 | + | var extra []string | |
| 189 | + | for _, g := range d.Registry().GetGlobals() { | |
| 190 | + | if !known[g.Interface] { | |
| 191 | + | extra = append(extra, g.Interface) | |
| 192 | + | } | |
| 193 | + | } | |
| 194 | + | sort.Strings(extra) | |
| 195 | + | t.Logf("announced without a client binding: %v", extra) | |
| 196 | + | }) | |
| 197 | + | ||
| 198 | + | t.Run("output description", func(t *testing.T) { | |
| 199 | + | d := h.connect(t) | |
| 200 | + | h.waitGlobal(t, d, wayland.OutputInterface) | |
| 201 | + | out := wayland.NewOutput(d.Context()) | |
| 202 | + | h.bindOne(t, d, wayland.OutputInterface, 4, out) | |
| 203 | + | xm := xdgoutput.NewZxdgOutputManager(d.Context()) | |
| 204 | + | h.bindOne(t, d, xdgoutput.ZxdgOutputManagerInterface, 3, xm) | |
| 205 | + | xo, e := xm.GetXdgOutput(out) | |
| 206 | + | noerr(t, e) | |
| 207 | + | var lw, lh int32 | |
| 208 | + | var name string | |
| 209 | + | var wlDone, xdgDone bool | |
| 210 | + | var modes int | |
| 211 | + | out.OnMode(func(flags uint32, w, h, refresh int32) { modes++ }) | |
| 212 | + | out.OnDone(func() { wlDone = true }) | |
| 213 | + | xo.OnLogicalSize(func(w, h int32) { lw, lh = w, h }) | |
| 214 | + | xo.OnName(func(n string) { name = n }) | |
| 215 | + | xo.OnDone(func() { xdgDone = true }) | |
| 216 | + | // Registered after the bind request but before any event is read. | |
| 217 | + | h.sync(t, d, "xdg_output") | |
| 218 | + | if lw != 640 || lh != 480 || name == "" || modes == 0 || !(wlDone || xdgDone) { | |
| 219 | + | t.Fatalf("logical=%dx%d name=%q modes=%d wl_done=%t xdg_done=%t\n%s", lw, lh, name, modes, wlDone, xdgDone, h.Log()) | |
| 220 | + | } | |
| 221 | + | t.Logf("output %q logical %dx%d", name, lw, lh) | |
| 222 | + | ||
| 223 | + | // wlr-output-management lists the same output as a head with modes. | |
| 224 | + | om := outputmanagement.NewOutputManager(d.Context()) | |
| 225 | + | h.bindOne(t, d, outputmanagement.OutputManagerInterface, 4, om) | |
| 226 | + | // Head events arrive in any order, so each head keeps its own record. | |
| 227 | + | type head struct { | |
| 228 | + | name string | |
| 229 | + | modes int | |
| 230 | + | } | |
| 231 | + | var heads []*head | |
| 232 | + | done := false | |
| 233 | + | om.OnHead(func(hd *outputmanagement.OutputHead) { | |
| 234 | + | rec := &head{} | |
| 235 | + | heads = append(heads, rec) | |
| 236 | + | hd.OnName(func(s string) { rec.name = s }) | |
| 237 | + | hd.OnMode(func(*outputmanagement.OutputMode) { rec.modes++ }) | |
| 238 | + | }) | |
| 239 | + | om.OnDone(func(serial uint32) { done = true }) | |
| 240 | + | h.sync(t, d, "output manager") | |
| 241 | + | found := false | |
| 242 | + | for _, rec := range heads { | |
| 243 | + | found = found || (rec.name == name && rec.modes > 0) | |
| 244 | + | } | |
| 245 | + | if !done || !found { | |
| 246 | + | t.Fatalf("done=%t want head %q with modes; heads:%s\n%s", done, name, func() (s string) { | |
| 247 | + | for _, rec := range heads { | |
| 248 | + | s += fmt.Sprintf(" %q/%d", rec.name, rec.modes) | |
| 249 | + | } | |
| 250 | + | return | |
| 251 | + | }(), h.Log()) | |
| 252 | + | } | |
| 253 | + | noerr(t, xo.Destroy()) | |
| 254 | + | noerr(t, om.Stop()) | |
| 255 | + | h.sync(t, d, "output teardown") | |
| 256 | + | }) | |
| 257 | + | ||
| 258 | + | t.Run("decoration negotiation", func(t *testing.T) { | |
| 259 | + | d := h.connect(t) | |
| 260 | + | compositor := wayland.NewCompositor(d.Context()) | |
| 261 | + | h.bindOne(t, d, wayland.CompositorInterface, 6, compositor) | |
| 262 | + | wm := xdgshell.NewXdgWmBase(d.Context()) | |
| 263 | + | h.bindOne(t, d, xdgshell.XdgWmBaseInterface, 6, wm) | |
| 264 | + | dm := xdgdecoration.NewZxdgDecorationManager(d.Context()) | |
| 265 | + | h.bindOne(t, d, xdgdecoration.ZxdgDecorationManagerInterface, 2, dm) | |
| 266 | + | kde := kdeserverdecoration.NewOrgKdeKwinServerDecorationManager(d.Context()) | |
| 267 | + | var kdeDefault uint32 = 99 | |
| 268 | + | kde.OnDefaultMode(func(m uint32) { kdeDefault = m }) | |
| 269 | + | h.bindOne(t, d, kdeserverdecoration.OrgKdeKwinServerDecorationManagerInterface, 1, kde) | |
| 270 | + | ||
| 271 | + | surface, e := compositor.CreateSurface() | |
| 272 | + | noerr(t, e) | |
| 273 | + | xs, e := wm.GetXdgSurface(surface) | |
| 274 | + | noerr(t, e) | |
| 275 | + | top, e := xs.GetToplevel() | |
| 276 | + | noerr(t, e) | |
| 277 | + | deco, e := dm.GetToplevelDecoration(top) | |
| 278 | + | noerr(t, e) | |
| 279 | + | var modes []uint32 | |
| 280 | + | deco.OnConfigure(func(m uint32) { modes = append(modes, m) }) | |
| 281 | + | // A client asking for client-side is answered with the compositor's server-side mode. | |
| 282 | + | noerr(t, deco.SetMode(xdgdecoration.MODE_CLIENT_SIDE)) | |
| 283 | + | xs.OnConfigure(func(serial uint32) { noerr(t, xs.AckConfigure(serial)) }) | |
| 284 | + | // The initial empty commit lets the compositor send xdg_surface.configure. | |
| 285 | + | noerr(t, surface.Commit()) | |
| 286 | + | h.sync(t, d, "decoration") | |
| 287 | + | if len(modes) == 0 || modes[len(modes)-1] != xdgdecoration.MODE_SERVER_SIDE { | |
| 288 | + | t.Fatalf("xdg decoration modes %v\n%s", modes, h.Log()) | |
| 289 | + | } | |
| 290 | + | kdeDeco, e := kde.Create(surface) | |
| 291 | + | noerr(t, e) | |
| 292 | + | var kdeMode uint32 = 99 | |
| 293 | + | kdeDeco.OnMode(func(m uint32) { kdeMode = m }) | |
| 294 | + | h.sync(t, d, "kde decoration") | |
| 295 | + | if kdeDefault != kdeserverdecoration.ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER || kdeMode != kdeserverdecoration.ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER { | |
| 296 | + | t.Fatalf("kde default=%d mode=%d", kdeDefault, kdeMode) | |
| 297 | + | } | |
| 298 | + | noerr(t, kdeDeco.Release()) | |
| 299 | + | noerr(t, deco.Destroy()) | |
| 300 | + | noerr(t, top.Destroy()) | |
| 301 | + | noerr(t, xs.Destroy()) | |
| 302 | + | noerr(t, surface.Destroy()) | |
| 303 | + | h.sync(t, d, "decoration teardown") | |
| 304 | + | }) | |
| 305 | + | ||
| 306 | + | t.Run("workspaces", func(t *testing.T) { | |
| 307 | + | d := h.connect(t) | |
| 308 | + | wsm := workspace.NewExtWorkspaceManager(d.Context()) | |
| 309 | + | groups, workspaces, done, finished := 0, 0, false, false | |
| 310 | + | names := map[string]bool{} | |
| 311 | + | wsm.OnWorkspaceGroup(func(*workspace.ExtWorkspaceGroupHandle) { groups++ }) | |
| 312 | + | wsm.OnWorkspace(func(w *workspace.ExtWorkspaceHandle) { | |
| 313 | + | workspaces++ | |
| 314 | + | w.OnName(func(n string) { names[n] = true }) | |
| 315 | + | }) | |
| 316 | + | wsm.OnDone(func() { done = true }) | |
| 317 | + | wsm.OnFinished(func() { finished = true }) | |
| 318 | + | h.bindOne(t, d, workspace.ExtWorkspaceManagerInterface, 1, wsm) | |
| 319 | + | h.sync(t, d, "workspace snapshot") | |
| 320 | + | if !done || groups == 0 || workspaces == 0 || len(names) == 0 { | |
| 321 | + | t.Fatalf("done=%t groups=%d workspaces=%d names=%v\n%s", done, groups, workspaces, names, h.Log()) | |
| 322 | + | } | |
| 323 | + | t.Logf("workspaces: groups=%d workspaces=%d names=%v", groups, workspaces, names) | |
| 324 | + | // stop is answered by finished; wait for it with the blocking dispatch. | |
| 325 | + | noerr(t, wsm.Stop()) | |
| 326 | + | for !finished { | |
| 327 | + | if e := d.Dispatch(); e != nil { | |
| 328 | + | t.Fatalf("waiting for finished: %v\n%s", e, h.Log()) | |
| 329 | + | } | |
| 330 | + | } | |
| 331 | + | }) | |
| 332 | + | ||
| 333 | + | t.Run("color capabilities", func(t *testing.T) { | |
| 334 | + | d := h.connect(t) | |
| 335 | + | cm := colormanagement.NewWpColorManager(d.Context()) | |
| 336 | + | intents, features, tfs, prims := map[uint32]bool{}, map[uint32]bool{}, map[uint32]bool{}, map[uint32]bool{} | |
| 337 | + | cmDone := false | |
| 338 | + | cm.OnSupportedIntent(func(v uint32) { intents[v] = true }) | |
| 339 | + | cm.OnSupportedFeature(func(v uint32) { features[v] = true }) | |
| 340 | + | cm.OnSupportedTfNamed(func(v uint32) { tfs[v] = true }) | |
| 341 | + | cm.OnSupportedPrimariesNamed(func(v uint32) { prims[v] = true }) | |
| 342 | + | cm.OnDone(func() { cmDone = true }) | |
| 343 | + | version := h.bindOne(t, d, colormanagement.WpColorManagerInterface, 3, cm) | |
| 344 | + | ||
| 345 | + | cr := colorrepresentation.NewWpColorRepresentationManager(d.Context()) | |
| 346 | + | alpha, crDone := map[uint32]bool{}, false | |
| 347 | + | cr.OnSupportedAlphaMode(func(v uint32) { alpha[v] = true }) | |
| 348 | + | cr.OnDone(func() { crDone = true }) | |
| 349 | + | h.bindOne(t, d, colorrepresentation.WpColorRepresentationManagerInterface, 1, cr) | |
| 350 | + | h.sync(t, d, "color capabilities") | |
| 351 | + | ||
| 352 | + | if !cmDone || !intents[colormanagement.RENDER_INTENT_PERCEPTUAL] || !features[colormanagement.FEATURE_PARAMETRIC] || | |
| 353 | + | !tfs[colormanagement.TRANSFER_FUNCTION_SRGB] || !prims[colormanagement.PRIMARIES_SRGB] { | |
| 354 | + | t.Fatalf("color manager v%d done=%t intents=%v features=%v tf=%v primaries=%v\n%s", version, cmDone, intents, features, tfs, prims, h.Log()) | |
| 355 | + | } | |
| 356 | + | if !crDone || len(alpha) == 0 { | |
| 357 | + | t.Fatalf("color representation done=%t alpha=%v", crDone, alpha) | |
| 358 | + | } | |
| 359 | + | t.Logf("color v%d intents=%v features=%v tf=%v primaries=%v alpha=%v", version, intents, features, tfs, prims, alpha) | |
| 360 | + | }) | |
| 361 | + | ||
| 362 | + | t.Run("presentation clock", func(t *testing.T) { | |
| 363 | + | d := h.connect(t) | |
| 364 | + | p := presentation.NewWpPresentation(d.Context()) | |
| 365 | + | clock, got := uint32(0), false | |
| 366 | + | p.OnClockId(func(id uint32) { clock, got = id, true }) | |
| 367 | + | h.bindOne(t, d, presentation.WpPresentationInterface, 2, p) | |
| 368 | + | h.sync(t, d, "presentation clock") | |
| 369 | + | // An empty commit produces no frame, so only the clock is asserted. | |
| 370 | + | if !got || clock != unix.CLOCK_MONOTONIC { | |
| 371 | + | t.Fatalf("clock_id got=%t %d, want CLOCK_MONOTONIC", got, clock) | |
| 372 | + | } | |
| 373 | + | noerr(t, p.Destroy()) | |
| 374 | + | h.sync(t, d, "presentation teardown") | |
| 375 | + | }) | |
| 376 | + | ||
| 377 | + | t.Run("layer surface configure", func(t *testing.T) { | |
| 378 | + | d := h.connect(t) | |
| 379 | + | h.waitGlobal(t, d, wayland.OutputInterface) | |
| 380 | + | compositor := wayland.NewCompositor(d.Context()) | |
| 381 | + | h.bindOne(t, d, wayland.CompositorInterface, 6, compositor) | |
| 382 | + | shell := layershell.NewLayerShell(d.Context()) | |
| 383 | + | h.bindOne(t, d, layershell.LayerShellInterface, 5, shell) | |
| 384 | + | surface, e := compositor.CreateSurface() | |
| 385 | + | noerr(t, e) | |
| 386 | + | ls, e := shell.GetLayerSurface(surface, nil, layershell.LAYER_TOP, "wlturbo-test") | |
| 387 | + | noerr(t, e) | |
| 388 | + | noerr(t, ls.SetAnchor(layershell.ANCHOR_TOP|layershell.ANCHOR_LEFT|layershell.ANCHOR_RIGHT)) | |
| 389 | + | noerr(t, ls.SetSize(0, 30)) | |
| 390 | + | var serial, w, hgt uint32 | |
| 391 | + | configured := false | |
| 392 | + | ls.OnConfigure(func(s, cw, ch uint32) { serial, w, hgt, configured = s, cw, ch, true }) | |
| 393 | + | // The initial empty commit asks the compositor for the first configure. | |
| 394 | + | noerr(t, surface.Commit()) | |
| 395 | + | h.sync(t, d, "layer configure") | |
| 396 | + | if !configured || w != 640 || hgt != 30 { | |
| 397 | + | t.Fatalf("configured=%t %dx%d\n%s", configured, w, hgt, h.Log()) | |
| 398 | + | } | |
| 399 | + | noerr(t, ls.AckConfigure(serial)) | |
| 400 | + | noerr(t, ls.Destroy()) | |
| 401 | + | noerr(t, surface.Destroy()) | |
| 402 | + | h.sync(t, d, "layer teardown") | |
| 403 | + | }) | |
| 404 | + | ||
| 405 | + | t.Run("relative pointer object", func(t *testing.T) { | |
| 406 | + | d := h.connect(t) | |
| 407 | + | seat := wayland.NewSeat(d.Context()) | |
| 408 | + | var caps uint32 | |
| 409 | + | seat.OnCapabilities(func(c uint32) { caps = c }) | |
| 410 | + | h.bindOne(t, d, wayland.SeatInterface, 8, seat) | |
| 411 | + | rm := relativepointer.NewRelativePointerManager(d.Context()) | |
| 412 | + | h.bindOne(t, d, relativepointer.RelativePointerManagerInterface, 1, rm) | |
| 413 | + | h.sync(t, d, "seat capabilities") | |
| 414 | + | if caps&wayland.CAPABILITY_POINTER == 0 { | |
| 415 | + | t.Skipf("seat has no pointer (caps %d); headless input capability dependent", caps) | |
| 416 | + | } | |
| 417 | + | ptr, e := seat.GetPointer() | |
| 418 | + | noerr(t, e) | |
| 419 | + | rp, e := rm.GetRelativePointer(ptr) | |
| 420 | + | noerr(t, e) | |
| 421 | + | // Motion needs pointer focus on a mapped surface, which an empty | |
| 422 | + | // commit cannot provide; creation and teardown must still be valid. | |
| 423 | + | rp.OnRelativeMotion(func(uint32, uint32, wlturbo.Fixed, wlturbo.Fixed, wlturbo.Fixed, wlturbo.Fixed) {}) | |
| 424 | + | h.sync(t, d, "relative pointer") | |
| 425 | + | noerr(t, rp.Destroy()) | |
| 426 | + | noerr(t, ptr.Release()) | |
| 427 | + | noerr(t, rm.Destroy()) | |
| 428 | + | h.sync(t, d, "relative pointer teardown") | |
| 429 | + | }) | |
| 430 | + | } | |
A client/headless_test.go +319 -0
| @@ -0,0 +1,319 @@ | |||
| 1 | + | //go:build linux | |
| 2 | + | ||
| 3 | + | package client_test | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "context" | |
| 7 | + | "errors" | |
| 8 | + | "fmt" | |
| 9 | + | "net" | |
| 10 | + | "os" | |
| 11 | + | "os/exec" | |
| 12 | + | "path/filepath" | |
| 13 | + | "strings" | |
| 14 | + | "syscall" | |
| 15 | + | "testing" | |
| 16 | + | "time" | |
| 17 | + | ||
| 18 | + | "github.com/bnema/go-wayland-bindings/client/fractionalscale" | |
| 19 | + | "github.com/bnema/go-wayland-bindings/client/linuxdmabuf" | |
| 20 | + | drmsyncobj "github.com/bnema/go-wayland-bindings/client/linuxdrmsyncobj" | |
| 21 | + | "github.com/bnema/go-wayland-bindings/client/viewporter" | |
| 22 | + | "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 23 | + | "github.com/bnema/go-wayland-bindings/client/xdgshell" | |
| 24 | + | "github.com/bnema/wlturbo" | |
| 25 | + | "golang.org/x/sys/unix" | |
| 26 | + | ) | |
| 27 | + | ||
| 28 | + | func TestHeadlessNeferWL(t *testing.T) { | |
| 29 | + | h := startHeadless(t) | |
| 30 | + | d := h.connect(t) | |
| 31 | + | bind := h.binder(t, d) | |
| 32 | + | ctx := h.ctx | |
| 33 | + | compositor := wayland.NewCompositor(d.Context()) | |
| 34 | + | bind(wayland.CompositorInterface, 6, compositor) | |
| 35 | + | wm := xdgshell.NewXdgWmBase(d.Context()) | |
| 36 | + | bind(xdgshell.XdgWmBaseInterface, 7, wm) | |
| 37 | + | dm := linuxdmabuf.NewLinuxDmabuf(d.Context()) | |
| 38 | + | if bind(linuxdmabuf.LinuxDmabufInterface, 4, dm) < 4 { | |
| 39 | + | t.Fatal("dmabuf feedback requires v4") | |
| 40 | + | } | |
| 41 | + | syncManager := drmsyncobj.NewWpLinuxDrmSyncobjManager(d.Context()) | |
| 42 | + | bind(drmsyncobj.WpLinuxDrmSyncobjManagerInterface, 1, syncManager) | |
| 43 | + | dataManager := wayland.NewDataDeviceManager(d.Context()) | |
| 44 | + | dataVersion := bind(wayland.DataDeviceManagerInterface, 4, dataManager) | |
| 45 | + | vp := viewporter.NewWpViewporter(d.Context()) | |
| 46 | + | bind(viewporter.WpViewporterInterface, 1, vp) | |
| 47 | + | if g, ok := d.Registry().FindGlobal(fractionalscale.WpFractionalScaleManagerInterface); ok { | |
| 48 | + | fs := fractionalscale.NewWpFractionalScaleManager(d.Context()) | |
| 49 | + | v := bind(g.Interface, 1, fs) | |
| 50 | + | if v != 1 { | |
| 51 | + | t.Fatalf("fractional scale version %d", v) | |
| 52 | + | } | |
| 53 | + | noerr(t, fs.Destroy()) | |
| 54 | + | } else { | |
| 55 | + | t.Log("fractional scale absent") | |
| 56 | + | } | |
| 57 | + | surface, e := compositor.CreateSurface() | |
| 58 | + | noerr(t, e) | |
| 59 | + | xs, e := wm.GetXdgSurface(surface) | |
| 60 | + | noerr(t, e) | |
| 61 | + | top, e := xs.GetToplevel() | |
| 62 | + | noerr(t, e) | |
| 63 | + | feedback, e := dm.GetSurfaceFeedback(surface) | |
| 64 | + | noerr(t, e) | |
| 65 | + | ss, e := syncManager.GetSurface(surface) | |
| 66 | + | noerr(t, e) | |
| 67 | + | configured, done, mainDevice, tableOK := false, false, false, false | |
| 68 | + | top.OnConfigure(func(w, h int32, states []byte) { t.Logf("xdg_toplevel.configure %dx%d", w, h) }) | |
| 69 | + | xs.OnConfigure(func(serial uint32) { | |
| 70 | + | noerr(t, xs.AckConfigure(serial)) | |
| 71 | + | configured = true | |
| 72 | + | t.Logf("xdg_surface.configure ack=%d", serial) | |
| 73 | + | }) | |
| 74 | + | feedback.OnMainDevice(func(b []byte) { mainDevice = len(b) == 8; t.Logf("main_device=%x", b) }) | |
| 75 | + | feedback.OnFormatTable(func(fd *wlturbo.OwnedFD, size uint32) { | |
| 76 | + | entries, e := linuxdmabuf.ReadFormatTable(fd, size) | |
| 77 | + | if e != nil { | |
| 78 | + | t.Errorf("format table: %v", e) | |
| 79 | + | } else { | |
| 80 | + | tableOK = len(entries) > 0 | |
| 81 | + | t.Logf("format-table entries=%d", len(entries)) | |
| 82 | + | } | |
| 83 | + | }) | |
| 84 | + | feedback.OnDone(func() { done = true }) | |
| 85 | + | // Initial empty commit requests xdg configure; no buffer or window is shown. | |
| 86 | + | noerr(t, surface.Commit()) | |
| 87 | + | for (!configured || !done) && ctx.Err() == nil { | |
| 88 | + | if e := d.Dispatch(); e != nil { | |
| 89 | + | t.Fatalf("dispatch: %v\n%s", e, h.Log()) | |
| 90 | + | } | |
| 91 | + | } | |
| 92 | + | if !configured || !done || !mainDevice || !tableOK { | |
| 93 | + | t.Fatalf("configure=%t feedback=%t main_device=%t table=%t: %v\n%s", configured, done, mainDevice, tableOK, ctx.Err(), h.Log()) | |
| 94 | + | } | |
| 95 | + | noerr(t, surface.Commit()) | |
| 96 | + | // Drop all child objects while their parents are still alive. | |
| 97 | + | noerr(t, ss.Destroy()) | |
| 98 | + | noerr(t, feedback.Destroy()) | |
| 99 | + | noerr(t, top.Destroy()) | |
| 100 | + | noerr(t, xs.Destroy()) | |
| 101 | + | noerr(t, surface.Destroy()) | |
| 102 | + | noerr(t, vp.Destroy()) | |
| 103 | + | if dataVersion >= 4 { | |
| 104 | + | noerr(t, dataManager.Release()) | |
| 105 | + | } | |
| 106 | + | noerr(t, syncManager.Destroy()) | |
| 107 | + | noerr(t, dm.Destroy()) | |
| 108 | + | noerr(t, wm.Destroy()) | |
| 109 | + | noerr(t, d.Close()) | |
| 110 | + | } | |
| 111 | + | ||
| 112 | + | // headlessInstance is one isolated NeferWL process with its own runtime, | |
| 113 | + | // config, data and state directories. Cleanup kills the whole process group | |
| 114 | + | // and reaps it. ctx expires at the test deadline or when the process exits, so | |
| 115 | + | // a blocking Dispatch on a connection made by connect always returns. | |
| 116 | + | type headlessInstance struct { | |
| 117 | + | ctx context.Context | |
| 118 | + | socket string | |
| 119 | + | logf *os.File | |
| 120 | + | done chan struct{} // closed after the process is reaped | |
| 121 | + | waitErr error // valid once done is closed | |
| 122 | + | } | |
| 123 | + | ||
| 124 | + | // startHeadless launches WLTURBO_HEADLESS or skips the test when it is unset. | |
| 125 | + | // It returns once the compositor socket exists, or fails with the process log | |
| 126 | + | // if the process exits early or the 18s test deadline expires. | |
| 127 | + | func startHeadless(t *testing.T) *headlessInstance { | |
| 128 | + | t.Helper() | |
| 129 | + | binary := os.Getenv("WLTURBO_HEADLESS") | |
| 130 | + | if binary == "" { | |
| 131 | + | t.Skip("set WLTURBO_HEADLESS to a NeferWL binary") | |
| 132 | + | } | |
| 133 | + | binary, e := filepath.Abs(binary) | |
| 134 | + | noerr(t, e) | |
| 135 | + | root := t.TempDir() | |
| 136 | + | dirs := map[string]string{} | |
| 137 | + | for _, name := range []string{"run", "config", "data", "state"} { | |
| 138 | + | dirs[name] = filepath.Join(root, name) | |
| 139 | + | noerr(t, os.Mkdir(dirs[name], 0700)) | |
| 140 | + | } | |
| 141 | + | ctx, cancel := context.WithTimeout(context.Background(), 18*time.Second) | |
| 142 | + | t.Cleanup(cancel) | |
| 143 | + | logf, e := os.Create(filepath.Join(root, "neferwl.log")) | |
| 144 | + | noerr(t, e) | |
| 145 | + | t.Cleanup(func() { _ = logf.Close() }) | |
| 146 | + | h := &headlessInstance{logf: logf, done: make(chan struct{})} | |
| 147 | + | // Watch the runtime directory before starting so the socket creation cannot be missed. | |
| 148 | + | // Non-blocking makes os.File use the poller, so Close unblocks the reader goroutine. | |
| 149 | + | ifd, e := unix.InotifyInit1(unix.IN_NONBLOCK | unix.IN_CLOEXEC) | |
| 150 | + | noerr(t, e) | |
| 151 | + | watch := os.NewFile(uintptr(ifd), "inotify") | |
| 152 | + | t.Cleanup(func() { _ = watch.Close() }) | |
| 153 | + | _, e = unix.InotifyAddWatch(ifd, dirs["run"], unix.IN_CREATE|unix.IN_ATTRIB) | |
| 154 | + | noerr(t, e) | |
| 155 | + | cmd := exec.Command(binary, "--backend=headless", "--no-terminal", "--no-xwayland", "--size", "640x480", "--timeout", "20s") | |
| 156 | + | cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} | |
| 157 | + | cmd.Env = append(cleanDisplayEnv(os.Environ()), | |
| 158 | + | "XDG_RUNTIME_DIR="+dirs["run"], "XDG_CONFIG_HOME="+dirs["config"], | |
| 159 | + | "XDG_DATA_HOME="+dirs["data"], "XDG_STATE_HOME="+dirs["state"]) | |
| 160 | + | cmd.Stdout = logf | |
| 161 | + | cmd.Stderr = logf | |
| 162 | + | noerr(t, cmd.Start()) | |
| 163 | + | // A failed startup must still terminate the process group and reap it. | |
| 164 | + | t.Cleanup(func() { | |
| 165 | + | _ = syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) | |
| 166 | + | <-h.done | |
| 167 | + | }) | |
| 168 | + | // Process exit cancels ctx, which also unblocks any Dispatch (see connect). | |
| 169 | + | ctx, stopCtx := context.WithCancel(ctx) | |
| 170 | + | t.Cleanup(stopCtx) | |
| 171 | + | h.ctx = ctx | |
| 172 | + | go func() { | |
| 173 | + | h.waitErr = cmd.Wait() | |
| 174 | + | close(h.done) | |
| 175 | + | stopCtx() | |
| 176 | + | }() | |
| 177 | + | events := make(chan struct{}, 1) | |
| 178 | + | go func() { | |
| 179 | + | buf := make([]byte, 4096) | |
| 180 | + | for { | |
| 181 | + | if _, e := watch.Read(buf); e != nil { | |
| 182 | + | return | |
| 183 | + | } | |
| 184 | + | select { | |
| 185 | + | case events <- struct{}{}: | |
| 186 | + | default: | |
| 187 | + | } | |
| 188 | + | } | |
| 189 | + | }() | |
| 190 | + | find := func() string { | |
| 191 | + | paths, _ := filepath.Glob(filepath.Join(dirs["run"], "wayland-*")) | |
| 192 | + | for _, path := range paths { | |
| 193 | + | if info, e := os.Stat(path); e == nil && info.Mode()&os.ModeSocket != 0 { | |
| 194 | + | return path | |
| 195 | + | } | |
| 196 | + | } | |
| 197 | + | return "" | |
| 198 | + | } | |
| 199 | + | for h.socket = find(); h.socket == ""; h.socket = find() { | |
| 200 | + | select { | |
| 201 | + | case <-events: | |
| 202 | + | case <-h.done: | |
| 203 | + | t.Fatalf("neferwl exited before serving: %v\n%s", h.waitErr, h.Log()) | |
| 204 | + | case <-ctx.Done(): | |
| 205 | + | t.Fatalf("headless socket timeout: %v\n%s", ctx.Err(), h.Log()) | |
| 206 | + | } | |
| 207 | + | } | |
| 208 | + | return h | |
| 209 | + | } | |
| 210 | + | ||
| 211 | + | // Log returns the tail of the compositor output. | |
| 212 | + | func (h *headlessInstance) Log() string { return headlessLog(h.logf) } | |
| 213 | + | ||
| 214 | + | // connect dials the compositor and completes the initial registry roundtrip. | |
| 215 | + | // The instance context closes the connection when the test deadline expires or | |
| 216 | + | // the compositor exits, so a blocking Dispatch returns instead of hanging. | |
| 217 | + | func (h *headlessInstance) connect(t *testing.T) *wlturbo.Display { | |
| 218 | + | t.Helper() | |
| 219 | + | var conn net.Conn | |
| 220 | + | for { | |
| 221 | + | var e error | |
| 222 | + | conn, e = (&net.Dialer{Timeout: time.Second}).DialContext(h.ctx, "unix", h.socket) | |
| 223 | + | if e == nil { | |
| 224 | + | break | |
| 225 | + | } | |
| 226 | + | // The socket file appears at bind(); listen() follows immediately, so | |
| 227 | + | // a refused dial is transient unless the compositor is gone. | |
| 228 | + | if !errors.Is(e, syscall.ECONNREFUSED) { | |
| 229 | + | t.Fatalf("dial: %v\n%s", e, h.Log()) | |
| 230 | + | } | |
| 231 | + | select { | |
| 232 | + | case <-h.done: | |
| 233 | + | t.Fatalf("neferwl exited before accepting: %v\n%s", h.waitErr, h.Log()) | |
| 234 | + | case <-h.ctx.Done(): | |
| 235 | + | t.Fatalf("dial timeout: %v\n%s", h.ctx.Err(), h.Log()) | |
| 236 | + | case <-time.After(5 * time.Millisecond): | |
| 237 | + | } | |
| 238 | + | } | |
| 239 | + | d, e := wlturbo.ConnectFromConn(conn) | |
| 240 | + | if e != nil { | |
| 241 | + | _ = conn.Close() | |
| 242 | + | t.Fatal(e) | |
| 243 | + | } | |
| 244 | + | t.Cleanup(func() { _ = d.Close() }) | |
| 245 | + | stop := context.AfterFunc(h.ctx, func() { _ = d.Close() }) | |
| 246 | + | t.Cleanup(func() { stop() }) | |
| 247 | + | h.sync(t, d, "registry roundtrip") | |
| 248 | + | return d | |
| 249 | + | } | |
| 250 | + | ||
| 251 | + | // binder returns a bind function that fails the test with the compositor log. | |
| 252 | + | func (h *headlessInstance) binder(t *testing.T, d *wlturbo.Display) func(string, uint32, wlturbo.Proxy) uint32 { | |
| 253 | + | return func(iface string, supported uint32, proxy wlturbo.Proxy) uint32 { | |
| 254 | + | t.Helper() | |
| 255 | + | v, err := d.Registry().BindNegotiated(iface, supported, proxy) | |
| 256 | + | if err != nil { | |
| 257 | + | t.Fatalf("bind %s: %v\n%s", iface, err, h.Log()) | |
| 258 | + | } | |
| 259 | + | t.Logf("%s negotiated=%d", iface, v) | |
| 260 | + | return v | |
| 261 | + | } | |
| 262 | + | } | |
| 263 | + | ||
| 264 | + | // sync completes a roundtrip, reporting compositor protocol errors with its log. | |
| 265 | + | func (h *headlessInstance) sync(t *testing.T, d *wlturbo.Display, what string) { | |
| 266 | + | t.Helper() | |
| 267 | + | if e := d.Roundtrip(); e != nil { | |
| 268 | + | t.Fatalf("%s: %v (ctx %v)\n%s", what, e, h.ctx.Err(), h.Log()) | |
| 269 | + | } | |
| 270 | + | } | |
| 271 | + | ||
| 272 | + | // headlessEnvDrop lists the environment prefixes the child must not inherit: | |
| 273 | + | // anything that could attach it to, or make it act on, the caller's session, | |
| 274 | + | // plus NeferWL's own configuration. The test client's own environment is not | |
| 275 | + | // changed; only the child process is isolated. | |
| 276 | + | var headlessEnvDrop = []string{"DISPLAY=", "WAYLAND_DISPLAY=", "WAYLAND_SOCKET=", "NOTIFY_SOCKET=", "DBUS_SESSION_BUS_ADDRESS=", | |
| 277 | + | "XDG_RUNTIME_DIR=", "XDG_CONFIG_HOME=", "XDG_DATA_HOME=", "XDG_STATE_HOME=", "XDG_SESSION_", "XDG_VTNR=", "XDG_SEAT=", | |
| 278 | + | "XDG_CURRENT_DESKTOP=", "NIRI_SOCKET=", "SWAYSOCK=", "HYPRLAND_INSTANCE_SIGNATURE=", "NEFERWL_"} | |
| 279 | + | ||
| 280 | + | func cleanDisplayEnv(in []string) []string { | |
| 281 | + | out := make([]string, 0, len(in)) | |
| 282 | + | next: | |
| 283 | + | for _, e := range in { | |
| 284 | + | for _, p := range headlessEnvDrop { | |
| 285 | + | if strings.HasPrefix(e, p) { | |
| 286 | + | continue next | |
| 287 | + | } | |
| 288 | + | } | |
| 289 | + | out = append(out, e) | |
| 290 | + | } | |
| 291 | + | return out | |
| 292 | + | } | |
| 293 | + | ||
| 294 | + | func TestCleanDisplayEnv(t *testing.T) { | |
| 295 | + | keep := []string{"PATH=/bin", "HOME=/h", "DISPLAYS=x", "XDG_DATA_DIRS=/d", "MY_NEFERWL_X=1"} | |
| 296 | + | in := append([]string(nil), keep...) | |
| 297 | + | for _, p := range headlessEnvDrop { | |
| 298 | + | e := p + "placeholder" | |
| 299 | + | if !strings.HasSuffix(p, "=") { | |
| 300 | + | e += "=1" // a prefix such as XDG_SESSION_ names a family of variables | |
| 301 | + | } | |
| 302 | + | in = append(in, e) | |
| 303 | + | } | |
| 304 | + | got := cleanDisplayEnv(in) | |
| 305 | + | if strings.Join(got, "\n") != strings.Join(keep, "\n") { | |
| 306 | + | t.Fatalf("cleanDisplayEnv = %q, want %q", got, keep) | |
| 307 | + | } | |
| 308 | + | } | |
| 309 | + | ||
| 310 | + | func headlessLog(f *os.File) string { | |
| 311 | + | b, e := os.ReadFile(f.Name()) | |
| 312 | + | if e != nil { | |
| 313 | + | return fmt.Sprint(e) | |
| 314 | + | } | |
| 315 | + | if len(b) > 8192 { | |
| 316 | + | b = b[len(b)-8192:] | |
| 317 | + | } | |
| 318 | + | return string(b) | |
| 319 | + | } | |
A client/idleinhibit/idleinhibit_generated.go +124 -0
| @@ -0,0 +1,124 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: idle_inhibit_unstable_v1 | |
| 3 | + | // Source: idle-inhibit-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2015 Samsung Electronics Co., Ltd | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package idleinhibit | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 31 | + | "github.com/bnema/wlturbo/wl" | |
| 32 | + | ) | |
| 33 | + | ||
| 34 | + | // IdleInhibitManagerInterface is the protocol interface name. | |
| 35 | + | const IdleInhibitManagerInterface = "zwp_idle_inhibit_manager_v1" | |
| 36 | + | ||
| 37 | + | // IdleInhibitManager is the generated binding for zwp_idle_inhibit_manager_v1 version 1. | |
| 38 | + | type IdleInhibitManager struct { | |
| 39 | + | wl.BaseProxy | |
| 40 | + | } | |
| 41 | + | ||
| 42 | + | // NewIdleInhibitManager returns an unbound IdleInhibitManager. | |
| 43 | + | func NewIdleInhibitManager(ctx *wl.Context) *IdleInhibitManager { | |
| 44 | + | obj := &IdleInhibitManager{} | |
| 45 | + | obj.SetContext(ctx) | |
| 46 | + | ctx.Register(obj) | |
| 47 | + | return obj | |
| 48 | + | } | |
| 49 | + | ||
| 50 | + | // Destroy the inhibit manager. | |
| 51 | + | func (o *IdleInhibitManager) Destroy() error { | |
| 52 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_idle_inhibit_manager_v1.destroy", Destructor: true}); err != nil { | |
| 53 | + | return err | |
| 54 | + | } | |
| 55 | + | return nil | |
| 56 | + | } | |
| 57 | + | ||
| 58 | + | // Create a new inhibitor object associated with the given surface. | |
| 59 | + | func (o *IdleInhibitManager) CreateInhibitor(surface *cross_wl_surface.Surface) (*IdleInhibitor, error) { | |
| 60 | + | var arg1 wl.Object | |
| 61 | + | if surface != nil { | |
| 62 | + | arg1 = surface | |
| 63 | + | } | |
| 64 | + | child := &IdleInhibitor{} | |
| 65 | + | child.SetContext(o.Context()) | |
| 66 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_idle_inhibit_manager_v1.create_inhibitor", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 67 | + | return nil, err | |
| 68 | + | } | |
| 69 | + | return child, nil | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | // EventSignature returns the declared event argument types in wire order. | |
| 73 | + | func (o *IdleInhibitManager) EventSignature(opcode uint16) (string, bool) { | |
| 74 | + | switch opcode { | |
| 75 | + | default: | |
| 76 | + | return "", false | |
| 77 | + | } | |
| 78 | + | } | |
| 79 | + | ||
| 80 | + | // Dispatch decodes one event on zwp_idle_inhibit_manager_v1 and calls the registered handlers. | |
| 81 | + | func (o *IdleInhibitManager) Dispatch(event *wl.Event) { | |
| 82 | + | switch event.Opcode { | |
| 83 | + | default: | |
| 84 | + | } | |
| 85 | + | } | |
| 86 | + | ||
| 87 | + | // IdleInhibitorInterface is the protocol interface name. | |
| 88 | + | const IdleInhibitorInterface = "zwp_idle_inhibitor_v1" | |
| 89 | + | ||
| 90 | + | // IdleInhibitor is the generated binding for zwp_idle_inhibitor_v1 version 1. | |
| 91 | + | type IdleInhibitor struct { | |
| 92 | + | wl.BaseProxy | |
| 93 | + | } | |
| 94 | + | ||
| 95 | + | // NewIdleInhibitor returns an unbound IdleInhibitor. | |
| 96 | + | func NewIdleInhibitor(ctx *wl.Context) *IdleInhibitor { | |
| 97 | + | obj := &IdleInhibitor{} | |
| 98 | + | obj.SetContext(ctx) | |
| 99 | + | ctx.Register(obj) | |
| 100 | + | return obj | |
| 101 | + | } | |
| 102 | + | ||
| 103 | + | // Remove the inhibitor effect from the associated wl_surface. | |
| 104 | + | func (o *IdleInhibitor) Destroy() error { | |
| 105 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_idle_inhibitor_v1.destroy", Destructor: true}); err != nil { | |
| 106 | + | return err | |
| 107 | + | } | |
| 108 | + | return nil | |
| 109 | + | } | |
| 110 | + | ||
| 111 | + | // EventSignature returns the declared event argument types in wire order. | |
| 112 | + | func (o *IdleInhibitor) EventSignature(opcode uint16) (string, bool) { | |
| 113 | + | switch opcode { | |
| 114 | + | default: | |
| 115 | + | return "", false | |
| 116 | + | } | |
| 117 | + | } | |
| 118 | + | ||
| 119 | + | // Dispatch decodes one event on zwp_idle_inhibitor_v1 and calls the registered handlers. | |
| 120 | + | func (o *IdleInhibitor) Dispatch(event *wl.Event) { | |
| 121 | + | switch event.Opcode { | |
| 122 | + | default: | |
| 123 | + | } | |
| 124 | + | } | |
A client/input_desktop_extensions_test.go +726 -0
| @@ -0,0 +1,726 @@ | |||
| 1 | + | //go:build linux | |
| 2 | + | ||
| 3 | + | package client_test | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "encoding/binary" | |
| 7 | + | "errors" | |
| 8 | + | "os" | |
| 9 | + | "reflect" | |
| 10 | + | "testing" | |
| 11 | + | "time" | |
| 12 | + | ||
| 13 | + | datacontrol "github.com/bnema/go-wayland-bindings/client/extdatacontrol" | |
| 14 | + | extforeigntoplevel "github.com/bnema/go-wayland-bindings/client/extforeigntoplevellist" | |
| 15 | + | idlenotify "github.com/bnema/go-wayland-bindings/client/extidlenotify" | |
| 16 | + | imagecapturesource "github.com/bnema/go-wayland-bindings/client/extimagecapturesource" | |
| 17 | + | imagecopycapture "github.com/bnema/go-wayland-bindings/client/extimagecopycapture" | |
| 18 | + | workspace "github.com/bnema/go-wayland-bindings/client/extworkspace" | |
| 19 | + | "github.com/bnema/go-wayland-bindings/client/idleinhibit" | |
| 20 | + | shortcutsinhibit "github.com/bnema/go-wayland-bindings/client/keyboardshortcutsinhibit" | |
| 21 | + | "github.com/bnema/go-wayland-bindings/client/pointerconstraints" | |
| 22 | + | "github.com/bnema/go-wayland-bindings/client/primaryselection" | |
| 23 | + | "github.com/bnema/go-wayland-bindings/client/relativepointer" | |
| 24 | + | "github.com/bnema/go-wayland-bindings/client/xdgdecoration" | |
| 25 | + | "github.com/bnema/go-wayland-bindings/client/xdgoutput" | |
| 26 | + | "github.com/bnema/go-wayland-bindings/client/xdgshell" | |
| 27 | + | "github.com/bnema/wlturbo" | |
| 28 | + | "golang.org/x/sys/unix" | |
| 29 | + | ) | |
| 30 | + | ||
| 31 | + | func TestRelativePointerMotionDecode(t *testing.T) { | |
| 32 | + | s := newWireEnv(t) | |
| 33 | + | ptr := s.pointer() | |
| 34 | + | mgr := relativepointer.NewRelativePointerManager(s.d.Context()) | |
| 35 | + | s.bind(1, relativepointer.RelativePointerManagerInterface, 1, 1, mgr) | |
| 36 | + | rp, e := mgr.GetRelativePointer(ptr) | |
| 37 | + | noerr(t, e) | |
| 38 | + | wantWords(t, "get_relative_pointer", s.req(mgr.ID(), 1), rp.ID(), ptr.ID()) | |
| 39 | + | ||
| 40 | + | type motion struct { | |
| 41 | + | hi, lo uint32 | |
| 42 | + | dx, dy, ux, uy wlturbo.Fixed | |
| 43 | + | } | |
| 44 | + | var got []motion | |
| 45 | + | rp.OnRelativeMotion(func(hi, lo uint32, dx, dy, ux, uy wlturbo.Fixed) { | |
| 46 | + | got = append(got, motion{hi, lo, dx, dy, ux, uy}) | |
| 47 | + | }) | |
| 48 | + | // 64-bit microsecond timestamp split in two words; negative deltas must | |
| 49 | + | // keep their sign through the 24.8 fixed-point decode. | |
| 50 | + | want := motion{1, 0x89abcdef, wlturbo.NewFixed(-1.5), wlturbo.NewFixed(2.25), wlturbo.NewFixed(-3), wlturbo.NewFixed(0.5)} | |
| 51 | + | s.event(rp.ID(), 0, wordBytes(want.hi, want.lo, uint32(want.dx), uint32(want.dy), uint32(want.ux), uint32(want.uy))...) | |
| 52 | + | if len(got) != 1 || got[0] != want { | |
| 53 | + | t.Fatalf("motion %+v, want %+v", got, want) | |
| 54 | + | } | |
| 55 | + | if got[0].dx.Float64() != -1.5 || got[0].dy.Float64() != 2.25 { | |
| 56 | + | t.Fatalf("fixed decode %v %v", got[0].dx.Float64(), got[0].dy.Float64()) | |
| 57 | + | } | |
| 58 | + | // Two handlers are both called, in registration order. | |
| 59 | + | var order []int | |
| 60 | + | rp.OnRelativeMotion(func(_, _ uint32, _, _, _, _ wlturbo.Fixed) { order = append(order, 1) }) | |
| 61 | + | rp.OnRelativeMotion(func(_, _ uint32, _, _, _, _ wlturbo.Fixed) { order = append(order, 2) }) | |
| 62 | + | s.event(rp.ID(), 0, wordBytes(0, 1, 0, 0, 0, 0)...) | |
| 63 | + | if !reflect.DeepEqual(order, []int{1, 2}) || len(got) != 2 { | |
| 64 | + | t.Fatalf("handlers order=%v motions=%d", order, len(got)) | |
| 65 | + | } | |
| 66 | + | noerr(t, rp.Destroy()) | |
| 67 | + | s.req(rp.ID(), 0) | |
| 68 | + | noerr(t, mgr.Destroy()) | |
| 69 | + | s.req(mgr.ID(), 0) | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | func TestPointerConstraintsNullableRegion(t *testing.T) { | |
| 73 | + | s := newWireEnv(t) | |
| 74 | + | surf, ptr := s.surface(), s.pointer() | |
| 75 | + | pc := pointerconstraints.NewPointerConstraints(s.d.Context()) | |
| 76 | + | s.bind(1, pointerconstraints.PointerConstraintsInterface, 1, 1, pc) | |
| 77 | + | ||
| 78 | + | // A null region means "use the surface input region" and is wire id 0. | |
| 79 | + | lock, e := pc.LockPointer(surf, ptr, nil, pointerconstraints.LIFETIME_PERSISTENT) | |
| 80 | + | noerr(t, e) | |
| 81 | + | wantWords(t, "lock_pointer(nil)", s.req(pc.ID(), 1), lock.ID(), surf.ID(), ptr.ID(), 0, pointerconstraints.LIFETIME_PERSISTENT) | |
| 82 | + | ||
| 83 | + | reg := s.region() | |
| 84 | + | conf, e := pc.ConfinePointer(surf, ptr, reg, pointerconstraints.LIFETIME_ONESHOT) | |
| 85 | + | noerr(t, e) | |
| 86 | + | wantWords(t, "confine_pointer(region)", s.req(pc.ID(), 2), conf.ID(), surf.ID(), ptr.ID(), reg.ID(), pointerconstraints.LIFETIME_ONESHOT) | |
| 87 | + | ||
| 88 | + | noerr(t, lock.SetCursorPositionHint(wlturbo.NewFixed(10.5), wlturbo.NewFixed(-2))) | |
| 89 | + | wantWords(t, "set_cursor_position_hint", s.req(lock.ID(), 1), uint32(wlturbo.NewFixed(10.5)), uint32(wlturbo.NewFixed(-2))) | |
| 90 | + | noerr(t, lock.SetRegion(nil)) | |
| 91 | + | wantWords(t, "locked.set_region(nil)", s.req(lock.ID(), 2), 0) | |
| 92 | + | noerr(t, lock.SetRegion(reg)) | |
| 93 | + | wantWords(t, "locked.set_region", s.req(lock.ID(), 2), reg.ID()) | |
| 94 | + | noerr(t, conf.SetRegion(nil)) | |
| 95 | + | wantWords(t, "confined.set_region(nil)", s.req(conf.ID(), 1), 0) | |
| 96 | + | ||
| 97 | + | var seq []string | |
| 98 | + | lock.OnLocked(func() { seq = append(seq, "locked") }) | |
| 99 | + | lock.OnUnlocked(func() { seq = append(seq, "unlocked") }) | |
| 100 | + | conf.OnConfined(func() { seq = append(seq, "confined") }) | |
| 101 | + | conf.OnUnconfined(func() { seq = append(seq, "unconfined") }) | |
| 102 | + | s.event(lock.ID(), 0) | |
| 103 | + | s.event(lock.ID(), 1) | |
| 104 | + | s.event(conf.ID(), 0) | |
| 105 | + | s.event(conf.ID(), 1) | |
| 106 | + | if !reflect.DeepEqual(seq, []string{"locked", "unlocked", "confined", "unconfined"}) { | |
| 107 | + | t.Fatal(seq) | |
| 108 | + | } | |
| 109 | + | noerr(t, lock.Destroy()) | |
| 110 | + | s.req(lock.ID(), 0) | |
| 111 | + | noerr(t, conf.Destroy()) | |
| 112 | + | s.req(conf.ID(), 0) | |
| 113 | + | noerr(t, pc.Destroy()) | |
| 114 | + | s.req(pc.ID(), 0) | |
| 115 | + | } | |
| 116 | + | ||
| 117 | + | // rawPipe returns a pipe as plain descriptors. An *os.File would close a reused | |
| 118 | + | // descriptor number on Close after the binding already closed the original. | |
| 119 | + | func rawPipe(t *testing.T) (*os.File, int) { | |
| 120 | + | t.Helper() | |
| 121 | + | var fds [2]int | |
| 122 | + | noerr(t, unix.Pipe2(fds[:], unix.O_CLOEXEC)) | |
| 123 | + | r := os.NewFile(uintptr(fds[0]), "pipe-r") | |
| 124 | + | t.Cleanup(func() { r.Close() }) | |
| 125 | + | return r, fds[1] | |
| 126 | + | } | |
| 127 | + | ||
| 128 | + | func TestPrimarySelectionNewIDAndFDOwnership(t *testing.T) { | |
| 129 | + | s := newWireEnv(t) | |
| 130 | + | seat := s.seat() | |
| 131 | + | mgr := primaryselection.NewPrimarySelectionDeviceManager(s.d.Context()) | |
| 132 | + | s.bind(1, primaryselection.PrimarySelectionDeviceManagerInterface, 1, 1, mgr) | |
| 133 | + | dev, e := mgr.GetDevice(seat) | |
| 134 | + | noerr(t, e) | |
| 135 | + | wantWords(t, "get_device", s.req(mgr.ID(), 1), dev.ID(), seat.ID()) | |
| 136 | + | src, e := mgr.CreateSource() | |
| 137 | + | noerr(t, e) | |
| 138 | + | wantWords(t, "create_source", s.req(mgr.ID(), 0), src.ID()) | |
| 139 | + | noerr(t, src.Offer("text/plain")) | |
| 140 | + | s.req(src.ID(), 0) | |
| 141 | + | noerr(t, dev.SetSelection(src, 77)) | |
| 142 | + | wantWords(t, "set_selection", s.req(dev.ID(), 0), src.ID(), 77) | |
| 143 | + | noerr(t, dev.SetSelection(nil, 78)) | |
| 144 | + | wantWords(t, "set_selection(nil)", s.req(dev.ID(), 0), 0, 78) | |
| 145 | + | ||
| 146 | + | // data_offer carries a server-allocated new_id which must come back as a | |
| 147 | + | // typed, registered child inheriting the device version. | |
| 148 | + | var offer *primaryselection.PrimarySelectionOffer | |
| 149 | + | var mimes []string | |
| 150 | + | dev.OnDataOffer(func(o *primaryselection.PrimarySelectionOffer) { | |
| 151 | + | offer = o | |
| 152 | + | o.OnOffer(func(m string) { mimes = append(mimes, m) }) | |
| 153 | + | }) | |
| 154 | + | var selected []uint32 | |
| 155 | + | dev.OnSelection(func(id uint32) { selected = append(selected, id) }) | |
| 156 | + | s.event(dev.ID(), 0, wordBytes(serverID+1)...) | |
| 157 | + | if offer == nil || offer.ID() != serverID+1 || offer.Version() != dev.Version() { | |
| 158 | + | t.Fatalf("offer %+v", offer) | |
| 159 | + | } | |
| 160 | + | s.event(offer.ID(), 0, str("text/plain")...) | |
| 161 | + | s.event(dev.ID(), 1, wordBytes(offer.ID())...) | |
| 162 | + | s.event(dev.ID(), 1, wordBytes(0)...) // null selection | |
| 163 | + | if !reflect.DeepEqual(mimes, []string{"text/plain"}) || !reflect.DeepEqual(selected, []uint32{offer.ID(), 0}) { | |
| 164 | + | t.Fatalf("mimes=%v selected=%v", mimes, selected) | |
| 165 | + | } | |
| 166 | + | ||
| 167 | + | // Client -> compositor: the sent descriptor is duplicated by the kernel and | |
| 168 | + | // the client's copy is closed by the binding. | |
| 169 | + | r, w := rawPipe(t) | |
| 170 | + | noerr(t, offer.Receive("text/plain", w)) | |
| 171 | + | // Check before reading the request: the received duplicate may reuse the | |
| 172 | + | // number of the descriptor the client just closed. | |
| 173 | + | requireFDClosed(t, w) | |
| 174 | + | body, fd := s.reqFD(offer.ID(), 0) | |
| 175 | + | // Closed explicitly below; the guard covers early t.Fatal paths only. | |
| 176 | + | defer func() { | |
| 177 | + | if fd >= 0 { | |
| 178 | + | unix.Close(fd) | |
| 179 | + | } | |
| 180 | + | }() | |
| 181 | + | if len(body) < 4 { | |
| 182 | + | t.Fatalf("receive body %x", body) | |
| 183 | + | } | |
| 184 | + | _, e = unix.Write(fd, []byte("payload")) | |
| 185 | + | noerr(t, e) | |
| 186 | + | noerr(t, unix.Close(fd)) | |
| 187 | + | fd = -1 | |
| 188 | + | buf := make([]byte, 16) | |
| 189 | + | n, e := r.Read(buf) | |
| 190 | + | noerr(t, e) | |
| 191 | + | if string(buf[:n]) != "payload" { | |
| 192 | + | t.Fatalf("payload %q", buf[:n]) | |
| 193 | + | } | |
| 194 | + | ||
| 195 | + | // Compositor -> client: source.send hands over an owned descriptor. | |
| 196 | + | var taken, ignored *wlturbo.OwnedFD | |
| 197 | + | var sendMimes []string | |
| 198 | + | src.OnSend(func(m string, f *wlturbo.OwnedFD) { | |
| 199 | + | sendMimes = append(sendMimes, m) | |
| 200 | + | if taken == nil { | |
| 201 | + | taken = f | |
| 202 | + | n, e := f.Take() | |
| 203 | + | noerr(t, e) | |
| 204 | + | _, e = unix.Write(n, []byte("from-client")) | |
| 205 | + | noerr(t, e) | |
| 206 | + | unix.Close(n) | |
| 207 | + | return | |
| 208 | + | } | |
| 209 | + | ignored = f // deliberately neither taken nor closed | |
| 210 | + | }) | |
| 211 | + | sr, sw, e := os.Pipe() | |
| 212 | + | noerr(t, e) | |
| 213 | + | send(t, s.p, payload(src.ID(), 0, str("text/plain")...), int(sw.Fd())) | |
| 214 | + | s.dispatch() | |
| 215 | + | sw.Close() | |
| 216 | + | n, e = sr.Read(buf) | |
| 217 | + | noerr(t, e) | |
| 218 | + | if string(buf[:n]) != "from-client" { | |
| 219 | + | t.Fatalf("source payload %q", buf[:n]) | |
| 220 | + | } | |
| 221 | + | if _, e := taken.Take(); e == nil { | |
| 222 | + | t.Fatal("second Take on a taken descriptor must fail") | |
| 223 | + | } | |
| 224 | + | sr.Close() | |
| 225 | + | // An unclaimed descriptor is closed by the transport when dispatch ends, | |
| 226 | + | // so the pipe reader sees EOF although the handler never closed it. | |
| 227 | + | pr, pw, e := os.Pipe() | |
| 228 | + | noerr(t, e) | |
| 229 | + | defer pr.Close() | |
| 230 | + | send(t, s.p, payload(src.ID(), 0, str("text/html")...), int(pw.Fd())) | |
| 231 | + | pw.Close() // only the in-flight duplicate keeps the write end alive | |
| 232 | + | s.dispatch() | |
| 233 | + | if ignored == nil || len(sendMimes) != 2 { | |
| 234 | + | t.Fatalf("send events %v", sendMimes) | |
| 235 | + | } | |
| 236 | + | if _, e := ignored.Take(); e == nil { | |
| 237 | + | t.Fatal("unclaimed descriptor must be closed after dispatch, but Take succeeded") | |
| 238 | + | } | |
| 239 | + | pr.SetReadDeadline(time.Now().Add(2 * time.Second)) | |
| 240 | + | if n, e := pr.Read(buf); n != 0 || e == nil { | |
| 241 | + | t.Fatalf("unclaimed descriptor still open: n=%d err=%v", n, e) | |
| 242 | + | } | |
| 243 | + | var cancelled bool | |
| 244 | + | src.OnCancelled(func() { cancelled = true }) | |
| 245 | + | s.event(src.ID(), 1) | |
| 246 | + | if !cancelled { | |
| 247 | + | t.Fatal("cancelled not delivered") | |
| 248 | + | } | |
| 249 | + | noerr(t, offer.Destroy()) | |
| 250 | + | s.req(offer.ID(), 1) | |
| 251 | + | noerr(t, src.Destroy()) | |
| 252 | + | s.req(src.ID(), 1) | |
| 253 | + | noerr(t, dev.Destroy()) | |
| 254 | + | s.req(dev.ID(), 1) | |
| 255 | + | noerr(t, mgr.Destroy()) | |
| 256 | + | s.req(mgr.ID(), 2) | |
| 257 | + | } | |
| 258 | + | ||
| 259 | + | func TestDataControlNewIDAndFDOwnership(t *testing.T) { | |
| 260 | + | s := newWireEnv(t) | |
| 261 | + | seat := s.seat() | |
| 262 | + | mgr := datacontrol.NewExtDataControlManager(s.d.Context()) | |
| 263 | + | s.bind(1, datacontrol.ExtDataControlManagerInterface, 1, 1, mgr) | |
| 264 | + | dev, e := mgr.GetDataDevice(seat) | |
| 265 | + | noerr(t, e) | |
| 266 | + | wantWords(t, "get_data_device", s.req(mgr.ID(), 1), dev.ID(), seat.ID()) | |
| 267 | + | src, e := mgr.CreateDataSource() | |
| 268 | + | noerr(t, e) | |
| 269 | + | wantWords(t, "create_data_source", s.req(mgr.ID(), 0), src.ID()) | |
| 270 | + | noerr(t, dev.SetSelection(src)) | |
| 271 | + | wantWords(t, "set_selection", s.req(dev.ID(), 0), src.ID()) | |
| 272 | + | noerr(t, dev.SetPrimarySelection(nil)) | |
| 273 | + | wantWords(t, "set_primary_selection(nil)", s.req(dev.ID(), 2), 0) | |
| 274 | + | ||
| 275 | + | var offers []*datacontrol.ExtDataControlOffer | |
| 276 | + | dev.OnDataOffer(func(o *datacontrol.ExtDataControlOffer) { offers = append(offers, o) }) | |
| 277 | + | var sel, primary []uint32 | |
| 278 | + | dev.OnSelection(func(id uint32) { sel = append(sel, id) }) | |
| 279 | + | dev.OnPrimarySelection(func(id uint32) { primary = append(primary, id) }) | |
| 280 | + | var finished bool | |
| 281 | + | dev.OnFinished(func() { finished = true }) | |
| 282 | + | s.event(dev.ID(), 0, wordBytes(serverID+1)...) | |
| 283 | + | s.event(dev.ID(), 0, wordBytes(serverID+2)...) | |
| 284 | + | if len(offers) != 2 || offers[0].ID() != serverID+1 || offers[1].ID() != serverID+2 { | |
| 285 | + | t.Fatalf("offers %+v", offers) | |
| 286 | + | } | |
| 287 | + | s.event(dev.ID(), 1, wordBytes(serverID+1)...) | |
| 288 | + | s.event(dev.ID(), 3, wordBytes(serverID+2)...) | |
| 289 | + | s.event(dev.ID(), 3, wordBytes(0)...) | |
| 290 | + | if !reflect.DeepEqual(sel, []uint32{serverID + 1}) || !reflect.DeepEqual(primary, []uint32{serverID + 2, 0}) { | |
| 291 | + | t.Fatalf("sel=%v primary=%v", sel, primary) | |
| 292 | + | } | |
| 293 | + | var mime string | |
| 294 | + | offers[0].OnOffer(func(m string) { mime = m }) | |
| 295 | + | s.event(offers[0].ID(), 0, str("text/uri-list")...) | |
| 296 | + | if mime != "text/uri-list" { | |
| 297 | + | t.Fatal(mime) | |
| 298 | + | } | |
| 299 | + | ||
| 300 | + | r, w := rawPipe(t) | |
| 301 | + | noerr(t, offers[0].Receive("text/uri-list", w)) | |
| 302 | + | requireFDClosed(t, w) | |
| 303 | + | _, fd := s.reqFD(offers[0].ID(), 0) | |
| 304 | + | unix.Close(fd) | |
| 305 | + | buf := make([]byte, 8) | |
| 306 | + | if n, e := r.Read(buf); n != 0 || e == nil { | |
| 307 | + | t.Fatalf("expected EOF once both write ends closed, n=%d err=%v", n, e) | |
| 308 | + | } | |
| 309 | + | ||
| 310 | + | // source.send: the handler owns the descriptor and can Close it early. | |
| 311 | + | var closedByHandler bool | |
| 312 | + | src.OnSend(func(m string, f *wlturbo.OwnedFD) { | |
| 313 | + | noerr(t, f.Close()) | |
| 314 | + | noerr(t, f.Close()) // idempotent | |
| 315 | + | if _, e := f.Take(); e == nil { | |
| 316 | + | t.Error("Take after Close must fail") | |
| 317 | + | } | |
| 318 | + | closedByHandler = true | |
| 319 | + | }) | |
| 320 | + | pr, pw, e := os.Pipe() | |
| 321 | + | noerr(t, e) | |
| 322 | + | defer pr.Close() | |
| 323 | + | send(t, s.p, payload(src.ID(), 0, str("text/plain")...), int(pw.Fd())) | |
| 324 | + | pw.Close() | |
| 325 | + | s.dispatch() | |
| 326 | + | pr.SetReadDeadline(time.Now().Add(2 * time.Second)) | |
| 327 | + | if n, e := pr.Read(buf); !closedByHandler || n != 0 || e == nil { | |
| 328 | + | t.Fatalf("closed=%v n=%d err=%v", closedByHandler, n, e) | |
| 329 | + | } | |
| 330 | + | s.event(dev.ID(), 2) | |
| 331 | + | if !finished { | |
| 332 | + | t.Fatal("finished not delivered") | |
| 333 | + | } | |
| 334 | + | noerr(t, src.Offer("text/plain")) | |
| 335 | + | s.req(src.ID(), 0) | |
| 336 | + | noerr(t, offers[0].Destroy()) | |
| 337 | + | s.req(offers[0].ID(), 1) | |
| 338 | + | noerr(t, src.Destroy()) | |
| 339 | + | s.req(src.ID(), 1) | |
| 340 | + | noerr(t, dev.Destroy()) | |
| 341 | + | s.req(dev.ID(), 1) | |
| 342 | + | noerr(t, mgr.Destroy()) | |
| 343 | + | s.req(mgr.ID(), 2) | |
| 344 | + | } | |
| 345 | + | ||
| 346 | + | func TestWorkspaceLifecycle(t *testing.T) { | |
| 347 | + | s := newWireEnv(t) | |
| 348 | + | out := s.output() | |
| 349 | + | mgr := workspace.NewExtWorkspaceManager(s.d.Context()) | |
| 350 | + | s.bind(1, workspace.ExtWorkspaceManagerInterface, 1, 1, mgr) | |
| 351 | + | ||
| 352 | + | var groups []*workspace.ExtWorkspaceGroupHandle | |
| 353 | + | var spaces []*workspace.ExtWorkspaceHandle | |
| 354 | + | var log []string | |
| 355 | + | mgr.OnWorkspaceGroup(func(g *workspace.ExtWorkspaceGroupHandle) { groups = append(groups, g) }) | |
| 356 | + | mgr.OnWorkspace(func(w *workspace.ExtWorkspaceHandle) { spaces = append(spaces, w) }) | |
| 357 | + | mgr.OnDone(func() { log = append(log, "done") }) | |
| 358 | + | mgr.OnFinished(func() { log = append(log, "finished") }) | |
| 359 | + | ||
| 360 | + | s.event(mgr.ID(), 0, wordBytes(serverID+1)...) | |
| 361 | + | s.event(mgr.ID(), 1, wordBytes(serverID+2)...) | |
| 362 | + | if len(groups) != 1 || len(spaces) != 1 || groups[0].ID() != serverID+1 || spaces[0].ID() != serverID+2 { | |
| 363 | + | t.Fatal("typed children missing") | |
| 364 | + | } | |
| 365 | + | g, w := groups[0], spaces[0] | |
| 366 | + | var gcaps, wcaps, state uint32 | |
| 367 | + | var outs, entered []uint32 | |
| 368 | + | var id, name string | |
| 369 | + | var coords []byte | |
| 370 | + | g.OnCapabilities(func(c uint32) { gcaps = c }) | |
| 371 | + | g.OnOutputEnter(func(o uint32) { outs = append(outs, o) }) | |
| 372 | + | g.OnWorkspaceEnter(func(x uint32) { entered = append(entered, x) }) | |
| 373 | + | g.OnRemoved(func() { log = append(log, "group-removed") }) | |
| 374 | + | w.OnId(func(v string) { id = v }) | |
| 375 | + | w.OnName(func(v string) { name = v }) | |
| 376 | + | w.OnCoordinates(func(c []byte) { coords = c }) | |
| 377 | + | w.OnState(func(v uint32) { state = v }) | |
| 378 | + | w.OnCapabilities(func(v uint32) { wcaps = v }) | |
| 379 | + | w.OnRemoved(func() { log = append(log, "workspace-removed") }) | |
| 380 | + | ||
| 381 | + | s.event(g.ID(), 0, wordBytes(workspace.GROUP_CAPABILITIES_CREATE_WORKSPACE)...) | |
| 382 | + | s.event(g.ID(), 1, wordBytes(out.ID())...) | |
| 383 | + | s.event(g.ID(), 3, wordBytes(w.ID())...) | |
| 384 | + | s.event(w.ID(), 0, str("ws-1")...) | |
| 385 | + | s.event(w.ID(), 1, str("Workspace é")...) | |
| 386 | + | s.event(w.ID(), 2, arr(wordBytes(1, 2))...) | |
| 387 | + | s.event(w.ID(), 3, wordBytes(workspace.STATE_ACTIVE|workspace.STATE_URGENT)...) | |
| 388 | + | s.event(w.ID(), 4, wordBytes(workspace.WORKSPACE_CAPABILITIES_ACTIVATE|workspace.WORKSPACE_CAPABILITIES_ASSIGN)...) | |
| 389 | + | s.event(mgr.ID(), 2) | |
| 390 | + | if gcaps != workspace.GROUP_CAPABILITIES_CREATE_WORKSPACE || !reflect.DeepEqual(outs, []uint32{out.ID()}) || !reflect.DeepEqual(entered, []uint32{w.ID()}) || | |
| 391 | + | id != "ws-1" || name != "Workspace é" || !reflect.DeepEqual(decodeWords(coords), []uint32{1, 2}) || | |
| 392 | + | state != 3 || wcaps != 9 || !reflect.DeepEqual(log, []string{"done"}) { | |
| 393 | + | t.Fatalf("state gcaps=%d outs=%v entered=%v id=%q name=%q coords=%v state=%d wcaps=%d log=%v", gcaps, outs, entered, id, name, coords, state, wcaps, log) | |
| 394 | + | } | |
| 395 | + | ||
| 396 | + | // Requests are only transactional after commit, so the wire order is | |
| 397 | + | // request, request, commit. | |
| 398 | + | noerr(t, w.Activate()) | |
| 399 | + | s.req(w.ID(), 1) | |
| 400 | + | noerr(t, w.Assign(g)) | |
| 401 | + | wantWords(t, "assign", s.req(w.ID(), 3), g.ID()) | |
| 402 | + | noerr(t, g.CreateWorkspace("new")) | |
| 403 | + | if b := s.req(g.ID(), 0); binary.NativeEndian.Uint32(b) != 4 || string(b[4:7]) != "new" { | |
| 404 | + | t.Fatalf("create_workspace %x", b) | |
| 405 | + | } | |
| 406 | + | noerr(t, w.Deactivate()) | |
| 407 | + | s.req(w.ID(), 2) | |
| 408 | + | noerr(t, w.Remove()) | |
| 409 | + | s.req(w.ID(), 4) | |
| 410 | + | noerr(t, mgr.Commit()) | |
| 411 | + | s.req(mgr.ID(), 0) | |
| 412 | + | ||
| 413 | + | // Removal: the compositor sends removed, the client answers with destroy. | |
| 414 | + | s.event(w.ID(), 5) | |
| 415 | + | s.event(g.ID(), 5) | |
| 416 | + | noerr(t, w.Destroy()) | |
| 417 | + | s.req(w.ID(), 0) | |
| 418 | + | noerr(t, g.Destroy()) | |
| 419 | + | s.req(g.ID(), 1) | |
| 420 | + | // stop is answered by finished, which is the final event. | |
| 421 | + | noerr(t, mgr.Stop()) | |
| 422 | + | s.req(mgr.ID(), 1) | |
| 423 | + | s.event(mgr.ID(), 3) | |
| 424 | + | if !reflect.DeepEqual(log, []string{"done", "workspace-removed", "group-removed", "finished"}) { | |
| 425 | + | t.Fatal(log) | |
| 426 | + | } | |
| 427 | + | // finished is a destructor event: the manager is dead and must not | |
| 428 | + | // reach the compositor any more. | |
| 429 | + | if e := mgr.Commit(); e == nil { | |
| 430 | + | t.Fatal("Commit after finished must fail") | |
| 431 | + | } | |
| 432 | + | s.noRequest() | |
| 433 | + | } | |
| 434 | + | ||
| 435 | + | func TestIdleNotifyVersionGate(t *testing.T) { | |
| 436 | + | s := newWireEnv(t) | |
| 437 | + | seat := s.seat() | |
| 438 | + | old := idlenotify.NewExtIdleNotifier(s.d.Context()) | |
| 439 | + | s.bind(1, idlenotify.ExtIdleNotifierInterface, 2, 1, old) // negotiated v1 | |
| 440 | + | if _, e := old.GetInputIdleNotification(1000, seat); !errors.Is(e, wlturbo.ErrVersionTooLow) { | |
| 441 | + | t.Fatalf("v1 get_input_idle_notification = %v, want ErrVersionTooLow", e) | |
| 442 | + | } | |
| 443 | + | s.noRequest() // refused locally, nothing reaches the compositor | |
| 444 | + | n, e := old.GetIdleNotification(1000, seat) | |
| 445 | + | noerr(t, e) | |
| 446 | + | wantWords(t, "get_idle_notification", s.req(old.ID(), 1), n.ID(), 1000, seat.ID()) | |
| 447 | + | ||
| 448 | + | send(t, s.p, msg(s.d.Registry().ID(), 1, 1)) // global_remove for the v1 bind | |
| 449 | + | s.dispatch() | |
| 450 | + | cur := idlenotify.NewExtIdleNotifier(s.d.Context()) | |
| 451 | + | s.bind(2, idlenotify.ExtIdleNotifierInterface, 2, 2, cur) | |
| 452 | + | in, e := cur.GetInputIdleNotification(0, seat) // zero timeout is valid | |
| 453 | + | noerr(t, e) | |
| 454 | + | wantWords(t, "get_input_idle_notification", s.req(cur.ID(), 2), in.ID(), 0, seat.ID()) | |
| 455 | + | var seq []string | |
| 456 | + | in.OnIdled(func() { seq = append(seq, "idled") }) | |
| 457 | + | in.OnResumed(func() { seq = append(seq, "resumed") }) | |
| 458 | + | s.event(in.ID(), 0) | |
| 459 | + | s.event(in.ID(), 1) | |
| 460 | + | if !reflect.DeepEqual(seq, []string{"idled", "resumed"}) { | |
| 461 | + | t.Fatal(seq) | |
| 462 | + | } | |
| 463 | + | noerr(t, in.Destroy()) | |
| 464 | + | s.req(in.ID(), 0) | |
| 465 | + | noerr(t, n.Destroy()) | |
| 466 | + | s.req(n.ID(), 0) | |
| 467 | + | } | |
| 468 | + | ||
| 469 | + | func TestInhibitAndDesktopHintsWire(t *testing.T) { | |
| 470 | + | s := newWireEnv(t) | |
| 471 | + | surf, seat, out := s.surface(), s.seat(), s.output() | |
| 472 | + | ||
| 473 | + | ii := idleinhibit.NewIdleInhibitManager(s.d.Context()) | |
| 474 | + | s.bind(1, idleinhibit.IdleInhibitManagerInterface, 1, 1, ii) | |
| 475 | + | inh, e := ii.CreateInhibitor(surf) | |
| 476 | + | noerr(t, e) | |
| 477 | + | wantWords(t, "create_inhibitor", s.req(ii.ID(), 1), inh.ID(), surf.ID()) | |
| 478 | + | noerr(t, inh.Destroy()) | |
| 479 | + | s.req(inh.ID(), 0) | |
| 480 | + | noerr(t, ii.Destroy()) | |
| 481 | + | s.req(ii.ID(), 0) | |
| 482 | + | ||
| 483 | + | ks := shortcutsinhibit.NewKeyboardShortcutsInhibitManager(s.d.Context()) | |
| 484 | + | s.bind(2, shortcutsinhibit.KeyboardShortcutsInhibitManagerInterface, 1, 1, ks) | |
| 485 | + | k, e := ks.InhibitShortcuts(surf, seat) | |
| 486 | + | noerr(t, e) | |
| 487 | + | wantWords(t, "inhibit_shortcuts", s.req(ks.ID(), 1), k.ID(), surf.ID(), seat.ID()) | |
| 488 | + | var seq []string | |
| 489 | + | k.OnActive(func() { seq = append(seq, "active") }) | |
| 490 | + | k.OnInactive(func() { seq = append(seq, "inactive") }) | |
| 491 | + | s.event(k.ID(), 0) | |
| 492 | + | s.event(k.ID(), 1) | |
| 493 | + | if !reflect.DeepEqual(seq, []string{"active", "inactive"}) { | |
| 494 | + | t.Fatal(seq) | |
| 495 | + | } | |
| 496 | + | noerr(t, k.Destroy()) | |
| 497 | + | s.req(k.ID(), 0) | |
| 498 | + | noerr(t, ks.Destroy()) | |
| 499 | + | s.req(ks.ID(), 0) | |
| 500 | + | ||
| 501 | + | xo := xdgoutput.NewZxdgOutputManager(s.d.Context()) | |
| 502 | + | s.bind(3, xdgoutput.ZxdgOutputManagerInterface, 3, 3, xo) | |
| 503 | + | o, e := xo.GetXdgOutput(out) | |
| 504 | + | noerr(t, e) | |
| 505 | + | wantWords(t, "get_xdg_output", s.req(xo.ID(), 1), o.ID(), out.ID()) | |
| 506 | + | var pos, size [2]int32 | |
| 507 | + | var name string | |
| 508 | + | o.OnLogicalPosition(func(x, y int32) { pos = [2]int32{x, y} }) | |
| 509 | + | o.OnLogicalSize(func(w, h int32) { size = [2]int32{w, h} }) | |
| 510 | + | o.OnName(func(n string) { name = n }) | |
| 511 | + | s.event(o.ID(), 0, wordBytes(uint32(0xfffffff6), 20)...) // -10, 20 | |
| 512 | + | s.event(o.ID(), 1, wordBytes(1920, 1080)...) | |
| 513 | + | s.event(o.ID(), 3, str("DP-1")...) | |
| 514 | + | if pos != [2]int32{-10, 20} || size != [2]int32{1920, 1080} || name != "DP-1" { | |
| 515 | + | t.Fatal(pos, size, name) | |
| 516 | + | } | |
| 517 | + | noerr(t, o.Destroy()) | |
| 518 | + | s.req(o.ID(), 0) | |
| 519 | + | noerr(t, xo.Destroy()) | |
| 520 | + | s.req(xo.ID(), 0) | |
| 521 | + | } | |
| 522 | + | ||
| 523 | + | func TestXdgDecorationCrossPackageToplevel(t *testing.T) { | |
| 524 | + | s := newWireEnv(t) | |
| 525 | + | surf := s.surface() | |
| 526 | + | wm := xdgshell.NewXdgWmBase(s.d.Context()) | |
| 527 | + | s.bind(1, xdgshell.XdgWmBaseInterface, 6, 6, wm) | |
| 528 | + | xs, e := wm.GetXdgSurface(surf) | |
| 529 | + | noerr(t, e) | |
| 530 | + | s.req(wm.ID(), 2) | |
| 531 | + | top, e := xs.GetToplevel() | |
| 532 | + | noerr(t, e) | |
| 533 | + | s.req(xs.ID(), 1) | |
| 534 | + | ||
| 535 | + | dm := xdgdecoration.NewZxdgDecorationManager(s.d.Context()) | |
| 536 | + | s.bind(2, xdgdecoration.ZxdgDecorationManagerInterface, 2, 2, dm) | |
| 537 | + | dec, e := dm.GetToplevelDecoration(top) | |
| 538 | + | noerr(t, e) | |
| 539 | + | wantWords(t, "get_toplevel_decoration", s.req(dm.ID(), 1), dec.ID(), top.ID()) | |
| 540 | + | noerr(t, dec.SetMode(xdgdecoration.MODE_SERVER_SIDE)) | |
| 541 | + | wantWords(t, "set_mode", s.req(dec.ID(), 1), xdgdecoration.MODE_SERVER_SIDE) | |
| 542 | + | var modes []uint32 | |
| 543 | + | dec.OnConfigure(func(m uint32) { modes = append(modes, m) }) | |
| 544 | + | s.event(dec.ID(), 0, wordBytes(xdgdecoration.MODE_CLIENT_SIDE)...) | |
| 545 | + | if !reflect.DeepEqual(modes, []uint32{xdgdecoration.MODE_CLIENT_SIDE}) { | |
| 546 | + | t.Fatal(modes) | |
| 547 | + | } | |
| 548 | + | noerr(t, dec.UnsetMode()) | |
| 549 | + | s.req(dec.ID(), 2) | |
| 550 | + | noerr(t, dec.Destroy()) | |
| 551 | + | s.req(dec.ID(), 0) | |
| 552 | + | noerr(t, dm.Destroy()) | |
| 553 | + | s.req(dm.ID(), 0) | |
| 554 | + | } | |
| 555 | + | ||
| 556 | + | func TestImageCaptureCrossPackageChildren(t *testing.T) { | |
| 557 | + | s := newWireEnv(t) | |
| 558 | + | out, ptr := s.output(), s.pointer() | |
| 559 | + | ||
| 560 | + | // Foreign toplevel handles come from ext-foreign-toplevel-list and are | |
| 561 | + | // consumed by a different package (imagecapturesource). | |
| 562 | + | list := extforeigntoplevel.NewExtForeignToplevelList(s.d.Context()) | |
| 563 | + | s.bind(1, extforeigntoplevel.ExtForeignToplevelListInterface, 1, 1, list) | |
| 564 | + | var handle *extforeigntoplevel.ExtForeignToplevelHandle | |
| 565 | + | list.OnToplevel(func(h *extforeigntoplevel.ExtForeignToplevelHandle) { handle = h }) | |
| 566 | + | s.event(list.ID(), 0, wordBytes(serverID+1)...) | |
| 567 | + | if handle == nil || handle.ID() != serverID+1 { | |
| 568 | + | t.Fatal("toplevel handle missing") | |
| 569 | + | } | |
| 570 | + | var title, appID, ident string | |
| 571 | + | handle.OnTitle(func(v string) { title = v }) | |
| 572 | + | handle.OnAppId(func(v string) { appID = v }) | |
| 573 | + | handle.OnIdentifier(func(v string) { ident = v }) | |
| 574 | + | s.event(handle.ID(), 2, str("term")...) | |
| 575 | + | s.event(handle.ID(), 3, str("org.example.term")...) | |
| 576 | + | s.event(handle.ID(), 4, str("id-1")...) | |
| 577 | + | if title != "term" || appID != "org.example.term" || ident != "id-1" { | |
| 578 | + | t.Fatal(title, appID, ident) | |
| 579 | + | } | |
| 580 | + | ||
| 581 | + | om := imagecapturesource.NewExtOutputImageCaptureSourceManager(s.d.Context()) | |
| 582 | + | s.bind(2, imagecapturesource.ExtOutputImageCaptureSourceManagerInterface, 1, 1, om) | |
| 583 | + | fm := imagecapturesource.NewExtForeignToplevelImageCaptureSourceManager(s.d.Context()) | |
| 584 | + | s.bind(3, imagecapturesource.ExtForeignToplevelImageCaptureSourceManagerInterface, 1, 1, fm) | |
| 585 | + | outSrc, e := om.CreateSource(out) | |
| 586 | + | noerr(t, e) | |
| 587 | + | wantWords(t, "output create_source", s.req(om.ID(), 0), outSrc.ID(), out.ID()) | |
| 588 | + | topSrc, e := fm.CreateSource(handle) | |
| 589 | + | noerr(t, e) | |
| 590 | + | wantWords(t, "toplevel create_source", s.req(fm.ID(), 0), topSrc.ID(), handle.ID()) | |
| 591 | + | ||
| 592 | + | cm := imagecopycapture.NewExtImageCopyCaptureManager(s.d.Context()) | |
| 593 | + | s.bind(4, imagecopycapture.ExtImageCopyCaptureManagerInterface, 1, 1, cm) | |
| 594 | + | sess, e := cm.CreateSession(topSrc, imagecopycapture.OPTIONS_PAINT_CURSORS) | |
| 595 | + | noerr(t, e) | |
| 596 | + | wantWords(t, "create_session", s.req(cm.ID(), 0), sess.ID(), topSrc.ID(), imagecopycapture.OPTIONS_PAINT_CURSORS) | |
| 597 | + | cur, e := cm.CreatePointerCursorSession(outSrc, ptr) | |
| 598 | + | noerr(t, e) | |
| 599 | + | wantWords(t, "create_pointer_cursor_session", s.req(cm.ID(), 1), cur.ID(), outSrc.ID(), ptr.ID()) | |
| 600 | + | ||
| 601 | + | // Session constraints: advertised before done, arrays decoded. | |
| 602 | + | var log []string | |
| 603 | + | var size [2]uint32 | |
| 604 | + | var dev []byte | |
| 605 | + | var dmaFormat uint32 | |
| 606 | + | var mods []byte | |
| 607 | + | sess.OnBufferSize(func(w, h uint32) { size = [2]uint32{w, h}; log = append(log, "size") }) | |
| 608 | + | var shm []uint32 | |
| 609 | + | sess.OnShmFormat(func(f uint32) { shm = append(shm, f); log = append(log, "shm") }) | |
| 610 | + | sess.OnDmabufDevice(func(d []byte) { dev = d; log = append(log, "dev") }) | |
| 611 | + | sess.OnDmabufFormat(func(f uint32, m []byte) { dmaFormat, mods = f, m; log = append(log, "dmabuf") }) | |
| 612 | + | sess.OnDone(func() { log = append(log, "done") }) | |
| 613 | + | sess.OnStopped(func() { log = append(log, "stopped") }) | |
| 614 | + | s.event(sess.ID(), 0, wordBytes(1280, 720)...) | |
| 615 | + | s.event(sess.ID(), 1, wordBytes(1)...) // wl_shm.format xrgb8888 | |
| 616 | + | s.event(sess.ID(), 2, arr(make([]byte, 8))...) | |
| 617 | + | s.event(sess.ID(), 3, cat(wordBytes(0x34325258), arr(wordBytes(0, 0, 1, 0)))...) | |
| 618 | + | s.event(sess.ID(), 4) | |
| 619 | + | if !reflect.DeepEqual(shm, []uint32{1}) { | |
| 620 | + | t.Fatalf("shm formats %v", shm) | |
| 621 | + | } | |
| 622 | + | if size != [2]uint32{1280, 720} || len(dev) != 8 || dmaFormat != 0x34325258 || len(mods) != 16 || | |
| 623 | + | !reflect.DeepEqual(log, []string{"size", "shm", "dev", "dmabuf", "done"}) { | |
| 624 | + | t.Fatal(size, dev, dmaFormat, mods, log) | |
| 625 | + | } | |
| 626 | + | ||
| 627 | + | frame, e := sess.CreateFrame() | |
| 628 | + | noerr(t, e) | |
| 629 | + | wantWords(t, "create_frame", s.req(sess.ID(), 0), frame.ID()) | |
| 630 | + | buf := s.buffer() | |
| 631 | + | noerr(t, frame.AttachBuffer(buf)) | |
| 632 | + | wantWords(t, "attach_buffer", s.req(frame.ID(), 1), buf.ID()) | |
| 633 | + | noerr(t, frame.DamageBuffer(0, 0, 1280, 720)) | |
| 634 | + | wantWords(t, "damage_buffer", s.req(frame.ID(), 2), 0, 0, 1280, 720) | |
| 635 | + | noerr(t, frame.Capture()) | |
| 636 | + | s.req(frame.ID(), 3) | |
| 637 | + | ||
| 638 | + | var fl []string | |
| 639 | + | var damage [4]int32 | |
| 640 | + | var tv [3]uint32 | |
| 641 | + | frame.OnTransform(func(v uint32) { fl = append(fl, "transform") }) | |
| 642 | + | frame.OnDamage(func(x, y, w, h int32) { damage = [4]int32{x, y, w, h}; fl = append(fl, "damage") }) | |
| 643 | + | frame.OnPresentationTime(func(hi, lo, ns uint32) { tv = [3]uint32{hi, lo, ns}; fl = append(fl, "time") }) | |
| 644 | + | frame.OnReady(func() { fl = append(fl, "ready") }) | |
| 645 | + | frame.OnFailed(func(uint32) { fl = append(fl, "failed") }) | |
| 646 | + | s.event(frame.ID(), 0, wordBytes(0)...) | |
| 647 | + | s.event(frame.ID(), 1, wordBytes(1, 2, 3, 4)...) | |
| 648 | + | s.event(frame.ID(), 2, wordBytes(0, 1700000000, 999)...) | |
| 649 | + | s.event(frame.ID(), 3) | |
| 650 | + | if damage != [4]int32{1, 2, 3, 4} || tv != [3]uint32{0, 1700000000, 999} || | |
| 651 | + | !reflect.DeepEqual(fl, []string{"transform", "damage", "time", "ready"}) { | |
| 652 | + | t.Fatal(damage, tv, fl) | |
| 653 | + | } | |
| 654 | + | // ready is terminal for a frame, and a session allows one frame at a time | |
| 655 | + | // even after ready, so destroy it before creating the frame that fails. | |
| 656 | + | noerr(t, frame.Destroy()) | |
| 657 | + | s.req(frame.ID(), 0) | |
| 658 | + | failing, e := sess.CreateFrame() | |
| 659 | + | noerr(t, e) | |
| 660 | + | wantWords(t, "create_frame(2)", s.req(sess.ID(), 0), failing.ID()) | |
| 661 | + | noerr(t, failing.AttachBuffer(buf)) | |
| 662 | + | s.req(failing.ID(), 1) | |
| 663 | + | noerr(t, failing.Capture()) | |
| 664 | + | s.req(failing.ID(), 3) | |
| 665 | + | var reasons []uint32 | |
| 666 | + | failing.OnReady(func() { t.Error("failed frame must not become ready") }) | |
| 667 | + | failing.OnFailed(func(r uint32) { reasons = append(reasons, r) }) | |
| 668 | + | s.event(failing.ID(), 4, wordBytes(imagecopycapture.FAILURE_REASON_BUFFER_CONSTRAINTS)...) | |
| 669 | + | if !reflect.DeepEqual(reasons, []uint32{imagecopycapture.FAILURE_REASON_BUFFER_CONSTRAINTS}) { | |
| 670 | + | t.Fatal(reasons) | |
| 671 | + | } | |
| 672 | + | ||
| 673 | + | // Cursor session: get_capture_session is a typed child too. | |
| 674 | + | var cl []string | |
| 675 | + | var pos, hot [2]int32 | |
| 676 | + | cur.OnEnter(func() { cl = append(cl, "enter") }) | |
| 677 | + | cur.OnLeave(func() { cl = append(cl, "leave") }) | |
| 678 | + | cur.OnPosition(func(x, y int32) { pos = [2]int32{x, y} }) | |
| 679 | + | cur.OnHotspot(func(x, y int32) { hot = [2]int32{x, y} }) | |
| 680 | + | s.event(cur.ID(), 0) | |
| 681 | + | s.event(cur.ID(), 2, wordBytes(uint32(0xfffffffb), 9)...) // -5, 9 | |
| 682 | + | s.event(cur.ID(), 3, wordBytes(4, 6)...) | |
| 683 | + | s.event(cur.ID(), 1) | |
| 684 | + | if pos != [2]int32{-5, 9} || hot != [2]int32{4, 6} || !reflect.DeepEqual(cl, []string{"enter", "leave"}) { | |
| 685 | + | t.Fatal(pos, hot, cl) | |
| 686 | + | } | |
| 687 | + | csess, e := cur.GetCaptureSession() | |
| 688 | + | noerr(t, e) | |
| 689 | + | wantWords(t, "get_capture_session", s.req(cur.ID(), 1), csess.ID()) | |
| 690 | + | if csess.Version() != cur.Version() { | |
| 691 | + | t.Fatalf("child version %d, parent %d", csess.Version(), cur.Version()) | |
| 692 | + | } | |
| 693 | + | ||
| 694 | + | // destroy order: children, sources, managers, toplevel handle. | |
| 695 | + | for _, c := range []struct { | |
| 696 | + | name string | |
| 697 | + | id uint32 | |
| 698 | + | op uint16 | |
| 699 | + | fn func() error | |
| 700 | + | }{ | |
| 701 | + | {"failed frame", failing.ID(), 0, failing.Destroy}, | |
| 702 | + | {"capture session", csess.ID(), 1, csess.Destroy}, | |
| 703 | + | {"session", sess.ID(), 1, sess.Destroy}, | |
| 704 | + | {"cursor", cur.ID(), 0, cur.Destroy}, | |
| 705 | + | {"output source", outSrc.ID(), 0, outSrc.Destroy}, | |
| 706 | + | {"toplevel source", topSrc.ID(), 0, topSrc.Destroy}, | |
| 707 | + | {"copy manager", cm.ID(), 2, cm.Destroy}, | |
| 708 | + | {"output manager", om.ID(), 1, om.Destroy}, | |
| 709 | + | {"toplevel manager", fm.ID(), 1, fm.Destroy}, | |
| 710 | + | {"handle", handle.ID(), 0, handle.Destroy}, | |
| 711 | + | } { | |
| 712 | + | // Subtests run serially (no t.Parallel): the wire order of destroy | |
| 713 | + | // requests on the shared socketpair is part of what is asserted. | |
| 714 | + | ok := t.Run(c.name, func(t *testing.T) { | |
| 715 | + | ss := *s | |
| 716 | + | ss.t = t | |
| 717 | + | noerr(t, c.fn()) | |
| 718 | + | ss.req(c.id, c.op) | |
| 719 | + | }) | |
| 720 | + | if !ok { | |
| 721 | + | // A failed step leaves unread bytes on the socket; carrying on | |
| 722 | + | // would misattribute them to later destroys. | |
| 723 | + | t.FailNow() | |
| 724 | + | } | |
| 725 | + | } | |
| 726 | + | } | |
A client/inputmethod/inputmethod_generated.go +677 -0
| @@ -0,0 +1,677 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: input_method_unstable_v2 | |
| 3 | + | // Source: input-method-unstable-v2.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2008-2011 Kristian Høgsberg | |
| 7 | + | // Copyright © 2010-2011 Intel Corporation | |
| 8 | + | // Copyright © 2012-2013 Collabora, Ltd. | |
| 9 | + | // Copyright © 2012, 2013 Intel Corporation | |
| 10 | + | // Copyright © 2015, 2016 Jan Arne Petersen | |
| 11 | + | // Copyright © 2017, 2018 Red Hat, Inc. | |
| 12 | + | // Copyright © 2018 Purism SPC | |
| 13 | + | // | |
| 14 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 15 | + | // copy of this software and associated documentation files (the "Software"), | |
| 16 | + | // to deal in the Software without restriction, including without limitation | |
| 17 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 18 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 19 | + | // Software is furnished to do so, subject to the following conditions: | |
| 20 | + | // | |
| 21 | + | // The above copyright notice and this permission notice (including the next | |
| 22 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 23 | + | // Software. | |
| 24 | + | // | |
| 25 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 26 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 27 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 28 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 29 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 30 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 31 | + | // DEALINGS IN THE SOFTWARE. | |
| 32 | + | ||
| 33 | + | package inputmethod | |
| 34 | + | ||
| 35 | + | import ( | |
| 36 | + | "sync" | |
| 37 | + | ||
| 38 | + | cross_wl_seat "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 39 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 40 | + | "github.com/bnema/wlturbo/wl" | |
| 41 | + | ) | |
| 42 | + | ||
| 43 | + | // ERROR_ROLE is the error role value. | |
| 44 | + | const ERROR_ROLE = 0 | |
| 45 | + | ||
| 46 | + | // InputMethodInterface is the protocol interface name. | |
| 47 | + | const InputMethodInterface = "zwp_input_method_v2" | |
| 48 | + | ||
| 49 | + | // InputMethod is the generated binding for zwp_input_method_v2 version 1. | |
| 50 | + | type InputMethod struct { | |
| 51 | + | wl.BaseProxy | |
| 52 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 53 | + | // handlers while another goroutine dispatches events. | |
| 54 | + | handlersMu sync.Mutex | |
| 55 | + | onActivate []func() | |
| 56 | + | onDeactivate []func() | |
| 57 | + | onSurroundingText []func(text string, cursor uint32, anchor uint32) | |
| 58 | + | onTextChangeCause []func(cause uint32) | |
| 59 | + | onContentType []func(hint uint32, purpose uint32) | |
| 60 | + | onDone []func() | |
| 61 | + | onUnavailable []func() | |
| 62 | + | } | |
| 63 | + | ||
| 64 | + | // NewInputMethod returns an unbound InputMethod. | |
| 65 | + | func NewInputMethod(ctx *wl.Context) *InputMethod { | |
| 66 | + | obj := &InputMethod{} | |
| 67 | + | obj.SetContext(ctx) | |
| 68 | + | ctx.Register(obj) | |
| 69 | + | return obj | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | // Send the commit string text for insertion to the application. Inserts a string at current cursor position (see commit event sequence). The string to commit could be either just a single character after a key press or the result of some composing. The argument text is a buffer containing the string to insert. There is a maximum length of wayland messages, so text can not be longer than 4000 bytes. Values set with this event are double-buffered. They must be applied and reset to initial on the next zwp_text_input_v3.commit request. The initial value of text is an empty string. | |
| 73 | + | func (o *InputMethod) CommitString(text string) error { | |
| 74 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_input_method_v2.commit_string"}, wl.ArgString(text)); err != nil { | |
| 75 | + | return err | |
| 76 | + | } | |
| 77 | + | return nil | |
| 78 | + | } | |
| 79 | + | ||
| 80 | + | // Send the pre-edit string text to the application text input. Place a new composing text (pre-edit) at the current cursor position. Any previously set composing text must be removed. Any previously existing selected text must be removed. The cursor is moved to a new position within the preedit string. The argument text is a buffer containing the preedit string. There is a maximum length of wayland messages, so text can not be longer than 4000 bytes. The arguments cursor_begin and cursor_end are counted in bytes relative to the beginning of the submitted string buffer. Cursor should be hidden by the text input when both are equal to -1. cursor_begin indicates the beginning of the cursor. cursor_end indicates the end of the cursor. It may be equal or different than cursor_begin. Values set with this event are double-buffered. They must be applied on the next zwp_input_method_v2.commit event. The initial value of text is an empty string. The initial value of cursor_begin, and cursor_end are both 0. | |
| 81 | + | func (o *InputMethod) SetPreeditString(text string, cursorBegin int32, cursorEnd int32) error { | |
| 82 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_input_method_v2.set_preedit_string"}, wl.ArgString(text), wl.ArgInt(cursorBegin), wl.ArgInt(cursorEnd)); err != nil { | |
| 83 | + | return err | |
| 84 | + | } | |
| 85 | + | return nil | |
| 86 | + | } | |
| 87 | + | ||
| 88 | + | // Remove the surrounding text. before_length and after_length are the number of bytes before and after the current cursor index (excluding the preedit text) to delete. If any preedit text is present, it is replaced with the cursor for the purpose of this event. In effect before_length is counted from the beginning of preedit text, and after_length from its end (see commit event sequence). Values set with this event are double-buffered. They must be applied and reset to initial on the next zwp_input_method_v2.commit request. The initial values of both before_length and after_length are 0. | |
| 89 | + | func (o *InputMethod) DeleteSurroundingText(beforeLength uint32, afterLength uint32) error { | |
| 90 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_input_method_v2.delete_surrounding_text"}, wl.ArgUint(beforeLength), wl.ArgUint(afterLength)); err != nil { | |
| 91 | + | return err | |
| 92 | + | } | |
| 93 | + | return nil | |
| 94 | + | } | |
| 95 | + | ||
| 96 | + | // Apply state changes from commit_string, set_preedit_string and delete_surrounding_text requests. The state relating to these events is double-buffered, and each one modifies the pending state. This request replaces the current state with the pending state. The connected text input is expected to proceed by evaluating the changes in the following order: 1. Replace existing preedit string with the cursor. 2. Delete requested surrounding text. 3. Insert commit string with the cursor at its end. 4. Calculate surrounding text to send. 5. Insert new preedit text in cursor position. 6. Place cursor inside preedit text. The serial number reflects the last state of the zwp_input_method_v2 object known to the client. The value of the serial argument must be equal to the number of done events already issued by that object. When the compositor receives a commit request with a serial different than the number of past done events, it must proceed as normal, except it should not change the current state of the zwp_input_method_v2 object. | |
| 97 | + | func (o *InputMethod) Commit(serial uint32) error { | |
| 98 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "zwp_input_method_v2.commit"}, wl.ArgUint(serial)); err != nil { | |
| 99 | + | return err | |
| 100 | + | } | |
| 101 | + | return nil | |
| 102 | + | } | |
| 103 | + | ||
| 104 | + | // Creates a new zwp_input_popup_surface_v2 object wrapping a given surface. The surface gets assigned the "input_popup" role. If the surface already has an assigned role, the compositor must issue a protocol error. | |
| 105 | + | func (o *InputMethod) GetInputPopupSurface(surface *cross_wl_surface.Surface) (*InputPopupSurface, error) { | |
| 106 | + | var arg1 wl.Object | |
| 107 | + | if surface != nil { | |
| 108 | + | arg1 = surface | |
| 109 | + | } | |
| 110 | + | child := &InputPopupSurface{} | |
| 111 | + | child.SetContext(o.Context()) | |
| 112 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 4, Name: "zwp_input_method_v2.get_input_popup_surface", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 113 | + | return nil, err | |
| 114 | + | } | |
| 115 | + | return child, nil | |
| 116 | + | } | |
| 117 | + | ||
| 118 | + | // Allow an input method to receive hardware keyboard input and process key events to generate text events (with pre-edit) over the wire. This allows input methods which compose multiple key events for inputting text like it is done for CJK languages. The compositor should send all keyboard events on the seat to the grab holder via the returned wl_keyboard object. Nevertheless, the compositor may decide not to forward any particular event. The compositor must not further process any event after it has been forwarded to the grab holder. Releasing the resulting wl_keyboard object releases the grab. | |
| 119 | + | func (o *InputMethod) GrabKeyboard() (*InputMethodKeyboardGrab, error) { | |
| 120 | + | child := &InputMethodKeyboardGrab{} | |
| 121 | + | child.SetContext(o.Context()) | |
| 122 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 5, Name: "zwp_input_method_v2.grab_keyboard", Child: child}, wl.ArgObject(child)); err != nil { | |
| 123 | + | return nil, err | |
| 124 | + | } | |
| 125 | + | return child, nil | |
| 126 | + | } | |
| 127 | + | ||
| 128 | + | // Destroys the zwp_text_input_v2 object and any associated child objects, i.e. zwp_input_popup_surface_v2 and zwp_input_method_keyboard_grab_v2. | |
| 129 | + | func (o *InputMethod) Destroy() error { | |
| 130 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 6, Name: "zwp_input_method_v2.destroy", Destructor: true}); err != nil { | |
| 131 | + | return err | |
| 132 | + | } | |
| 133 | + | return nil | |
| 134 | + | } | |
| 135 | + | ||
| 136 | + | // OnActivate registers a handler for the activate event. | |
| 137 | + | // | |
| 138 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 139 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 140 | + | func (o *InputMethod) OnActivate(handler func()) { | |
| 141 | + | if handler == nil { | |
| 142 | + | return | |
| 143 | + | } | |
| 144 | + | o.handlersMu.Lock() | |
| 145 | + | defer o.handlersMu.Unlock() | |
| 146 | + | o.onActivate = append(o.onActivate, handler) | |
| 147 | + | } | |
| 148 | + | ||
| 149 | + | // handlersForActivate returns the handlers registered for activate, taken | |
| 150 | + | // under the lock so a handler may register another handler while events are | |
| 151 | + | // being dispatched. | |
| 152 | + | func (o *InputMethod) handlersForActivate() []func() { | |
| 153 | + | o.handlersMu.Lock() | |
| 154 | + | defer o.handlersMu.Unlock() | |
| 155 | + | return o.onActivate | |
| 156 | + | } | |
| 157 | + | ||
| 158 | + | // OnDeactivate registers a handler for the deactivate event. | |
| 159 | + | // | |
| 160 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 161 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 162 | + | func (o *InputMethod) OnDeactivate(handler func()) { | |
| 163 | + | if handler == nil { | |
| 164 | + | return | |
| 165 | + | } | |
| 166 | + | o.handlersMu.Lock() | |
| 167 | + | defer o.handlersMu.Unlock() | |
| 168 | + | o.onDeactivate = append(o.onDeactivate, handler) | |
| 169 | + | } | |
| 170 | + | ||
| 171 | + | // handlersForDeactivate returns the handlers registered for deactivate, taken | |
| 172 | + | // under the lock so a handler may register another handler while events are | |
| 173 | + | // being dispatched. | |
| 174 | + | func (o *InputMethod) handlersForDeactivate() []func() { | |
| 175 | + | o.handlersMu.Lock() | |
| 176 | + | defer o.handlersMu.Unlock() | |
| 177 | + | return o.onDeactivate | |
| 178 | + | } | |
| 179 | + | ||
| 180 | + | // OnSurroundingText registers a handler for the surrounding_text event. | |
| 181 | + | // | |
| 182 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 183 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 184 | + | func (o *InputMethod) OnSurroundingText(handler func(text string, cursor uint32, anchor uint32)) { | |
| 185 | + | if handler == nil { | |
| 186 | + | return | |
| 187 | + | } | |
| 188 | + | o.handlersMu.Lock() | |
| 189 | + | defer o.handlersMu.Unlock() | |
| 190 | + | o.onSurroundingText = append(o.onSurroundingText, handler) | |
| 191 | + | } | |
| 192 | + | ||
| 193 | + | // handlersForSurroundingText returns the handlers registered for surrounding_text, taken | |
| 194 | + | // under the lock so a handler may register another handler while events are | |
| 195 | + | // being dispatched. | |
| 196 | + | func (o *InputMethod) handlersForSurroundingText() []func(text string, cursor uint32, anchor uint32) { | |
| 197 | + | o.handlersMu.Lock() | |
| 198 | + | defer o.handlersMu.Unlock() | |
| 199 | + | return o.onSurroundingText | |
| 200 | + | } | |
| 201 | + | ||
| 202 | + | // OnTextChangeCause registers a handler for the text_change_cause event. | |
| 203 | + | // | |
| 204 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 205 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 206 | + | func (o *InputMethod) OnTextChangeCause(handler func(cause uint32)) { | |
| 207 | + | if handler == nil { | |
| 208 | + | return | |
| 209 | + | } | |
| 210 | + | o.handlersMu.Lock() | |
| 211 | + | defer o.handlersMu.Unlock() | |
| 212 | + | o.onTextChangeCause = append(o.onTextChangeCause, handler) | |
| 213 | + | } | |
| 214 | + | ||
| 215 | + | // handlersForTextChangeCause returns the handlers registered for text_change_cause, taken | |
| 216 | + | // under the lock so a handler may register another handler while events are | |
| 217 | + | // being dispatched. | |
| 218 | + | func (o *InputMethod) handlersForTextChangeCause() []func(cause uint32) { | |
| 219 | + | o.handlersMu.Lock() | |
| 220 | + | defer o.handlersMu.Unlock() | |
| 221 | + | return o.onTextChangeCause | |
| 222 | + | } | |
| 223 | + | ||
| 224 | + | // OnContentType registers a handler for the content_type event. | |
| 225 | + | // | |
| 226 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 227 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 228 | + | func (o *InputMethod) OnContentType(handler func(hint uint32, purpose uint32)) { | |
| 229 | + | if handler == nil { | |
| 230 | + | return | |
| 231 | + | } | |
| 232 | + | o.handlersMu.Lock() | |
| 233 | + | defer o.handlersMu.Unlock() | |
| 234 | + | o.onContentType = append(o.onContentType, handler) | |
| 235 | + | } | |
| 236 | + | ||
| 237 | + | // handlersForContentType returns the handlers registered for content_type, taken | |
| 238 | + | // under the lock so a handler may register another handler while events are | |
| 239 | + | // being dispatched. | |
| 240 | + | func (o *InputMethod) handlersForContentType() []func(hint uint32, purpose uint32) { | |
| 241 | + | o.handlersMu.Lock() | |
| 242 | + | defer o.handlersMu.Unlock() | |
| 243 | + | return o.onContentType | |
| 244 | + | } | |
| 245 | + | ||
| 246 | + | // OnDone registers a handler for the done event. | |
| 247 | + | // | |
| 248 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 249 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 250 | + | func (o *InputMethod) OnDone(handler func()) { | |
| 251 | + | if handler == nil { | |
| 252 | + | return | |
| 253 | + | } | |
| 254 | + | o.handlersMu.Lock() | |
| 255 | + | defer o.handlersMu.Unlock() | |
| 256 | + | o.onDone = append(o.onDone, handler) | |
| 257 | + | } | |
| 258 | + | ||
| 259 | + | // handlersForDone returns the handlers registered for done, taken | |
| 260 | + | // under the lock so a handler may register another handler while events are | |
| 261 | + | // being dispatched. | |
| 262 | + | func (o *InputMethod) handlersForDone() []func() { | |
| 263 | + | o.handlersMu.Lock() | |
| 264 | + | defer o.handlersMu.Unlock() | |
| 265 | + | return o.onDone | |
| 266 | + | } | |
| 267 | + | ||
| 268 | + | // OnUnavailable registers a handler for the unavailable event. | |
| 269 | + | // | |
| 270 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 271 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 272 | + | func (o *InputMethod) OnUnavailable(handler func()) { | |
| 273 | + | if handler == nil { | |
| 274 | + | return | |
| 275 | + | } | |
| 276 | + | o.handlersMu.Lock() | |
| 277 | + | defer o.handlersMu.Unlock() | |
| 278 | + | o.onUnavailable = append(o.onUnavailable, handler) | |
| 279 | + | } | |
| 280 | + | ||
| 281 | + | // handlersForUnavailable returns the handlers registered for unavailable, taken | |
| 282 | + | // under the lock so a handler may register another handler while events are | |
| 283 | + | // being dispatched. | |
| 284 | + | func (o *InputMethod) handlersForUnavailable() []func() { | |
| 285 | + | o.handlersMu.Lock() | |
| 286 | + | defer o.handlersMu.Unlock() | |
| 287 | + | return o.onUnavailable | |
| 288 | + | } | |
| 289 | + | ||
| 290 | + | // EventSignature returns the declared event argument types in wire order. | |
| 291 | + | func (o *InputMethod) EventSignature(opcode uint16) (string, bool) { | |
| 292 | + | switch opcode { | |
| 293 | + | case 0: | |
| 294 | + | return "", true | |
| 295 | + | case 1: | |
| 296 | + | return "", true | |
| 297 | + | case 2: | |
| 298 | + | return "string,uint,uint,", true | |
| 299 | + | case 3: | |
| 300 | + | return "uint,", true | |
| 301 | + | case 4: | |
| 302 | + | return "uint,uint,", true | |
| 303 | + | case 5: | |
| 304 | + | return "", true | |
| 305 | + | case 6: | |
| 306 | + | return "", true | |
| 307 | + | default: | |
| 308 | + | return "", false | |
| 309 | + | } | |
| 310 | + | } | |
| 311 | + | ||
| 312 | + | // Dispatch decodes one event on zwp_input_method_v2 and calls the registered handlers. | |
| 313 | + | func (o *InputMethod) Dispatch(event *wl.Event) { | |
| 314 | + | switch event.Opcode { | |
| 315 | + | case 0: // activate | |
| 316 | + | ||
| 317 | + | for i, handler := range o.handlersForActivate() { | |
| 318 | + | _ = i | |
| 319 | + | handler() | |
| 320 | + | } | |
| 321 | + | case 1: // deactivate | |
| 322 | + | ||
| 323 | + | for i, handler := range o.handlersForDeactivate() { | |
| 324 | + | _ = i | |
| 325 | + | handler() | |
| 326 | + | } | |
| 327 | + | case 2: // surrounding_text | |
| 328 | + | text := event.String() | |
| 329 | + | cursor := event.Uint32() | |
| 330 | + | anchor := event.Uint32() | |
| 331 | + | ||
| 332 | + | for i, handler := range o.handlersForSurroundingText() { | |
| 333 | + | _ = i | |
| 334 | + | handler(text, cursor, anchor) | |
| 335 | + | } | |
| 336 | + | case 3: // text_change_cause | |
| 337 | + | cause := event.Uint32() | |
| 338 | + | ||
| 339 | + | for i, handler := range o.handlersForTextChangeCause() { | |
| 340 | + | _ = i | |
| 341 | + | handler(cause) | |
| 342 | + | } | |
| 343 | + | case 4: // content_type | |
| 344 | + | hint := event.Uint32() | |
| 345 | + | purpose := event.Uint32() | |
| 346 | + | ||
| 347 | + | for i, handler := range o.handlersForContentType() { | |
| 348 | + | _ = i | |
| 349 | + | handler(hint, purpose) | |
| 350 | + | } | |
| 351 | + | case 5: // done | |
| 352 | + | ||
| 353 | + | for i, handler := range o.handlersForDone() { | |
| 354 | + | _ = i | |
| 355 | + | handler() | |
| 356 | + | } | |
| 357 | + | case 6: // unavailable | |
| 358 | + | ||
| 359 | + | for i, handler := range o.handlersForUnavailable() { | |
| 360 | + | _ = i | |
| 361 | + | handler() | |
| 362 | + | } | |
| 363 | + | default: | |
| 364 | + | } | |
| 365 | + | } | |
| 366 | + | ||
| 367 | + | // InputPopupSurfaceInterface is the protocol interface name. | |
| 368 | + | const InputPopupSurfaceInterface = "zwp_input_popup_surface_v2" | |
| 369 | + | ||
| 370 | + | // InputPopupSurface is the generated binding for zwp_input_popup_surface_v2 version 1. | |
| 371 | + | type InputPopupSurface struct { | |
| 372 | + | wl.BaseProxy | |
| 373 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 374 | + | // handlers while another goroutine dispatches events. | |
| 375 | + | handlersMu sync.Mutex | |
| 376 | + | onTextInputRectangle []func(x int32, y int32, width int32, height int32) | |
| 377 | + | } | |
| 378 | + | ||
| 379 | + | // NewInputPopupSurface returns an unbound InputPopupSurface. | |
| 380 | + | func NewInputPopupSurface(ctx *wl.Context) *InputPopupSurface { | |
| 381 | + | obj := &InputPopupSurface{} | |
| 382 | + | obj.SetContext(ctx) | |
| 383 | + | ctx.Register(obj) | |
| 384 | + | return obj | |
| 385 | + | } | |
| 386 | + | func (o *InputPopupSurface) Destroy() error { | |
| 387 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_input_popup_surface_v2.destroy", Destructor: true}); err != nil { | |
| 388 | + | return err | |
| 389 | + | } | |
| 390 | + | return nil | |
| 391 | + | } | |
| 392 | + | ||
| 393 | + | // OnTextInputRectangle registers a handler for the text_input_rectangle event. | |
| 394 | + | // | |
| 395 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 396 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 397 | + | func (o *InputPopupSurface) OnTextInputRectangle(handler func(x int32, y int32, width int32, height int32)) { | |
| 398 | + | if handler == nil { | |
| 399 | + | return | |
| 400 | + | } | |
| 401 | + | o.handlersMu.Lock() | |
| 402 | + | defer o.handlersMu.Unlock() | |
| 403 | + | o.onTextInputRectangle = append(o.onTextInputRectangle, handler) | |
| 404 | + | } | |
| 405 | + | ||
| 406 | + | // handlersForTextInputRectangle returns the handlers registered for text_input_rectangle, taken | |
| 407 | + | // under the lock so a handler may register another handler while events are | |
| 408 | + | // being dispatched. | |
| 409 | + | func (o *InputPopupSurface) handlersForTextInputRectangle() []func(x int32, y int32, width int32, height int32) { | |
| 410 | + | o.handlersMu.Lock() | |
| 411 | + | defer o.handlersMu.Unlock() | |
| 412 | + | return o.onTextInputRectangle | |
| 413 | + | } | |
| 414 | + | ||
| 415 | + | // EventSignature returns the declared event argument types in wire order. | |
| 416 | + | func (o *InputPopupSurface) EventSignature(opcode uint16) (string, bool) { | |
| 417 | + | switch opcode { | |
| 418 | + | case 0: | |
| 419 | + | return "int,int,int,int,", true | |
| 420 | + | default: | |
| 421 | + | return "", false | |
| 422 | + | } | |
| 423 | + | } | |
| 424 | + | ||
| 425 | + | // Dispatch decodes one event on zwp_input_popup_surface_v2 and calls the registered handlers. | |
| 426 | + | func (o *InputPopupSurface) Dispatch(event *wl.Event) { | |
| 427 | + | switch event.Opcode { | |
| 428 | + | case 0: // text_input_rectangle | |
| 429 | + | x := event.Int32() | |
| 430 | + | y := event.Int32() | |
| 431 | + | width := event.Int32() | |
| 432 | + | height := event.Int32() | |
| 433 | + | ||
| 434 | + | for i, handler := range o.handlersForTextInputRectangle() { | |
| 435 | + | _ = i | |
| 436 | + | handler(x, y, width, height) | |
| 437 | + | } | |
| 438 | + | default: | |
| 439 | + | } | |
| 440 | + | } | |
| 441 | + | ||
| 442 | + | // InputMethodKeyboardGrabInterface is the protocol interface name. | |
| 443 | + | const InputMethodKeyboardGrabInterface = "zwp_input_method_keyboard_grab_v2" | |
| 444 | + | ||
| 445 | + | // InputMethodKeyboardGrab is the generated binding for zwp_input_method_keyboard_grab_v2 version 1. | |
| 446 | + | type InputMethodKeyboardGrab struct { | |
| 447 | + | wl.BaseProxy | |
| 448 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 449 | + | // handlers while another goroutine dispatches events. | |
| 450 | + | handlersMu sync.Mutex | |
| 451 | + | onKeymap []func(format uint32, fd *wl.OwnedFD, size uint32) | |
| 452 | + | onKey []func(serial uint32, time uint32, key uint32, state uint32) | |
| 453 | + | onModifiers []func(serial uint32, modsDepressed uint32, modsLatched uint32, modsLocked uint32, group uint32) | |
| 454 | + | onRepeatInfo []func(rate int32, delay int32) | |
| 455 | + | } | |
| 456 | + | ||
| 457 | + | // NewInputMethodKeyboardGrab returns an unbound InputMethodKeyboardGrab. | |
| 458 | + | func NewInputMethodKeyboardGrab(ctx *wl.Context) *InputMethodKeyboardGrab { | |
| 459 | + | obj := &InputMethodKeyboardGrab{} | |
| 460 | + | obj.SetContext(ctx) | |
| 461 | + | ctx.Register(obj) | |
| 462 | + | return obj | |
| 463 | + | } | |
| 464 | + | ||
| 465 | + | // release the grab object | |
| 466 | + | func (o *InputMethodKeyboardGrab) Release() error { | |
| 467 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_input_method_keyboard_grab_v2.release", Destructor: true}); err != nil { | |
| 468 | + | return err | |
| 469 | + | } | |
| 470 | + | return nil | |
| 471 | + | } | |
| 472 | + | ||
| 473 | + | // OnKeymap registers a handler for the keymap event. | |
| 474 | + | // | |
| 475 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 476 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 477 | + | func (o *InputMethodKeyboardGrab) OnKeymap(handler func(format uint32, fd *wl.OwnedFD, size uint32)) { | |
| 478 | + | if handler == nil { | |
| 479 | + | return | |
| 480 | + | } | |
| 481 | + | o.handlersMu.Lock() | |
| 482 | + | defer o.handlersMu.Unlock() | |
| 483 | + | o.onKeymap = append(o.onKeymap, handler) | |
| 484 | + | } | |
| 485 | + | ||
| 486 | + | // handlersForKeymap returns the handlers registered for keymap, taken | |
| 487 | + | // under the lock so a handler may register another handler while events are | |
| 488 | + | // being dispatched. | |
| 489 | + | func (o *InputMethodKeyboardGrab) handlersForKeymap() []func(format uint32, fd *wl.OwnedFD, size uint32) { | |
| 490 | + | o.handlersMu.Lock() | |
| 491 | + | defer o.handlersMu.Unlock() | |
| 492 | + | return o.onKeymap | |
| 493 | + | } | |
| 494 | + | ||
| 495 | + | // OnKey registers a handler for the key event. | |
| 496 | + | // | |
| 497 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 498 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 499 | + | func (o *InputMethodKeyboardGrab) OnKey(handler func(serial uint32, time uint32, key uint32, state uint32)) { | |
| 500 | + | if handler == nil { | |
| 501 | + | return | |
| 502 | + | } | |
| 503 | + | o.handlersMu.Lock() | |
| 504 | + | defer o.handlersMu.Unlock() | |
| 505 | + | o.onKey = append(o.onKey, handler) | |
| 506 | + | } | |
| 507 | + | ||
| 508 | + | // handlersForKey returns the handlers registered for key, taken | |
| 509 | + | // under the lock so a handler may register another handler while events are | |
| 510 | + | // being dispatched. | |
| 511 | + | func (o *InputMethodKeyboardGrab) handlersForKey() []func(serial uint32, time uint32, key uint32, state uint32) { | |
| 512 | + | o.handlersMu.Lock() | |
| 513 | + | defer o.handlersMu.Unlock() | |
| 514 | + | return o.onKey | |
| 515 | + | } | |
| 516 | + | ||
| 517 | + | // OnModifiers registers a handler for the modifiers event. | |
| 518 | + | // | |
| 519 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 520 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 521 | + | func (o *InputMethodKeyboardGrab) OnModifiers(handler func(serial uint32, modsDepressed uint32, modsLatched uint32, modsLocked uint32, group uint32)) { | |
| 522 | + | if handler == nil { | |
| 523 | + | return | |
| 524 | + | } | |
| 525 | + | o.handlersMu.Lock() | |
| 526 | + | defer o.handlersMu.Unlock() | |
| 527 | + | o.onModifiers = append(o.onModifiers, handler) | |
| 528 | + | } | |
| 529 | + | ||
| 530 | + | // handlersForModifiers returns the handlers registered for modifiers, taken | |
| 531 | + | // under the lock so a handler may register another handler while events are | |
| 532 | + | // being dispatched. | |
| 533 | + | func (o *InputMethodKeyboardGrab) handlersForModifiers() []func(serial uint32, modsDepressed uint32, modsLatched uint32, modsLocked uint32, group uint32) { | |
| 534 | + | o.handlersMu.Lock() | |
| 535 | + | defer o.handlersMu.Unlock() | |
| 536 | + | return o.onModifiers | |
| 537 | + | } | |
| 538 | + | ||
| 539 | + | // OnRepeatInfo registers a handler for the repeat_info event. | |
| 540 | + | // | |
| 541 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 542 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 543 | + | func (o *InputMethodKeyboardGrab) OnRepeatInfo(handler func(rate int32, delay int32)) { | |
| 544 | + | if handler == nil { | |
| 545 | + | return | |
| 546 | + | } | |
| 547 | + | o.handlersMu.Lock() | |
| 548 | + | defer o.handlersMu.Unlock() | |
| 549 | + | o.onRepeatInfo = append(o.onRepeatInfo, handler) | |
| 550 | + | } | |
| 551 | + | ||
| 552 | + | // handlersForRepeatInfo returns the handlers registered for repeat_info, taken | |
| 553 | + | // under the lock so a handler may register another handler while events are | |
| 554 | + | // being dispatched. | |
| 555 | + | func (o *InputMethodKeyboardGrab) handlersForRepeatInfo() []func(rate int32, delay int32) { | |
| 556 | + | o.handlersMu.Lock() | |
| 557 | + | defer o.handlersMu.Unlock() | |
| 558 | + | return o.onRepeatInfo | |
| 559 | + | } | |
| 560 | + | ||
| 561 | + | // EventSignature returns the declared event argument types in wire order. | |
| 562 | + | func (o *InputMethodKeyboardGrab) EventSignature(opcode uint16) (string, bool) { | |
| 563 | + | switch opcode { | |
| 564 | + | case 0: | |
| 565 | + | return "uint,fd,uint,", true | |
| 566 | + | case 1: | |
| 567 | + | return "uint,uint,uint,uint,", true | |
| 568 | + | case 2: | |
| 569 | + | return "uint,uint,uint,uint,uint,", true | |
| 570 | + | case 3: | |
| 571 | + | return "int,int,", true | |
| 572 | + | default: | |
| 573 | + | return "", false | |
| 574 | + | } | |
| 575 | + | } | |
| 576 | + | ||
| 577 | + | // Dispatch decodes one event on zwp_input_method_keyboard_grab_v2 and calls the registered handlers. | |
| 578 | + | func (o *InputMethodKeyboardGrab) Dispatch(event *wl.Event) { | |
| 579 | + | switch event.Opcode { | |
| 580 | + | case 0: // keymap | |
| 581 | + | format := event.Uint32() | |
| 582 | + | fd := event.FD() | |
| 583 | + | size := event.Uint32() | |
| 584 | + | ownedfd := fd | |
| 585 | + | defer ownedfd.Close() | |
| 586 | + | ||
| 587 | + | for i, handler := range o.handlersForKeymap() { | |
| 588 | + | if i > 0 { | |
| 589 | + | fd = nil | |
| 590 | + | } | |
| 591 | + | handler(format, fd, size) | |
| 592 | + | } | |
| 593 | + | case 1: // key | |
| 594 | + | serial := event.Uint32() | |
| 595 | + | time := event.Uint32() | |
| 596 | + | key := event.Uint32() | |
| 597 | + | state := event.Uint32() | |
| 598 | + | ||
| 599 | + | for i, handler := range o.handlersForKey() { | |
| 600 | + | _ = i | |
| 601 | + | handler(serial, time, key, state) | |
| 602 | + | } | |
| 603 | + | case 2: // modifiers | |
| 604 | + | serial := event.Uint32() | |
| 605 | + | modsDepressed := event.Uint32() | |
| 606 | + | modsLatched := event.Uint32() | |
| 607 | + | modsLocked := event.Uint32() | |
| 608 | + | group := event.Uint32() | |
| 609 | + | ||
| 610 | + | for i, handler := range o.handlersForModifiers() { | |
| 611 | + | _ = i | |
| 612 | + | handler(serial, modsDepressed, modsLatched, modsLocked, group) | |
| 613 | + | } | |
| 614 | + | case 3: // repeat_info | |
| 615 | + | rate := event.Int32() | |
| 616 | + | delay := event.Int32() | |
| 617 | + | ||
| 618 | + | for i, handler := range o.handlersForRepeatInfo() { | |
| 619 | + | _ = i | |
| 620 | + | handler(rate, delay) | |
| 621 | + | } | |
| 622 | + | default: | |
| 623 | + | } | |
| 624 | + | } | |
| 625 | + | ||
| 626 | + | // InputMethodManagerInterface is the protocol interface name. | |
| 627 | + | const InputMethodManagerInterface = "zwp_input_method_manager_v2" | |
| 628 | + | ||
| 629 | + | // InputMethodManager is the generated binding for zwp_input_method_manager_v2 version 1. | |
| 630 | + | type InputMethodManager struct { | |
| 631 | + | wl.BaseProxy | |
| 632 | + | } | |
| 633 | + | ||
| 634 | + | // NewInputMethodManager returns an unbound InputMethodManager. | |
| 635 | + | func NewInputMethodManager(ctx *wl.Context) *InputMethodManager { | |
| 636 | + | obj := &InputMethodManager{} | |
| 637 | + | obj.SetContext(ctx) | |
| 638 | + | ctx.Register(obj) | |
| 639 | + | return obj | |
| 640 | + | } | |
| 641 | + | ||
| 642 | + | // Request a new input zwp_input_method_v2 object associated with a given seat. | |
| 643 | + | func (o *InputMethodManager) GetInputMethod(seat *cross_wl_seat.Seat) (*InputMethod, error) { | |
| 644 | + | var arg0 wl.Object | |
| 645 | + | if seat != nil { | |
| 646 | + | arg0 = seat | |
| 647 | + | } | |
| 648 | + | child := &InputMethod{} | |
| 649 | + | child.SetContext(o.Context()) | |
| 650 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_input_method_manager_v2.get_input_method", Child: child}, wl.ArgObject(arg0), wl.ArgObject(child)); err != nil { | |
| 651 | + | return nil, err | |
| 652 | + | } | |
| 653 | + | return child, nil | |
| 654 | + | } | |
| 655 | + | ||
| 656 | + | // Destroys the zwp_input_method_manager_v2 object. The zwp_input_method_v2 objects originating from it remain valid. | |
| 657 | + | func (o *InputMethodManager) Destroy() error { | |
| 658 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_input_method_manager_v2.destroy", Destructor: true}); err != nil { | |
| 659 | + | return err | |
| 660 | + | } | |
| 661 | + | return nil | |
| 662 | + | } | |
| 663 | + | ||
| 664 | + | // EventSignature returns the declared event argument types in wire order. | |
| 665 | + | func (o *InputMethodManager) EventSignature(opcode uint16) (string, bool) { | |
| 666 | + | switch opcode { | |
| 667 | + | default: | |
| 668 | + | return "", false | |
| 669 | + | } | |
| 670 | + | } | |
| 671 | + | ||
| 672 | + | // Dispatch decodes one event on zwp_input_method_manager_v2 and calls the registered handlers. | |
| 673 | + | func (o *InputMethodManager) Dispatch(event *wl.Event) { | |
| 674 | + | switch event.Opcode { | |
| 675 | + | default: | |
| 676 | + | } | |
| 677 | + | } | |
A client/inputtimestamps/inputtimestamps_generated.go +193 -0
| @@ -0,0 +1,193 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: input_timestamps_unstable_v1 | |
| 3 | + | // Source: input-timestamps-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2017 Collabora, Ltd. | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package inputtimestamps | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | "sync" | |
| 31 | + | ||
| 32 | + | cross_wl_keyboard "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 33 | + | cross_wl_pointer "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 34 | + | cross_wl_touch "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 35 | + | "github.com/bnema/wlturbo/wl" | |
| 36 | + | ) | |
| 37 | + | ||
| 38 | + | // InputTimestampsManagerInterface is the protocol interface name. | |
| 39 | + | const InputTimestampsManagerInterface = "zwp_input_timestamps_manager_v1" | |
| 40 | + | ||
| 41 | + | // InputTimestampsManager is the generated binding for zwp_input_timestamps_manager_v1 version 1. | |
| 42 | + | type InputTimestampsManager struct { | |
| 43 | + | wl.BaseProxy | |
| 44 | + | } | |
| 45 | + | ||
| 46 | + | // NewInputTimestampsManager returns an unbound InputTimestampsManager. | |
| 47 | + | func NewInputTimestampsManager(ctx *wl.Context) *InputTimestampsManager { | |
| 48 | + | obj := &InputTimestampsManager{} | |
| 49 | + | obj.SetContext(ctx) | |
| 50 | + | ctx.Register(obj) | |
| 51 | + | return obj | |
| 52 | + | } | |
| 53 | + | ||
| 54 | + | // Informs the server that the client will no longer be using this protocol object. Existing objects created by this object are not affected. | |
| 55 | + | func (o *InputTimestampsManager) Destroy() error { | |
| 56 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_input_timestamps_manager_v1.destroy", Destructor: true}); err != nil { | |
| 57 | + | return err | |
| 58 | + | } | |
| 59 | + | return nil | |
| 60 | + | } | |
| 61 | + | ||
| 62 | + | // Creates a new input timestamps object that represents a subscription to high-resolution timestamp events for all wl_keyboard events that carry a timestamp. If the associated wl_keyboard object is invalidated, either through client action (e.g. release) or server-side changes, the input timestamps object becomes inert and the client should destroy it by calling zwp_input_timestamps_v1.destroy. | |
| 63 | + | func (o *InputTimestampsManager) GetKeyboardTimestamps(keyboard *cross_wl_keyboard.Keyboard) (*InputTimestamps, error) { | |
| 64 | + | var arg1 wl.Object | |
| 65 | + | if keyboard != nil { | |
| 66 | + | arg1 = keyboard | |
| 67 | + | } | |
| 68 | + | child := &InputTimestamps{} | |
| 69 | + | child.SetContext(o.Context()) | |
| 70 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_input_timestamps_manager_v1.get_keyboard_timestamps", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 71 | + | return nil, err | |
| 72 | + | } | |
| 73 | + | return child, nil | |
| 74 | + | } | |
| 75 | + | ||
| 76 | + | // Creates a new input timestamps object that represents a subscription to high-resolution timestamp events for all wl_pointer events that carry a timestamp. If the associated wl_pointer object is invalidated, either through client action (e.g. release) or server-side changes, the input timestamps object becomes inert and the client should destroy it by calling zwp_input_timestamps_v1.destroy. | |
| 77 | + | func (o *InputTimestampsManager) GetPointerTimestamps(pointer *cross_wl_pointer.Pointer) (*InputTimestamps, error) { | |
| 78 | + | var arg1 wl.Object | |
| 79 | + | if pointer != nil { | |
| 80 | + | arg1 = pointer | |
| 81 | + | } | |
| 82 | + | child := &InputTimestamps{} | |
| 83 | + | child.SetContext(o.Context()) | |
| 84 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_input_timestamps_manager_v1.get_pointer_timestamps", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 85 | + | return nil, err | |
| 86 | + | } | |
| 87 | + | return child, nil | |
| 88 | + | } | |
| 89 | + | ||
| 90 | + | // Creates a new input timestamps object that represents a subscription to high-resolution timestamp events for all wl_touch events that carry a timestamp. If the associated wl_touch object becomes invalid, either through client action (e.g. release) or server-side changes, the input timestamps object becomes inert and the client should destroy it by calling zwp_input_timestamps_v1.destroy. | |
| 91 | + | func (o *InputTimestampsManager) GetTouchTimestamps(touch *cross_wl_touch.Touch) (*InputTimestamps, error) { | |
| 92 | + | var arg1 wl.Object | |
| 93 | + | if touch != nil { | |
| 94 | + | arg1 = touch | |
| 95 | + | } | |
| 96 | + | child := &InputTimestamps{} | |
| 97 | + | child.SetContext(o.Context()) | |
| 98 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "zwp_input_timestamps_manager_v1.get_touch_timestamps", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 99 | + | return nil, err | |
| 100 | + | } | |
| 101 | + | return child, nil | |
| 102 | + | } | |
| 103 | + | ||
| 104 | + | // EventSignature returns the declared event argument types in wire order. | |
| 105 | + | func (o *InputTimestampsManager) EventSignature(opcode uint16) (string, bool) { | |
| 106 | + | switch opcode { | |
| 107 | + | default: | |
| 108 | + | return "", false | |
| 109 | + | } | |
| 110 | + | } | |
| 111 | + | ||
| 112 | + | // Dispatch decodes one event on zwp_input_timestamps_manager_v1 and calls the registered handlers. | |
| 113 | + | func (o *InputTimestampsManager) Dispatch(event *wl.Event) { | |
| 114 | + | switch event.Opcode { | |
| 115 | + | default: | |
| 116 | + | } | |
| 117 | + | } | |
| 118 | + | ||
| 119 | + | // InputTimestampsInterface is the protocol interface name. | |
| 120 | + | const InputTimestampsInterface = "zwp_input_timestamps_v1" | |
| 121 | + | ||
| 122 | + | // InputTimestamps is the generated binding for zwp_input_timestamps_v1 version 1. | |
| 123 | + | type InputTimestamps struct { | |
| 124 | + | wl.BaseProxy | |
| 125 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 126 | + | // handlers while another goroutine dispatches events. | |
| 127 | + | handlersMu sync.Mutex | |
| 128 | + | onTimestamp []func(tvSecHi uint32, tvSecLo uint32, tvNsec uint32) | |
| 129 | + | } | |
| 130 | + | ||
| 131 | + | // NewInputTimestamps returns an unbound InputTimestamps. | |
| 132 | + | func NewInputTimestamps(ctx *wl.Context) *InputTimestamps { | |
| 133 | + | obj := &InputTimestamps{} | |
| 134 | + | obj.SetContext(ctx) | |
| 135 | + | ctx.Register(obj) | |
| 136 | + | return obj | |
| 137 | + | } | |
| 138 | + | ||
| 139 | + | // Informs the server that the client will no longer be using this protocol object. After the server processes the request, no more timestamp events will be emitted. | |
| 140 | + | func (o *InputTimestamps) Destroy() error { | |
| 141 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_input_timestamps_v1.destroy", Destructor: true}); err != nil { | |
| 142 | + | return err | |
| 143 | + | } | |
| 144 | + | return nil | |
| 145 | + | } | |
| 146 | + | ||
| 147 | + | // OnTimestamp registers a handler for the timestamp event. | |
| 148 | + | // | |
| 149 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 150 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 151 | + | func (o *InputTimestamps) OnTimestamp(handler func(tvSecHi uint32, tvSecLo uint32, tvNsec uint32)) { | |
| 152 | + | if handler == nil { | |
| 153 | + | return | |
| 154 | + | } | |
| 155 | + | o.handlersMu.Lock() | |
| 156 | + | defer o.handlersMu.Unlock() | |
| 157 | + | o.onTimestamp = append(o.onTimestamp, handler) | |
| 158 | + | } | |
| 159 | + | ||
| 160 | + | // handlersForTimestamp returns the handlers registered for timestamp, taken | |
| 161 | + | // under the lock so a handler may register another handler while events are | |
| 162 | + | // being dispatched. | |
| 163 | + | func (o *InputTimestamps) handlersForTimestamp() []func(tvSecHi uint32, tvSecLo uint32, tvNsec uint32) { | |
| 164 | + | o.handlersMu.Lock() | |
| 165 | + | defer o.handlersMu.Unlock() | |
| 166 | + | return o.onTimestamp | |
| 167 | + | } | |
| 168 | + | ||
| 169 | + | // EventSignature returns the declared event argument types in wire order. | |
| 170 | + | func (o *InputTimestamps) EventSignature(opcode uint16) (string, bool) { | |
| 171 | + | switch opcode { | |
| 172 | + | case 0: | |
| 173 | + | return "uint,uint,uint,", true | |
| 174 | + | default: | |
| 175 | + | return "", false | |
| 176 | + | } | |
| 177 | + | } | |
| 178 | + | ||
| 179 | + | // Dispatch decodes one event on zwp_input_timestamps_v1 and calls the registered handlers. | |
| 180 | + | func (o *InputTimestamps) Dispatch(event *wl.Event) { | |
| 181 | + | switch event.Opcode { | |
| 182 | + | case 0: // timestamp | |
| 183 | + | tvSecHi := event.Uint32() | |
| 184 | + | tvSecLo := event.Uint32() | |
| 185 | + | tvNsec := event.Uint32() | |
| 186 | + | ||
| 187 | + | for i, handler := range o.handlersForTimestamp() { | |
| 188 | + | _ = i | |
| 189 | + | handler(tvSecHi, tvSecLo, tvNsec) | |
| 190 | + | } | |
| 191 | + | default: | |
| 192 | + | } | |
| 193 | + | } | |
A client/keyboardshortcutsinhibit/keyboardshortcutsinhibit_generated.go +199 -0
| @@ -0,0 +1,199 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: keyboard_shortcuts_inhibit_unstable_v1 | |
| 3 | + | // Source: keyboard-shortcuts-inhibit-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2017 Red Hat Inc. | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package keyboardshortcutsinhibit | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | "sync" | |
| 31 | + | ||
| 32 | + | cross_wl_seat "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 33 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 34 | + | "github.com/bnema/wlturbo/wl" | |
| 35 | + | ) | |
| 36 | + | ||
| 37 | + | // ERROR_ALREADY_INHIBITED is the error already_inhibited value. | |
| 38 | + | const ERROR_ALREADY_INHIBITED = 0 | |
| 39 | + | ||
| 40 | + | // KeyboardShortcutsInhibitManagerInterface is the protocol interface name. | |
| 41 | + | const KeyboardShortcutsInhibitManagerInterface = "zwp_keyboard_shortcuts_inhibit_manager_v1" | |
| 42 | + | ||
| 43 | + | // KeyboardShortcutsInhibitManager is the generated binding for zwp_keyboard_shortcuts_inhibit_manager_v1 version 1. | |
| 44 | + | type KeyboardShortcutsInhibitManager struct { | |
| 45 | + | wl.BaseProxy | |
| 46 | + | } | |
| 47 | + | ||
| 48 | + | // NewKeyboardShortcutsInhibitManager returns an unbound KeyboardShortcutsInhibitManager. | |
| 49 | + | func NewKeyboardShortcutsInhibitManager(ctx *wl.Context) *KeyboardShortcutsInhibitManager { | |
| 50 | + | obj := &KeyboardShortcutsInhibitManager{} | |
| 51 | + | obj.SetContext(ctx) | |
| 52 | + | ctx.Register(obj) | |
| 53 | + | return obj | |
| 54 | + | } | |
| 55 | + | ||
| 56 | + | // Destroy the keyboard shortcuts inhibitor manager. | |
| 57 | + | func (o *KeyboardShortcutsInhibitManager) Destroy() error { | |
| 58 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_keyboard_shortcuts_inhibit_manager_v1.destroy", Destructor: true}); err != nil { | |
| 59 | + | return err | |
| 60 | + | } | |
| 61 | + | return nil | |
| 62 | + | } | |
| 63 | + | ||
| 64 | + | // Create a new keyboard shortcuts inhibitor object associated with the given surface for the given seat. If shortcuts are already inhibited for the specified seat and surface, a protocol error "already_inhibited" is raised by the compositor. | |
| 65 | + | func (o *KeyboardShortcutsInhibitManager) InhibitShortcuts(surface *cross_wl_surface.Surface, seat *cross_wl_seat.Seat) (*KeyboardShortcutsInhibitor, error) { | |
| 66 | + | var arg1 wl.Object | |
| 67 | + | if surface != nil { | |
| 68 | + | arg1 = surface | |
| 69 | + | } | |
| 70 | + | var arg2 wl.Object | |
| 71 | + | if seat != nil { | |
| 72 | + | arg2 = seat | |
| 73 | + | } | |
| 74 | + | child := &KeyboardShortcutsInhibitor{} | |
| 75 | + | child.SetContext(o.Context()) | |
| 76 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_keyboard_shortcuts_inhibit_manager_v1.inhibit_shortcuts", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1), wl.ArgObject(arg2)); err != nil { | |
| 77 | + | return nil, err | |
| 78 | + | } | |
| 79 | + | return child, nil | |
| 80 | + | } | |
| 81 | + | ||
| 82 | + | // EventSignature returns the declared event argument types in wire order. | |
| 83 | + | func (o *KeyboardShortcutsInhibitManager) EventSignature(opcode uint16) (string, bool) { | |
| 84 | + | switch opcode { | |
| 85 | + | default: | |
| 86 | + | return "", false | |
| 87 | + | } | |
| 88 | + | } | |
| 89 | + | ||
| 90 | + | // Dispatch decodes one event on zwp_keyboard_shortcuts_inhibit_manager_v1 and calls the registered handlers. | |
| 91 | + | func (o *KeyboardShortcutsInhibitManager) Dispatch(event *wl.Event) { | |
| 92 | + | switch event.Opcode { | |
| 93 | + | default: | |
| 94 | + | } | |
| 95 | + | } | |
| 96 | + | ||
| 97 | + | // KeyboardShortcutsInhibitorInterface is the protocol interface name. | |
| 98 | + | const KeyboardShortcutsInhibitorInterface = "zwp_keyboard_shortcuts_inhibitor_v1" | |
| 99 | + | ||
| 100 | + | // KeyboardShortcutsInhibitor is the generated binding for zwp_keyboard_shortcuts_inhibitor_v1 version 1. | |
| 101 | + | type KeyboardShortcutsInhibitor struct { | |
| 102 | + | wl.BaseProxy | |
| 103 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 104 | + | // handlers while another goroutine dispatches events. | |
| 105 | + | handlersMu sync.Mutex | |
| 106 | + | onActive []func() | |
| 107 | + | onInactive []func() | |
| 108 | + | } | |
| 109 | + | ||
| 110 | + | // NewKeyboardShortcutsInhibitor returns an unbound KeyboardShortcutsInhibitor. | |
| 111 | + | func NewKeyboardShortcutsInhibitor(ctx *wl.Context) *KeyboardShortcutsInhibitor { | |
| 112 | + | obj := &KeyboardShortcutsInhibitor{} | |
| 113 | + | obj.SetContext(ctx) | |
| 114 | + | ctx.Register(obj) | |
| 115 | + | return obj | |
| 116 | + | } | |
| 117 | + | ||
| 118 | + | // Remove the keyboard shortcuts inhibitor from the associated wl_surface. | |
| 119 | + | func (o *KeyboardShortcutsInhibitor) Destroy() error { | |
| 120 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_keyboard_shortcuts_inhibitor_v1.destroy", Destructor: true}); err != nil { | |
| 121 | + | return err | |
| 122 | + | } | |
| 123 | + | return nil | |
| 124 | + | } | |
| 125 | + | ||
| 126 | + | // OnActive registers a handler for the active event. | |
| 127 | + | // | |
| 128 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 129 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 130 | + | func (o *KeyboardShortcutsInhibitor) OnActive(handler func()) { | |
| 131 | + | if handler == nil { | |
| 132 | + | return | |
| 133 | + | } | |
| 134 | + | o.handlersMu.Lock() | |
| 135 | + | defer o.handlersMu.Unlock() | |
| 136 | + | o.onActive = append(o.onActive, handler) | |
| 137 | + | } | |
| 138 | + | ||
| 139 | + | // handlersForActive returns the handlers registered for active, taken | |
| 140 | + | // under the lock so a handler may register another handler while events are | |
| 141 | + | // being dispatched. | |
| 142 | + | func (o *KeyboardShortcutsInhibitor) handlersForActive() []func() { | |
| 143 | + | o.handlersMu.Lock() | |
| 144 | + | defer o.handlersMu.Unlock() | |
| 145 | + | return o.onActive | |
| 146 | + | } | |
| 147 | + | ||
| 148 | + | // OnInactive registers a handler for the inactive event. | |
| 149 | + | // | |
| 150 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 151 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 152 | + | func (o *KeyboardShortcutsInhibitor) OnInactive(handler func()) { | |
| 153 | + | if handler == nil { | |
| 154 | + | return | |
| 155 | + | } | |
| 156 | + | o.handlersMu.Lock() | |
| 157 | + | defer o.handlersMu.Unlock() | |
| 158 | + | o.onInactive = append(o.onInactive, handler) | |
| 159 | + | } | |
| 160 | + | ||
| 161 | + | // handlersForInactive returns the handlers registered for inactive, taken | |
| 162 | + | // under the lock so a handler may register another handler while events are | |
| 163 | + | // being dispatched. | |
| 164 | + | func (o *KeyboardShortcutsInhibitor) handlersForInactive() []func() { | |
| 165 | + | o.handlersMu.Lock() | |
| 166 | + | defer o.handlersMu.Unlock() | |
| 167 | + | return o.onInactive | |
| 168 | + | } | |
| 169 | + | ||
| 170 | + | // EventSignature returns the declared event argument types in wire order. | |
| 171 | + | func (o *KeyboardShortcutsInhibitor) EventSignature(opcode uint16) (string, bool) { | |
| 172 | + | switch opcode { | |
| 173 | + | case 0: | |
| 174 | + | return "", true | |
| 175 | + | case 1: | |
| 176 | + | return "", true | |
| 177 | + | default: | |
| 178 | + | return "", false | |
| 179 | + | } | |
| 180 | + | } | |
| 181 | + | ||
| 182 | + | // Dispatch decodes one event on zwp_keyboard_shortcuts_inhibitor_v1 and calls the registered handlers. | |
| 183 | + | func (o *KeyboardShortcutsInhibitor) Dispatch(event *wl.Event) { | |
| 184 | + | switch event.Opcode { | |
| 185 | + | case 0: // active | |
| 186 | + | ||
| 187 | + | for i, handler := range o.handlersForActive() { | |
| 188 | + | _ = i | |
| 189 | + | handler() | |
| 190 | + | } | |
| 191 | + | case 1: // inactive | |
| 192 | + | ||
| 193 | + | for i, handler := range o.handlersForInactive() { | |
| 194 | + | _ = i | |
| 195 | + | handler() | |
| 196 | + | } | |
| 197 | + | default: | |
| 198 | + | } | |
| 199 | + | } | |
A client/linuxdmabuf/linuxdmabuf_generated.go +630 -0
| @@ -0,0 +1,630 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: linux_dmabuf_v1 | |
| 3 | + | // Source: linux-dmabuf-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2014, 2015 Collabora, Ltd. | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package linuxdmabuf | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | "sync" | |
| 31 | + | ||
| 32 | + | cross_wl_buffer "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 33 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 34 | + | "github.com/bnema/wlturbo/wl" | |
| 35 | + | ) | |
| 36 | + | ||
| 37 | + | // ERROR_ALREADY_USED is the error already_used value. | |
| 38 | + | const ERROR_ALREADY_USED = 0 | |
| 39 | + | ||
| 40 | + | // ERROR_PLANE_IDX is the error plane_idx value. | |
| 41 | + | const ERROR_PLANE_IDX = 1 | |
| 42 | + | ||
| 43 | + | // ERROR_PLANE_SET is the error plane_set value. | |
| 44 | + | const ERROR_PLANE_SET = 2 | |
| 45 | + | ||
| 46 | + | // ERROR_INCOMPLETE is the error incomplete value. | |
| 47 | + | const ERROR_INCOMPLETE = 3 | |
| 48 | + | ||
| 49 | + | // ERROR_INVALID_FORMAT is the error invalid_format value. | |
| 50 | + | const ERROR_INVALID_FORMAT = 4 | |
| 51 | + | ||
| 52 | + | // ERROR_INVALID_DIMENSIONS is the error invalid_dimensions value. | |
| 53 | + | const ERROR_INVALID_DIMENSIONS = 5 | |
| 54 | + | ||
| 55 | + | // ERROR_OUT_OF_BOUNDS is the error out_of_bounds value. | |
| 56 | + | const ERROR_OUT_OF_BOUNDS = 6 | |
| 57 | + | ||
| 58 | + | // ERROR_INVALID_WL_BUFFER is the error invalid_wl_buffer value. | |
| 59 | + | const ERROR_INVALID_WL_BUFFER = 7 | |
| 60 | + | ||
| 61 | + | // ERROR_INVALID_DEV_T_SIZE is the error invalid_dev_t_size value. | |
| 62 | + | const ERROR_INVALID_DEV_T_SIZE = 8 | |
| 63 | + | ||
| 64 | + | // FLAGS_Y_INVERT is the flags y_invert value. | |
| 65 | + | const FLAGS_Y_INVERT = 1 | |
| 66 | + | ||
| 67 | + | // FLAGS_INTERLACED is the flags interlaced value. | |
| 68 | + | const FLAGS_INTERLACED = 2 | |
| 69 | + | ||
| 70 | + | // FLAGS_BOTTOM_FIRST is the flags bottom_first value. | |
| 71 | + | const FLAGS_BOTTOM_FIRST = 4 | |
| 72 | + | ||
| 73 | + | // TRANCHE_FLAGS_SCANOUT is the tranche_flags scanout value. | |
| 74 | + | const TRANCHE_FLAGS_SCANOUT = 1 | |
| 75 | + | ||
| 76 | + | // TRANCHE_FLAGS_SAMPLING is the tranche_flags sampling value. | |
| 77 | + | const TRANCHE_FLAGS_SAMPLING = 2 | |
| 78 | + | ||
| 79 | + | // LinuxDmabufInterface is the protocol interface name. | |
| 80 | + | const LinuxDmabufInterface = "zwp_linux_dmabuf_v1" | |
| 81 | + | ||
| 82 | + | // LinuxDmabuf is the generated binding for zwp_linux_dmabuf_v1 version 6. | |
| 83 | + | type LinuxDmabuf struct { | |
| 84 | + | wl.BaseProxy | |
| 85 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 86 | + | // handlers while another goroutine dispatches events. | |
| 87 | + | handlersMu sync.Mutex | |
| 88 | + | onFormat []func(format uint32) | |
| 89 | + | onModifier []func(format uint32, modifierHi uint32, modifierLo uint32) | |
| 90 | + | } | |
| 91 | + | ||
| 92 | + | // NewLinuxDmabuf returns an unbound LinuxDmabuf. | |
| 93 | + | func NewLinuxDmabuf(ctx *wl.Context) *LinuxDmabuf { | |
| 94 | + | obj := &LinuxDmabuf{} | |
| 95 | + | obj.SetContext(ctx) | |
| 96 | + | ctx.Register(obj) | |
| 97 | + | return obj | |
| 98 | + | } | |
| 99 | + | ||
| 100 | + | // Objects created through this interface, especially wl_buffers, will remain valid. | |
| 101 | + | func (o *LinuxDmabuf) Destroy() error { | |
| 102 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_linux_dmabuf_v1.destroy", Destructor: true}); err != nil { | |
| 103 | + | return err | |
| 104 | + | } | |
| 105 | + | return nil | |
| 106 | + | } | |
| 107 | + | ||
| 108 | + | // This temporary object is used to collect multiple dmabuf handles into a single batch to create a wl_buffer. It can only be used once and should be destroyed after a 'created' or 'failed' event has been received. | |
| 109 | + | func (o *LinuxDmabuf) CreateParams() (*LinuxBufferParams, error) { | |
| 110 | + | child := &LinuxBufferParams{} | |
| 111 | + | child.SetContext(o.Context()) | |
| 112 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_linux_dmabuf_v1.create_params", Child: child}, wl.ArgObject(child)); err != nil { | |
| 113 | + | return nil, err | |
| 114 | + | } | |
| 115 | + | return child, nil | |
| 116 | + | } | |
| 117 | + | ||
| 118 | + | // This request creates a new zwp_linux_dmabuf_feedback_v1 object not bound to a particular surface. This object will deliver feedback about dmabuf parameters to use if the client doesn't support per-surface feedback (see get_surface_feedback). | |
| 119 | + | func (o *LinuxDmabuf) GetDefaultFeedback() (*LinuxDmabufFeedback, error) { | |
| 120 | + | child := &LinuxDmabufFeedback{} | |
| 121 | + | child.SetContext(o.Context()) | |
| 122 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_linux_dmabuf_v1.get_default_feedback", Since: 4, Child: child}, wl.ArgObject(child)); err != nil { | |
| 123 | + | return nil, err | |
| 124 | + | } | |
| 125 | + | return child, nil | |
| 126 | + | } | |
| 127 | + | ||
| 128 | + | // This request creates a new zwp_linux_dmabuf_feedback_v1 object for the specified wl_surface. This object will deliver feedback about dmabuf parameters to use for buffers attached to this surface. If the surface is destroyed before the zwp_linux_dmabuf_feedback_v1 object, the feedback object becomes inert. | |
| 129 | + | func (o *LinuxDmabuf) GetSurfaceFeedback(surface *cross_wl_surface.Surface) (*LinuxDmabufFeedback, error) { | |
| 130 | + | var arg1 wl.Object | |
| 131 | + | if surface != nil { | |
| 132 | + | arg1 = surface | |
| 133 | + | } | |
| 134 | + | child := &LinuxDmabufFeedback{} | |
| 135 | + | child.SetContext(o.Context()) | |
| 136 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "zwp_linux_dmabuf_v1.get_surface_feedback", Since: 4, Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 137 | + | return nil, err | |
| 138 | + | } | |
| 139 | + | return child, nil | |
| 140 | + | } | |
| 141 | + | ||
| 142 | + | // OnFormat registers a handler for the format event. | |
| 143 | + | // | |
| 144 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 145 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 146 | + | func (o *LinuxDmabuf) OnFormat(handler func(format uint32)) { | |
| 147 | + | if handler == nil { | |
| 148 | + | return | |
| 149 | + | } | |
| 150 | + | o.handlersMu.Lock() | |
| 151 | + | defer o.handlersMu.Unlock() | |
| 152 | + | o.onFormat = append(o.onFormat, handler) | |
| 153 | + | } | |
| 154 | + | ||
| 155 | + | // handlersForFormat returns the handlers registered for format, taken | |
| 156 | + | // under the lock so a handler may register another handler while events are | |
| 157 | + | // being dispatched. | |
| 158 | + | func (o *LinuxDmabuf) handlersForFormat() []func(format uint32) { | |
| 159 | + | o.handlersMu.Lock() | |
| 160 | + | defer o.handlersMu.Unlock() | |
| 161 | + | return o.onFormat | |
| 162 | + | } | |
| 163 | + | ||
| 164 | + | // OnModifier registers a handler for the modifier event. | |
| 165 | + | // | |
| 166 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 167 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 168 | + | func (o *LinuxDmabuf) OnModifier(handler func(format uint32, modifierHi uint32, modifierLo uint32)) { | |
| 169 | + | if handler == nil { | |
| 170 | + | return | |
| 171 | + | } | |
| 172 | + | o.handlersMu.Lock() | |
| 173 | + | defer o.handlersMu.Unlock() | |
| 174 | + | o.onModifier = append(o.onModifier, handler) | |
| 175 | + | } | |
| 176 | + | ||
| 177 | + | // handlersForModifier returns the handlers registered for modifier, taken | |
| 178 | + | // under the lock so a handler may register another handler while events are | |
| 179 | + | // being dispatched. | |
| 180 | + | func (o *LinuxDmabuf) handlersForModifier() []func(format uint32, modifierHi uint32, modifierLo uint32) { | |
| 181 | + | o.handlersMu.Lock() | |
| 182 | + | defer o.handlersMu.Unlock() | |
| 183 | + | return o.onModifier | |
| 184 | + | } | |
| 185 | + | ||
| 186 | + | // EventSignature returns the declared event argument types in wire order. | |
| 187 | + | func (o *LinuxDmabuf) EventSignature(opcode uint16) (string, bool) { | |
| 188 | + | switch opcode { | |
| 189 | + | case 0: | |
| 190 | + | return "uint,", true | |
| 191 | + | case 1: | |
| 192 | + | return "uint,uint,uint,", true | |
| 193 | + | default: | |
| 194 | + | return "", false | |
| 195 | + | } | |
| 196 | + | } | |
| 197 | + | ||
| 198 | + | // Dispatch decodes one event on zwp_linux_dmabuf_v1 and calls the registered handlers. | |
| 199 | + | func (o *LinuxDmabuf) Dispatch(event *wl.Event) { | |
| 200 | + | switch event.Opcode { | |
| 201 | + | case 0: // format | |
| 202 | + | format := event.Uint32() | |
| 203 | + | ||
| 204 | + | for i, handler := range o.handlersForFormat() { | |
| 205 | + | _ = i | |
| 206 | + | handler(format) | |
| 207 | + | } | |
| 208 | + | case 1: // modifier | |
| 209 | + | format := event.Uint32() | |
| 210 | + | modifierHi := event.Uint32() | |
| 211 | + | modifierLo := event.Uint32() | |
| 212 | + | ||
| 213 | + | for i, handler := range o.handlersForModifier() { | |
| 214 | + | _ = i | |
| 215 | + | handler(format, modifierHi, modifierLo) | |
| 216 | + | } | |
| 217 | + | default: | |
| 218 | + | } | |
| 219 | + | } | |
| 220 | + | ||
| 221 | + | // LinuxBufferParamsInterface is the protocol interface name. | |
| 222 | + | const LinuxBufferParamsInterface = "zwp_linux_buffer_params_v1" | |
| 223 | + | ||
| 224 | + | // LinuxBufferParams is the generated binding for zwp_linux_buffer_params_v1 version 6. | |
| 225 | + | type LinuxBufferParams struct { | |
| 226 | + | wl.BaseProxy | |
| 227 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 228 | + | // handlers while another goroutine dispatches events. | |
| 229 | + | handlersMu sync.Mutex | |
| 230 | + | onCreated []func(bufferObject *cross_wl_buffer.Buffer) | |
| 231 | + | onFailed []func() | |
| 232 | + | } | |
| 233 | + | ||
| 234 | + | // NewLinuxBufferParams returns an unbound LinuxBufferParams. | |
| 235 | + | func NewLinuxBufferParams(ctx *wl.Context) *LinuxBufferParams { | |
| 236 | + | obj := &LinuxBufferParams{} | |
| 237 | + | obj.SetContext(ctx) | |
| 238 | + | ctx.Register(obj) | |
| 239 | + | return obj | |
| 240 | + | } | |
| 241 | + | ||
| 242 | + | // Cleans up the temporary data sent to the server for dmabuf-based wl_buffer creation. | |
| 243 | + | func (o *LinuxBufferParams) Destroy() error { | |
| 244 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_linux_buffer_params_v1.destroy", Destructor: true}); err != nil { | |
| 245 | + | return err | |
| 246 | + | } | |
| 247 | + | return nil | |
| 248 | + | } | |
| 249 | + | ||
| 250 | + | // This request adds one dmabuf to the set in this zwp_linux_buffer_params_v1. The 64-bit unsigned value combined from modifier_hi and modifier_lo is the dmabuf layout modifier. DRM AddFB2 ioctl calls this the fb modifier, which is defined in drm_mode.h of Linux UAPI. This is an opaque token. Drivers use this token to express tiling, compression, etc. driver-specific modifications to the base format defined by the DRM fourcc code. Starting from version 4, the invalid_format protocol error is sent if the format + modifier pair was not advertised as supported. Starting from version 5, the invalid_format protocol error is sent if all planes don't use the same modifier. This request raises the PLANE_IDX error if plane_idx is too large. The error PLANE_SET is raised if attempting to set a plane that was already set. | |
| 251 | + | func (o *LinuxBufferParams) Add(fd int, planeIdx uint32, offset uint32, stride uint32, modifierHi uint32, modifierLo uint32) error { | |
| 252 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_linux_buffer_params_v1.add", FDs: []int{fd}}, wl.ArgFD(), wl.ArgUint(planeIdx), wl.ArgUint(offset), wl.ArgUint(stride), wl.ArgUint(modifierHi), wl.ArgUint(modifierLo)); err != nil { | |
| 253 | + | return err | |
| 254 | + | } | |
| 255 | + | return nil | |
| 256 | + | } | |
| 257 | + | ||
| 258 | + | // This asks for creation of a wl_buffer from the added dmabuf buffers. The wl_buffer is not created immediately but returned via the 'created' event if the dmabuf sharing succeeds. The sharing may fail at runtime for reasons a client cannot predict, in which case the 'failed' event is triggered. The 'format' argument is a DRM_FORMAT code, as defined by the libdrm's drm_fourcc.h. The Linux kernel's DRM sub-system is the authoritative source on how the format codes should work. The 'flags' is a bitfield of the flags defined in enum "flags". 'y_invert' means that the image needs to be y-flipped. Flag 'interlaced' means that the frame in the buffer is not progressive as usual, but interlaced. An interlaced buffer as supported here must always contain both top and bottom fields. The top field always begins on the first pixel row. The temporal ordering between the two fields is top field first, unless 'bottom_first' is specified. It is undefined whether 'bottom_first' is ignored if 'interlaced' is not set. This protocol does not convey any information about field rate, duration, or timing, other than the relative ordering between the two fields in one buffer. A compositor may have to estimate the intended field rate from the incoming buffer rate. It is undefined whether the time of receiving wl_surface.commit with a new buffer attached, applying the wl_surface state, wl_surface.frame callback trigger, presentation, or any other point in the compositor cycle is used to measure the frame or field times. There is no support for detecting missed or late frames/fields/buffers either, and there is no support whatsoever for cooperating with interlaced compositor output. The composited image quality resulting from the use of interlaced buffers is explicitly undefined. A compositor may use elaborate hardware features or software to deinterlace and create progressive output frames from a sequence of interlaced input buffers, or it may produce substandard image quality. However, compositors that cannot guarantee reasonable image quality in all cases are recommended to just reject all interlaced buffers. Any argument errors, including non-positive width or height, mismatch between the number of planes and the format, bad format, bad offset or stride, may be indicated by fatal protocol errors: INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS, OUT_OF_BOUNDS. Dmabuf import errors in the server that are not obvious client bugs are returned via the 'failed' event as non-fatal. This allows attempting dmabuf sharing and falling back in the client if it fails. This request can be sent only once in the object's lifetime, after which the only legal request is destroy. This object should be destroyed after issuing a 'create' request. Attempting to use this object after issuing 'create' raises the ALREADY_USED protocol error. It is not mandatory to issue 'create'. If a client wants to cancel the buffer creation, it can just destroy this object. | |
| 259 | + | func (o *LinuxBufferParams) Create(width int32, height int32, format uint32, flags uint32) error { | |
| 260 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_linux_buffer_params_v1.create"}, wl.ArgInt(width), wl.ArgInt(height), wl.ArgUint(format), wl.ArgUint(flags)); err != nil { | |
| 261 | + | return err | |
| 262 | + | } | |
| 263 | + | return nil | |
| 264 | + | } | |
| 265 | + | ||
| 266 | + | // This asks for immediate creation of a wl_buffer by importing the added dmabufs. In case of import success, no event is sent from the server, and the wl_buffer is ready to be used by the client. Upon import failure, either of the following may happen, as seen fit by the implementation: - the client is terminated with one of the following fatal protocol errors: - INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS, OUT_OF_BOUNDS, in case of argument errors such as mismatch between the number of planes and the format, bad format, non-positive width or height, or bad offset or stride. - INVALID_WL_BUFFER, in case the cause for failure is unknown or platform specific. - the server creates an invalid wl_buffer, marks it as failed and sends a 'failed' event to the client. The result of using this invalid wl_buffer as an argument in any request by the client is defined by the compositor implementation. This takes the same arguments as a 'create' request, and obeys the same restrictions. | |
| 267 | + | func (o *LinuxBufferParams) CreateImmed(width int32, height int32, format uint32, flags uint32) (*cross_wl_buffer.Buffer, error) { | |
| 268 | + | child := cross_wl_buffer.NewBuffer(o.Context()) | |
| 269 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "zwp_linux_buffer_params_v1.create_immed", Since: 2, Child: child}, wl.ArgObject(child), wl.ArgInt(width), wl.ArgInt(height), wl.ArgUint(format), wl.ArgUint(flags)); err != nil { | |
| 270 | + | return nil, err | |
| 271 | + | } | |
| 272 | + | return child, nil | |
| 273 | + | } | |
| 274 | + | ||
| 275 | + | // Set the device the compositor should import the dmabufs to for sampling in the next create or create_immed request. To avoid race conditions when the compositor removes a device from the tranches, it is not a protocol error if the device hasn't been advertised by the compositor in a tranche with the sampling flag, but the import is likely to fail in that case. If the client doesn't know a suitable target device, it shouldn't set one, and the compositor should attempt import on all devices it supports. If the array is too small to contain a dev_t or larger than required, the invalid_dev_t_size error will be emitted. | |
| 276 | + | func (o *LinuxBufferParams) SetSamplingDevice(device []byte) error { | |
| 277 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 4, Name: "zwp_linux_buffer_params_v1.set_sampling_device", Since: 6}, wl.ArgArray(device)); err != nil { | |
| 278 | + | return err | |
| 279 | + | } | |
| 280 | + | return nil | |
| 281 | + | } | |
| 282 | + | ||
| 283 | + | // OnCreated registers a handler for the created event. | |
| 284 | + | // | |
| 285 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 286 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 287 | + | func (o *LinuxBufferParams) OnCreated(handler func(bufferObject *cross_wl_buffer.Buffer)) { | |
| 288 | + | if handler == nil { | |
| 289 | + | return | |
| 290 | + | } | |
| 291 | + | o.handlersMu.Lock() | |
| 292 | + | defer o.handlersMu.Unlock() | |
| 293 | + | o.onCreated = append(o.onCreated, handler) | |
| 294 | + | } | |
| 295 | + | ||
| 296 | + | // handlersForCreated returns the handlers registered for created, taken | |
| 297 | + | // under the lock so a handler may register another handler while events are | |
| 298 | + | // being dispatched. | |
| 299 | + | func (o *LinuxBufferParams) handlersForCreated() []func(bufferObject *cross_wl_buffer.Buffer) { | |
| 300 | + | o.handlersMu.Lock() | |
| 301 | + | defer o.handlersMu.Unlock() | |
| 302 | + | return o.onCreated | |
| 303 | + | } | |
| 304 | + | ||
| 305 | + | // OnFailed registers a handler for the failed event. | |
| 306 | + | // | |
| 307 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 308 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 309 | + | func (o *LinuxBufferParams) OnFailed(handler func()) { | |
| 310 | + | if handler == nil { | |
| 311 | + | return | |
| 312 | + | } | |
| 313 | + | o.handlersMu.Lock() | |
| 314 | + | defer o.handlersMu.Unlock() | |
| 315 | + | o.onFailed = append(o.onFailed, handler) | |
| 316 | + | } | |
| 317 | + | ||
| 318 | + | // handlersForFailed returns the handlers registered for failed, taken | |
| 319 | + | // under the lock so a handler may register another handler while events are | |
| 320 | + | // being dispatched. | |
| 321 | + | func (o *LinuxBufferParams) handlersForFailed() []func() { | |
| 322 | + | o.handlersMu.Lock() | |
| 323 | + | defer o.handlersMu.Unlock() | |
| 324 | + | return o.onFailed | |
| 325 | + | } | |
| 326 | + | ||
| 327 | + | // EventSignature returns the declared event argument types in wire order. | |
| 328 | + | func (o *LinuxBufferParams) EventSignature(opcode uint16) (string, bool) { | |
| 329 | + | switch opcode { | |
| 330 | + | case 0: | |
| 331 | + | return "new_id,", true | |
| 332 | + | case 1: | |
| 333 | + | return "", true | |
| 334 | + | default: | |
| 335 | + | return "", false | |
| 336 | + | } | |
| 337 | + | } | |
| 338 | + | ||
| 339 | + | // Dispatch decodes one event on zwp_linux_buffer_params_v1 and calls the registered handlers. | |
| 340 | + | func (o *LinuxBufferParams) Dispatch(event *wl.Event) { | |
| 341 | + | switch event.Opcode { | |
| 342 | + | case 0: // created | |
| 343 | + | bufferID := event.Uint32() | |
| 344 | + | bufferObject := cross_wl_buffer.NewBuffer(o.Context()) | |
| 345 | + | bufferObject.SetID(bufferID) | |
| 346 | + | bufferObject.SetVersion(o.Version()) | |
| 347 | + | o.Context().Register(bufferObject) | |
| 348 | + | ||
| 349 | + | for i, handler := range o.handlersForCreated() { | |
| 350 | + | _ = i | |
| 351 | + | handler(bufferObject) | |
| 352 | + | } | |
| 353 | + | case 1: // failed | |
| 354 | + | ||
| 355 | + | for i, handler := range o.handlersForFailed() { | |
| 356 | + | _ = i | |
| 357 | + | handler() | |
| 358 | + | } | |
| 359 | + | default: | |
| 360 | + | } | |
| 361 | + | } | |
| 362 | + | ||
| 363 | + | // LinuxDmabufFeedbackInterface is the protocol interface name. | |
| 364 | + | const LinuxDmabufFeedbackInterface = "zwp_linux_dmabuf_feedback_v1" | |
| 365 | + | ||
| 366 | + | // LinuxDmabufFeedback is the generated binding for zwp_linux_dmabuf_feedback_v1 version 6. | |
| 367 | + | type LinuxDmabufFeedback struct { | |
| 368 | + | wl.BaseProxy | |
| 369 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 370 | + | // handlers while another goroutine dispatches events. | |
| 371 | + | handlersMu sync.Mutex | |
| 372 | + | onDone []func() | |
| 373 | + | onFormatTable []func(fd *wl.OwnedFD, size uint32) | |
| 374 | + | onMainDevice []func(device []byte) | |
| 375 | + | onTrancheDone []func() | |
| 376 | + | onTrancheTargetDevice []func(device []byte) | |
| 377 | + | onTrancheFormats []func(indices []byte) | |
| 378 | + | onTrancheFlags []func(flags uint32) | |
| 379 | + | } | |
| 380 | + | ||
| 381 | + | // NewLinuxDmabufFeedback returns an unbound LinuxDmabufFeedback. | |
| 382 | + | func NewLinuxDmabufFeedback(ctx *wl.Context) *LinuxDmabufFeedback { | |
| 383 | + | obj := &LinuxDmabufFeedback{} | |
| 384 | + | obj.SetContext(ctx) | |
| 385 | + | ctx.Register(obj) | |
| 386 | + | return obj | |
| 387 | + | } | |
| 388 | + | ||
| 389 | + | // Using this request a client can tell the server that it is not going to use the zwp_linux_dmabuf_feedback_v1 object anymore. | |
| 390 | + | func (o *LinuxDmabufFeedback) Destroy() error { | |
| 391 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_linux_dmabuf_feedback_v1.destroy", Destructor: true}); err != nil { | |
| 392 | + | return err | |
| 393 | + | } | |
| 394 | + | return nil | |
| 395 | + | } | |
| 396 | + | ||
| 397 | + | // OnDone registers a handler for the done event. | |
| 398 | + | // | |
| 399 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 400 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 401 | + | func (o *LinuxDmabufFeedback) OnDone(handler func()) { | |
| 402 | + | if handler == nil { | |
| 403 | + | return | |
| 404 | + | } | |
| 405 | + | o.handlersMu.Lock() | |
| 406 | + | defer o.handlersMu.Unlock() | |
| 407 | + | o.onDone = append(o.onDone, handler) | |
| 408 | + | } | |
| 409 | + | ||
| 410 | + | // handlersForDone returns the handlers registered for done, taken | |
| 411 | + | // under the lock so a handler may register another handler while events are | |
| 412 | + | // being dispatched. | |
| 413 | + | func (o *LinuxDmabufFeedback) handlersForDone() []func() { | |
| 414 | + | o.handlersMu.Lock() | |
| 415 | + | defer o.handlersMu.Unlock() | |
| 416 | + | return o.onDone | |
| 417 | + | } | |
| 418 | + | ||
| 419 | + | // OnFormatTable registers a handler for the format_table event. | |
| 420 | + | // | |
| 421 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 422 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 423 | + | func (o *LinuxDmabufFeedback) OnFormatTable(handler func(fd *wl.OwnedFD, size uint32)) { | |
| 424 | + | if handler == nil { | |
| 425 | + | return | |
| 426 | + | } | |
| 427 | + | o.handlersMu.Lock() | |
| 428 | + | defer o.handlersMu.Unlock() | |
| 429 | + | o.onFormatTable = append(o.onFormatTable, handler) | |
| 430 | + | } | |
| 431 | + | ||
| 432 | + | // handlersForFormatTable returns the handlers registered for format_table, taken | |
| 433 | + | // under the lock so a handler may register another handler while events are | |
| 434 | + | // being dispatched. | |
| 435 | + | func (o *LinuxDmabufFeedback) handlersForFormatTable() []func(fd *wl.OwnedFD, size uint32) { | |
| 436 | + | o.handlersMu.Lock() | |
| 437 | + | defer o.handlersMu.Unlock() | |
| 438 | + | return o.onFormatTable | |
| 439 | + | } | |
| 440 | + | ||
| 441 | + | // OnMainDevice registers a handler for the main_device event. | |
| 442 | + | // | |
| 443 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 444 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 445 | + | func (o *LinuxDmabufFeedback) OnMainDevice(handler func(device []byte)) { | |
| 446 | + | if handler == nil { | |
| 447 | + | return | |
| 448 | + | } | |
| 449 | + | o.handlersMu.Lock() | |
| 450 | + | defer o.handlersMu.Unlock() | |
| 451 | + | o.onMainDevice = append(o.onMainDevice, handler) | |
| 452 | + | } | |
| 453 | + | ||
| 454 | + | // handlersForMainDevice returns the handlers registered for main_device, taken | |
| 455 | + | // under the lock so a handler may register another handler while events are | |
| 456 | + | // being dispatched. | |
| 457 | + | func (o *LinuxDmabufFeedback) handlersForMainDevice() []func(device []byte) { | |
| 458 | + | o.handlersMu.Lock() | |
| 459 | + | defer o.handlersMu.Unlock() | |
| 460 | + | return o.onMainDevice | |
| 461 | + | } | |
| 462 | + | ||
| 463 | + | // OnTrancheDone registers a handler for the tranche_done event. | |
| 464 | + | // | |
| 465 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 466 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 467 | + | func (o *LinuxDmabufFeedback) OnTrancheDone(handler func()) { | |
| 468 | + | if handler == nil { | |
| 469 | + | return | |
| 470 | + | } | |
| 471 | + | o.handlersMu.Lock() | |
| 472 | + | defer o.handlersMu.Unlock() | |
| 473 | + | o.onTrancheDone = append(o.onTrancheDone, handler) | |
| 474 | + | } | |
| 475 | + | ||
| 476 | + | // handlersForTrancheDone returns the handlers registered for tranche_done, taken | |
| 477 | + | // under the lock so a handler may register another handler while events are | |
| 478 | + | // being dispatched. | |
| 479 | + | func (o *LinuxDmabufFeedback) handlersForTrancheDone() []func() { | |
| 480 | + | o.handlersMu.Lock() | |
| 481 | + | defer o.handlersMu.Unlock() | |
| 482 | + | return o.onTrancheDone | |
| 483 | + | } | |
| 484 | + | ||
| 485 | + | // OnTrancheTargetDevice registers a handler for the tranche_target_device event. | |
| 486 | + | // | |
| 487 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 488 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 489 | + | func (o *LinuxDmabufFeedback) OnTrancheTargetDevice(handler func(device []byte)) { | |
| 490 | + | if handler == nil { | |
| 491 | + | return | |
| 492 | + | } | |
| 493 | + | o.handlersMu.Lock() | |
| 494 | + | defer o.handlersMu.Unlock() | |
| 495 | + | o.onTrancheTargetDevice = append(o.onTrancheTargetDevice, handler) | |
| 496 | + | } | |
| 497 | + | ||
| 498 | + | // handlersForTrancheTargetDevice returns the handlers registered for tranche_target_device, taken | |
| 499 | + | // under the lock so a handler may register another handler while events are | |
| 500 | + | // being dispatched. | |
| 501 | + | func (o *LinuxDmabufFeedback) handlersForTrancheTargetDevice() []func(device []byte) { | |
| 502 | + | o.handlersMu.Lock() | |
| 503 | + | defer o.handlersMu.Unlock() | |
| 504 | + | return o.onTrancheTargetDevice | |
| 505 | + | } | |
| 506 | + | ||
| 507 | + | // OnTrancheFormats registers a handler for the tranche_formats event. | |
| 508 | + | // | |
| 509 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 510 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 511 | + | func (o *LinuxDmabufFeedback) OnTrancheFormats(handler func(indices []byte)) { | |
| 512 | + | if handler == nil { | |
| 513 | + | return | |
| 514 | + | } | |
| 515 | + | o.handlersMu.Lock() | |
| 516 | + | defer o.handlersMu.Unlock() | |
| 517 | + | o.onTrancheFormats = append(o.onTrancheFormats, handler) | |
| 518 | + | } | |
| 519 | + | ||
| 520 | + | // handlersForTrancheFormats returns the handlers registered for tranche_formats, taken | |
| 521 | + | // under the lock so a handler may register another handler while events are | |
| 522 | + | // being dispatched. | |
| 523 | + | func (o *LinuxDmabufFeedback) handlersForTrancheFormats() []func(indices []byte) { | |
| 524 | + | o.handlersMu.Lock() | |
| 525 | + | defer o.handlersMu.Unlock() | |
| 526 | + | return o.onTrancheFormats | |
| 527 | + | } | |
| 528 | + | ||
| 529 | + | // OnTrancheFlags registers a handler for the tranche_flags event. | |
| 530 | + | // | |
| 531 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 532 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 533 | + | func (o *LinuxDmabufFeedback) OnTrancheFlags(handler func(flags uint32)) { | |
| 534 | + | if handler == nil { | |
| 535 | + | return | |
| 536 | + | } | |
| 537 | + | o.handlersMu.Lock() | |
| 538 | + | defer o.handlersMu.Unlock() | |
| 539 | + | o.onTrancheFlags = append(o.onTrancheFlags, handler) | |
| 540 | + | } | |
| 541 | + | ||
| 542 | + | // handlersForTrancheFlags returns the handlers registered for tranche_flags, taken | |
| 543 | + | // under the lock so a handler may register another handler while events are | |
| 544 | + | // being dispatched. | |
| 545 | + | func (o *LinuxDmabufFeedback) handlersForTrancheFlags() []func(flags uint32) { | |
| 546 | + | o.handlersMu.Lock() | |
| 547 | + | defer o.handlersMu.Unlock() | |
| 548 | + | return o.onTrancheFlags | |
| 549 | + | } | |
| 550 | + | ||
| 551 | + | // EventSignature returns the declared event argument types in wire order. | |
| 552 | + | func (o *LinuxDmabufFeedback) EventSignature(opcode uint16) (string, bool) { | |
| 553 | + | switch opcode { | |
| 554 | + | case 0: | |
| 555 | + | return "", true | |
| 556 | + | case 1: | |
| 557 | + | return "fd,uint,", true | |
| 558 | + | case 2: | |
| 559 | + | return "array,", true | |
| 560 | + | case 3: | |
| 561 | + | return "", true | |
| 562 | + | case 4: | |
| 563 | + | return "array,", true | |
| 564 | + | case 5: | |
| 565 | + | return "array,", true | |
| 566 | + | case 6: | |
| 567 | + | return "uint,", true | |
| 568 | + | default: | |
| 569 | + | return "", false | |
| 570 | + | } | |
| 571 | + | } | |
| 572 | + | ||
| 573 | + | // Dispatch decodes one event on zwp_linux_dmabuf_feedback_v1 and calls the registered handlers. | |
| 574 | + | func (o *LinuxDmabufFeedback) Dispatch(event *wl.Event) { | |
| 575 | + | switch event.Opcode { | |
| 576 | + | case 0: // done | |
| 577 | + | ||
| 578 | + | for i, handler := range o.handlersForDone() { | |
| 579 | + | _ = i | |
| 580 | + | handler() | |
| 581 | + | } | |
| 582 | + | case 1: // format_table | |
| 583 | + | fd := event.FD() | |
| 584 | + | size := event.Uint32() | |
| 585 | + | ownedfd := fd | |
| 586 | + | defer ownedfd.Close() | |
| 587 | + | ||
| 588 | + | for i, handler := range o.handlersForFormatTable() { | |
| 589 | + | if i > 0 { | |
| 590 | + | fd = nil | |
| 591 | + | } | |
| 592 | + | handler(fd, size) | |
| 593 | + | } | |
| 594 | + | case 2: // main_device | |
| 595 | + | device := event.Array() | |
| 596 | + | ||
| 597 | + | for i, handler := range o.handlersForMainDevice() { | |
| 598 | + | _ = i | |
| 599 | + | handler(device) | |
| 600 | + | } | |
| 601 | + | case 3: // tranche_done | |
| 602 | + | ||
| 603 | + | for i, handler := range o.handlersForTrancheDone() { | |
| 604 | + | _ = i | |
| 605 | + | handler() | |
| 606 | + | } | |
| 607 | + | case 4: // tranche_target_device | |
| 608 | + | device := event.Array() | |
| 609 | + | ||
| 610 | + | for i, handler := range o.handlersForTrancheTargetDevice() { | |
| 611 | + | _ = i | |
| 612 | + | handler(device) | |
| 613 | + | } | |
| 614 | + | case 5: // tranche_formats | |
| 615 | + | indices := event.Array() | |
| 616 | + | ||
| 617 | + | for i, handler := range o.handlersForTrancheFormats() { | |
| 618 | + | _ = i | |
| 619 | + | handler(indices) | |
| 620 | + | } | |
| 621 | + | case 6: // tranche_flags | |
| 622 | + | flags := event.Uint32() | |
| 623 | + | ||
| 624 | + | for i, handler := range o.handlersForTrancheFlags() { | |
| 625 | + | _ = i | |
| 626 | + | handler(flags) | |
| 627 | + | } | |
| 628 | + | default: | |
| 629 | + | } | |
| 630 | + | } | |
A client/linuxdmabuf/table.go +68 -0
| @@ -0,0 +1,68 @@ | |||
| 1 | + | package linuxdmabuf | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "encoding/binary" | |
| 5 | + | "fmt" | |
| 6 | + | "io" | |
| 7 | + | ||
| 8 | + | "github.com/bnema/wlturbo/wl" | |
| 9 | + | "golang.org/x/sys/unix" | |
| 10 | + | ) | |
| 11 | + | ||
| 12 | + | // FormatEntry is one 16-byte format-table record. Padding is ignored. | |
| 13 | + | type FormatEntry struct { | |
| 14 | + | Format uint32 | |
| 15 | + | Modifier uint64 | |
| 16 | + | } | |
| 17 | + | ||
| 18 | + | // ReadFormatTable consumes an owned format_table descriptor, even on error. | |
| 19 | + | // It reads a bounded snapshot with pread rather than mapping compositor-owned | |
| 20 | + | // memory, avoiding SIGBUS if the backing file is unexpectedly truncated. | |
| 21 | + | func ReadFormatTable(fd *wl.OwnedFD, size uint32) ([]FormatEntry, error) { | |
| 22 | + | if fd == nil { | |
| 23 | + | return nil, fmt.Errorf("missing format table descriptor") | |
| 24 | + | } | |
| 25 | + | n, err := fd.Take() | |
| 26 | + | if err != nil { | |
| 27 | + | return nil, err | |
| 28 | + | } | |
| 29 | + | defer unix.Close(n) | |
| 30 | + | if size%16 != 0 || size > 16<<20 { | |
| 31 | + | return nil, fmt.Errorf("invalid format table size %d", size) | |
| 32 | + | } | |
| 33 | + | b := make([]byte, size) | |
| 34 | + | for off := 0; off < len(b); { | |
| 35 | + | read, e := unix.Pread(n, b[off:], int64(off)) | |
| 36 | + | off += read | |
| 37 | + | if e == unix.EINTR { | |
| 38 | + | continue | |
| 39 | + | } | |
| 40 | + | if e != nil { | |
| 41 | + | return nil, e | |
| 42 | + | } | |
| 43 | + | if read == 0 { | |
| 44 | + | return nil, io.ErrUnexpectedEOF | |
| 45 | + | } | |
| 46 | + | } | |
| 47 | + | entries := make([]FormatEntry, size/16) | |
| 48 | + | for i := range entries { | |
| 49 | + | off := i * 16 | |
| 50 | + | entries[i] = FormatEntry{binary.NativeEndian.Uint32(b[off:]), binary.NativeEndian.Uint64(b[off+8:])} | |
| 51 | + | } | |
| 52 | + | return entries, nil | |
| 53 | + | } | |
| 54 | + | ||
| 55 | + | // TrancheIndices decodes the uint16 indices into a format table. | |
| 56 | + | func TrancheIndices(data []byte, count int) ([]uint16, error) { | |
| 57 | + | if len(data)%2 != 0 { | |
| 58 | + | return nil, fmt.Errorf("odd tranche indices length") | |
| 59 | + | } | |
| 60 | + | indices := make([]uint16, len(data)/2) | |
| 61 | + | for i := range indices { | |
| 62 | + | indices[i] = binary.NativeEndian.Uint16(data[i*2:]) | |
| 63 | + | if int(indices[i]) >= count { | |
| 64 | + | return nil, fmt.Errorf("format table index %d out of range", indices[i]) | |
| 65 | + | } | |
| 66 | + | } | |
| 67 | + | return indices, nil | |
| 68 | + | } | |
A client/linuxdmabuf/table_test.go +28 -0
| @@ -0,0 +1,28 @@ | |||
| 1 | + | //go:build linux | |
| 2 | + | ||
| 3 | + | package linuxdmabuf_test | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "encoding/binary" | |
| 7 | + | "github.com/bnema/go-wayland-bindings/client/linuxdmabuf" | |
| 8 | + | "testing" | |
| 9 | + | ) | |
| 10 | + | ||
| 11 | + | func TestTrancheIndices(t *testing.T) { | |
| 12 | + | b := make([]byte, 4) | |
| 13 | + | binary.NativeEndian.PutUint16(b, 1) | |
| 14 | + | binary.NativeEndian.PutUint16(b[2:], 0) | |
| 15 | + | got, e := linuxdmabuf.TrancheIndices(b, 2) | |
| 16 | + | if e != nil || len(got) != 2 || got[0] != 1 || got[1] != 0 { | |
| 17 | + | t.Fatalf("indices %v %v", got, e) | |
| 18 | + | } | |
| 19 | + | if _, e = linuxdmabuf.TrancheIndices(b, 1); e == nil { | |
| 20 | + | t.Fatal("out of range accepted") | |
| 21 | + | } | |
| 22 | + | if _, e = linuxdmabuf.TrancheIndices(b[:3], 2); e == nil { | |
| 23 | + | t.Fatal("odd length accepted") | |
| 24 | + | } | |
| 25 | + | if _, e = linuxdmabuf.ReadFormatTable(nil, 0); e == nil { | |
| 26 | + | t.Fatal("missing fd accepted") | |
| 27 | + | } | |
| 28 | + | } | |
A client/linuxdrmsyncobj/linuxdrmsyncobj_generated.go +224 -0
| @@ -0,0 +1,224 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: linux_drm_syncobj_v1 | |
| 3 | + | // Source: linux-drm-syncobj-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright 2016 The Chromium Authors. | |
| 7 | + | // Copyright 2017 Intel Corporation | |
| 8 | + | // Copyright 2018 Collabora, Ltd | |
| 9 | + | // Copyright 2021 Simon Ser | |
| 10 | + | // | |
| 11 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 12 | + | // copy of this software and associated documentation files (the "Software"), | |
| 13 | + | // to deal in the Software without restriction, including without limitation | |
| 14 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 15 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 16 | + | // Software is furnished to do so, subject to the following conditions: | |
| 17 | + | // | |
| 18 | + | // The above copyright notice and this permission notice (including the next | |
| 19 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 20 | + | // Software. | |
| 21 | + | // | |
| 22 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 23 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 24 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 25 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 26 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 27 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 28 | + | // DEALINGS IN THE SOFTWARE. | |
| 29 | + | ||
| 30 | + | package linuxdrmsyncobj | |
| 31 | + | ||
| 32 | + | import ( | |
| 33 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 34 | + | "github.com/bnema/wlturbo/wl" | |
| 35 | + | ) | |
| 36 | + | ||
| 37 | + | // ERROR_SURFACE_EXISTS is the error surface_exists value. | |
| 38 | + | const ERROR_SURFACE_EXISTS = 0 | |
| 39 | + | ||
| 40 | + | // ERROR_INVALID_TIMELINE is the error invalid_timeline value. | |
| 41 | + | const ERROR_INVALID_TIMELINE = 1 | |
| 42 | + | ||
| 43 | + | // ERROR_NO_SURFACE is the error no_surface value. | |
| 44 | + | const ERROR_NO_SURFACE = 1 | |
| 45 | + | ||
| 46 | + | // ERROR_UNSUPPORTED_BUFFER is the error unsupported_buffer value. | |
| 47 | + | const ERROR_UNSUPPORTED_BUFFER = 2 | |
| 48 | + | ||
| 49 | + | // ERROR_NO_BUFFER is the error no_buffer value. | |
| 50 | + | const ERROR_NO_BUFFER = 3 | |
| 51 | + | ||
| 52 | + | // ERROR_NO_ACQUIRE_POINT is the error no_acquire_point value. | |
| 53 | + | const ERROR_NO_ACQUIRE_POINT = 4 | |
| 54 | + | ||
| 55 | + | // ERROR_NO_RELEASE_POINT is the error no_release_point value. | |
| 56 | + | const ERROR_NO_RELEASE_POINT = 5 | |
| 57 | + | ||
| 58 | + | // ERROR_CONFLICTING_POINTS is the error conflicting_points value. | |
| 59 | + | const ERROR_CONFLICTING_POINTS = 6 | |
| 60 | + | ||
| 61 | + | // WpLinuxDrmSyncobjManagerInterface is the protocol interface name. | |
| 62 | + | const WpLinuxDrmSyncobjManagerInterface = "wp_linux_drm_syncobj_manager_v1" | |
| 63 | + | ||
| 64 | + | // WpLinuxDrmSyncobjManager is the generated binding for wp_linux_drm_syncobj_manager_v1 version 1. | |
| 65 | + | type WpLinuxDrmSyncobjManager struct { | |
| 66 | + | wl.BaseProxy | |
| 67 | + | } | |
| 68 | + | ||
| 69 | + | // NewWpLinuxDrmSyncobjManager returns an unbound WpLinuxDrmSyncobjManager. | |
| 70 | + | func NewWpLinuxDrmSyncobjManager(ctx *wl.Context) *WpLinuxDrmSyncobjManager { | |
| 71 | + | obj := &WpLinuxDrmSyncobjManager{} | |
| 72 | + | obj.SetContext(ctx) | |
| 73 | + | ctx.Register(obj) | |
| 74 | + | return obj | |
| 75 | + | } | |
| 76 | + | ||
| 77 | + | // Destroy this explicit synchronization factory object. Other objects shall not be affected by this request. | |
| 78 | + | func (o *WpLinuxDrmSyncobjManager) Destroy() error { | |
| 79 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_linux_drm_syncobj_manager_v1.destroy", Destructor: true}); err != nil { | |
| 80 | + | return err | |
| 81 | + | } | |
| 82 | + | return nil | |
| 83 | + | } | |
| 84 | + | ||
| 85 | + | // Instantiate an interface extension for the given wl_surface to provide explicit synchronization. If the given wl_surface already has an explicit synchronization object associated, the surface_exists protocol error is raised. Graphics APIs, like EGL or Vulkan, that manage the buffer queue and commits of a wl_surface themselves, are likely to be using this extension internally. If a client is using such an API for a wl_surface, it should not directly use this extension on that surface, to avoid raising a surface_exists protocol error. | |
| 86 | + | func (o *WpLinuxDrmSyncobjManager) GetSurface(surface *cross_wl_surface.Surface) (*WpLinuxDrmSyncobjSurface, error) { | |
| 87 | + | var arg1 wl.Object | |
| 88 | + | if surface != nil { | |
| 89 | + | arg1 = surface | |
| 90 | + | } | |
| 91 | + | child := &WpLinuxDrmSyncobjSurface{} | |
| 92 | + | child.SetContext(o.Context()) | |
| 93 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_linux_drm_syncobj_manager_v1.get_surface", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 94 | + | return nil, err | |
| 95 | + | } | |
| 96 | + | return child, nil | |
| 97 | + | } | |
| 98 | + | ||
| 99 | + | // Import a DRM synchronization object timeline. If the FD cannot be imported, the invalid_timeline error is raised. | |
| 100 | + | func (o *WpLinuxDrmSyncobjManager) ImportTimeline(fd int) (*WpLinuxDrmSyncobjTimeline, error) { | |
| 101 | + | child := &WpLinuxDrmSyncobjTimeline{} | |
| 102 | + | child.SetContext(o.Context()) | |
| 103 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wp_linux_drm_syncobj_manager_v1.import_timeline", Child: child, FDs: []int{fd}}, wl.ArgObject(child), wl.ArgFD()); err != nil { | |
| 104 | + | return nil, err | |
| 105 | + | } | |
| 106 | + | return child, nil | |
| 107 | + | } | |
| 108 | + | ||
| 109 | + | // EventSignature returns the declared event argument types in wire order. | |
| 110 | + | func (o *WpLinuxDrmSyncobjManager) EventSignature(opcode uint16) (string, bool) { | |
| 111 | + | switch opcode { | |
| 112 | + | default: | |
| 113 | + | return "", false | |
| 114 | + | } | |
| 115 | + | } | |
| 116 | + | ||
| 117 | + | // Dispatch decodes one event on wp_linux_drm_syncobj_manager_v1 and calls the registered handlers. | |
| 118 | + | func (o *WpLinuxDrmSyncobjManager) Dispatch(event *wl.Event) { | |
| 119 | + | switch event.Opcode { | |
| 120 | + | default: | |
| 121 | + | } | |
| 122 | + | } | |
| 123 | + | ||
| 124 | + | // WpLinuxDrmSyncobjTimelineInterface is the protocol interface name. | |
| 125 | + | const WpLinuxDrmSyncobjTimelineInterface = "wp_linux_drm_syncobj_timeline_v1" | |
| 126 | + | ||
| 127 | + | // WpLinuxDrmSyncobjTimeline is the generated binding for wp_linux_drm_syncobj_timeline_v1 version 1. | |
| 128 | + | type WpLinuxDrmSyncobjTimeline struct { | |
| 129 | + | wl.BaseProxy | |
| 130 | + | } | |
| 131 | + | ||
| 132 | + | // NewWpLinuxDrmSyncobjTimeline returns an unbound WpLinuxDrmSyncobjTimeline. | |
| 133 | + | func NewWpLinuxDrmSyncobjTimeline(ctx *wl.Context) *WpLinuxDrmSyncobjTimeline { | |
| 134 | + | obj := &WpLinuxDrmSyncobjTimeline{} | |
| 135 | + | obj.SetContext(ctx) | |
| 136 | + | ctx.Register(obj) | |
| 137 | + | return obj | |
| 138 | + | } | |
| 139 | + | ||
| 140 | + | // Destroy the synchronization object timeline. Other objects are not affected by this request, in particular timeline points set by set_acquire_point and set_release_point are not unset. | |
| 141 | + | func (o *WpLinuxDrmSyncobjTimeline) Destroy() error { | |
| 142 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_linux_drm_syncobj_timeline_v1.destroy", Destructor: true}); err != nil { | |
| 143 | + | return err | |
| 144 | + | } | |
| 145 | + | return nil | |
| 146 | + | } | |
| 147 | + | ||
| 148 | + | // EventSignature returns the declared event argument types in wire order. | |
| 149 | + | func (o *WpLinuxDrmSyncobjTimeline) EventSignature(opcode uint16) (string, bool) { | |
| 150 | + | switch opcode { | |
| 151 | + | default: | |
| 152 | + | return "", false | |
| 153 | + | } | |
| 154 | + | } | |
| 155 | + | ||
| 156 | + | // Dispatch decodes one event on wp_linux_drm_syncobj_timeline_v1 and calls the registered handlers. | |
| 157 | + | func (o *WpLinuxDrmSyncobjTimeline) Dispatch(event *wl.Event) { | |
| 158 | + | switch event.Opcode { | |
| 159 | + | default: | |
| 160 | + | } | |
| 161 | + | } | |
| 162 | + | ||
| 163 | + | // WpLinuxDrmSyncobjSurfaceInterface is the protocol interface name. | |
| 164 | + | const WpLinuxDrmSyncobjSurfaceInterface = "wp_linux_drm_syncobj_surface_v1" | |
| 165 | + | ||
| 166 | + | // WpLinuxDrmSyncobjSurface is the generated binding for wp_linux_drm_syncobj_surface_v1 version 1. | |
| 167 | + | type WpLinuxDrmSyncobjSurface struct { | |
| 168 | + | wl.BaseProxy | |
| 169 | + | } | |
| 170 | + | ||
| 171 | + | // NewWpLinuxDrmSyncobjSurface returns an unbound WpLinuxDrmSyncobjSurface. | |
| 172 | + | func NewWpLinuxDrmSyncobjSurface(ctx *wl.Context) *WpLinuxDrmSyncobjSurface { | |
| 173 | + | obj := &WpLinuxDrmSyncobjSurface{} | |
| 174 | + | obj.SetContext(ctx) | |
| 175 | + | ctx.Register(obj) | |
| 176 | + | return obj | |
| 177 | + | } | |
| 178 | + | ||
| 179 | + | // Destroy this surface synchronization object. Any timeline point set by this object with set_acquire_point or set_release_point since the last commit may be discarded by the compositor. Any timeline point set by this object before the last commit will not be affected. | |
| 180 | + | func (o *WpLinuxDrmSyncobjSurface) Destroy() error { | |
| 181 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_linux_drm_syncobj_surface_v1.destroy", Destructor: true}); err != nil { | |
| 182 | + | return err | |
| 183 | + | } | |
| 184 | + | return nil | |
| 185 | + | } | |
| 186 | + | ||
| 187 | + | // Set the timeline point that must be signalled before the compositor may sample from the buffer attached with wl_surface.attach. The 64-bit unsigned value combined from point_hi and point_lo is the point value. The acquire point is double-buffered state, and will be applied on the next wl_surface.commit request for the associated surface. Thus, it applies only to the buffer that is attached to the surface at commit time. If an acquire point has already been attached during the same commit cycle, the new point replaces the old one. If the associated wl_surface was destroyed, a no_surface error is raised. If at surface commit time there is a pending acquire timeline point set but no pending buffer attached, a no_buffer error is raised. If at surface commit time there is a pending buffer attached but no pending acquire timeline point set, the no_acquire_point protocol error is raised. | |
| 188 | + | func (o *WpLinuxDrmSyncobjSurface) SetAcquirePoint(timeline *WpLinuxDrmSyncobjTimeline, pointHi uint32, pointLo uint32) error { | |
| 189 | + | var arg0 wl.Object | |
| 190 | + | if timeline != nil { | |
| 191 | + | arg0 = timeline | |
| 192 | + | } | |
| 193 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_linux_drm_syncobj_surface_v1.set_acquire_point"}, wl.ArgObject(arg0), wl.ArgUint(pointHi), wl.ArgUint(pointLo)); err != nil { | |
| 194 | + | return err | |
| 195 | + | } | |
| 196 | + | return nil | |
| 197 | + | } | |
| 198 | + | ||
| 199 | + | // Set the timeline point that must be signalled by the compositor when it has finished its usage of the buffer attached with wl_surface.attach for the relevant commit. Once the timeline point is signaled, and assuming the associated buffer is not pending release from other wl_surface.commit requests, no additional explicit or implicit synchronization with the compositor is required to safely re-use the buffer. Note that clients cannot rely on the release point being always signaled after the acquire point: compositors may release buffers without ever reading from them. In addition, the compositor may use different presentation paths for different commits, which may have different release behavior. As a result, the compositor may signal the release points in a different order than the client committed them. Because signaling a timeline point also signals every previous point, it is generally not safe to use the same timeline object for the release points of multiple buffers. The out-of-order signaling described above may lead to a release point being signaled before the compositor has finished reading. To avoid this, it is strongly recommended that each buffer should use a separate timeline for its release points. The 64-bit unsigned value combined from point_hi and point_lo is the point value. The release point is double-buffered state, and will be applied on the next wl_surface.commit request for the associated surface. Thus, it applies only to the buffer that is attached to the surface at commit time. If a release point has already been attached during the same commit cycle, the new point replaces the old one. If the associated wl_surface was destroyed, a no_surface error is raised. If at surface commit time there is a pending release timeline point set but no pending buffer attached, a no_buffer error is raised. If at surface commit time there is a pending buffer attached but no pending release timeline point set, the no_release_point protocol error is raised. | |
| 200 | + | func (o *WpLinuxDrmSyncobjSurface) SetReleasePoint(timeline *WpLinuxDrmSyncobjTimeline, pointHi uint32, pointLo uint32) error { | |
| 201 | + | var arg0 wl.Object | |
| 202 | + | if timeline != nil { | |
| 203 | + | arg0 = timeline | |
| 204 | + | } | |
| 205 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wp_linux_drm_syncobj_surface_v1.set_release_point"}, wl.ArgObject(arg0), wl.ArgUint(pointHi), wl.ArgUint(pointLo)); err != nil { | |
| 206 | + | return err | |
| 207 | + | } | |
| 208 | + | return nil | |
| 209 | + | } | |
| 210 | + | ||
| 211 | + | // EventSignature returns the declared event argument types in wire order. | |
| 212 | + | func (o *WpLinuxDrmSyncobjSurface) EventSignature(opcode uint16) (string, bool) { | |
| 213 | + | switch opcode { | |
| 214 | + | default: | |
| 215 | + | return "", false | |
| 216 | + | } | |
| 217 | + | } | |
| 218 | + | ||
| 219 | + | // Dispatch decodes one event on wp_linux_drm_syncobj_surface_v1 and calls the registered handlers. | |
| 220 | + | func (o *WpLinuxDrmSyncobjSurface) Dispatch(event *wl.Event) { | |
| 221 | + | switch event.Opcode { | |
| 222 | + | default: | |
| 223 | + | } | |
| 224 | + | } | |
A client/linuxexplicitsynchronization/linuxexplicitsynchronization_generated.go +270 -0
| @@ -0,0 +1,270 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: zwp_linux_explicit_synchronization_unstable_v1 | |
| 3 | + | // Source: linux-explicit-synchronization-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright 2016 The Chromium Authors. | |
| 7 | + | // Copyright 2017 Intel Corporation | |
| 8 | + | // Copyright 2018 Collabora, Ltd | |
| 9 | + | // | |
| 10 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 11 | + | // copy of this software and associated documentation files (the "Software"), | |
| 12 | + | // to deal in the Software without restriction, including without limitation | |
| 13 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 14 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 15 | + | // Software is furnished to do so, subject to the following conditions: | |
| 16 | + | // | |
| 17 | + | // The above copyright notice and this permission notice (including the next | |
| 18 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 19 | + | // Software. | |
| 20 | + | // | |
| 21 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 22 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 23 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 24 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 25 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 26 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 27 | + | // DEALINGS IN THE SOFTWARE. | |
| 28 | + | ||
| 29 | + | package linuxexplicitsynchronization | |
| 30 | + | ||
| 31 | + | import ( | |
| 32 | + | "sync" | |
| 33 | + | ||
| 34 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 35 | + | "github.com/bnema/wlturbo/wl" | |
| 36 | + | ) | |
| 37 | + | ||
| 38 | + | // ERROR_SYNCHRONIZATION_EXISTS is the error synchronization_exists value. | |
| 39 | + | const ERROR_SYNCHRONIZATION_EXISTS = 0 | |
| 40 | + | ||
| 41 | + | // ERROR_INVALID_FENCE is the error invalid_fence value. | |
| 42 | + | const ERROR_INVALID_FENCE = 0 | |
| 43 | + | ||
| 44 | + | // ERROR_DUPLICATE_FENCE is the error duplicate_fence value. | |
| 45 | + | const ERROR_DUPLICATE_FENCE = 1 | |
| 46 | + | ||
| 47 | + | // ERROR_DUPLICATE_RELEASE is the error duplicate_release value. | |
| 48 | + | const ERROR_DUPLICATE_RELEASE = 2 | |
| 49 | + | ||
| 50 | + | // ERROR_NO_SURFACE is the error no_surface value. | |
| 51 | + | const ERROR_NO_SURFACE = 3 | |
| 52 | + | ||
| 53 | + | // ERROR_UNSUPPORTED_BUFFER is the error unsupported_buffer value. | |
| 54 | + | const ERROR_UNSUPPORTED_BUFFER = 4 | |
| 55 | + | ||
| 56 | + | // ERROR_NO_BUFFER is the error no_buffer value. | |
| 57 | + | const ERROR_NO_BUFFER = 5 | |
| 58 | + | ||
| 59 | + | // LinuxExplicitSynchronizationInterface is the protocol interface name. | |
| 60 | + | const LinuxExplicitSynchronizationInterface = "zwp_linux_explicit_synchronization_v1" | |
| 61 | + | ||
| 62 | + | // LinuxExplicitSynchronization is the generated binding for zwp_linux_explicit_synchronization_v1 version 2. | |
| 63 | + | type LinuxExplicitSynchronization struct { | |
| 64 | + | wl.BaseProxy | |
| 65 | + | } | |
| 66 | + | ||
| 67 | + | // NewLinuxExplicitSynchronization returns an unbound LinuxExplicitSynchronization. | |
| 68 | + | func NewLinuxExplicitSynchronization(ctx *wl.Context) *LinuxExplicitSynchronization { | |
| 69 | + | obj := &LinuxExplicitSynchronization{} | |
| 70 | + | obj.SetContext(ctx) | |
| 71 | + | ctx.Register(obj) | |
| 72 | + | return obj | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | // Destroy this explicit synchronization factory object. Other objects, including zwp_linux_surface_synchronization_v1 objects created by this factory, shall not be affected by this request. | |
| 76 | + | func (o *LinuxExplicitSynchronization) Destroy() error { | |
| 77 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_linux_explicit_synchronization_v1.destroy", Destructor: true}); err != nil { | |
| 78 | + | return err | |
| 79 | + | } | |
| 80 | + | return nil | |
| 81 | + | } | |
| 82 | + | ||
| 83 | + | // Instantiate an interface extension for the given wl_surface to provide explicit synchronization. If the given wl_surface already has an explicit synchronization object associated, the synchronization_exists protocol error is raised. Graphics APIs, like EGL or Vulkan, that manage the buffer queue and commits of a wl_surface themselves, are likely to be using this extension internally. If a client is using such an API for a wl_surface, it should not directly use this extension on that surface, to avoid raising a synchronization_exists protocol error. | |
| 84 | + | func (o *LinuxExplicitSynchronization) GetSynchronization(surface *cross_wl_surface.Surface) (*LinuxSurfaceSynchronization, error) { | |
| 85 | + | var arg1 wl.Object | |
| 86 | + | if surface != nil { | |
| 87 | + | arg1 = surface | |
| 88 | + | } | |
| 89 | + | child := &LinuxSurfaceSynchronization{} | |
| 90 | + | child.SetContext(o.Context()) | |
| 91 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_linux_explicit_synchronization_v1.get_synchronization", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 92 | + | return nil, err | |
| 93 | + | } | |
| 94 | + | return child, nil | |
| 95 | + | } | |
| 96 | + | ||
| 97 | + | // EventSignature returns the declared event argument types in wire order. | |
| 98 | + | func (o *LinuxExplicitSynchronization) EventSignature(opcode uint16) (string, bool) { | |
| 99 | + | switch opcode { | |
| 100 | + | default: | |
| 101 | + | return "", false | |
| 102 | + | } | |
| 103 | + | } | |
| 104 | + | ||
| 105 | + | // Dispatch decodes one event on zwp_linux_explicit_synchronization_v1 and calls the registered handlers. | |
| 106 | + | func (o *LinuxExplicitSynchronization) Dispatch(event *wl.Event) { | |
| 107 | + | switch event.Opcode { | |
| 108 | + | default: | |
| 109 | + | } | |
| 110 | + | } | |
| 111 | + | ||
| 112 | + | // LinuxSurfaceSynchronizationInterface is the protocol interface name. | |
| 113 | + | const LinuxSurfaceSynchronizationInterface = "zwp_linux_surface_synchronization_v1" | |
| 114 | + | ||
| 115 | + | // LinuxSurfaceSynchronization is the generated binding for zwp_linux_surface_synchronization_v1 version 2. | |
| 116 | + | type LinuxSurfaceSynchronization struct { | |
| 117 | + | wl.BaseProxy | |
| 118 | + | } | |
| 119 | + | ||
| 120 | + | // NewLinuxSurfaceSynchronization returns an unbound LinuxSurfaceSynchronization. | |
| 121 | + | func NewLinuxSurfaceSynchronization(ctx *wl.Context) *LinuxSurfaceSynchronization { | |
| 122 | + | obj := &LinuxSurfaceSynchronization{} | |
| 123 | + | obj.SetContext(ctx) | |
| 124 | + | ctx.Register(obj) | |
| 125 | + | return obj | |
| 126 | + | } | |
| 127 | + | ||
| 128 | + | // Destroy this explicit synchronization object. Any fence set by this object with set_acquire_fence since the last commit will be discarded by the server. Any fences set by this object before the last commit are not affected. zwp_linux_buffer_release_v1 objects created by this object are not affected by this request. | |
| 129 | + | func (o *LinuxSurfaceSynchronization) Destroy() error { | |
| 130 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_linux_surface_synchronization_v1.destroy", Destructor: true}); err != nil { | |
| 131 | + | return err | |
| 132 | + | } | |
| 133 | + | return nil | |
| 134 | + | } | |
| 135 | + | ||
| 136 | + | // Set the acquire fence that must be signaled before the compositor may sample from the buffer attached with wl_surface.attach. The fence is a dma_fence kernel object. The acquire fence is double-buffered state, and will be applied on the next wl_surface.commit request for the associated surface. Thus, it applies only to the buffer that is attached to the surface at commit time. If the provided fd is not a valid dma_fence fd, then an INVALID_FENCE error is raised. If a fence has already been attached during the same commit cycle, a DUPLICATE_FENCE error is raised. If the associated wl_surface was destroyed, a NO_SURFACE error is raised. If at surface commit time the attached buffer does not support explicit synchronization, an UNSUPPORTED_BUFFER error is raised. If at surface commit time there is no buffer attached, a NO_BUFFER error is raised. | |
| 137 | + | func (o *LinuxSurfaceSynchronization) SetAcquireFence(fd int) error { | |
| 138 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_linux_surface_synchronization_v1.set_acquire_fence", FDs: []int{fd}}, wl.ArgFD()); err != nil { | |
| 139 | + | return err | |
| 140 | + | } | |
| 141 | + | return nil | |
| 142 | + | } | |
| 143 | + | ||
| 144 | + | // Create a listener for the release of the buffer attached by the client with wl_surface.attach. See zwp_linux_buffer_release_v1 documentation for more information. The release object is double-buffered state, and will be associated with the buffer that is attached to the surface at wl_surface.commit time. If a zwp_linux_buffer_release_v1 object has already been requested for the surface in the same commit cycle, a DUPLICATE_RELEASE error is raised. If the associated wl_surface was destroyed, a NO_SURFACE error is raised. If at surface commit time there is no buffer attached, a NO_BUFFER error is raised. | |
| 145 | + | func (o *LinuxSurfaceSynchronization) GetRelease() (*LinuxBufferRelease, error) { | |
| 146 | + | child := &LinuxBufferRelease{} | |
| 147 | + | child.SetContext(o.Context()) | |
| 148 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_linux_surface_synchronization_v1.get_release", Child: child}, wl.ArgObject(child)); err != nil { | |
| 149 | + | return nil, err | |
| 150 | + | } | |
| 151 | + | return child, nil | |
| 152 | + | } | |
| 153 | + | ||
| 154 | + | // EventSignature returns the declared event argument types in wire order. | |
| 155 | + | func (o *LinuxSurfaceSynchronization) EventSignature(opcode uint16) (string, bool) { | |
| 156 | + | switch opcode { | |
| 157 | + | default: | |
| 158 | + | return "", false | |
| 159 | + | } | |
| 160 | + | } | |
| 161 | + | ||
| 162 | + | // Dispatch decodes one event on zwp_linux_surface_synchronization_v1 and calls the registered handlers. | |
| 163 | + | func (o *LinuxSurfaceSynchronization) Dispatch(event *wl.Event) { | |
| 164 | + | switch event.Opcode { | |
| 165 | + | default: | |
| 166 | + | } | |
| 167 | + | } | |
| 168 | + | ||
| 169 | + | // LinuxBufferReleaseInterface is the protocol interface name. | |
| 170 | + | const LinuxBufferReleaseInterface = "zwp_linux_buffer_release_v1" | |
| 171 | + | ||
| 172 | + | // LinuxBufferRelease is the generated binding for zwp_linux_buffer_release_v1 version 1. | |
| 173 | + | type LinuxBufferRelease struct { | |
| 174 | + | wl.BaseProxy | |
| 175 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 176 | + | // handlers while another goroutine dispatches events. | |
| 177 | + | handlersMu sync.Mutex | |
| 178 | + | onFencedRelease []func(fence *wl.OwnedFD) | |
| 179 | + | onImmediateRelease []func() | |
| 180 | + | } | |
| 181 | + | ||
| 182 | + | // NewLinuxBufferRelease returns an unbound LinuxBufferRelease. | |
| 183 | + | func NewLinuxBufferRelease(ctx *wl.Context) *LinuxBufferRelease { | |
| 184 | + | obj := &LinuxBufferRelease{} | |
| 185 | + | obj.SetContext(ctx) | |
| 186 | + | ctx.Register(obj) | |
| 187 | + | return obj | |
| 188 | + | } | |
| 189 | + | ||
| 190 | + | // OnFencedRelease registers a handler for the fenced_release event. | |
| 191 | + | // | |
| 192 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 193 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 194 | + | func (o *LinuxBufferRelease) OnFencedRelease(handler func(fence *wl.OwnedFD)) { | |
| 195 | + | if handler == nil { | |
| 196 | + | return | |
| 197 | + | } | |
| 198 | + | o.handlersMu.Lock() | |
| 199 | + | defer o.handlersMu.Unlock() | |
| 200 | + | o.onFencedRelease = append(o.onFencedRelease, handler) | |
| 201 | + | } | |
| 202 | + | ||
| 203 | + | // handlersForFencedRelease returns the handlers registered for fenced_release, taken | |
| 204 | + | // under the lock so a handler may register another handler while events are | |
| 205 | + | // being dispatched. | |
| 206 | + | func (o *LinuxBufferRelease) handlersForFencedRelease() []func(fence *wl.OwnedFD) { | |
| 207 | + | o.handlersMu.Lock() | |
| 208 | + | defer o.handlersMu.Unlock() | |
| 209 | + | return o.onFencedRelease | |
| 210 | + | } | |
| 211 | + | ||
| 212 | + | // OnImmediateRelease registers a handler for the immediate_release event. | |
| 213 | + | // | |
| 214 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 215 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 216 | + | func (o *LinuxBufferRelease) OnImmediateRelease(handler func()) { | |
| 217 | + | if handler == nil { | |
| 218 | + | return | |
| 219 | + | } | |
| 220 | + | o.handlersMu.Lock() | |
| 221 | + | defer o.handlersMu.Unlock() | |
| 222 | + | o.onImmediateRelease = append(o.onImmediateRelease, handler) | |
| 223 | + | } | |
| 224 | + | ||
| 225 | + | // handlersForImmediateRelease returns the handlers registered for immediate_release, taken | |
| 226 | + | // under the lock so a handler may register another handler while events are | |
| 227 | + | // being dispatched. | |
| 228 | + | func (o *LinuxBufferRelease) handlersForImmediateRelease() []func() { | |
| 229 | + | o.handlersMu.Lock() | |
| 230 | + | defer o.handlersMu.Unlock() | |
| 231 | + | return o.onImmediateRelease | |
| 232 | + | } | |
| 233 | + | ||
| 234 | + | // EventSignature returns the declared event argument types in wire order. | |
| 235 | + | func (o *LinuxBufferRelease) EventSignature(opcode uint16) (string, bool) { | |
| 236 | + | switch opcode { | |
| 237 | + | case 0: | |
| 238 | + | return "fd,", true | |
| 239 | + | case 1: | |
| 240 | + | return "", true | |
| 241 | + | default: | |
| 242 | + | return "", false | |
| 243 | + | } | |
| 244 | + | } | |
| 245 | + | ||
| 246 | + | // Dispatch decodes one event on zwp_linux_buffer_release_v1 and calls the registered handlers. | |
| 247 | + | func (o *LinuxBufferRelease) Dispatch(event *wl.Event) { | |
| 248 | + | switch event.Opcode { | |
| 249 | + | case 0: // fenced_release | |
| 250 | + | fence := event.FD() | |
| 251 | + | ownedfence := fence | |
| 252 | + | defer ownedfence.Close() | |
| 253 | + | ||
| 254 | + | for i, handler := range o.handlersForFencedRelease() { | |
| 255 | + | if i > 0 { | |
| 256 | + | fence = nil | |
| 257 | + | } | |
| 258 | + | handler(fence) | |
| 259 | + | } | |
| 260 | + | o.Context().Unregister(o) | |
| 261 | + | case 1: // immediate_release | |
| 262 | + | ||
| 263 | + | for i, handler := range o.handlersForImmediateRelease() { | |
| 264 | + | _ = i | |
| 265 | + | handler() | |
| 266 | + | } | |
| 267 | + | o.Context().Unregister(o) | |
| 268 | + | default: | |
| 269 | + | } | |
| 270 | + | } | |
A client/negotiation_test.go +50 -0
| @@ -0,0 +1,50 @@ | |||
| 1 | + | //go:build linux | |
| 2 | + | ||
| 3 | + | package client_test | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "encoding/binary" | |
| 7 | + | "errors" | |
| 8 | + | "testing" | |
| 9 | + | ||
| 10 | + | "github.com/bnema/go-wayland-bindings/client/xdgshell" | |
| 11 | + | "github.com/bnema/wlturbo" | |
| 12 | + | ) | |
| 13 | + | ||
| 14 | + | func TestAnnouncedVersionNegotiation(t *testing.T) { | |
| 15 | + | c, p := pair(t) | |
| 16 | + | d, e := wlturbo.ConnectFromConn(c) | |
| 17 | + | noerr(t, e) | |
| 18 | + | defer d.Close() | |
| 19 | + | request(t, p) | |
| 20 | + | iface := xdgshell.XdgWmBaseInterface | |
| 21 | + | if v, e := d.Registry().BindNegotiated(iface, 6, xdgshell.NewXdgWmBase(d.Context())); v != 0 || !errors.Is(e, wlturbo.ErrGlobalNotFound) { | |
| 22 | + | t.Fatalf("missing: %d %v", v, e) | |
| 23 | + | } | |
| 24 | + | if v, e := d.Registry().BindNegotiated(iface, 0, xdgshell.NewXdgWmBase(d.Context())); v != 0 || e == nil || errors.Is(e, wlturbo.ErrGlobalNotFound) { | |
| 25 | + | t.Fatalf("unsupported zero: %d %v", v, e) | |
| 26 | + | } | |
| 27 | + | for i, version := range []uint32{2, 9} { | |
| 28 | + | name := uint32(30 + i) | |
| 29 | + | announcement := append(msg(0, 0, name)[8:], str(iface)...) | |
| 30 | + | announcement = append(announcement, msg(0, 0, version)[8:]...) | |
| 31 | + | send(t, p, payload(d.Registry().ID(), 0, announcement...)) | |
| 32 | + | noerr(t, d.Dispatch()) | |
| 33 | + | proxy := xdgshell.NewXdgWmBase(d.Context()) | |
| 34 | + | if v, e := d.Registry().BindNegotiated(iface, 0, proxy); v != 0 || e == nil || errors.Is(e, wlturbo.ErrGlobalNotFound) { | |
| 35 | + | t.Fatalf("supported zero with global: %d %v", v, e) | |
| 36 | + | } | |
| 37 | + | negotiated, e := d.Registry().BindNegotiated(iface, 6, proxy) | |
| 38 | + | noerr(t, e) | |
| 39 | + | want := version | |
| 40 | + | if want > 6 { | |
| 41 | + | want = 6 | |
| 42 | + | } | |
| 43 | + | _, op, body := request(t, p) | |
| 44 | + | if op != 0 || negotiated != want || binary.NativeEndian.Uint32(body) != name || binary.NativeEndian.Uint32(body[len(body)-8:]) != want || binary.NativeEndian.Uint32(body[len(body)-4:]) != proxy.ID() { | |
| 45 | + | t.Fatalf("server=%d negotiated=%d wire=%x", version, negotiated, body) | |
| 46 | + | } | |
| 47 | + | send(t, p, msg(d.Registry().ID(), 1, name)) | |
| 48 | + | noerr(t, d.Dispatch()) | |
| 49 | + | } | |
| 50 | + | } | |
A client/performance_test.go +393 -0
| @@ -0,0 +1,393 @@ | |||
| 1 | + | //go:build linux | |
| 2 | + | ||
| 3 | + | package client_test | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "encoding/binary" | |
| 7 | + | "net" | |
| 8 | + | "os" | |
| 9 | + | "testing" | |
| 10 | + | "time" | |
| 11 | + | ||
| 12 | + | "github.com/bnema/go-wayland-bindings/client/cursorshape" | |
| 13 | + | "github.com/bnema/go-wayland-bindings/client/fractionalscale" | |
| 14 | + | "github.com/bnema/go-wayland-bindings/client/viewporter" | |
| 15 | + | "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 16 | + | "github.com/bnema/wlturbo" | |
| 17 | + | "golang.org/x/sys/unix" | |
| 18 | + | ) | |
| 19 | + | ||
| 20 | + | // Allocation profile of generated bindings, measured against the current | |
| 21 | + | // transport (see the regression tests below for what is pinned): | |
| 22 | + | // | |
| 23 | + | // - Event dispatch of numeric arguments (uint/int/fixed) is allocation-free. | |
| 24 | + | // - Zero-argument requests are allocation-free. | |
| 25 | + | // - Generated requests pass typed wl.Arg values to Context.RequestArgs, so | |
| 26 | + | // numeric requests are allocation-free for every value. (The legacy | |
| 27 | + | // Context.Request boxed each argument into an interface: one heap | |
| 28 | + | // allocation per 32-bit value >= 256, e.g. set_source 4, set_destination | |
| 29 | + | // 2, set_shape 1 before this path existed.) | |
| 30 | + | // - Allocations that are inherent to the operation are kept separate below: | |
| 31 | + | // new_id child creation (proxy object + map entries), received strings | |
| 32 | + | // (Event.String copies), and received file descriptors (OwnedFD). | |
| 33 | + | ||
| 34 | + | // loopConn is an in-memory net.Conn. Reads replay a fixed byte pattern made of | |
| 35 | + | // whole frames (never splitting one), and writes are discarded, so a benchmark | |
| 36 | + | // measures generated-binding and transport cost without socket scheduling. | |
| 37 | + | type loopConn struct{ pattern []byte } | |
| 38 | + | ||
| 39 | + | func (c *loopConn) Read(p []byte) (int, error) { | |
| 40 | + | n := len(p) / len(c.pattern) * len(c.pattern) | |
| 41 | + | if n == 0 { | |
| 42 | + | return 0, net.ErrClosed | |
| 43 | + | } | |
| 44 | + | for off := 0; off < n; off += len(c.pattern) { | |
| 45 | + | copy(p[off:], c.pattern) | |
| 46 | + | } | |
| 47 | + | return n, nil | |
| 48 | + | } | |
| 49 | + | func (c *loopConn) Write(p []byte) (int, error) { return len(p), nil } | |
| 50 | + | func (c *loopConn) Close() error { return nil } | |
| 51 | + | func (c *loopConn) LocalAddr() net.Addr { return loopAddr{} } | |
| 52 | + | func (c *loopConn) RemoteAddr() net.Addr { return loopAddr{} } | |
| 53 | + | func (c *loopConn) SetDeadline(time.Time) error { return nil } | |
| 54 | + | func (c *loopConn) SetReadDeadline(time.Time) error { return nil } | |
| 55 | + | func (c *loopConn) SetWriteDeadline(time.Time) error { return nil } | |
| 56 | + | ||
| 57 | + | type loopAddr struct{} | |
| 58 | + | ||
| 59 | + | func (loopAddr) Network() string { return "loop" } | |
| 60 | + | func (loopAddr) String() string { return "loop" } | |
| 61 | + | ||
| 62 | + | // loopEnv is a display over loopConn with one registered object of each kind | |
| 63 | + | // used by the tests. Tests replay an event by assigning its frame to c.pattern. | |
| 64 | + | type loopEnv struct { | |
| 65 | + | d *wlturbo.Display | |
| 66 | + | c *loopConn | |
| 67 | + | surface *wayland.Surface | |
| 68 | + | ptr *wayland.Pointer | |
| 69 | + | output *wayland.Output | |
| 70 | + | vp *viewporter.WpViewport | |
| 71 | + | shape *cursorshape.WpCursorShapeDevice | |
| 72 | + | scale *fractionalscale.WpFractionalScale | |
| 73 | + | vpr *viewporter.WpViewporter | |
| 74 | + | } | |
| 75 | + | ||
| 76 | + | func newLoopEnv(tb testing.TB) *loopEnv { | |
| 77 | + | tb.Helper() | |
| 78 | + | c := &loopConn{pattern: make([]byte, 12)} | |
| 79 | + | d, err := wlturbo.ConnectFromConn(c) | |
| 80 | + | if err != nil { | |
| 81 | + | tb.Fatal(err) | |
| 82 | + | } | |
| 83 | + | tb.Cleanup(func() { d.Close() }) | |
| 84 | + | e := &loopEnv{d: d, c: c} | |
| 85 | + | reg := func(p wlturbo.Proxy) { | |
| 86 | + | p.SetID(d.AllocateID()) | |
| 87 | + | d.Context().Register(p) | |
| 88 | + | } | |
| 89 | + | e.surface = wayland.NewSurface(d.Context()) | |
| 90 | + | e.ptr = wayland.NewPointer(d.Context()) | |
| 91 | + | e.output = wayland.NewOutput(d.Context()) | |
| 92 | + | e.vp = viewporter.NewWpViewport(d.Context()) | |
| 93 | + | e.shape = cursorshape.NewWpCursorShapeDevice(d.Context()) | |
| 94 | + | e.scale = fractionalscale.NewWpFractionalScale(d.Context()) | |
| 95 | + | e.vpr = viewporter.NewWpViewporter(d.Context()) | |
| 96 | + | for _, p := range []wlturbo.Proxy{e.surface, e.ptr, e.output, e.vp, e.shape, e.scale, e.vpr} { | |
| 97 | + | reg(p) | |
| 98 | + | } | |
| 99 | + | return e | |
| 100 | + | } | |
| 101 | + | ||
| 102 | + | // perfFrame encodes one event with 32-bit words as its whole body. | |
| 103 | + | func perfFrame(id uint32, op uint16, words ...uint32) []byte { | |
| 104 | + | b := make([]byte, 8+4*len(words)) | |
| 105 | + | binary.LittleEndian.PutUint32(b, id) | |
| 106 | + | binary.LittleEndian.PutUint32(b[4:], uint32(len(b))<<16|uint32(op)) | |
| 107 | + | for i, v := range words { | |
| 108 | + | binary.LittleEndian.PutUint32(b[8+i*4:], v) | |
| 109 | + | } | |
| 110 | + | return b | |
| 111 | + | } | |
| 112 | + | ||
| 113 | + | // perfStringFrame encodes an event whose only argument is a string. | |
| 114 | + | func perfStringFrame(id uint32, op uint16, s string) []byte { | |
| 115 | + | n := len(s) + 1 | |
| 116 | + | padded := (n + 3) &^ 3 | |
| 117 | + | b := make([]byte, 8+4+padded) | |
| 118 | + | binary.LittleEndian.PutUint32(b, id) | |
| 119 | + | binary.LittleEndian.PutUint32(b[4:], uint32(len(b))<<16|uint32(op)) | |
| 120 | + | binary.LittleEndian.PutUint32(b[8:], uint32(n)) | |
| 121 | + | copy(b[12:], s) | |
| 122 | + | return b | |
| 123 | + | } | |
| 124 | + | ||
| 125 | + | // numericRequests are numeric requests with values that do NOT hit the | |
| 126 | + | // runtime's small-integer boxing table: this is the realistic cost. | |
| 127 | + | func (e *loopEnv) numericRequests() []struct { | |
| 128 | + | name string | |
| 129 | + | args int // number of numeric arguments | |
| 130 | + | run func() error | |
| 131 | + | } { | |
| 132 | + | x, w := wlturbo.NewFixed(10.5), wlturbo.NewFixed(1920) | |
| 133 | + | return []struct { | |
| 134 | + | name string | |
| 135 | + | args int | |
| 136 | + | run func() error | |
| 137 | + | }{ | |
| 138 | + | {"wp_viewport.set_source", 4, func() error { return e.vp.SetSource(x, x, w, w) }}, | |
| 139 | + | {"wp_viewport.set_destination", 2, func() error { return e.vp.SetDestination(1920, 1080) }}, | |
| 140 | + | {"wp_cursor_shape_device_v1.set_shape", 2, func() error { return e.shape.SetShape(123456, cursorshape.SHAPE_POINTER) }}, | |
| 141 | + | {"wl_surface.damage_buffer", 4, func() error { return e.surface.DamageBuffer(0, 0, 1920, 1080) }}, | |
| 142 | + | {"wl_surface.set_buffer_scale", 1, func() error { return e.surface.SetBufferScale(1000) }}, | |
| 143 | + | } | |
| 144 | + | } | |
| 145 | + | ||
| 146 | + | // TestRequestAllocations pins the request-side allocation contract. | |
| 147 | + | func TestRequestAllocations(t *testing.T) { | |
| 148 | + | e := newLoopEnv(t) | |
| 149 | + | run := func(name string, f func() error) float64 { | |
| 150 | + | var err error | |
| 151 | + | n := testing.AllocsPerRun(500, func() { err = f() }) | |
| 152 | + | if err != nil { | |
| 153 | + | t.Fatalf("%s: %v", name, err) | |
| 154 | + | } | |
| 155 | + | return n | |
| 156 | + | } | |
| 157 | + | // Requests without arguments, and numeric requests whose values are | |
| 158 | + | // below 256 (the runtime's static boxing table), are allocation-free. | |
| 159 | + | // Both must stay so, whatever the generator does with arguments. | |
| 160 | + | for _, tc := range []struct { | |
| 161 | + | name string | |
| 162 | + | f func() error | |
| 163 | + | }{ | |
| 164 | + | {"wl_surface.commit", e.surface.Commit}, | |
| 165 | + | {"wl_surface.set_buffer_scale(2)", func() error { return e.surface.SetBufferScale(2) }}, | |
| 166 | + | {"wp_viewport.set_destination(64,32)", func() error { return e.vp.SetDestination(64, 32) }}, | |
| 167 | + | {"wp_cursor_shape_device_v1.set_shape(small)", func() error { return e.shape.SetShape(7, cursorshape.SHAPE_DEFAULT) }}, | |
| 168 | + | } { | |
| 169 | + | if n := run(tc.name, tc.f); n != 0 { | |
| 170 | + | t.Errorf("%s: %v allocs/op, want 0", tc.name, n) | |
| 171 | + | } | |
| 172 | + | } | |
| 173 | + | // Realistic values (outside the runtime's small-integer boxing table) | |
| 174 | + | // travel as typed wl.Arg values and must not allocate either. | |
| 175 | + | for _, tc := range e.numericRequests() { | |
| 176 | + | if n := run(tc.name, tc.run); n != 0 { | |
| 177 | + | t.Errorf("%s: %v allocs/op, want 0 (%d numeric args)", tc.name, n, tc.args) | |
| 178 | + | } | |
| 179 | + | } | |
| 180 | + | } | |
| 181 | + | ||
| 182 | + | // TestNumericEventDispatchAllocationFree pins the event side: framing, | |
| 183 | + | // signature validation, pooled Event and typed handler dispatch for numeric | |
| 184 | + | // arguments must not allocate. | |
| 185 | + | func TestNumericEventDispatchAllocationFree(t *testing.T) { | |
| 186 | + | // One environment per case: loopConn refills a whole receive chunk, so | |
| 187 | + | // frames of a previous pattern would still be buffered. | |
| 188 | + | for _, tc := range []struct { | |
| 189 | + | name string | |
| 190 | + | setup func(e *loopEnv) (frame []byte, observed func() bool) | |
| 191 | + | }{ | |
| 192 | + | {"wp_fractional_scale_v1.preferred_scale", func(e *loopEnv) ([]byte, func() bool) { | |
| 193 | + | var scale uint32 | |
| 194 | + | e.scale.OnPreferredScale(func(s uint32) { scale = s }) | |
| 195 | + | return perfFrame(e.scale.ID(), 0, 180), func() bool { return scale == 180 } | |
| 196 | + | }}, | |
| 197 | + | {"wl_pointer.motion", func(e *loopEnv) ([]byte, func() bool) { | |
| 198 | + | var tm uint32 | |
| 199 | + | var fx, fy wlturbo.Fixed | |
| 200 | + | e.ptr.OnMotion(func(t uint32, x, y wlturbo.Fixed) { tm, fx, fy = t, x, y }) | |
| 201 | + | return perfFrame(e.ptr.ID(), 2, 1234567, 300*256, 0xffffff00), func() bool { return tm == 1234567 && fx == 300*256 && fy == -256 } | |
| 202 | + | }}, | |
| 203 | + | {"wl_surface.preferred_buffer_scale", func(e *loopEnv) ([]byte, func() bool) { | |
| 204 | + | var factor int32 | |
| 205 | + | e.surface.OnPreferredBufferScale(func(f int32) { factor = f }) | |
| 206 | + | return perfFrame(e.surface.ID(), 2, 3), func() bool { return factor == 3 } | |
| 207 | + | }}, | |
| 208 | + | } { | |
| 209 | + | t.Run(tc.name, func(t *testing.T) { | |
| 210 | + | e := newLoopEnv(t) | |
| 211 | + | f, observed := tc.setup(e) | |
| 212 | + | e.c.pattern = f | |
| 213 | + | var derr error | |
| 214 | + | n := testing.AllocsPerRun(1000, func() { | |
| 215 | + | if err := e.d.Dispatch(); err != nil { | |
| 216 | + | derr = err | |
| 217 | + | } | |
| 218 | + | }) | |
| 219 | + | if derr != nil { | |
| 220 | + | t.Fatal(derr) | |
| 221 | + | } | |
| 222 | + | if !observed() { | |
| 223 | + | t.Fatal("handler did not observe the event") | |
| 224 | + | } | |
| 225 | + | if n != 0 { | |
| 226 | + | t.Errorf("%v allocs/op, want 0", n) | |
| 227 | + | } | |
| 228 | + | }) | |
| 229 | + | } | |
| 230 | + | } | |
| 231 | + | ||
| 232 | + | // TestNecessaryAllocations documents allocations that are inherent to the | |
| 233 | + | // operation. They are bounded so they cannot silently grow, but they are not | |
| 234 | + | // expected to reach zero. | |
| 235 | + | func TestNecessaryAllocations(t *testing.T) { | |
| 236 | + | e := newLoopEnv(t) | |
| 237 | + | ||
| 238 | + | // A received string is copied out of the receive buffer: one allocation. | |
| 239 | + | var name string | |
| 240 | + | e.output.OnName(func(s string) { name = s }) | |
| 241 | + | e.c.pattern = perfStringFrame(e.output.ID(), 4, "HDMI-A-1") | |
| 242 | + | n := testing.AllocsPerRun(1000, func() { _ = e.d.Dispatch() }) | |
| 243 | + | if name != "HDMI-A-1" { | |
| 244 | + | t.Fatalf("string event not delivered: %q", name) | |
| 245 | + | } | |
| 246 | + | if n > 1 { | |
| 247 | + | t.Errorf("wl_output.name: %v allocs/op, want <= 1 (the string copy)", n) | |
| 248 | + | } | |
| 249 | + | ||
| 250 | + | // A new_id request creates a proxy and registers it in two maps; that is | |
| 251 | + | // the object-creation cost, reported rather than asserted to be zero. | |
| 252 | + | // The IDs are never released in this loopback, so keep the run short. | |
| 253 | + | n = testing.AllocsPerRun(50, func() { | |
| 254 | + | if _, err := e.vpr.GetViewport(e.surface); err != nil { | |
| 255 | + | t.Fatal(err) | |
| 256 | + | } | |
| 257 | + | }) | |
| 258 | + | t.Logf("wp_viewporter.get_viewport (object creation): %v allocs/op", n) | |
| 259 | + | if n < 1 { | |
| 260 | + | t.Errorf("get_viewport allocated %v; a child proxy must be created", n) | |
| 261 | + | } | |
| 262 | + | } | |
| 263 | + | ||
| 264 | + | // BenchmarkRequests measures generated numeric requests with small and | |
| 265 | + | // realistic values; both are allocation-free. | |
| 266 | + | func BenchmarkRequests(b *testing.B) { | |
| 267 | + | e := newLoopEnv(b) | |
| 268 | + | b.Run("no_args/wl_surface.commit", func(b *testing.B) { | |
| 269 | + | b.ReportAllocs() | |
| 270 | + | for i := 0; i < b.N; i++ { | |
| 271 | + | if err := e.surface.Commit(); err != nil { | |
| 272 | + | b.Fatal(err) | |
| 273 | + | } | |
| 274 | + | } | |
| 275 | + | }) | |
| 276 | + | b.Run("small_values/wl_surface.set_buffer_scale", func(b *testing.B) { | |
| 277 | + | b.ReportAllocs() | |
| 278 | + | for i := 0; i < b.N; i++ { | |
| 279 | + | if err := e.surface.SetBufferScale(2); err != nil { | |
| 280 | + | b.Fatal(err) | |
| 281 | + | } | |
| 282 | + | } | |
| 283 | + | }) | |
| 284 | + | for _, tc := range e.numericRequests() { | |
| 285 | + | b.Run("realistic_values/"+tc.name, func(b *testing.B) { | |
| 286 | + | b.ReportAllocs() | |
| 287 | + | for i := 0; i < b.N; i++ { | |
| 288 | + | if err := tc.run(); err != nil { | |
| 289 | + | b.Fatal(err) | |
| 290 | + | } | |
| 291 | + | } | |
| 292 | + | }) | |
| 293 | + | } | |
| 294 | + | } | |
| 295 | + | ||
| 296 | + | // BenchmarkEventDispatch measures typed numeric event dispatch through the | |
| 297 | + | // generated Dispatch methods, without socket scheduling. | |
| 298 | + | func BenchmarkEventDispatch(b *testing.B) { | |
| 299 | + | e := newLoopEnv(b) | |
| 300 | + | var sink uint32 | |
| 301 | + | e.scale.OnPreferredScale(func(s uint32) { sink += s }) | |
| 302 | + | e.ptr.OnMotion(func(tm uint32, x, y wlturbo.Fixed) { sink += tm + uint32(x) + uint32(y) }) | |
| 303 | + | for _, tc := range []struct { | |
| 304 | + | name string | |
| 305 | + | frame []byte | |
| 306 | + | }{ | |
| 307 | + | {"wp_fractional_scale_v1.preferred_scale", perfFrame(e.scale.ID(), 0, 180)}, | |
| 308 | + | {"wl_pointer.motion", perfFrame(e.ptr.ID(), 2, 1234567, 300*256, 400*256)}, | |
| 309 | + | } { | |
| 310 | + | b.Run("numeric/"+tc.name, func(b *testing.B) { | |
| 311 | + | e.c.pattern = tc.frame | |
| 312 | + | b.ReportAllocs() | |
| 313 | + | for i := 0; i < b.N; i++ { | |
| 314 | + | if err := e.d.Dispatch(); err != nil { | |
| 315 | + | b.Fatal(err) | |
| 316 | + | } | |
| 317 | + | } | |
| 318 | + | }) | |
| 319 | + | } | |
| 320 | + | _ = sink | |
| 321 | + | } | |
| 322 | + | ||
| 323 | + | // BenchmarkNecessaryAllocations reports operations whose allocations cannot be | |
| 324 | + | // removed by the generator: string copies, object creation and received FDs. | |
| 325 | + | func BenchmarkNecessaryAllocations(b *testing.B) { | |
| 326 | + | b.Run("string_event/wl_output.name", func(b *testing.B) { | |
| 327 | + | e := newLoopEnv(b) | |
| 328 | + | var name string | |
| 329 | + | e.output.OnName(func(s string) { name = s }) | |
| 330 | + | e.c.pattern = perfStringFrame(e.output.ID(), 4, "HDMI-A-1") | |
| 331 | + | b.ReportAllocs() | |
| 332 | + | for i := 0; i < b.N; i++ { | |
| 333 | + | if err := e.d.Dispatch(); err != nil { | |
| 334 | + | b.Fatal(err) | |
| 335 | + | } | |
| 336 | + | } | |
| 337 | + | _ = name | |
| 338 | + | }) | |
| 339 | + | b.Run("new_id/wp_viewporter.get_viewport", func(b *testing.B) { | |
| 340 | + | e := newLoopEnv(b) | |
| 341 | + | b.ReportAllocs() | |
| 342 | + | for i := 0; i < b.N; i++ { | |
| 343 | + | if _, err := e.vpr.GetViewport(e.surface); err != nil { | |
| 344 | + | b.Fatal(err) | |
| 345 | + | } | |
| 346 | + | } | |
| 347 | + | }) | |
| 348 | + | b.Run("received_fd/wl_keyboard.keymap", func(b *testing.B) { | |
| 349 | + | fds, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0) | |
| 350 | + | if err != nil { | |
| 351 | + | b.Fatal(err) | |
| 352 | + | } | |
| 353 | + | fa, fb := os.NewFile(uintptr(fds[0]), "a"), os.NewFile(uintptr(fds[1]), "b") | |
| 354 | + | ca, err := net.FileConn(fa) | |
| 355 | + | fa.Close() | |
| 356 | + | if err != nil { | |
| 357 | + | b.Fatal(err) | |
| 358 | + | } | |
| 359 | + | cb, err := net.FileConn(fb) | |
| 360 | + | fb.Close() | |
| 361 | + | if err != nil { | |
| 362 | + | b.Fatal(err) | |
| 363 | + | } | |
| 364 | + | defer cb.Close() | |
| 365 | + | peer := cb.(*net.UnixConn) | |
| 366 | + | d, err := wlturbo.ConnectFromConn(ca) | |
| 367 | + | if err != nil { | |
| 368 | + | b.Fatal(err) | |
| 369 | + | } | |
| 370 | + | defer d.Close() | |
| 371 | + | kb := wayland.NewKeyboard(d.Context()) | |
| 372 | + | kb.SetID(d.AllocateID()) | |
| 373 | + | d.Context().Register(kb) | |
| 374 | + | kb.OnKeymap(func(format uint32, fd *wlturbo.OwnedFD, size uint32) {}) | |
| 375 | + | // The descriptor sent each iteration; the receiver closes its copy. | |
| 376 | + | null, err := os.Open(os.DevNull) | |
| 377 | + | if err != nil { | |
| 378 | + | b.Fatal(err) | |
| 379 | + | } | |
| 380 | + | defer null.Close() | |
| 381 | + | msg := perfFrame(kb.ID(), 0, 1, 4096) | |
| 382 | + | rights := unix.UnixRights(int(null.Fd())) | |
| 383 | + | b.ReportAllocs() | |
| 384 | + | for i := 0; i < b.N; i++ { | |
| 385 | + | if _, _, err := peer.WriteMsgUnix(msg, rights, nil); err != nil { | |
| 386 | + | b.Fatal(err) | |
| 387 | + | } | |
| 388 | + | if err := d.Dispatch(); err != nil { | |
| 389 | + | b.Fatal(err) | |
| 390 | + | } | |
| 391 | + | } | |
| 392 | + | }) | |
| 393 | + | } | |
A client/pointerconstraints/pointerconstraints_generated.go +369 -0
| @@ -0,0 +1,369 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: pointer_constraints_unstable_v1 | |
| 3 | + | // Source: pointer-constraints-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2014 Jonas Ådahl | |
| 7 | + | // Copyright © 2015 Red Hat Inc. | |
| 8 | + | // | |
| 9 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 10 | + | // copy of this software and associated documentation files (the "Software"), | |
| 11 | + | // to deal in the Software without restriction, including without limitation | |
| 12 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 13 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 14 | + | // Software is furnished to do so, subject to the following conditions: | |
| 15 | + | // | |
| 16 | + | // The above copyright notice and this permission notice (including the next | |
| 17 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 18 | + | // Software. | |
| 19 | + | // | |
| 20 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 21 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 22 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 23 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 24 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 25 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 26 | + | // DEALINGS IN THE SOFTWARE. | |
| 27 | + | ||
| 28 | + | package pointerconstraints | |
| 29 | + | ||
| 30 | + | import ( | |
| 31 | + | "sync" | |
| 32 | + | ||
| 33 | + | cross_wl_pointer "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 34 | + | cross_wl_region "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 35 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 36 | + | "github.com/bnema/wlturbo/wl" | |
| 37 | + | ) | |
| 38 | + | ||
| 39 | + | // ERROR_ALREADY_CONSTRAINED is the error already_constrained value. | |
| 40 | + | const ERROR_ALREADY_CONSTRAINED = 1 | |
| 41 | + | ||
| 42 | + | // LIFETIME_ONESHOT is the lifetime oneshot value. | |
| 43 | + | const LIFETIME_ONESHOT = 1 | |
| 44 | + | ||
| 45 | + | // LIFETIME_PERSISTENT is the lifetime persistent value. | |
| 46 | + | const LIFETIME_PERSISTENT = 2 | |
| 47 | + | ||
| 48 | + | // PointerConstraintsInterface is the protocol interface name. | |
| 49 | + | const PointerConstraintsInterface = "zwp_pointer_constraints_v1" | |
| 50 | + | ||
| 51 | + | // PointerConstraints is the generated binding for zwp_pointer_constraints_v1 version 1. | |
| 52 | + | type PointerConstraints struct { | |
| 53 | + | wl.BaseProxy | |
| 54 | + | } | |
| 55 | + | ||
| 56 | + | // NewPointerConstraints returns an unbound PointerConstraints. | |
| 57 | + | func NewPointerConstraints(ctx *wl.Context) *PointerConstraints { | |
| 58 | + | obj := &PointerConstraints{} | |
| 59 | + | obj.SetContext(ctx) | |
| 60 | + | ctx.Register(obj) | |
| 61 | + | return obj | |
| 62 | + | } | |
| 63 | + | ||
| 64 | + | // Used by the client to notify the server that it will no longer use this pointer constraints object. | |
| 65 | + | func (o *PointerConstraints) Destroy() error { | |
| 66 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_pointer_constraints_v1.destroy", Destructor: true}); err != nil { | |
| 67 | + | return err | |
| 68 | + | } | |
| 69 | + | return nil | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | // The lock_pointer request lets the client request to disable movements of the virtual pointer (i.e. the cursor), effectively locking the pointer to a position. This request may not take effect immediately; in the future, when the compositor deems implementation-specific constraints are satisfied, the pointer lock will be activated and the compositor sends a locked event. The protocol provides no guarantee that the constraints are ever satisfied, and does not require the compositor to send an error if the constraints cannot ever be satisfied. It is thus possible to request a lock that will never activate. There may not be another pointer constraint of any kind requested or active on the surface for any of the wl_pointer objects of the seat of the passed pointer when requesting a lock. If there is, an error will be raised. See general pointer lock documentation for more details. The intersection of the region passed with this request and the input region of the surface is used to determine where the pointer must be in order for the lock to activate. It is up to the compositor whether to warp the pointer or require some kind of user interaction for the lock to activate. If the region is null the surface input region is used. A surface may receive pointer focus without the lock being activated. The request creates a new object wp_locked_pointer which is used to interact with the lock as well as receive updates about its state. See the the description of wp_locked_pointer for further information. Note that while a pointer is locked, the wl_pointer objects of the corresponding seat will not emit any wl_pointer.motion events, but relative motion events will still be emitted via wp_relative_pointer objects of the same seat. wl_pointer.axis and wl_pointer.button events are unaffected. | |
| 73 | + | func (o *PointerConstraints) LockPointer(surface *cross_wl_surface.Surface, pointer *cross_wl_pointer.Pointer, region *cross_wl_region.Region, lifetime uint32) (*LockedPointer, error) { | |
| 74 | + | var arg1 wl.Object | |
| 75 | + | if surface != nil { | |
| 76 | + | arg1 = surface | |
| 77 | + | } | |
| 78 | + | var arg2 wl.Object | |
| 79 | + | if pointer != nil { | |
| 80 | + | arg2 = pointer | |
| 81 | + | } | |
| 82 | + | var arg3 wl.Object | |
| 83 | + | if region != nil { | |
| 84 | + | arg3 = region | |
| 85 | + | } | |
| 86 | + | child := &LockedPointer{} | |
| 87 | + | child.SetContext(o.Context()) | |
| 88 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_pointer_constraints_v1.lock_pointer", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1), wl.ArgObject(arg2), wl.ArgObject(arg3), wl.ArgUint(lifetime)); err != nil { | |
| 89 | + | return nil, err | |
| 90 | + | } | |
| 91 | + | return child, nil | |
| 92 | + | } | |
| 93 | + | ||
| 94 | + | // The confine_pointer request lets the client request to confine the pointer cursor to a given region. This request may not take effect immediately; in the future, when the compositor deems implementation- specific constraints are satisfied, the pointer confinement will be activated and the compositor sends a confined event. The intersection of the region passed with this request and the input region of the surface is used to determine where the pointer must be in order for the confinement to activate. It is up to the compositor whether to warp the pointer or require some kind of user interaction for the confinement to activate. If the region is null the surface input region is used. The request will create a new object wp_confined_pointer which is used to interact with the confinement as well as receive updates about its state. See the the description of wp_confined_pointer for further information. | |
| 95 | + | func (o *PointerConstraints) ConfinePointer(surface *cross_wl_surface.Surface, pointer *cross_wl_pointer.Pointer, region *cross_wl_region.Region, lifetime uint32) (*ConfinedPointer, error) { | |
| 96 | + | var arg1 wl.Object | |
| 97 | + | if surface != nil { | |
| 98 | + | arg1 = surface | |
| 99 | + | } | |
| 100 | + | var arg2 wl.Object | |
| 101 | + | if pointer != nil { | |
| 102 | + | arg2 = pointer | |
| 103 | + | } | |
| 104 | + | var arg3 wl.Object | |
| 105 | + | if region != nil { | |
| 106 | + | arg3 = region | |
| 107 | + | } | |
| 108 | + | child := &ConfinedPointer{} | |
| 109 | + | child.SetContext(o.Context()) | |
| 110 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_pointer_constraints_v1.confine_pointer", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1), wl.ArgObject(arg2), wl.ArgObject(arg3), wl.ArgUint(lifetime)); err != nil { | |
| 111 | + | return nil, err | |
| 112 | + | } | |
| 113 | + | return child, nil | |
| 114 | + | } | |
| 115 | + | ||
| 116 | + | // EventSignature returns the declared event argument types in wire order. | |
| 117 | + | func (o *PointerConstraints) EventSignature(opcode uint16) (string, bool) { | |
| 118 | + | switch opcode { | |
| 119 | + | default: | |
| 120 | + | return "", false | |
| 121 | + | } | |
| 122 | + | } | |
| 123 | + | ||
| 124 | + | // Dispatch decodes one event on zwp_pointer_constraints_v1 and calls the registered handlers. | |
| 125 | + | func (o *PointerConstraints) Dispatch(event *wl.Event) { | |
| 126 | + | switch event.Opcode { | |
| 127 | + | default: | |
| 128 | + | } | |
| 129 | + | } | |
| 130 | + | ||
| 131 | + | // LockedPointerInterface is the protocol interface name. | |
| 132 | + | const LockedPointerInterface = "zwp_locked_pointer_v1" | |
| 133 | + | ||
| 134 | + | // LockedPointer is the generated binding for zwp_locked_pointer_v1 version 1. | |
| 135 | + | type LockedPointer struct { | |
| 136 | + | wl.BaseProxy | |
| 137 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 138 | + | // handlers while another goroutine dispatches events. | |
| 139 | + | handlersMu sync.Mutex | |
| 140 | + | onLocked []func() | |
| 141 | + | onUnlocked []func() | |
| 142 | + | } | |
| 143 | + | ||
| 144 | + | // NewLockedPointer returns an unbound LockedPointer. | |
| 145 | + | func NewLockedPointer(ctx *wl.Context) *LockedPointer { | |
| 146 | + | obj := &LockedPointer{} | |
| 147 | + | obj.SetContext(ctx) | |
| 148 | + | ctx.Register(obj) | |
| 149 | + | return obj | |
| 150 | + | } | |
| 151 | + | ||
| 152 | + | // Destroy the locked pointer object. If applicable, the compositor will unlock the pointer. | |
| 153 | + | func (o *LockedPointer) Destroy() error { | |
| 154 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_locked_pointer_v1.destroy", Destructor: true}); err != nil { | |
| 155 | + | return err | |
| 156 | + | } | |
| 157 | + | return nil | |
| 158 | + | } | |
| 159 | + | ||
| 160 | + | // Set the cursor position hint relative to the top left corner of the surface. If the client is drawing its own cursor, it should update the position hint to the position of its own cursor. A compositor may use this information to warp the pointer upon unlock in order to avoid pointer jumps. The cursor position hint is double-buffered state, see wl_surface.commit. | |
| 161 | + | func (o *LockedPointer) SetCursorPositionHint(surfaceX wl.Fixed, surfaceY wl.Fixed) error { | |
| 162 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_locked_pointer_v1.set_cursor_position_hint"}, wl.ArgFixed(surfaceX), wl.ArgFixed(surfaceY)); err != nil { | |
| 163 | + | return err | |
| 164 | + | } | |
| 165 | + | return nil | |
| 166 | + | } | |
| 167 | + | ||
| 168 | + | // Set a new region used to lock the pointer. The new lock region is double-buffered, see wl_surface.commit. For details about the lock region, see wp_locked_pointer. | |
| 169 | + | func (o *LockedPointer) SetRegion(region *cross_wl_region.Region) error { | |
| 170 | + | var arg0 wl.Object | |
| 171 | + | if region != nil { | |
| 172 | + | arg0 = region | |
| 173 | + | } | |
| 174 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_locked_pointer_v1.set_region"}, wl.ArgObject(arg0)); err != nil { | |
| 175 | + | return err | |
| 176 | + | } | |
| 177 | + | return nil | |
| 178 | + | } | |
| 179 | + | ||
| 180 | + | // OnLocked registers a handler for the locked event. | |
| 181 | + | // | |
| 182 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 183 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 184 | + | func (o *LockedPointer) OnLocked(handler func()) { | |
| 185 | + | if handler == nil { | |
| 186 | + | return | |
| 187 | + | } | |
| 188 | + | o.handlersMu.Lock() | |
| 189 | + | defer o.handlersMu.Unlock() | |
| 190 | + | o.onLocked = append(o.onLocked, handler) | |
| 191 | + | } | |
| 192 | + | ||
| 193 | + | // handlersForLocked returns the handlers registered for locked, taken | |
| 194 | + | // under the lock so a handler may register another handler while events are | |
| 195 | + | // being dispatched. | |
| 196 | + | func (o *LockedPointer) handlersForLocked() []func() { | |
| 197 | + | o.handlersMu.Lock() | |
| 198 | + | defer o.handlersMu.Unlock() | |
| 199 | + | return o.onLocked | |
| 200 | + | } | |
| 201 | + | ||
| 202 | + | // OnUnlocked registers a handler for the unlocked event. | |
| 203 | + | // | |
| 204 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 205 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 206 | + | func (o *LockedPointer) OnUnlocked(handler func()) { | |
| 207 | + | if handler == nil { | |
| 208 | + | return | |
| 209 | + | } | |
| 210 | + | o.handlersMu.Lock() | |
| 211 | + | defer o.handlersMu.Unlock() | |
| 212 | + | o.onUnlocked = append(o.onUnlocked, handler) | |
| 213 | + | } | |
| 214 | + | ||
| 215 | + | // handlersForUnlocked returns the handlers registered for unlocked, taken | |
| 216 | + | // under the lock so a handler may register another handler while events are | |
| 217 | + | // being dispatched. | |
| 218 | + | func (o *LockedPointer) handlersForUnlocked() []func() { | |
| 219 | + | o.handlersMu.Lock() | |
| 220 | + | defer o.handlersMu.Unlock() | |
| 221 | + | return o.onUnlocked | |
| 222 | + | } | |
| 223 | + | ||
| 224 | + | // EventSignature returns the declared event argument types in wire order. | |
| 225 | + | func (o *LockedPointer) EventSignature(opcode uint16) (string, bool) { | |
| 226 | + | switch opcode { | |
| 227 | + | case 0: | |
| 228 | + | return "", true | |
| 229 | + | case 1: | |
| 230 | + | return "", true | |
| 231 | + | default: | |
| 232 | + | return "", false | |
| 233 | + | } | |
| 234 | + | } | |
| 235 | + | ||
| 236 | + | // Dispatch decodes one event on zwp_locked_pointer_v1 and calls the registered handlers. | |
| 237 | + | func (o *LockedPointer) Dispatch(event *wl.Event) { | |
| 238 | + | switch event.Opcode { | |
| 239 | + | case 0: // locked | |
| 240 | + | ||
| 241 | + | for i, handler := range o.handlersForLocked() { | |
| 242 | + | _ = i | |
| 243 | + | handler() | |
| 244 | + | } | |
| 245 | + | case 1: // unlocked | |
| 246 | + | ||
| 247 | + | for i, handler := range o.handlersForUnlocked() { | |
| 248 | + | _ = i | |
| 249 | + | handler() | |
| 250 | + | } | |
| 251 | + | default: | |
| 252 | + | } | |
| 253 | + | } | |
| 254 | + | ||
| 255 | + | // ConfinedPointerInterface is the protocol interface name. | |
| 256 | + | const ConfinedPointerInterface = "zwp_confined_pointer_v1" | |
| 257 | + | ||
| 258 | + | // ConfinedPointer is the generated binding for zwp_confined_pointer_v1 version 1. | |
| 259 | + | type ConfinedPointer struct { | |
| 260 | + | wl.BaseProxy | |
| 261 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 262 | + | // handlers while another goroutine dispatches events. | |
| 263 | + | handlersMu sync.Mutex | |
| 264 | + | onConfined []func() | |
| 265 | + | onUnconfined []func() | |
| 266 | + | } | |
| 267 | + | ||
| 268 | + | // NewConfinedPointer returns an unbound ConfinedPointer. | |
| 269 | + | func NewConfinedPointer(ctx *wl.Context) *ConfinedPointer { | |
| 270 | + | obj := &ConfinedPointer{} | |
| 271 | + | obj.SetContext(ctx) | |
| 272 | + | ctx.Register(obj) | |
| 273 | + | return obj | |
| 274 | + | } | |
| 275 | + | ||
| 276 | + | // Destroy the confined pointer object. If applicable, the compositor will unconfine the pointer. | |
| 277 | + | func (o *ConfinedPointer) Destroy() error { | |
| 278 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_confined_pointer_v1.destroy", Destructor: true}); err != nil { | |
| 279 | + | return err | |
| 280 | + | } | |
| 281 | + | return nil | |
| 282 | + | } | |
| 283 | + | ||
| 284 | + | // Set a new region used to confine the pointer. The new confine region is double-buffered, see wl_surface.commit. If the confinement is active when the new confinement region is applied and the pointer ends up outside of newly applied region, the pointer may warped to a position within the new confinement region. If warped, a wl_pointer.motion event will be emitted, but no wp_relative_pointer.relative_motion event. The compositor may also, instead of using the new region, unconfine the pointer. For details about the confine region, see wp_confined_pointer. | |
| 285 | + | func (o *ConfinedPointer) SetRegion(region *cross_wl_region.Region) error { | |
| 286 | + | var arg0 wl.Object | |
| 287 | + | if region != nil { | |
| 288 | + | arg0 = region | |
| 289 | + | } | |
| 290 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_confined_pointer_v1.set_region"}, wl.ArgObject(arg0)); err != nil { | |
| 291 | + | return err | |
| 292 | + | } | |
| 293 | + | return nil | |
| 294 | + | } | |
| 295 | + | ||
| 296 | + | // OnConfined registers a handler for the confined event. | |
| 297 | + | // | |
| 298 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 299 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 300 | + | func (o *ConfinedPointer) OnConfined(handler func()) { | |
| 301 | + | if handler == nil { | |
| 302 | + | return | |
| 303 | + | } | |
| 304 | + | o.handlersMu.Lock() | |
| 305 | + | defer o.handlersMu.Unlock() | |
| 306 | + | o.onConfined = append(o.onConfined, handler) | |
| 307 | + | } | |
| 308 | + | ||
| 309 | + | // handlersForConfined returns the handlers registered for confined, taken | |
| 310 | + | // under the lock so a handler may register another handler while events are | |
| 311 | + | // being dispatched. | |
| 312 | + | func (o *ConfinedPointer) handlersForConfined() []func() { | |
| 313 | + | o.handlersMu.Lock() | |
| 314 | + | defer o.handlersMu.Unlock() | |
| 315 | + | return o.onConfined | |
| 316 | + | } | |
| 317 | + | ||
| 318 | + | // OnUnconfined registers a handler for the unconfined event. | |
| 319 | + | // | |
| 320 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 321 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 322 | + | func (o *ConfinedPointer) OnUnconfined(handler func()) { | |
| 323 | + | if handler == nil { | |
| 324 | + | return | |
| 325 | + | } | |
| 326 | + | o.handlersMu.Lock() | |
| 327 | + | defer o.handlersMu.Unlock() | |
| 328 | + | o.onUnconfined = append(o.onUnconfined, handler) | |
| 329 | + | } | |
| 330 | + | ||
| 331 | + | // handlersForUnconfined returns the handlers registered for unconfined, taken | |
| 332 | + | // under the lock so a handler may register another handler while events are | |
| 333 | + | // being dispatched. | |
| 334 | + | func (o *ConfinedPointer) handlersForUnconfined() []func() { | |
| 335 | + | o.handlersMu.Lock() | |
| 336 | + | defer o.handlersMu.Unlock() | |
| 337 | + | return o.onUnconfined | |
| 338 | + | } | |
| 339 | + | ||
| 340 | + | // EventSignature returns the declared event argument types in wire order. | |
| 341 | + | func (o *ConfinedPointer) EventSignature(opcode uint16) (string, bool) { | |
| 342 | + | switch opcode { | |
| 343 | + | case 0: | |
| 344 | + | return "", true | |
| 345 | + | case 1: | |
| 346 | + | return "", true | |
| 347 | + | default: | |
| 348 | + | return "", false | |
| 349 | + | } | |
| 350 | + | } | |
| 351 | + | ||
| 352 | + | // Dispatch decodes one event on zwp_confined_pointer_v1 and calls the registered handlers. | |
| 353 | + | func (o *ConfinedPointer) Dispatch(event *wl.Event) { | |
| 354 | + | switch event.Opcode { | |
| 355 | + | case 0: // confined | |
| 356 | + | ||
| 357 | + | for i, handler := range o.handlersForConfined() { | |
| 358 | + | _ = i | |
| 359 | + | handler() | |
| 360 | + | } | |
| 361 | + | case 1: // unconfined | |
| 362 | + | ||
| 363 | + | for i, handler := range o.handlersForUnconfined() { | |
| 364 | + | _ = i | |
| 365 | + | handler() | |
| 366 | + | } | |
| 367 | + | default: | |
| 368 | + | } | |
| 369 | + | } | |
A client/pointergestures/pointergestures_generated.go +520 -0
| @@ -0,0 +1,520 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: pointer_gestures_unstable_v1 | |
| 3 | + | // Source: pointer-gestures-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2015, 2021 Red Hat Inc. | |
| 7 | + | // | |
| 8 | + | // Permission to use, copy, modify, distribute, and sell this | |
| 9 | + | // software and its documentation for any purpose is hereby granted | |
| 10 | + | // without fee, provided that the above copyright notice appear in | |
| 11 | + | // all copies and that both that copyright notice and this permission | |
| 12 | + | // notice appear in supporting documentation, and that the name of | |
| 13 | + | // the copyright holders not be used in advertising or publicity | |
| 14 | + | // pertaining to distribution of the software without specific, | |
| 15 | + | // written prior permission. The copyright holders make no | |
| 16 | + | // representations about the suitability of this software for any | |
| 17 | + | // purpose. It is provided "as is" without express or implied | |
| 18 | + | // warranty. | |
| 19 | + | // | |
| 20 | + | // THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
| 21 | + | // SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| 22 | + | // FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| 23 | + | // SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 24 | + | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
| 25 | + | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
| 26 | + | // ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| 27 | + | // THIS SOFTWARE. | |
| 28 | + | ||
| 29 | + | package pointergestures | |
| 30 | + | ||
| 31 | + | import ( | |
| 32 | + | "sync" | |
| 33 | + | ||
| 34 | + | cross_wl_pointer "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 35 | + | "github.com/bnema/wlturbo/wl" | |
| 36 | + | ) | |
| 37 | + | ||
| 38 | + | // PointerGesturesInterface is the protocol interface name. | |
| 39 | + | const PointerGesturesInterface = "zwp_pointer_gestures_v1" | |
| 40 | + | ||
| 41 | + | // PointerGestures is the generated binding for zwp_pointer_gestures_v1 version 3. | |
| 42 | + | type PointerGestures struct { | |
| 43 | + | wl.BaseProxy | |
| 44 | + | } | |
| 45 | + | ||
| 46 | + | // NewPointerGestures returns an unbound PointerGestures. | |
| 47 | + | func NewPointerGestures(ctx *wl.Context) *PointerGestures { | |
| 48 | + | obj := &PointerGestures{} | |
| 49 | + | obj.SetContext(ctx) | |
| 50 | + | ctx.Register(obj) | |
| 51 | + | return obj | |
| 52 | + | } | |
| 53 | + | ||
| 54 | + | // Create a swipe gesture object. See the wl_pointer_gesture_swipe interface for details. | |
| 55 | + | func (o *PointerGestures) GetSwipeGesture(pointer *cross_wl_pointer.Pointer) (*PointerGestureSwipe, error) { | |
| 56 | + | var arg1 wl.Object | |
| 57 | + | if pointer != nil { | |
| 58 | + | arg1 = pointer | |
| 59 | + | } | |
| 60 | + | child := &PointerGestureSwipe{} | |
| 61 | + | child.SetContext(o.Context()) | |
| 62 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_pointer_gestures_v1.get_swipe_gesture", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 63 | + | return nil, err | |
| 64 | + | } | |
| 65 | + | return child, nil | |
| 66 | + | } | |
| 67 | + | ||
| 68 | + | // Create a pinch gesture object. See the wl_pointer_gesture_pinch interface for details. | |
| 69 | + | func (o *PointerGestures) GetPinchGesture(pointer *cross_wl_pointer.Pointer) (*PointerGesturePinch, error) { | |
| 70 | + | var arg1 wl.Object | |
| 71 | + | if pointer != nil { | |
| 72 | + | arg1 = pointer | |
| 73 | + | } | |
| 74 | + | child := &PointerGesturePinch{} | |
| 75 | + | child.SetContext(o.Context()) | |
| 76 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_pointer_gestures_v1.get_pinch_gesture", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 77 | + | return nil, err | |
| 78 | + | } | |
| 79 | + | return child, nil | |
| 80 | + | } | |
| 81 | + | ||
| 82 | + | // Destroy the pointer gesture object. Swipe, pinch and hold objects created via this gesture object remain valid. | |
| 83 | + | func (o *PointerGestures) Release() error { | |
| 84 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_pointer_gestures_v1.release", Since: 2, Destructor: true}); err != nil { | |
| 85 | + | return err | |
| 86 | + | } | |
| 87 | + | return nil | |
| 88 | + | } | |
| 89 | + | ||
| 90 | + | // Create a hold gesture object. See the wl_pointer_gesture_hold interface for details. | |
| 91 | + | func (o *PointerGestures) GetHoldGesture(pointer *cross_wl_pointer.Pointer) (*PointerGestureHold, error) { | |
| 92 | + | var arg1 wl.Object | |
| 93 | + | if pointer != nil { | |
| 94 | + | arg1 = pointer | |
| 95 | + | } | |
| 96 | + | child := &PointerGestureHold{} | |
| 97 | + | child.SetContext(o.Context()) | |
| 98 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "zwp_pointer_gestures_v1.get_hold_gesture", Since: 3, Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 99 | + | return nil, err | |
| 100 | + | } | |
| 101 | + | return child, nil | |
| 102 | + | } | |
| 103 | + | ||
| 104 | + | // EventSignature returns the declared event argument types in wire order. | |
| 105 | + | func (o *PointerGestures) EventSignature(opcode uint16) (string, bool) { | |
| 106 | + | switch opcode { | |
| 107 | + | default: | |
| 108 | + | return "", false | |
| 109 | + | } | |
| 110 | + | } | |
| 111 | + | ||
| 112 | + | // Dispatch decodes one event on zwp_pointer_gestures_v1 and calls the registered handlers. | |
| 113 | + | func (o *PointerGestures) Dispatch(event *wl.Event) { | |
| 114 | + | switch event.Opcode { | |
| 115 | + | default: | |
| 116 | + | } | |
| 117 | + | } | |
| 118 | + | ||
| 119 | + | // PointerGestureSwipeInterface is the protocol interface name. | |
| 120 | + | const PointerGestureSwipeInterface = "zwp_pointer_gesture_swipe_v1" | |
| 121 | + | ||
| 122 | + | // PointerGestureSwipe is the generated binding for zwp_pointer_gesture_swipe_v1 version 3. | |
| 123 | + | type PointerGestureSwipe struct { | |
| 124 | + | wl.BaseProxy | |
| 125 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 126 | + | // handlers while another goroutine dispatches events. | |
| 127 | + | handlersMu sync.Mutex | |
| 128 | + | onBegin []func(serial uint32, time uint32, surfaceID uint32, fingers uint32) | |
| 129 | + | onUpdate []func(time uint32, dx wl.Fixed, dy wl.Fixed) | |
| 130 | + | onEnd []func(serial uint32, time uint32, cancelled int32) | |
| 131 | + | } | |
| 132 | + | ||
| 133 | + | // NewPointerGestureSwipe returns an unbound PointerGestureSwipe. | |
| 134 | + | func NewPointerGestureSwipe(ctx *wl.Context) *PointerGestureSwipe { | |
| 135 | + | obj := &PointerGestureSwipe{} | |
| 136 | + | obj.SetContext(ctx) | |
| 137 | + | ctx.Register(obj) | |
| 138 | + | return obj | |
| 139 | + | } | |
| 140 | + | ||
| 141 | + | // destroy the pointer swipe gesture object | |
| 142 | + | func (o *PointerGestureSwipe) Destroy() error { | |
| 143 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_pointer_gesture_swipe_v1.destroy", Destructor: true}); err != nil { | |
| 144 | + | return err | |
| 145 | + | } | |
| 146 | + | return nil | |
| 147 | + | } | |
| 148 | + | ||
| 149 | + | // OnBegin registers a handler for the begin event. | |
| 150 | + | // | |
| 151 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 152 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 153 | + | func (o *PointerGestureSwipe) OnBegin(handler func(serial uint32, time uint32, surfaceID uint32, fingers uint32)) { | |
| 154 | + | if handler == nil { | |
| 155 | + | return | |
| 156 | + | } | |
| 157 | + | o.handlersMu.Lock() | |
| 158 | + | defer o.handlersMu.Unlock() | |
| 159 | + | o.onBegin = append(o.onBegin, handler) | |
| 160 | + | } | |
| 161 | + | ||
| 162 | + | // handlersForBegin returns the handlers registered for begin, taken | |
| 163 | + | // under the lock so a handler may register another handler while events are | |
| 164 | + | // being dispatched. | |
| 165 | + | func (o *PointerGestureSwipe) handlersForBegin() []func(serial uint32, time uint32, surfaceID uint32, fingers uint32) { | |
| 166 | + | o.handlersMu.Lock() | |
| 167 | + | defer o.handlersMu.Unlock() | |
| 168 | + | return o.onBegin | |
| 169 | + | } | |
| 170 | + | ||
| 171 | + | // OnUpdate registers a handler for the update event. | |
| 172 | + | // | |
| 173 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 174 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 175 | + | func (o *PointerGestureSwipe) OnUpdate(handler func(time uint32, dx wl.Fixed, dy wl.Fixed)) { | |
| 176 | + | if handler == nil { | |
| 177 | + | return | |
| 178 | + | } | |
| 179 | + | o.handlersMu.Lock() | |
| 180 | + | defer o.handlersMu.Unlock() | |
| 181 | + | o.onUpdate = append(o.onUpdate, handler) | |
| 182 | + | } | |
| 183 | + | ||
| 184 | + | // handlersForUpdate returns the handlers registered for update, taken | |
| 185 | + | // under the lock so a handler may register another handler while events are | |
| 186 | + | // being dispatched. | |
| 187 | + | func (o *PointerGestureSwipe) handlersForUpdate() []func(time uint32, dx wl.Fixed, dy wl.Fixed) { | |
| 188 | + | o.handlersMu.Lock() | |
| 189 | + | defer o.handlersMu.Unlock() | |
| 190 | + | return o.onUpdate | |
| 191 | + | } | |
| 192 | + | ||
| 193 | + | // OnEnd registers a handler for the end event. | |
| 194 | + | // | |
| 195 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 196 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 197 | + | func (o *PointerGestureSwipe) OnEnd(handler func(serial uint32, time uint32, cancelled int32)) { | |
| 198 | + | if handler == nil { | |
| 199 | + | return | |
| 200 | + | } | |
| 201 | + | o.handlersMu.Lock() | |
| 202 | + | defer o.handlersMu.Unlock() | |
| 203 | + | o.onEnd = append(o.onEnd, handler) | |
| 204 | + | } | |
| 205 | + | ||
| 206 | + | // handlersForEnd returns the handlers registered for end, taken | |
| 207 | + | // under the lock so a handler may register another handler while events are | |
| 208 | + | // being dispatched. | |
| 209 | + | func (o *PointerGestureSwipe) handlersForEnd() []func(serial uint32, time uint32, cancelled int32) { | |
| 210 | + | o.handlersMu.Lock() | |
| 211 | + | defer o.handlersMu.Unlock() | |
| 212 | + | return o.onEnd | |
| 213 | + | } | |
| 214 | + | ||
| 215 | + | // EventSignature returns the declared event argument types in wire order. | |
| 216 | + | func (o *PointerGestureSwipe) EventSignature(opcode uint16) (string, bool) { | |
| 217 | + | switch opcode { | |
| 218 | + | case 0: | |
| 219 | + | return "uint,uint,object,uint,", true | |
| 220 | + | case 1: | |
| 221 | + | return "uint,fixed,fixed,", true | |
| 222 | + | case 2: | |
| 223 | + | return "uint,uint,int,", true | |
| 224 | + | default: | |
| 225 | + | return "", false | |
| 226 | + | } | |
| 227 | + | } | |
| 228 | + | ||
| 229 | + | // Dispatch decodes one event on zwp_pointer_gesture_swipe_v1 and calls the registered handlers. | |
| 230 | + | func (o *PointerGestureSwipe) Dispatch(event *wl.Event) { | |
| 231 | + | switch event.Opcode { | |
| 232 | + | case 0: // begin | |
| 233 | + | serial := event.Uint32() | |
| 234 | + | time := event.Uint32() | |
| 235 | + | surfaceID := event.Uint32() | |
| 236 | + | fingers := event.Uint32() | |
| 237 | + | ||
| 238 | + | for i, handler := range o.handlersForBegin() { | |
| 239 | + | _ = i | |
| 240 | + | handler(serial, time, surfaceID, fingers) | |
| 241 | + | } | |
| 242 | + | case 1: // update | |
| 243 | + | time := event.Uint32() | |
| 244 | + | dx := event.Fixed() | |
| 245 | + | dy := event.Fixed() | |
| 246 | + | ||
| 247 | + | for i, handler := range o.handlersForUpdate() { | |
| 248 | + | _ = i | |
| 249 | + | handler(time, dx, dy) | |
| 250 | + | } | |
| 251 | + | case 2: // end | |
| 252 | + | serial := event.Uint32() | |
| 253 | + | time := event.Uint32() | |
| 254 | + | cancelled := event.Int32() | |
| 255 | + | ||
| 256 | + | for i, handler := range o.handlersForEnd() { | |
| 257 | + | _ = i | |
| 258 | + | handler(serial, time, cancelled) | |
| 259 | + | } | |
| 260 | + | default: | |
| 261 | + | } | |
| 262 | + | } | |
| 263 | + | ||
| 264 | + | // PointerGesturePinchInterface is the protocol interface name. | |
| 265 | + | const PointerGesturePinchInterface = "zwp_pointer_gesture_pinch_v1" | |
| 266 | + | ||
| 267 | + | // PointerGesturePinch is the generated binding for zwp_pointer_gesture_pinch_v1 version 3. | |
| 268 | + | type PointerGesturePinch struct { | |
| 269 | + | wl.BaseProxy | |
| 270 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 271 | + | // handlers while another goroutine dispatches events. | |
| 272 | + | handlersMu sync.Mutex | |
| 273 | + | onBegin []func(serial uint32, time uint32, surfaceID uint32, fingers uint32) | |
| 274 | + | onUpdate []func(time uint32, dx wl.Fixed, dy wl.Fixed, scale wl.Fixed, rotation wl.Fixed) | |
| 275 | + | onEnd []func(serial uint32, time uint32, cancelled int32) | |
| 276 | + | } | |
| 277 | + | ||
| 278 | + | // NewPointerGesturePinch returns an unbound PointerGesturePinch. | |
| 279 | + | func NewPointerGesturePinch(ctx *wl.Context) *PointerGesturePinch { | |
| 280 | + | obj := &PointerGesturePinch{} | |
| 281 | + | obj.SetContext(ctx) | |
| 282 | + | ctx.Register(obj) | |
| 283 | + | return obj | |
| 284 | + | } | |
| 285 | + | ||
| 286 | + | // destroy the pinch gesture object | |
| 287 | + | func (o *PointerGesturePinch) Destroy() error { | |
| 288 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_pointer_gesture_pinch_v1.destroy", Destructor: true}); err != nil { | |
| 289 | + | return err | |
| 290 | + | } | |
| 291 | + | return nil | |
| 292 | + | } | |
| 293 | + | ||
| 294 | + | // OnBegin registers a handler for the begin event. | |
| 295 | + | // | |
| 296 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 297 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 298 | + | func (o *PointerGesturePinch) OnBegin(handler func(serial uint32, time uint32, surfaceID uint32, fingers uint32)) { | |
| 299 | + | if handler == nil { | |
| 300 | + | return | |
| 301 | + | } | |
| 302 | + | o.handlersMu.Lock() | |
| 303 | + | defer o.handlersMu.Unlock() | |
| 304 | + | o.onBegin = append(o.onBegin, handler) | |
| 305 | + | } | |
| 306 | + | ||
| 307 | + | // handlersForBegin returns the handlers registered for begin, taken | |
| 308 | + | // under the lock so a handler may register another handler while events are | |
| 309 | + | // being dispatched. | |
| 310 | + | func (o *PointerGesturePinch) handlersForBegin() []func(serial uint32, time uint32, surfaceID uint32, fingers uint32) { | |
| 311 | + | o.handlersMu.Lock() | |
| 312 | + | defer o.handlersMu.Unlock() | |
| 313 | + | return o.onBegin | |
| 314 | + | } | |
| 315 | + | ||
| 316 | + | // OnUpdate registers a handler for the update event. | |
| 317 | + | // | |
| 318 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 319 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 320 | + | func (o *PointerGesturePinch) OnUpdate(handler func(time uint32, dx wl.Fixed, dy wl.Fixed, scale wl.Fixed, rotation wl.Fixed)) { | |
| 321 | + | if handler == nil { | |
| 322 | + | return | |
| 323 | + | } | |
| 324 | + | o.handlersMu.Lock() | |
| 325 | + | defer o.handlersMu.Unlock() | |
| 326 | + | o.onUpdate = append(o.onUpdate, handler) | |
| 327 | + | } | |
| 328 | + | ||
| 329 | + | // handlersForUpdate returns the handlers registered for update, taken | |
| 330 | + | // under the lock so a handler may register another handler while events are | |
| 331 | + | // being dispatched. | |
| 332 | + | func (o *PointerGesturePinch) handlersForUpdate() []func(time uint32, dx wl.Fixed, dy wl.Fixed, scale wl.Fixed, rotation wl.Fixed) { | |
| 333 | + | o.handlersMu.Lock() | |
| 334 | + | defer o.handlersMu.Unlock() | |
| 335 | + | return o.onUpdate | |
| 336 | + | } | |
| 337 | + | ||
| 338 | + | // OnEnd registers a handler for the end event. | |
| 339 | + | // | |
| 340 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 341 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 342 | + | func (o *PointerGesturePinch) OnEnd(handler func(serial uint32, time uint32, cancelled int32)) { | |
| 343 | + | if handler == nil { | |
| 344 | + | return | |
| 345 | + | } | |
| 346 | + | o.handlersMu.Lock() | |
| 347 | + | defer o.handlersMu.Unlock() | |
| 348 | + | o.onEnd = append(o.onEnd, handler) | |
| 349 | + | } | |
| 350 | + | ||
| 351 | + | // handlersForEnd returns the handlers registered for end, taken | |
| 352 | + | // under the lock so a handler may register another handler while events are | |
| 353 | + | // being dispatched. | |
| 354 | + | func (o *PointerGesturePinch) handlersForEnd() []func(serial uint32, time uint32, cancelled int32) { | |
| 355 | + | o.handlersMu.Lock() | |
| 356 | + | defer o.handlersMu.Unlock() | |
| 357 | + | return o.onEnd | |
| 358 | + | } | |
| 359 | + | ||
| 360 | + | // EventSignature returns the declared event argument types in wire order. | |
| 361 | + | func (o *PointerGesturePinch) EventSignature(opcode uint16) (string, bool) { | |
| 362 | + | switch opcode { | |
| 363 | + | case 0: | |
| 364 | + | return "uint,uint,object,uint,", true | |
| 365 | + | case 1: | |
| 366 | + | return "uint,fixed,fixed,fixed,fixed,", true | |
| 367 | + | case 2: | |
| 368 | + | return "uint,uint,int,", true | |
| 369 | + | default: | |
| 370 | + | return "", false | |
| 371 | + | } | |
| 372 | + | } | |
| 373 | + | ||
| 374 | + | // Dispatch decodes one event on zwp_pointer_gesture_pinch_v1 and calls the registered handlers. | |
| 375 | + | func (o *PointerGesturePinch) Dispatch(event *wl.Event) { | |
| 376 | + | switch event.Opcode { | |
| 377 | + | case 0: // begin | |
| 378 | + | serial := event.Uint32() | |
| 379 | + | time := event.Uint32() | |
| 380 | + | surfaceID := event.Uint32() | |
| 381 | + | fingers := event.Uint32() | |
| 382 | + | ||
| 383 | + | for i, handler := range o.handlersForBegin() { | |
| 384 | + | _ = i | |
| 385 | + | handler(serial, time, surfaceID, fingers) | |
| 386 | + | } | |
| 387 | + | case 1: // update | |
| 388 | + | time := event.Uint32() | |
| 389 | + | dx := event.Fixed() | |
| 390 | + | dy := event.Fixed() | |
| 391 | + | scale := event.Fixed() | |
| 392 | + | rotation := event.Fixed() | |
| 393 | + | ||
| 394 | + | for i, handler := range o.handlersForUpdate() { | |
| 395 | + | _ = i | |
| 396 | + | handler(time, dx, dy, scale, rotation) | |
| 397 | + | } | |
| 398 | + | case 2: // end | |
| 399 | + | serial := event.Uint32() | |
| 400 | + | time := event.Uint32() | |
| 401 | + | cancelled := event.Int32() | |
| 402 | + | ||
| 403 | + | for i, handler := range o.handlersForEnd() { | |
| 404 | + | _ = i | |
| 405 | + | handler(serial, time, cancelled) | |
| 406 | + | } | |
| 407 | + | default: | |
| 408 | + | } | |
| 409 | + | } | |
| 410 | + | ||
| 411 | + | // PointerGestureHoldInterface is the protocol interface name. | |
| 412 | + | const PointerGestureHoldInterface = "zwp_pointer_gesture_hold_v1" | |
| 413 | + | ||
| 414 | + | // PointerGestureHold is the generated binding for zwp_pointer_gesture_hold_v1 version 3. | |
| 415 | + | type PointerGestureHold struct { | |
| 416 | + | wl.BaseProxy | |
| 417 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 418 | + | // handlers while another goroutine dispatches events. | |
| 419 | + | handlersMu sync.Mutex | |
| 420 | + | onBegin []func(serial uint32, time uint32, surfaceID uint32, fingers uint32) | |
| 421 | + | onEnd []func(serial uint32, time uint32, cancelled int32) | |
| 422 | + | } | |
| 423 | + | ||
| 424 | + | // NewPointerGestureHold returns an unbound PointerGestureHold. | |
| 425 | + | func NewPointerGestureHold(ctx *wl.Context) *PointerGestureHold { | |
| 426 | + | obj := &PointerGestureHold{} | |
| 427 | + | obj.SetContext(ctx) | |
| 428 | + | ctx.Register(obj) | |
| 429 | + | return obj | |
| 430 | + | } | |
| 431 | + | ||
| 432 | + | // destroy the hold gesture object | |
| 433 | + | func (o *PointerGestureHold) Destroy() error { | |
| 434 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_pointer_gesture_hold_v1.destroy", Since: 3, Destructor: true}); err != nil { | |
| 435 | + | return err | |
| 436 | + | } | |
| 437 | + | return nil | |
| 438 | + | } | |
| 439 | + | ||
| 440 | + | // OnBegin registers a handler for the begin event. | |
| 441 | + | // | |
| 442 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 443 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 444 | + | func (o *PointerGestureHold) OnBegin(handler func(serial uint32, time uint32, surfaceID uint32, fingers uint32)) { | |
| 445 | + | if handler == nil { | |
| 446 | + | return | |
| 447 | + | } | |
| 448 | + | o.handlersMu.Lock() | |
| 449 | + | defer o.handlersMu.Unlock() | |
| 450 | + | o.onBegin = append(o.onBegin, handler) | |
| 451 | + | } | |
| 452 | + | ||
| 453 | + | // handlersForBegin returns the handlers registered for begin, taken | |
| 454 | + | // under the lock so a handler may register another handler while events are | |
| 455 | + | // being dispatched. | |
| 456 | + | func (o *PointerGestureHold) handlersForBegin() []func(serial uint32, time uint32, surfaceID uint32, fingers uint32) { | |
| 457 | + | o.handlersMu.Lock() | |
| 458 | + | defer o.handlersMu.Unlock() | |
| 459 | + | return o.onBegin | |
| 460 | + | } | |
| 461 | + | ||
| 462 | + | // OnEnd registers a handler for the end event. | |
| 463 | + | // | |
| 464 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 465 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 466 | + | func (o *PointerGestureHold) OnEnd(handler func(serial uint32, time uint32, cancelled int32)) { | |
| 467 | + | if handler == nil { | |
| 468 | + | return | |
| 469 | + | } | |
| 470 | + | o.handlersMu.Lock() | |
| 471 | + | defer o.handlersMu.Unlock() | |
| 472 | + | o.onEnd = append(o.onEnd, handler) | |
| 473 | + | } | |
| 474 | + | ||
| 475 | + | // handlersForEnd returns the handlers registered for end, taken | |
| 476 | + | // under the lock so a handler may register another handler while events are | |
| 477 | + | // being dispatched. | |
| 478 | + | func (o *PointerGestureHold) handlersForEnd() []func(serial uint32, time uint32, cancelled int32) { | |
| 479 | + | o.handlersMu.Lock() | |
| 480 | + | defer o.handlersMu.Unlock() | |
| 481 | + | return o.onEnd | |
| 482 | + | } | |
| 483 | + | ||
| 484 | + | // EventSignature returns the declared event argument types in wire order. | |
| 485 | + | func (o *PointerGestureHold) EventSignature(opcode uint16) (string, bool) { | |
| 486 | + | switch opcode { | |
| 487 | + | case 0: | |
| 488 | + | return "uint,uint,object,uint,", true | |
| 489 | + | case 1: | |
| 490 | + | return "uint,uint,int,", true | |
| 491 | + | default: | |
| 492 | + | return "", false | |
| 493 | + | } | |
| 494 | + | } | |
| 495 | + | ||
| 496 | + | // Dispatch decodes one event on zwp_pointer_gesture_hold_v1 and calls the registered handlers. | |
| 497 | + | func (o *PointerGestureHold) Dispatch(event *wl.Event) { | |
| 498 | + | switch event.Opcode { | |
| 499 | + | case 0: // begin | |
| 500 | + | serial := event.Uint32() | |
| 501 | + | time := event.Uint32() | |
| 502 | + | surfaceID := event.Uint32() | |
| 503 | + | fingers := event.Uint32() | |
| 504 | + | ||
| 505 | + | for i, handler := range o.handlersForBegin() { | |
| 506 | + | _ = i | |
| 507 | + | handler(serial, time, surfaceID, fingers) | |
| 508 | + | } | |
| 509 | + | case 1: // end | |
| 510 | + | serial := event.Uint32() | |
| 511 | + | time := event.Uint32() | |
| 512 | + | cancelled := event.Int32() | |
| 513 | + | ||
| 514 | + | for i, handler := range o.handlersForEnd() { | |
| 515 | + | _ = i | |
| 516 | + | handler(serial, time, cancelled) | |
| 517 | + | } | |
| 518 | + | default: | |
| 519 | + | } | |
| 520 | + | } | |
A client/pointerwarp/pointerwarp_generated.go +89 -0
| @@ -0,0 +1,89 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: pointer_warp_v1 | |
| 3 | + | // Source: pointer-warp-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2024 Neal Gompa | |
| 7 | + | // Copyright © 2024 Xaver Hugl | |
| 8 | + | // Copyright © 2024 Matthias Klumpp | |
| 9 | + | // Copyright © 2024 Vlad Zahorodnii | |
| 10 | + | // | |
| 11 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 12 | + | // copy of this software and associated documentation files (the "Software"), | |
| 13 | + | // to deal in the Software without restriction, including without limitation | |
| 14 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 15 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 16 | + | // Software is furnished to do so, subject to the following conditions: | |
| 17 | + | // The above copyright notice and this permission notice (including the next | |
| 18 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 19 | + | // Software. | |
| 20 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 21 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 22 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 23 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 24 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 25 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 26 | + | // DEALINGS IN THE SOFTWARE. | |
| 27 | + | ||
| 28 | + | package pointerwarp | |
| 29 | + | ||
| 30 | + | import ( | |
| 31 | + | cross_wl_pointer "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 32 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 33 | + | "github.com/bnema/wlturbo/wl" | |
| 34 | + | ) | |
| 35 | + | ||
| 36 | + | // WpPointerWarpInterface is the protocol interface name. | |
| 37 | + | const WpPointerWarpInterface = "wp_pointer_warp_v1" | |
| 38 | + | ||
| 39 | + | // WpPointerWarp is the generated binding for wp_pointer_warp_v1 version 1. | |
| 40 | + | type WpPointerWarp struct { | |
| 41 | + | wl.BaseProxy | |
| 42 | + | } | |
| 43 | + | ||
| 44 | + | // NewWpPointerWarp returns an unbound WpPointerWarp. | |
| 45 | + | func NewWpPointerWarp(ctx *wl.Context) *WpPointerWarp { | |
| 46 | + | obj := &WpPointerWarp{} | |
| 47 | + | obj.SetContext(ctx) | |
| 48 | + | ctx.Register(obj) | |
| 49 | + | return obj | |
| 50 | + | } | |
| 51 | + | ||
| 52 | + | // Destroy the pointer warp manager. | |
| 53 | + | func (o *WpPointerWarp) Destroy() error { | |
| 54 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_pointer_warp_v1.destroy", Destructor: true}); err != nil { | |
| 55 | + | return err | |
| 56 | + | } | |
| 57 | + | return nil | |
| 58 | + | } | |
| 59 | + | ||
| 60 | + | // Request the compositor to move the pointer to a surface-local position. Whether or not the compositor honors the request is implementation defined, but it should - honor it if the surface has pointer focus, including when it has an implicit pointer grab - reject it if the enter serial is incorrect - reject it if the requested position is outside of the surface Note that the enter serial is valid for any surface of the client, and does not have to be from the surface the pointer is warped to. | |
| 61 | + | func (o *WpPointerWarp) WarpPointer(surface *cross_wl_surface.Surface, pointer *cross_wl_pointer.Pointer, x wl.Fixed, y wl.Fixed, serial uint32) error { | |
| 62 | + | var arg0 wl.Object | |
| 63 | + | if surface != nil { | |
| 64 | + | arg0 = surface | |
| 65 | + | } | |
| 66 | + | var arg1 wl.Object | |
| 67 | + | if pointer != nil { | |
| 68 | + | arg1 = pointer | |
| 69 | + | } | |
| 70 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_pointer_warp_v1.warp_pointer"}, wl.ArgObject(arg0), wl.ArgObject(arg1), wl.ArgFixed(x), wl.ArgFixed(y), wl.ArgUint(serial)); err != nil { | |
| 71 | + | return err | |
| 72 | + | } | |
| 73 | + | return nil | |
| 74 | + | } | |
| 75 | + | ||
| 76 | + | // EventSignature returns the declared event argument types in wire order. | |
| 77 | + | func (o *WpPointerWarp) EventSignature(opcode uint16) (string, bool) { | |
| 78 | + | switch opcode { | |
| 79 | + | default: | |
| 80 | + | return "", false | |
| 81 | + | } | |
| 82 | + | } | |
| 83 | + | ||
| 84 | + | // Dispatch decodes one event on wp_pointer_warp_v1 and calls the registered handlers. | |
| 85 | + | func (o *WpPointerWarp) Dispatch(event *wl.Event) { | |
| 86 | + | switch event.Opcode { | |
| 87 | + | default: | |
| 88 | + | } | |
| 89 | + | } | |
A client/presentationtime/presentationtime_generated.go +277 -0
| @@ -0,0 +1,277 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: presentation_time | |
| 3 | + | // Source: presentation-time.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2013-2014 Collabora, Ltd. | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package presentationtime | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | "sync" | |
| 31 | + | ||
| 32 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 33 | + | "github.com/bnema/wlturbo/wl" | |
| 34 | + | ) | |
| 35 | + | ||
| 36 | + | // ERROR_INVALID_TIMESTAMP is the error invalid_timestamp value. | |
| 37 | + | const ERROR_INVALID_TIMESTAMP = 0 | |
| 38 | + | ||
| 39 | + | // ERROR_INVALID_FLAG is the error invalid_flag value. | |
| 40 | + | const ERROR_INVALID_FLAG = 1 | |
| 41 | + | ||
| 42 | + | // KIND_VSYNC is the kind vsync value. | |
| 43 | + | const KIND_VSYNC = 0x1 | |
| 44 | + | ||
| 45 | + | // KIND_HW_CLOCK is the kind hw_clock value. | |
| 46 | + | const KIND_HW_CLOCK = 0x2 | |
| 47 | + | ||
| 48 | + | // KIND_HW_COMPLETION is the kind hw_completion value. | |
| 49 | + | const KIND_HW_COMPLETION = 0x4 | |
| 50 | + | ||
| 51 | + | // KIND_ZERO_COPY is the kind zero_copy value. | |
| 52 | + | const KIND_ZERO_COPY = 0x8 | |
| 53 | + | ||
| 54 | + | // WpPresentationInterface is the protocol interface name. | |
| 55 | + | const WpPresentationInterface = "wp_presentation" | |
| 56 | + | ||
| 57 | + | // WpPresentation is the generated binding for wp_presentation version 2. | |
| 58 | + | type WpPresentation struct { | |
| 59 | + | wl.BaseProxy | |
| 60 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 61 | + | // handlers while another goroutine dispatches events. | |
| 62 | + | handlersMu sync.Mutex | |
| 63 | + | onClockId []func(clkId uint32) | |
| 64 | + | } | |
| 65 | + | ||
| 66 | + | // NewWpPresentation returns an unbound WpPresentation. | |
| 67 | + | func NewWpPresentation(ctx *wl.Context) *WpPresentation { | |
| 68 | + | obj := &WpPresentation{} | |
| 69 | + | obj.SetContext(ctx) | |
| 70 | + | ctx.Register(obj) | |
| 71 | + | return obj | |
| 72 | + | } | |
| 73 | + | ||
| 74 | + | // Informs the server that the client will no longer be using this protocol object. Existing objects created by this object are not affected. | |
| 75 | + | func (o *WpPresentation) Destroy() error { | |
| 76 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_presentation.destroy", Destructor: true}); err != nil { | |
| 77 | + | return err | |
| 78 | + | } | |
| 79 | + | return nil | |
| 80 | + | } | |
| 81 | + | ||
| 82 | + | // Request presentation feedback for the current content submission on the given surface. This creates a new presentation_feedback object, which will deliver the feedback information once. If multiple presentation_feedback objects are created for the same submission, they will all deliver the same information. For details on what information is returned, see the presentation_feedback interface. | |
| 83 | + | func (o *WpPresentation) Feedback(surface *cross_wl_surface.Surface) (*WpPresentationFeedback, error) { | |
| 84 | + | var arg0 wl.Object | |
| 85 | + | if surface != nil { | |
| 86 | + | arg0 = surface | |
| 87 | + | } | |
| 88 | + | child := &WpPresentationFeedback{} | |
| 89 | + | child.SetContext(o.Context()) | |
| 90 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_presentation.feedback", Child: child}, wl.ArgObject(arg0), wl.ArgObject(child)); err != nil { | |
| 91 | + | return nil, err | |
| 92 | + | } | |
| 93 | + | return child, nil | |
| 94 | + | } | |
| 95 | + | ||
| 96 | + | // OnClockId registers a handler for the clock_id event. | |
| 97 | + | // | |
| 98 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 99 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 100 | + | func (o *WpPresentation) OnClockId(handler func(clkId uint32)) { | |
| 101 | + | if handler == nil { | |
| 102 | + | return | |
| 103 | + | } | |
| 104 | + | o.handlersMu.Lock() | |
| 105 | + | defer o.handlersMu.Unlock() | |
| 106 | + | o.onClockId = append(o.onClockId, handler) | |
| 107 | + | } | |
| 108 | + | ||
| 109 | + | // handlersForClockId returns the handlers registered for clock_id, taken | |
| 110 | + | // under the lock so a handler may register another handler while events are | |
| 111 | + | // being dispatched. | |
| 112 | + | func (o *WpPresentation) handlersForClockId() []func(clkId uint32) { | |
| 113 | + | o.handlersMu.Lock() | |
| 114 | + | defer o.handlersMu.Unlock() | |
| 115 | + | return o.onClockId | |
| 116 | + | } | |
| 117 | + | ||
| 118 | + | // EventSignature returns the declared event argument types in wire order. | |
| 119 | + | func (o *WpPresentation) EventSignature(opcode uint16) (string, bool) { | |
| 120 | + | switch opcode { | |
| 121 | + | case 0: | |
| 122 | + | return "uint,", true | |
| 123 | + | default: | |
| 124 | + | return "", false | |
| 125 | + | } | |
| 126 | + | } | |
| 127 | + | ||
| 128 | + | // Dispatch decodes one event on wp_presentation and calls the registered handlers. | |
| 129 | + | func (o *WpPresentation) Dispatch(event *wl.Event) { | |
| 130 | + | switch event.Opcode { | |
| 131 | + | case 0: // clock_id | |
| 132 | + | clkId := event.Uint32() | |
| 133 | + | ||
| 134 | + | for i, handler := range o.handlersForClockId() { | |
| 135 | + | _ = i | |
| 136 | + | handler(clkId) | |
| 137 | + | } | |
| 138 | + | default: | |
| 139 | + | } | |
| 140 | + | } | |
| 141 | + | ||
| 142 | + | // WpPresentationFeedbackInterface is the protocol interface name. | |
| 143 | + | const WpPresentationFeedbackInterface = "wp_presentation_feedback" | |
| 144 | + | ||
| 145 | + | // WpPresentationFeedback is the generated binding for wp_presentation_feedback version 2. | |
| 146 | + | type WpPresentationFeedback struct { | |
| 147 | + | wl.BaseProxy | |
| 148 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 149 | + | // handlers while another goroutine dispatches events. | |
| 150 | + | handlersMu sync.Mutex | |
| 151 | + | onSyncOutput []func(outputID uint32) | |
| 152 | + | onPresented []func(tvSecHi uint32, tvSecLo uint32, tvNsec uint32, refresh uint32, seqHi uint32, seqLo uint32, flags uint32) | |
| 153 | + | onDiscarded []func() | |
| 154 | + | } | |
| 155 | + | ||
| 156 | + | // NewWpPresentationFeedback returns an unbound WpPresentationFeedback. | |
| 157 | + | func NewWpPresentationFeedback(ctx *wl.Context) *WpPresentationFeedback { | |
| 158 | + | obj := &WpPresentationFeedback{} | |
| 159 | + | obj.SetContext(ctx) | |
| 160 | + | ctx.Register(obj) | |
| 161 | + | return obj | |
| 162 | + | } | |
| 163 | + | ||
| 164 | + | // OnSyncOutput registers a handler for the sync_output event. | |
| 165 | + | // | |
| 166 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 167 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 168 | + | func (o *WpPresentationFeedback) OnSyncOutput(handler func(outputID uint32)) { | |
| 169 | + | if handler == nil { | |
| 170 | + | return | |
| 171 | + | } | |
| 172 | + | o.handlersMu.Lock() | |
| 173 | + | defer o.handlersMu.Unlock() | |
| 174 | + | o.onSyncOutput = append(o.onSyncOutput, handler) | |
| 175 | + | } | |
| 176 | + | ||
| 177 | + | // handlersForSyncOutput returns the handlers registered for sync_output, taken | |
| 178 | + | // under the lock so a handler may register another handler while events are | |
| 179 | + | // being dispatched. | |
| 180 | + | func (o *WpPresentationFeedback) handlersForSyncOutput() []func(outputID uint32) { | |
| 181 | + | o.handlersMu.Lock() | |
| 182 | + | defer o.handlersMu.Unlock() | |
| 183 | + | return o.onSyncOutput | |
| 184 | + | } | |
| 185 | + | ||
| 186 | + | // OnPresented registers a handler for the presented event. | |
| 187 | + | // | |
| 188 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 189 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 190 | + | func (o *WpPresentationFeedback) OnPresented(handler func(tvSecHi uint32, tvSecLo uint32, tvNsec uint32, refresh uint32, seqHi uint32, seqLo uint32, flags uint32)) { | |
| 191 | + | if handler == nil { | |
| 192 | + | return | |
| 193 | + | } | |
| 194 | + | o.handlersMu.Lock() | |
| 195 | + | defer o.handlersMu.Unlock() | |
| 196 | + | o.onPresented = append(o.onPresented, handler) | |
| 197 | + | } | |
| 198 | + | ||
| 199 | + | // handlersForPresented returns the handlers registered for presented, taken | |
| 200 | + | // under the lock so a handler may register another handler while events are | |
| 201 | + | // being dispatched. | |
| 202 | + | func (o *WpPresentationFeedback) handlersForPresented() []func(tvSecHi uint32, tvSecLo uint32, tvNsec uint32, refresh uint32, seqHi uint32, seqLo uint32, flags uint32) { | |
| 203 | + | o.handlersMu.Lock() | |
| 204 | + | defer o.handlersMu.Unlock() | |
| 205 | + | return o.onPresented | |
| 206 | + | } | |
| 207 | + | ||
| 208 | + | // OnDiscarded registers a handler for the discarded event. | |
| 209 | + | // | |
| 210 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 211 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 212 | + | func (o *WpPresentationFeedback) OnDiscarded(handler func()) { | |
| 213 | + | if handler == nil { | |
| 214 | + | return | |
| 215 | + | } | |
| 216 | + | o.handlersMu.Lock() | |
| 217 | + | defer o.handlersMu.Unlock() | |
| 218 | + | o.onDiscarded = append(o.onDiscarded, handler) | |
| 219 | + | } | |
| 220 | + | ||
| 221 | + | // handlersForDiscarded returns the handlers registered for discarded, taken | |
| 222 | + | // under the lock so a handler may register another handler while events are | |
| 223 | + | // being dispatched. | |
| 224 | + | func (o *WpPresentationFeedback) handlersForDiscarded() []func() { | |
| 225 | + | o.handlersMu.Lock() | |
| 226 | + | defer o.handlersMu.Unlock() | |
| 227 | + | return o.onDiscarded | |
| 228 | + | } | |
| 229 | + | ||
| 230 | + | // EventSignature returns the declared event argument types in wire order. | |
| 231 | + | func (o *WpPresentationFeedback) EventSignature(opcode uint16) (string, bool) { | |
| 232 | + | switch opcode { | |
| 233 | + | case 0: | |
| 234 | + | return "object,", true | |
| 235 | + | case 1: | |
| 236 | + | return "uint,uint,uint,uint,uint,uint,uint,", true | |
| 237 | + | case 2: | |
| 238 | + | return "", true | |
| 239 | + | default: | |
| 240 | + | return "", false | |
| 241 | + | } | |
| 242 | + | } | |
| 243 | + | ||
| 244 | + | // Dispatch decodes one event on wp_presentation_feedback and calls the registered handlers. | |
| 245 | + | func (o *WpPresentationFeedback) Dispatch(event *wl.Event) { | |
| 246 | + | switch event.Opcode { | |
| 247 | + | case 0: // sync_output | |
| 248 | + | outputID := event.Uint32() | |
| 249 | + | ||
| 250 | + | for i, handler := range o.handlersForSyncOutput() { | |
| 251 | + | _ = i | |
| 252 | + | handler(outputID) | |
| 253 | + | } | |
| 254 | + | case 1: // presented | |
| 255 | + | tvSecHi := event.Uint32() | |
| 256 | + | tvSecLo := event.Uint32() | |
| 257 | + | tvNsec := event.Uint32() | |
| 258 | + | refresh := event.Uint32() | |
| 259 | + | seqHi := event.Uint32() | |
| 260 | + | seqLo := event.Uint32() | |
| 261 | + | flags := event.Uint32() | |
| 262 | + | ||
| 263 | + | for i, handler := range o.handlersForPresented() { | |
| 264 | + | _ = i | |
| 265 | + | handler(tvSecHi, tvSecLo, tvNsec, refresh, seqHi, seqLo, flags) | |
| 266 | + | } | |
| 267 | + | o.Context().Unregister(o) | |
| 268 | + | case 2: // discarded | |
| 269 | + | ||
| 270 | + | for i, handler := range o.handlersForDiscarded() { | |
| 271 | + | _ = i | |
| 272 | + | handler() | |
| 273 | + | } | |
| 274 | + | o.Context().Unregister(o) | |
| 275 | + | default: | |
| 276 | + | } | |
| 277 | + | } | |
A client/primaryselection/primaryselection_generated.go +420 -0
| @@ -0,0 +1,420 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: wp_primary_selection_unstable_v1 | |
| 3 | + | // Source: primary-selection-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2015, 2016 Red Hat | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package primaryselection | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | "sync" | |
| 31 | + | ||
| 32 | + | cross_wl_seat "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 33 | + | "github.com/bnema/wlturbo/wl" | |
| 34 | + | ) | |
| 35 | + | ||
| 36 | + | // PrimarySelectionDeviceManagerInterface is the protocol interface name. | |
| 37 | + | const PrimarySelectionDeviceManagerInterface = "zwp_primary_selection_device_manager_v1" | |
| 38 | + | ||
| 39 | + | // PrimarySelectionDeviceManager is the generated binding for zwp_primary_selection_device_manager_v1 version 1. | |
| 40 | + | type PrimarySelectionDeviceManager struct { | |
| 41 | + | wl.BaseProxy | |
| 42 | + | } | |
| 43 | + | ||
| 44 | + | // NewPrimarySelectionDeviceManager returns an unbound PrimarySelectionDeviceManager. | |
| 45 | + | func NewPrimarySelectionDeviceManager(ctx *wl.Context) *PrimarySelectionDeviceManager { | |
| 46 | + | obj := &PrimarySelectionDeviceManager{} | |
| 47 | + | obj.SetContext(ctx) | |
| 48 | + | ctx.Register(obj) | |
| 49 | + | return obj | |
| 50 | + | } | |
| 51 | + | ||
| 52 | + | // Create a new primary selection source. | |
| 53 | + | func (o *PrimarySelectionDeviceManager) CreateSource() (*PrimarySelectionSource, error) { | |
| 54 | + | child := &PrimarySelectionSource{} | |
| 55 | + | child.SetContext(o.Context()) | |
| 56 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_primary_selection_device_manager_v1.create_source", Child: child}, wl.ArgObject(child)); err != nil { | |
| 57 | + | return nil, err | |
| 58 | + | } | |
| 59 | + | return child, nil | |
| 60 | + | } | |
| 61 | + | ||
| 62 | + | // Create a new data device for a given seat. | |
| 63 | + | func (o *PrimarySelectionDeviceManager) GetDevice(seat *cross_wl_seat.Seat) (*PrimarySelectionDevice, error) { | |
| 64 | + | var arg1 wl.Object | |
| 65 | + | if seat != nil { | |
| 66 | + | arg1 = seat | |
| 67 | + | } | |
| 68 | + | child := &PrimarySelectionDevice{} | |
| 69 | + | child.SetContext(o.Context()) | |
| 70 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_primary_selection_device_manager_v1.get_device", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 71 | + | return nil, err | |
| 72 | + | } | |
| 73 | + | return child, nil | |
| 74 | + | } | |
| 75 | + | ||
| 76 | + | // Destroy the primary selection device manager. | |
| 77 | + | func (o *PrimarySelectionDeviceManager) Destroy() error { | |
| 78 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_primary_selection_device_manager_v1.destroy", Destructor: true}); err != nil { | |
| 79 | + | return err | |
| 80 | + | } | |
| 81 | + | return nil | |
| 82 | + | } | |
| 83 | + | ||
| 84 | + | // EventSignature returns the declared event argument types in wire order. | |
| 85 | + | func (o *PrimarySelectionDeviceManager) EventSignature(opcode uint16) (string, bool) { | |
| 86 | + | switch opcode { | |
| 87 | + | default: | |
| 88 | + | return "", false | |
| 89 | + | } | |
| 90 | + | } | |
| 91 | + | ||
| 92 | + | // Dispatch decodes one event on zwp_primary_selection_device_manager_v1 and calls the registered handlers. | |
| 93 | + | func (o *PrimarySelectionDeviceManager) Dispatch(event *wl.Event) { | |
| 94 | + | switch event.Opcode { | |
| 95 | + | default: | |
| 96 | + | } | |
| 97 | + | } | |
| 98 | + | ||
| 99 | + | // PrimarySelectionDeviceInterface is the protocol interface name. | |
| 100 | + | const PrimarySelectionDeviceInterface = "zwp_primary_selection_device_v1" | |
| 101 | + | ||
| 102 | + | // PrimarySelectionDevice is the generated binding for zwp_primary_selection_device_v1 version 1. | |
| 103 | + | type PrimarySelectionDevice struct { | |
| 104 | + | wl.BaseProxy | |
| 105 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 106 | + | // handlers while another goroutine dispatches events. | |
| 107 | + | handlersMu sync.Mutex | |
| 108 | + | onDataOffer []func(offerObject *PrimarySelectionOffer) | |
| 109 | + | onSelection []func(idID uint32) | |
| 110 | + | } | |
| 111 | + | ||
| 112 | + | // NewPrimarySelectionDevice returns an unbound PrimarySelectionDevice. | |
| 113 | + | func NewPrimarySelectionDevice(ctx *wl.Context) *PrimarySelectionDevice { | |
| 114 | + | obj := &PrimarySelectionDevice{} | |
| 115 | + | obj.SetContext(ctx) | |
| 116 | + | ctx.Register(obj) | |
| 117 | + | return obj | |
| 118 | + | } | |
| 119 | + | ||
| 120 | + | // Replaces the current selection. The previous owner of the primary selection will receive a wp_primary_selection_source.cancelled event. To unset the selection, set the source to NULL. | |
| 121 | + | func (o *PrimarySelectionDevice) SetSelection(source *PrimarySelectionSource, serial uint32) error { | |
| 122 | + | var arg0 wl.Object | |
| 123 | + | if source != nil { | |
| 124 | + | arg0 = source | |
| 125 | + | } | |
| 126 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_primary_selection_device_v1.set_selection"}, wl.ArgObject(arg0), wl.ArgUint(serial)); err != nil { | |
| 127 | + | return err | |
| 128 | + | } | |
| 129 | + | return nil | |
| 130 | + | } | |
| 131 | + | ||
| 132 | + | // Destroy the primary selection device. | |
| 133 | + | func (o *PrimarySelectionDevice) Destroy() error { | |
| 134 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_primary_selection_device_v1.destroy", Destructor: true}); err != nil { | |
| 135 | + | return err | |
| 136 | + | } | |
| 137 | + | return nil | |
| 138 | + | } | |
| 139 | + | ||
| 140 | + | // OnDataOffer registers a handler for the data_offer event. | |
| 141 | + | // | |
| 142 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 143 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 144 | + | func (o *PrimarySelectionDevice) OnDataOffer(handler func(offerObject *PrimarySelectionOffer)) { | |
| 145 | + | if handler == nil { | |
| 146 | + | return | |
| 147 | + | } | |
| 148 | + | o.handlersMu.Lock() | |
| 149 | + | defer o.handlersMu.Unlock() | |
| 150 | + | o.onDataOffer = append(o.onDataOffer, handler) | |
| 151 | + | } | |
| 152 | + | ||
| 153 | + | // handlersForDataOffer returns the handlers registered for data_offer, taken | |
| 154 | + | // under the lock so a handler may register another handler while events are | |
| 155 | + | // being dispatched. | |
| 156 | + | func (o *PrimarySelectionDevice) handlersForDataOffer() []func(offerObject *PrimarySelectionOffer) { | |
| 157 | + | o.handlersMu.Lock() | |
| 158 | + | defer o.handlersMu.Unlock() | |
| 159 | + | return o.onDataOffer | |
| 160 | + | } | |
| 161 | + | ||
| 162 | + | // OnSelection registers a handler for the selection event. | |
| 163 | + | // | |
| 164 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 165 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 166 | + | func (o *PrimarySelectionDevice) OnSelection(handler func(idID uint32)) { | |
| 167 | + | if handler == nil { | |
| 168 | + | return | |
| 169 | + | } | |
| 170 | + | o.handlersMu.Lock() | |
| 171 | + | defer o.handlersMu.Unlock() | |
| 172 | + | o.onSelection = append(o.onSelection, handler) | |
| 173 | + | } | |
| 174 | + | ||
| 175 | + | // handlersForSelection returns the handlers registered for selection, taken | |
| 176 | + | // under the lock so a handler may register another handler while events are | |
| 177 | + | // being dispatched. | |
| 178 | + | func (o *PrimarySelectionDevice) handlersForSelection() []func(idID uint32) { | |
| 179 | + | o.handlersMu.Lock() | |
| 180 | + | defer o.handlersMu.Unlock() | |
| 181 | + | return o.onSelection | |
| 182 | + | } | |
| 183 | + | ||
| 184 | + | // EventSignature returns the declared event argument types in wire order. | |
| 185 | + | func (o *PrimarySelectionDevice) EventSignature(opcode uint16) (string, bool) { | |
| 186 | + | switch opcode { | |
| 187 | + | case 0: | |
| 188 | + | return "new_id,", true | |
| 189 | + | case 1: | |
| 190 | + | return "object,", true | |
| 191 | + | default: | |
| 192 | + | return "", false | |
| 193 | + | } | |
| 194 | + | } | |
| 195 | + | ||
| 196 | + | // Dispatch decodes one event on zwp_primary_selection_device_v1 and calls the registered handlers. | |
| 197 | + | func (o *PrimarySelectionDevice) Dispatch(event *wl.Event) { | |
| 198 | + | switch event.Opcode { | |
| 199 | + | case 0: // data_offer | |
| 200 | + | offerID := event.Uint32() | |
| 201 | + | offerObject := &PrimarySelectionOffer{} | |
| 202 | + | offerObject.SetContext(o.Context()) | |
| 203 | + | offerObject.SetID(offerID) | |
| 204 | + | offerObject.SetVersion(o.Version()) | |
| 205 | + | o.Context().Register(offerObject) | |
| 206 | + | ||
| 207 | + | for i, handler := range o.handlersForDataOffer() { | |
| 208 | + | _ = i | |
| 209 | + | handler(offerObject) | |
| 210 | + | } | |
| 211 | + | case 1: // selection | |
| 212 | + | idID := event.Uint32() | |
| 213 | + | ||
| 214 | + | for i, handler := range o.handlersForSelection() { | |
| 215 | + | _ = i | |
| 216 | + | handler(idID) | |
| 217 | + | } | |
| 218 | + | default: | |
| 219 | + | } | |
| 220 | + | } | |
| 221 | + | ||
| 222 | + | // PrimarySelectionOfferInterface is the protocol interface name. | |
| 223 | + | const PrimarySelectionOfferInterface = "zwp_primary_selection_offer_v1" | |
| 224 | + | ||
| 225 | + | // PrimarySelectionOffer is the generated binding for zwp_primary_selection_offer_v1 version 1. | |
| 226 | + | type PrimarySelectionOffer struct { | |
| 227 | + | wl.BaseProxy | |
| 228 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 229 | + | // handlers while another goroutine dispatches events. | |
| 230 | + | handlersMu sync.Mutex | |
| 231 | + | onOffer []func(mimeType string) | |
| 232 | + | } | |
| 233 | + | ||
| 234 | + | // NewPrimarySelectionOffer returns an unbound PrimarySelectionOffer. | |
| 235 | + | func NewPrimarySelectionOffer(ctx *wl.Context) *PrimarySelectionOffer { | |
| 236 | + | obj := &PrimarySelectionOffer{} | |
| 237 | + | obj.SetContext(ctx) | |
| 238 | + | ctx.Register(obj) | |
| 239 | + | return obj | |
| 240 | + | } | |
| 241 | + | ||
| 242 | + | // To transfer the contents of the primary selection clipboard, the client issues this request and indicates the mime type that it wants to receive. The transfer happens through the passed file descriptor (typically created with the pipe system call). The source client writes the data in the mime type representation requested and then closes the file descriptor. The receiving client reads from the read end of the pipe until EOF and closes its end, at which point the transfer is complete. | |
| 243 | + | func (o *PrimarySelectionOffer) Receive(mimeType string, fd int) error { | |
| 244 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_primary_selection_offer_v1.receive", FDs: []int{fd}}, wl.ArgString(mimeType), wl.ArgFD()); err != nil { | |
| 245 | + | return err | |
| 246 | + | } | |
| 247 | + | return nil | |
| 248 | + | } | |
| 249 | + | ||
| 250 | + | // Destroy the primary selection offer. | |
| 251 | + | func (o *PrimarySelectionOffer) Destroy() error { | |
| 252 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_primary_selection_offer_v1.destroy", Destructor: true}); err != nil { | |
| 253 | + | return err | |
| 254 | + | } | |
| 255 | + | return nil | |
| 256 | + | } | |
| 257 | + | ||
| 258 | + | // OnOffer registers a handler for the offer event. | |
| 259 | + | // | |
| 260 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 261 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 262 | + | func (o *PrimarySelectionOffer) OnOffer(handler func(mimeType string)) { | |
| 263 | + | if handler == nil { | |
| 264 | + | return | |
| 265 | + | } | |
| 266 | + | o.handlersMu.Lock() | |
| 267 | + | defer o.handlersMu.Unlock() | |
| 268 | + | o.onOffer = append(o.onOffer, handler) | |
| 269 | + | } | |
| 270 | + | ||
| 271 | + | // handlersForOffer returns the handlers registered for offer, taken | |
| 272 | + | // under the lock so a handler may register another handler while events are | |
| 273 | + | // being dispatched. | |
| 274 | + | func (o *PrimarySelectionOffer) handlersForOffer() []func(mimeType string) { | |
| 275 | + | o.handlersMu.Lock() | |
| 276 | + | defer o.handlersMu.Unlock() | |
| 277 | + | return o.onOffer | |
| 278 | + | } | |
| 279 | + | ||
| 280 | + | // EventSignature returns the declared event argument types in wire order. | |
| 281 | + | func (o *PrimarySelectionOffer) EventSignature(opcode uint16) (string, bool) { | |
| 282 | + | switch opcode { | |
| 283 | + | case 0: | |
| 284 | + | return "string,", true | |
| 285 | + | default: | |
| 286 | + | return "", false | |
| 287 | + | } | |
| 288 | + | } | |
| 289 | + | ||
| 290 | + | // Dispatch decodes one event on zwp_primary_selection_offer_v1 and calls the registered handlers. | |
| 291 | + | func (o *PrimarySelectionOffer) Dispatch(event *wl.Event) { | |
| 292 | + | switch event.Opcode { | |
| 293 | + | case 0: // offer | |
| 294 | + | mimeType := event.String() | |
| 295 | + | ||
| 296 | + | for i, handler := range o.handlersForOffer() { | |
| 297 | + | _ = i | |
| 298 | + | handler(mimeType) | |
| 299 | + | } | |
| 300 | + | default: | |
| 301 | + | } | |
| 302 | + | } | |
| 303 | + | ||
| 304 | + | // PrimarySelectionSourceInterface is the protocol interface name. | |
| 305 | + | const PrimarySelectionSourceInterface = "zwp_primary_selection_source_v1" | |
| 306 | + | ||
| 307 | + | // PrimarySelectionSource is the generated binding for zwp_primary_selection_source_v1 version 1. | |
| 308 | + | type PrimarySelectionSource struct { | |
| 309 | + | wl.BaseProxy | |
| 310 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 311 | + | // handlers while another goroutine dispatches events. | |
| 312 | + | handlersMu sync.Mutex | |
| 313 | + | onSend []func(mimeType string, fd *wl.OwnedFD) | |
| 314 | + | onCancelled []func() | |
| 315 | + | } | |
| 316 | + | ||
| 317 | + | // NewPrimarySelectionSource returns an unbound PrimarySelectionSource. | |
| 318 | + | func NewPrimarySelectionSource(ctx *wl.Context) *PrimarySelectionSource { | |
| 319 | + | obj := &PrimarySelectionSource{} | |
| 320 | + | obj.SetContext(ctx) | |
| 321 | + | ctx.Register(obj) | |
| 322 | + | return obj | |
| 323 | + | } | |
| 324 | + | ||
| 325 | + | // This request adds a mime type to the set of mime types advertised to targets. Can be called several times to offer multiple types. | |
| 326 | + | func (o *PrimarySelectionSource) Offer(mimeType string) error { | |
| 327 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_primary_selection_source_v1.offer"}, wl.ArgString(mimeType)); err != nil { | |
| 328 | + | return err | |
| 329 | + | } | |
| 330 | + | return nil | |
| 331 | + | } | |
| 332 | + | ||
| 333 | + | // Destroy the primary selection source. | |
| 334 | + | func (o *PrimarySelectionSource) Destroy() error { | |
| 335 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_primary_selection_source_v1.destroy", Destructor: true}); err != nil { | |
| 336 | + | return err | |
| 337 | + | } | |
| 338 | + | return nil | |
| 339 | + | } | |
| 340 | + | ||
| 341 | + | // OnSend registers a handler for the send event. | |
| 342 | + | // | |
| 343 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 344 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 345 | + | func (o *PrimarySelectionSource) OnSend(handler func(mimeType string, fd *wl.OwnedFD)) { | |
| 346 | + | if handler == nil { | |
| 347 | + | return | |
| 348 | + | } | |
| 349 | + | o.handlersMu.Lock() | |
| 350 | + | defer o.handlersMu.Unlock() | |
| 351 | + | o.onSend = append(o.onSend, handler) | |
| 352 | + | } | |
| 353 | + | ||
| 354 | + | // handlersForSend returns the handlers registered for send, taken | |
| 355 | + | // under the lock so a handler may register another handler while events are | |
| 356 | + | // being dispatched. | |
| 357 | + | func (o *PrimarySelectionSource) handlersForSend() []func(mimeType string, fd *wl.OwnedFD) { | |
| 358 | + | o.handlersMu.Lock() | |
| 359 | + | defer o.handlersMu.Unlock() | |
| 360 | + | return o.onSend | |
| 361 | + | } | |
| 362 | + | ||
| 363 | + | // OnCancelled registers a handler for the cancelled event. | |
| 364 | + | // | |
| 365 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 366 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 367 | + | func (o *PrimarySelectionSource) OnCancelled(handler func()) { | |
| 368 | + | if handler == nil { | |
| 369 | + | return | |
| 370 | + | } | |
| 371 | + | o.handlersMu.Lock() | |
| 372 | + | defer o.handlersMu.Unlock() | |
| 373 | + | o.onCancelled = append(o.onCancelled, handler) | |
| 374 | + | } | |
| 375 | + | ||
| 376 | + | // handlersForCancelled returns the handlers registered for cancelled, taken | |
| 377 | + | // under the lock so a handler may register another handler while events are | |
| 378 | + | // being dispatched. | |
| 379 | + | func (o *PrimarySelectionSource) handlersForCancelled() []func() { | |
| 380 | + | o.handlersMu.Lock() | |
| 381 | + | defer o.handlersMu.Unlock() | |
| 382 | + | return o.onCancelled | |
| 383 | + | } | |
| 384 | + | ||
| 385 | + | // EventSignature returns the declared event argument types in wire order. | |
| 386 | + | func (o *PrimarySelectionSource) EventSignature(opcode uint16) (string, bool) { | |
| 387 | + | switch opcode { | |
| 388 | + | case 0: | |
| 389 | + | return "string,fd,", true | |
| 390 | + | case 1: | |
| 391 | + | return "", true | |
| 392 | + | default: | |
| 393 | + | return "", false | |
| 394 | + | } | |
| 395 | + | } | |
| 396 | + | ||
| 397 | + | // Dispatch decodes one event on zwp_primary_selection_source_v1 and calls the registered handlers. | |
| 398 | + | func (o *PrimarySelectionSource) Dispatch(event *wl.Event) { | |
| 399 | + | switch event.Opcode { | |
| 400 | + | case 0: // send | |
| 401 | + | mimeType := event.String() | |
| 402 | + | fd := event.FD() | |
| 403 | + | ownedfd := fd | |
| 404 | + | defer ownedfd.Close() | |
| 405 | + | ||
| 406 | + | for i, handler := range o.handlersForSend() { | |
| 407 | + | if i > 0 { | |
| 408 | + | fd = nil | |
| 409 | + | } | |
| 410 | + | handler(mimeType, fd) | |
| 411 | + | } | |
| 412 | + | case 1: // cancelled | |
| 413 | + | ||
| 414 | + | for i, handler := range o.handlersForCancelled() { | |
| 415 | + | _ = i | |
| 416 | + | handler() | |
| 417 | + | } | |
| 418 | + | default: | |
| 419 | + | } | |
| 420 | + | } | |
A client/relativepointer/relativepointer_generated.go +167 -0
| @@ -0,0 +1,167 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: relative_pointer_unstable_v1 | |
| 3 | + | // Source: relative-pointer-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2014 Jonas Ådahl | |
| 7 | + | // Copyright © 2015 Red Hat Inc. | |
| 8 | + | // | |
| 9 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 10 | + | // copy of this software and associated documentation files (the "Software"), | |
| 11 | + | // to deal in the Software without restriction, including without limitation | |
| 12 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 13 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 14 | + | // Software is furnished to do so, subject to the following conditions: | |
| 15 | + | // | |
| 16 | + | // The above copyright notice and this permission notice (including the next | |
| 17 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 18 | + | // Software. | |
| 19 | + | // | |
| 20 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 21 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 22 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 23 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 24 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 25 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 26 | + | // DEALINGS IN THE SOFTWARE. | |
| 27 | + | ||
| 28 | + | package relativepointer | |
| 29 | + | ||
| 30 | + | import ( | |
| 31 | + | "sync" | |
| 32 | + | ||
| 33 | + | cross_wl_pointer "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 34 | + | "github.com/bnema/wlturbo/wl" | |
| 35 | + | ) | |
| 36 | + | ||
| 37 | + | // RelativePointerManagerInterface is the protocol interface name. | |
| 38 | + | const RelativePointerManagerInterface = "zwp_relative_pointer_manager_v1" | |
| 39 | + | ||
| 40 | + | // RelativePointerManager is the generated binding for zwp_relative_pointer_manager_v1 version 1. | |
| 41 | + | type RelativePointerManager struct { | |
| 42 | + | wl.BaseProxy | |
| 43 | + | } | |
| 44 | + | ||
| 45 | + | // NewRelativePointerManager returns an unbound RelativePointerManager. | |
| 46 | + | func NewRelativePointerManager(ctx *wl.Context) *RelativePointerManager { | |
| 47 | + | obj := &RelativePointerManager{} | |
| 48 | + | obj.SetContext(ctx) | |
| 49 | + | ctx.Register(obj) | |
| 50 | + | return obj | |
| 51 | + | } | |
| 52 | + | ||
| 53 | + | // Used by the client to notify the server that it will no longer use this relative pointer manager object. | |
| 54 | + | func (o *RelativePointerManager) Destroy() error { | |
| 55 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_relative_pointer_manager_v1.destroy", Destructor: true}); err != nil { | |
| 56 | + | return err | |
| 57 | + | } | |
| 58 | + | return nil | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | // Create a relative pointer interface given a wl_pointer object. See the wp_relative_pointer interface for more details. | |
| 62 | + | func (o *RelativePointerManager) GetRelativePointer(pointer *cross_wl_pointer.Pointer) (*RelativePointer, error) { | |
| 63 | + | var arg1 wl.Object | |
| 64 | + | if pointer != nil { | |
| 65 | + | arg1 = pointer | |
| 66 | + | } | |
| 67 | + | child := &RelativePointer{} | |
| 68 | + | child.SetContext(o.Context()) | |
| 69 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_relative_pointer_manager_v1.get_relative_pointer", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 70 | + | return nil, err | |
| 71 | + | } | |
| 72 | + | return child, nil | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | // EventSignature returns the declared event argument types in wire order. | |
| 76 | + | func (o *RelativePointerManager) EventSignature(opcode uint16) (string, bool) { | |
| 77 | + | switch opcode { | |
| 78 | + | default: | |
| 79 | + | return "", false | |
| 80 | + | } | |
| 81 | + | } | |
| 82 | + | ||
| 83 | + | // Dispatch decodes one event on zwp_relative_pointer_manager_v1 and calls the registered handlers. | |
| 84 | + | func (o *RelativePointerManager) Dispatch(event *wl.Event) { | |
| 85 | + | switch event.Opcode { | |
| 86 | + | default: | |
| 87 | + | } | |
| 88 | + | } | |
| 89 | + | ||
| 90 | + | // RelativePointerInterface is the protocol interface name. | |
| 91 | + | const RelativePointerInterface = "zwp_relative_pointer_v1" | |
| 92 | + | ||
| 93 | + | // RelativePointer is the generated binding for zwp_relative_pointer_v1 version 1. | |
| 94 | + | type RelativePointer struct { | |
| 95 | + | wl.BaseProxy | |
| 96 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 97 | + | // handlers while another goroutine dispatches events. | |
| 98 | + | handlersMu sync.Mutex | |
| 99 | + | onRelativeMotion []func(utimeHi uint32, utimeLo uint32, dx wl.Fixed, dy wl.Fixed, dxUnaccel wl.Fixed, dyUnaccel wl.Fixed) | |
| 100 | + | } | |
| 101 | + | ||
| 102 | + | // NewRelativePointer returns an unbound RelativePointer. | |
| 103 | + | func NewRelativePointer(ctx *wl.Context) *RelativePointer { | |
| 104 | + | obj := &RelativePointer{} | |
| 105 | + | obj.SetContext(ctx) | |
| 106 | + | ctx.Register(obj) | |
| 107 | + | return obj | |
| 108 | + | } | |
| 109 | + | ||
| 110 | + | // release the relative pointer object | |
| 111 | + | func (o *RelativePointer) Destroy() error { | |
| 112 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_relative_pointer_v1.destroy", Destructor: true}); err != nil { | |
| 113 | + | return err | |
| 114 | + | } | |
| 115 | + | return nil | |
| 116 | + | } | |
| 117 | + | ||
| 118 | + | // OnRelativeMotion registers a handler for the relative_motion event. | |
| 119 | + | // | |
| 120 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 121 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 122 | + | func (o *RelativePointer) OnRelativeMotion(handler func(utimeHi uint32, utimeLo uint32, dx wl.Fixed, dy wl.Fixed, dxUnaccel wl.Fixed, dyUnaccel wl.Fixed)) { | |
| 123 | + | if handler == nil { | |
| 124 | + | return | |
| 125 | + | } | |
| 126 | + | o.handlersMu.Lock() | |
| 127 | + | defer o.handlersMu.Unlock() | |
| 128 | + | o.onRelativeMotion = append(o.onRelativeMotion, handler) | |
| 129 | + | } | |
| 130 | + | ||
| 131 | + | // handlersForRelativeMotion returns the handlers registered for relative_motion, taken | |
| 132 | + | // under the lock so a handler may register another handler while events are | |
| 133 | + | // being dispatched. | |
| 134 | + | func (o *RelativePointer) handlersForRelativeMotion() []func(utimeHi uint32, utimeLo uint32, dx wl.Fixed, dy wl.Fixed, dxUnaccel wl.Fixed, dyUnaccel wl.Fixed) { | |
| 135 | + | o.handlersMu.Lock() | |
| 136 | + | defer o.handlersMu.Unlock() | |
| 137 | + | return o.onRelativeMotion | |
| 138 | + | } | |
| 139 | + | ||
| 140 | + | // EventSignature returns the declared event argument types in wire order. | |
| 141 | + | func (o *RelativePointer) EventSignature(opcode uint16) (string, bool) { | |
| 142 | + | switch opcode { | |
| 143 | + | case 0: | |
| 144 | + | return "uint,uint,fixed,fixed,fixed,fixed,", true | |
| 145 | + | default: | |
| 146 | + | return "", false | |
| 147 | + | } | |
| 148 | + | } | |
| 149 | + | ||
| 150 | + | // Dispatch decodes one event on zwp_relative_pointer_v1 and calls the registered handlers. | |
| 151 | + | func (o *RelativePointer) Dispatch(event *wl.Event) { | |
| 152 | + | switch event.Opcode { | |
| 153 | + | case 0: // relative_motion | |
| 154 | + | utimeHi := event.Uint32() | |
| 155 | + | utimeLo := event.Uint32() | |
| 156 | + | dx := event.Fixed() | |
| 157 | + | dy := event.Fixed() | |
| 158 | + | dxUnaccel := event.Fixed() | |
| 159 | + | dyUnaccel := event.Fixed() | |
| 160 | + | ||
| 161 | + | for i, handler := range o.handlersForRelativeMotion() { | |
| 162 | + | _ = i | |
| 163 | + | handler(utimeHi, utimeLo, dx, dy, dxUnaccel, dyUnaccel) | |
| 164 | + | } | |
| 165 | + | default: | |
| 166 | + | } | |
| 167 | + | } | |
A client/render_extensions_test.go +864 -0
| @@ -0,0 +1,864 @@ | |||
| 1 | + | //go:build linux | |
| 2 | + | ||
| 3 | + | package client_test | |
| 4 | + | ||
| 5 | + | // Group A client bindings (presentation timing, surface render hints, | |
| 6 | + | // activation, pointer warp, colour and DRM lease). Every test drives a real | |
| 7 | + | // Display over a socketpair and checks the bytes the client writes and the | |
| 8 | + | // bytes it accepts, not just that a method exists. | |
| 9 | + | ||
| 10 | + | import ( | |
| 11 | + | "bytes" | |
| 12 | + | "encoding/binary" | |
| 13 | + | "errors" | |
| 14 | + | "net" | |
| 15 | + | "os" | |
| 16 | + | "testing" | |
| 17 | + | ||
| 18 | + | "github.com/bnema/go-wayland-bindings/client/alphamodifier" | |
| 19 | + | "github.com/bnema/go-wayland-bindings/client/colormanagement" | |
| 20 | + | "github.com/bnema/go-wayland-bindings/client/colorrepresentation" | |
| 21 | + | "github.com/bnema/go-wayland-bindings/client/committiming" | |
| 22 | + | "github.com/bnema/go-wayland-bindings/client/contenttype" | |
| 23 | + | "github.com/bnema/go-wayland-bindings/client/drmlease" | |
| 24 | + | "github.com/bnema/go-wayland-bindings/client/fifo" | |
| 25 | + | "github.com/bnema/go-wayland-bindings/client/pointerwarp" | |
| 26 | + | presentation "github.com/bnema/go-wayland-bindings/client/presentationtime" | |
| 27 | + | "github.com/bnema/go-wayland-bindings/client/tearingcontrol" | |
| 28 | + | "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 29 | + | "github.com/bnema/go-wayland-bindings/client/xdgactivation" | |
| 30 | + | "github.com/bnema/wlturbo" | |
| 31 | + | "golang.org/x/sys/unix" | |
| 32 | + | ) | |
| 33 | + | ||
| 34 | + | // rxEnv is the shared wire environment plus one object of each core kind the | |
| 35 | + | // group A protocols refer to. | |
| 36 | + | type rxEnv struct { | |
| 37 | + | *wireEnv | |
| 38 | + | surface *wayland.Surface | |
| 39 | + | output *wayland.Output | |
| 40 | + | seat *wayland.Seat | |
| 41 | + | pointer *wayland.Pointer | |
| 42 | + | } | |
| 43 | + | ||
| 44 | + | func rxNew(t *testing.T) *rxEnv { | |
| 45 | + | t.Helper() | |
| 46 | + | s := newWireEnv(t) | |
| 47 | + | return &rxEnv{wireEnv: s, surface: s.surface(), output: s.output(), seat: s.seat(), pointer: s.pointer()} | |
| 48 | + | } | |
| 49 | + | ||
| 50 | + | // rxWant reads one request and requires its exact object, opcode and | |
| 51 | + | // 32-bit word arguments. | |
| 52 | + | func rxWant(t *testing.T, p *net.UnixConn, id uint32, op uint16, want ...uint32) { | |
| 53 | + | t.Helper() | |
| 54 | + | wantRequestWords(t, p, id, op, want...) | |
| 55 | + | } | |
| 56 | + | ||
| 57 | + | // rxWantRaw reads one request and requires its exact object, opcode and body. | |
| 58 | + | func rxWantRaw(t *testing.T, p *net.UnixConn, id uint32, op uint16, want []byte) { | |
| 59 | + | t.Helper() | |
| 60 | + | gid, gop, body := request(t, p) | |
| 61 | + | if gid != id || gop != op || !bytes.Equal(body, want) { | |
| 62 | + | t.Fatalf("request object=%d op=%d body=%x, want object=%d op=%d body=%x", gid, gop, body, id, op, want) | |
| 63 | + | } | |
| 64 | + | } | |
| 65 | + | ||
| 66 | + | // rxRebind binds a second object to an interface that is already bound: the | |
| 67 | + | // earlier announcement is withdrawn first so BindNegotiated finds the new one. | |
| 68 | + | func rxRebind(e *rxEnv, oldName, name uint32, iface string, announced, supported uint32, proxy wlturbo.Proxy) { | |
| 69 | + | e.t.Helper() | |
| 70 | + | e.event(e.d.Registry().ID(), 1, wordBytes(oldName)...) | |
| 71 | + | e.bind(name, iface, announced, supported, proxy) | |
| 72 | + | } | |
| 73 | + | ||
| 74 | + | func rxOpenFDs(t *testing.T) int { | |
| 75 | + | t.Helper() | |
| 76 | + | ents, err := os.ReadDir("/proc/self/fd") | |
| 77 | + | noerr(t, err) | |
| 78 | + | return len(ents) | |
| 79 | + | } | |
| 80 | + | ||
| 81 | + | func rxTempFile(t *testing.T, content string) *os.File { | |
| 82 | + | t.Helper() | |
| 83 | + | f, err := os.CreateTemp(t.TempDir(), "rx") | |
| 84 | + | noerr(t, err) | |
| 85 | + | _, err = f.WriteString(content) | |
| 86 | + | noerr(t, err) | |
| 87 | + | t.Cleanup(func() { f.Close() }) | |
| 88 | + | return f | |
| 89 | + | } | |
| 90 | + | ||
| 91 | + | // rxReadFD reads want bytes at offset 0 of a descriptor and closes it. | |
| 92 | + | func rxReadFD(t *testing.T, fd int, want string) { | |
| 93 | + | t.Helper() | |
| 94 | + | buf := make([]byte, len(want)) | |
| 95 | + | n, err := unix.Pread(fd, buf, 0) | |
| 96 | + | noerr(t, err) | |
| 97 | + | if string(buf[:n]) != want { | |
| 98 | + | t.Fatalf("fd content %q, want %q", buf[:n], want) | |
| 99 | + | } | |
| 100 | + | noerr(t, unix.Close(fd)) | |
| 101 | + | } | |
| 102 | + | ||
| 103 | + | func TestPresentationFeedbackDestructorEvents(t *testing.T) { | |
| 104 | + | e := rxNew(t) | |
| 105 | + | pres := presentation.NewWpPresentation(e.d.Context()) | |
| 106 | + | bind(t, e.d, e.p, 1, presentation.WpPresentationInterface, 2, 2, pres) | |
| 107 | + | if pres.Version() != 2 { | |
| 108 | + | t.Fatalf("version %d", pres.Version()) | |
| 109 | + | } | |
| 110 | + | var clock uint32 | |
| 111 | + | pres.OnClockId(func(id uint32) { clock = id }) | |
| 112 | + | e.eventFD(pres.ID(), 0, wordBytes(1)) // CLOCK_MONOTONIC | |
| 113 | + | if clock != 1 { | |
| 114 | + | t.Fatalf("clock %d", clock) | |
| 115 | + | } | |
| 116 | + | ||
| 117 | + | fb1, err := pres.Feedback(e.surface) | |
| 118 | + | noerr(t, err) | |
| 119 | + | rxWant(t, e.p, pres.ID(), 1, e.surface.ID(), fb1.ID()) | |
| 120 | + | fb2, err := pres.Feedback(e.surface) | |
| 121 | + | noerr(t, err) | |
| 122 | + | rxWant(t, e.p, pres.ID(), 1, e.surface.ID(), fb2.ID()) | |
| 123 | + | if fb1.Version() != 2 || fb1.ID() == fb2.ID() { | |
| 124 | + | t.Fatalf("children id=%d/%d version=%d", fb1.ID(), fb2.ID(), fb1.Version()) | |
| 125 | + | } | |
| 126 | + | ||
| 127 | + | // Destroying the manager must not affect feedback it already created. | |
| 128 | + | noerr(t, pres.Destroy()) | |
| 129 | + | rxWant(t, e.p, pres.ID(), 0) | |
| 130 | + | if err := pres.Destroy(); err == nil { | |
| 131 | + | t.Fatal("second manager destroy accepted") | |
| 132 | + | } | |
| 133 | + | ||
| 134 | + | type presented struct{ hi, lo, nsec, refresh, seqHi, seqLo, flags uint32 } | |
| 135 | + | var outputs []uint32 | |
| 136 | + | var got []presented | |
| 137 | + | fb1.OnSyncOutput(func(id uint32) { outputs = append(outputs, id) }) | |
| 138 | + | fb1.OnPresented(func(hi, lo, nsec, refresh, sh, sl, flags uint32) { | |
| 139 | + | got = append(got, presented{hi, lo, nsec, refresh, sh, sl, flags}) | |
| 140 | + | }) | |
| 141 | + | discarded := 0 | |
| 142 | + | fb2.OnDiscarded(func() { discarded++ }) | |
| 143 | + | fb2.OnPresented(func(uint32, uint32, uint32, uint32, uint32, uint32, uint32) { t.Fatal("discarded feedback presented") }) | |
| 144 | + | ||
| 145 | + | e.eventFD(fb1.ID(), 0, wordBytes(e.output.ID())) | |
| 146 | + | if len(outputs) != 1 || outputs[0] != e.output.ID() { | |
| 147 | + | t.Fatalf("sync_output %v", outputs) | |
| 148 | + | } | |
| 149 | + | // A presented event missing its last argument is malformed and must not | |
| 150 | + | // destroy the object or reach the handler. | |
| 151 | + | send(t, e.p, payload(fb1.ID(), 1, wordBytes(0, 1, 2, 3, 4, 5)...)) | |
| 152 | + | if err := e.d.Dispatch(); !errors.Is(err, wlturbo.ErrMalformedFrame) { | |
| 153 | + | t.Fatalf("short presented = %v, want ErrMalformedFrame", err) | |
| 154 | + | } | |
| 155 | + | if len(got) != 0 { | |
| 156 | + | t.Fatal("handler ran for a malformed event") | |
| 157 | + | } | |
| 158 | + | flags := uint32(presentation.KIND_VSYNC | presentation.KIND_HW_CLOCK | presentation.KIND_ZERO_COPY) | |
| 159 | + | e.eventFD(fb1.ID(), 1, wordBytes(0, 0x12345678, 999999999, 16666666, 1, 2, flags)) | |
| 160 | + | want := presented{0, 0x12345678, 999999999, 16666666, 1, 2, 0xb} | |
| 161 | + | if len(got) != 1 || got[0] != want { | |
| 162 | + | t.Fatalf("presented %+v, want %+v", got, want) | |
| 163 | + | } | |
| 164 | + | ||
| 165 | + | e.eventFD(fb2.ID(), 2, nil) | |
| 166 | + | if discarded != 1 { | |
| 167 | + | t.Fatalf("discarded %d", discarded) | |
| 168 | + | } | |
| 169 | + | ||
| 170 | + | // Both terminal events are destructors: the objects are gone, so a | |
| 171 | + | // further event for either is an unknown-object protocol error. | |
| 172 | + | send(t, e.p, msg(fb1.ID(), 2)) | |
| 173 | + | if err := e.d.Dispatch(); !errors.Is(err, wlturbo.ErrUnknownObject) { | |
| 174 | + | t.Fatalf("event after presented = %v, want ErrUnknownObject", err) | |
| 175 | + | } | |
| 176 | + | send(t, e.p, msg(fb2.ID(), 2)) | |
| 177 | + | if err := e.d.Dispatch(); !errors.Is(err, wlturbo.ErrUnknownObject) { | |
| 178 | + | t.Fatalf("event after discarded = %v, want ErrUnknownObject", err) | |
| 179 | + | } | |
| 180 | + | } | |
| 181 | + | ||
| 182 | + | func TestPresentationVersionNegotiation(t *testing.T) { | |
| 183 | + | e := rxNew(t) | |
| 184 | + | old := presentation.NewWpPresentation(e.d.Context()) | |
| 185 | + | bind(t, e.d, e.p, 1, presentation.WpPresentationInterface, 1, 2, old) | |
| 186 | + | if old.Version() != 1 { | |
| 187 | + | t.Fatalf("server v1: bound at %d", old.Version()) | |
| 188 | + | } | |
| 189 | + | fb, err := old.Feedback(e.surface) | |
| 190 | + | noerr(t, err) | |
| 191 | + | if fb.Version() != 1 { | |
| 192 | + | t.Fatalf("child version %d, want the parent's 1", fb.Version()) | |
| 193 | + | } | |
| 194 | + | rxWant(t, e.p, old.ID(), 1, e.surface.ID(), fb.ID()) | |
| 195 | + | ||
| 196 | + | newer := presentation.NewWpPresentation(e.d.Context()) | |
| 197 | + | rxRebind(e, 1, 2, presentation.WpPresentationInterface, 5, 2, newer) | |
| 198 | + | if newer.Version() != 2 { | |
| 199 | + | t.Fatalf("server v5: bound at %d, want the supported 2", newer.Version()) | |
| 200 | + | } | |
| 201 | + | absent := presentation.NewWpPresentation(e.d.Context()) | |
| 202 | + | if _, err := e.d.Registry().BindNegotiated(presentation.WpPresentationInterface+"_x", 2, absent); !errors.Is(err, wlturbo.ErrGlobalNotFound) { | |
| 203 | + | t.Fatalf("absent global = %v", err) | |
| 204 | + | } | |
| 205 | + | requireNoWrite(t, e.p) | |
| 206 | + | } | |
| 207 | + | ||
| 208 | + | func TestColorManagementVersionRejection(t *testing.T) { | |
| 209 | + | e := rxNew(t) | |
| 210 | + | cm := colormanagement.NewWpColorManager(e.d.Context()) | |
| 211 | + | bind(t, e.d, e.p, 1, colormanagement.WpColorManagerInterface, 1, 3, cm) | |
| 212 | + | if cm.Version() != 1 { | |
| 213 | + | t.Fatalf("bound at %d", cm.Version()) | |
| 214 | + | } | |
| 215 | + | // Version 1 requests still work... | |
| 216 | + | surf, err := cm.GetSurface(e.surface) | |
| 217 | + | noerr(t, err) | |
| 218 | + | rxWant(t, e.p, cm.ID(), 2, surf.ID(), e.surface.ID()) | |
| 219 | + | // ...but the version 2 and 3 additions are refused locally, without a | |
| 220 | + | // byte reaching the compositor and without consuming an object ID. | |
| 221 | + | ref := colormanagement.NewWpImageDescriptionReference(e.d.Context()) | |
| 222 | + | ref.SetID(e.d.AllocateID()) | |
| 223 | + | e.d.Context().Register(ref) | |
| 224 | + | next := e.d.AllocateID() | |
| 225 | + | if _, err := cm.GetImageDescription(ref); !errors.Is(err, wlturbo.ErrVersionTooLow) { | |
| 226 | + | t.Fatalf("get_image_description on v1 = %v", err) | |
| 227 | + | } | |
| 228 | + | if _, err := cm.CreateWindowsBt2100(); !errors.Is(err, wlturbo.ErrVersionTooLow) { | |
| 229 | + | t.Fatalf("create_windows_bt2100 on v1 = %v", err) | |
| 230 | + | } | |
| 231 | + | requireNoWrite(t, e.p) | |
| 232 | + | if after := e.d.AllocateID(); after != next+1 { | |
| 233 | + | t.Fatalf("rejected requests allocated ids: %d then %d", next, after) | |
| 234 | + | } | |
| 235 | + | ||
| 236 | + | // Announced v2 admits get_image_description but still not the v3 request. | |
| 237 | + | cm2 := colormanagement.NewWpColorManager(e.d.Context()) | |
| 238 | + | rxRebind(e, 1, 2, colormanagement.WpColorManagerInterface, 2, 3, cm2) | |
| 239 | + | desc, err := cm2.GetImageDescription(ref) | |
| 240 | + | noerr(t, err) | |
| 241 | + | rxWant(t, e.p, cm2.ID(), 7, desc.ID(), ref.ID()) | |
| 242 | + | if _, err := cm2.CreateWindowsBt2100(); !errors.Is(err, wlturbo.ErrVersionTooLow) { | |
| 243 | + | t.Fatalf("create_windows_bt2100 on v2 = %v", err) | |
| 244 | + | } | |
| 245 | + | requireNoWrite(t, e.p) | |
| 246 | + | ||
| 247 | + | cm3 := colormanagement.NewWpColorManager(e.d.Context()) | |
| 248 | + | rxRebind(e, 2, 3, colormanagement.WpColorManagerInterface, 3, 3, cm3) | |
| 249 | + | bt, err := cm3.CreateWindowsBt2100() | |
| 250 | + | noerr(t, err) | |
| 251 | + | rxWant(t, e.p, cm3.ID(), 8, bt.ID()) | |
| 252 | + | } | |
| 253 | + | ||
| 254 | + | func TestColorManagementParametricWire(t *testing.T) { | |
| 255 | + | e := rxNew(t) | |
| 256 | + | cm := colormanagement.NewWpColorManager(e.d.Context()) | |
| 257 | + | bind(t, e.d, e.p, 1, colormanagement.WpColorManagerInterface, 3, 3, cm) | |
| 258 | + | ||
| 259 | + | var seq []string | |
| 260 | + | cm.OnSupportedIntent(func(v uint32) { | |
| 261 | + | if v != colormanagement.RENDER_INTENT_PERCEPTUAL { | |
| 262 | + | t.Fatal(v) | |
| 263 | + | } | |
| 264 | + | seq = append(seq, "intent") | |
| 265 | + | }) | |
| 266 | + | cm.OnSupportedFeature(func(v uint32) { | |
| 267 | + | if v != colormanagement.FEATURE_PARAMETRIC { | |
| 268 | + | t.Fatal(v) | |
| 269 | + | } | |
| 270 | + | seq = append(seq, "feature") | |
| 271 | + | }) | |
| 272 | + | cm.OnSupportedTfNamed(func(v uint32) { | |
| 273 | + | if v != colormanagement.TRANSFER_FUNCTION_ST2084_PQ { | |
| 274 | + | t.Fatal(v) | |
| 275 | + | } | |
| 276 | + | seq = append(seq, "tf") | |
| 277 | + | }) | |
| 278 | + | cm.OnSupportedPrimariesNamed(func(v uint32) { | |
| 279 | + | if v != colormanagement.PRIMARIES_SRGB { | |
| 280 | + | t.Fatal(v) | |
| 281 | + | } | |
| 282 | + | seq = append(seq, "primaries") | |
| 283 | + | }) | |
| 284 | + | cm.OnDone(func() { seq = append(seq, "done") }) | |
| 285 | + | e.eventFD(cm.ID(), 0, wordBytes(colormanagement.RENDER_INTENT_PERCEPTUAL)) | |
| 286 | + | e.eventFD(cm.ID(), 1, wordBytes(colormanagement.FEATURE_PARAMETRIC)) | |
| 287 | + | e.eventFD(cm.ID(), 2, wordBytes(colormanagement.TRANSFER_FUNCTION_ST2084_PQ)) | |
| 288 | + | e.eventFD(cm.ID(), 3, wordBytes(colormanagement.PRIMARIES_SRGB)) | |
| 289 | + | e.eventFD(cm.ID(), 4, nil) | |
| 290 | + | if len(seq) != 5 || seq[0] != "intent" || seq[4] != "done" { | |
| 291 | + | t.Fatalf("manager events %v", seq) | |
| 292 | + | } | |
| 293 | + | ||
| 294 | + | out, err := cm.GetOutput(e.output) | |
| 295 | + | noerr(t, err) | |
| 296 | + | rxWant(t, e.p, cm.ID(), 1, out.ID(), e.output.ID()) | |
| 297 | + | changed := 0 | |
| 298 | + | out.OnImageDescriptionChanged(func() { changed++ }) | |
| 299 | + | e.eventFD(out.ID(), 0, nil) | |
| 300 | + | if changed != 1 { | |
| 301 | + | t.Fatal(changed) | |
| 302 | + | } | |
| 303 | + | outDesc, err := out.GetImageDescription() | |
| 304 | + | noerr(t, err) | |
| 305 | + | rxWant(t, e.p, out.ID(), 1, outDesc.ID()) | |
| 306 | + | ||
| 307 | + | creator, err := cm.CreateParametricCreator() | |
| 308 | + | noerr(t, err) | |
| 309 | + | rxWant(t, e.p, cm.ID(), 5, creator.ID()) | |
| 310 | + | noerr(t, creator.SetTfNamed(colormanagement.TRANSFER_FUNCTION_ST2084_PQ)) | |
| 311 | + | rxWant(t, e.p, creator.ID(), 1, colormanagement.TRANSFER_FUNCTION_ST2084_PQ) | |
| 312 | + | noerr(t, creator.SetTfPower(22000)) | |
| 313 | + | rxWant(t, e.p, creator.ID(), 2, 22000) | |
| 314 | + | noerr(t, creator.SetPrimariesNamed(colormanagement.PRIMARIES_SRGB)) | |
| 315 | + | rxWant(t, e.p, creator.ID(), 3, colormanagement.PRIMARIES_SRGB) | |
| 316 | + | // Chromaticities are signed: negative values must survive as two's | |
| 317 | + | // complement words. | |
| 318 | + | noerr(t, creator.SetPrimaries(640000, 330000, 300000, 600000, 150000, 60000, -312700, 329000)) | |
| 319 | + | negWhiteX := int32(-312700) | |
| 320 | + | rxWant(t, e.p, creator.ID(), 4, 640000, 330000, 300000, 600000, 150000, 60000, uint32(negWhiteX), 329000) | |
| 321 | + | noerr(t, creator.SetLuminances(2, 10000, 203)) | |
| 322 | + | rxWant(t, e.p, creator.ID(), 5, 2, 10000, 203) | |
| 323 | + | noerr(t, creator.SetMasteringDisplayPrimaries(1, -2, 3, -4, 5, -6, 7, -8)) | |
| 324 | + | rxWant(t, e.p, creator.ID(), 6, 1, 0xfffffffe, 3, 0xfffffffc, 5, 0xfffffffa, 7, 0xfffffff8) | |
| 325 | + | noerr(t, creator.SetMasteringLuminance(50, 1000)) | |
| 326 | + | rxWant(t, e.p, creator.ID(), 7, 50, 1000) | |
| 327 | + | noerr(t, creator.SetMaxCll(1000)) | |
| 328 | + | rxWant(t, e.p, creator.ID(), 8, 1000) | |
| 329 | + | noerr(t, creator.SetMaxFall(400)) | |
| 330 | + | rxWant(t, e.p, creator.ID(), 9, 400) | |
| 331 | + | ||
| 332 | + | desc, err := creator.Create() | |
| 333 | + | noerr(t, err) | |
| 334 | + | rxWant(t, e.p, creator.ID(), 0, desc.ID()) | |
| 335 | + | // create is a destructor: the creator cannot be used again. | |
| 336 | + | if err := creator.SetMaxCll(1); err == nil { | |
| 337 | + | t.Fatal("request on a consumed creator accepted") | |
| 338 | + | } | |
| 339 | + | requireNoWrite(t, e.p) | |
| 340 | + | ||
| 341 | + | var ready [][2]uint32 | |
| 342 | + | desc.OnReady2(func(hi, lo uint32) { ready = append(ready, [2]uint32{hi, lo}) }) | |
| 343 | + | e.eventFD(desc.ID(), 2, wordBytes(0xdeadbeef, 7)) | |
| 344 | + | if len(ready) != 1 || ready[0] != [2]uint32{0xdeadbeef, 7} { | |
| 345 | + | t.Fatalf("ready2 %v", ready) | |
| 346 | + | } | |
| 347 | + | ||
| 348 | + | cs, err := cm.GetSurface(e.surface) | |
| 349 | + | noerr(t, err) | |
| 350 | + | rxWant(t, e.p, cm.ID(), 2, cs.ID(), e.surface.ID()) | |
| 351 | + | noerr(t, cs.SetImageDescription(desc, colormanagement.RENDER_INTENT_PERCEPTUAL)) | |
| 352 | + | rxWant(t, e.p, cs.ID(), 1, desc.ID(), colormanagement.RENDER_INTENT_PERCEPTUAL) | |
| 353 | + | noerr(t, cs.UnsetImageDescription()) | |
| 354 | + | rxWant(t, e.p, cs.ID(), 2) | |
| 355 | + | // A nil description travels as object 0. | |
| 356 | + | noerr(t, cs.SetImageDescription(nil, 0)) | |
| 357 | + | rxWant(t, e.p, cs.ID(), 1, 0, 0) | |
| 358 | + | ||
| 359 | + | // A refused creation arrives as failed(cause, msg). | |
| 360 | + | scrgb, err := cm.CreateWindowsScrgb() | |
| 361 | + | noerr(t, err) | |
| 362 | + | rxWant(t, e.p, cm.ID(), 6, scrgb.ID()) | |
| 363 | + | var cause uint32 | |
| 364 | + | var why string | |
| 365 | + | scrgb.OnFailed(func(c uint32, m string) { cause, why = c, m }) | |
| 366 | + | e.eventFD(scrgb.ID(), 0, cat(wordBytes(colormanagement.CAUSE_UNSUPPORTED), str("not supported"))) | |
| 367 | + | if cause != colormanagement.CAUSE_UNSUPPORTED || why != "not supported" { | |
| 368 | + | t.Fatalf("failed %d %q", cause, why) | |
| 369 | + | } | |
| 370 | + | ||
| 371 | + | fbk, err := cm.GetSurfaceFeedback(e.surface) | |
| 372 | + | noerr(t, err) | |
| 373 | + | rxWant(t, e.p, cm.ID(), 3, fbk.ID(), e.surface.ID()) | |
| 374 | + | var pref [2]uint32 | |
| 375 | + | fbk.OnPreferredChanged2(func(hi, lo uint32) { pref = [2]uint32{hi, lo} }) | |
| 376 | + | e.eventFD(fbk.ID(), 1, wordBytes(1, 2)) | |
| 377 | + | if pref != [2]uint32{1, 2} { | |
| 378 | + | t.Fatalf("preferred_changed2 %v", pref) | |
| 379 | + | } | |
| 380 | + | pd, err := fbk.GetPreferredParametric() | |
| 381 | + | noerr(t, err) | |
| 382 | + | rxWant(t, e.p, fbk.ID(), 2, pd.ID()) | |
| 383 | + | ||
| 384 | + | noerr(t, desc.Destroy()) | |
| 385 | + | rxWant(t, e.p, desc.ID(), 0) | |
| 386 | + | noerr(t, cs.Destroy()) | |
| 387 | + | rxWant(t, e.p, cs.ID(), 0) | |
| 388 | + | noerr(t, cm.Destroy()) | |
| 389 | + | rxWant(t, e.p, cm.ID(), 0) | |
| 390 | + | } | |
| 391 | + | ||
| 392 | + | func TestColorManagementICCDescriptorOwnership(t *testing.T) { | |
| 393 | + | e := rxNew(t) | |
| 394 | + | cm := colormanagement.NewWpColorManager(e.d.Context()) | |
| 395 | + | bind(t, e.d, e.p, 1, colormanagement.WpColorManagerInterface, 3, 3, cm) | |
| 396 | + | ||
| 397 | + | icc, err := cm.CreateIccCreator() | |
| 398 | + | noerr(t, err) | |
| 399 | + | rxWant(t, e.p, cm.ID(), 4, icc.ID()) | |
| 400 | + | ||
| 401 | + | // Request direction: the descriptor is attached as SCM_RIGHTS, the body | |
| 402 | + | // carries only offset and length, and the client closes its copy. | |
| 403 | + | profile := rxTempFile(t, "ICC-PROFILE-BYTES") | |
| 404 | + | fd, err := unix.Dup(int(profile.Fd())) | |
| 405 | + | noerr(t, err) | |
| 406 | + | noerr(t, icc.SetIccFile(fd, 4, 13)) | |
| 407 | + | requireFDClosed(t, fd) | |
| 408 | + | id, op, body, fds := recvRequestFDs(t, e.p) | |
| 409 | + | if id != icc.ID() || op != 1 || len(body) != 8 || | |
| 410 | + | binary.NativeEndian.Uint32(body) != 4 || binary.NativeEndian.Uint32(body[4:]) != 13 || len(fds) != 1 { | |
| 411 | + | t.Fatalf("set_icc_file id=%d op=%d body=%x fds=%v", id, op, body, fds) | |
| 412 | + | } | |
| 413 | + | rxReadFD(t, fds[0], "ICC-PROFILE-BYTES") | |
| 414 | + | ||
| 415 | + | // A failed send must leave the descriptor with the caller. | |
| 416 | + | fd2, err := unix.Dup(int(profile.Fd())) | |
| 417 | + | noerr(t, err) | |
| 418 | + | created, err := icc.Create() | |
| 419 | + | noerr(t, err) | |
| 420 | + | rxWant(t, e.p, icc.ID(), 0, created.ID()) | |
| 421 | + | if err := icc.SetIccFile(fd2, 0, 1); err == nil { | |
| 422 | + | t.Fatal("set_icc_file on a consumed creator accepted") | |
| 423 | + | } | |
| 424 | + | if _, err := unix.FcntlInt(uintptr(fd2), unix.F_GETFD, 0); err != nil { | |
| 425 | + | t.Fatalf("descriptor of a rejected request was closed: %v", err) | |
| 426 | + | } | |
| 427 | + | noerr(t, unix.Close(fd2)) | |
| 428 | + | requireNoWrite(t, e.p) | |
| 429 | + | ||
| 430 | + | // Event direction: image_description_info.icc_file carries an owned fd. | |
| 431 | + | info, err := created.GetInformation() | |
| 432 | + | noerr(t, err) | |
| 433 | + | rxWant(t, e.p, created.ID(), 1, info.ID()) | |
| 434 | + | ||
| 435 | + | // The first handler is offered the descriptor and must Take it during | |
| 436 | + | // dispatch; anything left is closed when dispatch returns. Later handlers | |
| 437 | + | // only ever see nil. | |
| 438 | + | var first, second *wlturbo.OwnedFD | |
| 439 | + | var taken int | |
| 440 | + | var size uint32 | |
| 441 | + | src2 := rxTempFile(t, "ICC-FROM-COMPOSITOR") | |
| 442 | + | before := rxOpenFDs(t) | |
| 443 | + | info.OnIccFile(func(f *wlturbo.OwnedFD, n uint32) { | |
| 444 | + | first, size = f, n | |
| 445 | + | var err error | |
| 446 | + | taken, err = f.Take() | |
| 447 | + | noerr(t, err) | |
| 448 | + | }) | |
| 449 | + | info.OnIccFile(func(f *wlturbo.OwnedFD, n uint32) { second = f }) | |
| 450 | + | var prim [8]int32 | |
| 451 | + | info.OnPrimaries(func(a, b, c, d, e2, f, g, h int32) { prim = [8]int32{a, b, c, d, e2, f, g, h} }) | |
| 452 | + | doneCalls := 0 | |
| 453 | + | info.OnDone(func() { doneCalls++ }) | |
| 454 | + | ||
| 455 | + | e.eventFD(info.ID(), 1, wordBytes(19), int(src2.Fd())) | |
| 456 | + | if first == nil || second != nil || size != 19 { | |
| 457 | + | t.Fatalf("icc_file first=%v second=%v size=%d", first, second, size) | |
| 458 | + | } | |
| 459 | + | // The taken descriptor survives dispatch and is now the caller's. | |
| 460 | + | if now := rxOpenFDs(t); now != before+1 { | |
| 461 | + | t.Fatalf("open fds %d -> %d, want +1", before, now) | |
| 462 | + | } | |
| 463 | + | rxReadFD(t, taken, "ICC-FROM-COMPOSITOR") | |
| 464 | + | if now := rxOpenFDs(t); now != before { | |
| 465 | + | t.Fatalf("open fds %d after close, want %d", now, before) | |
| 466 | + | } | |
| 467 | + | if _, err := first.Take(); err == nil { | |
| 468 | + | t.Fatal("descriptor taken twice") | |
| 469 | + | } | |
| 470 | + | ||
| 471 | + | e.eventFD(info.ID(), 2, wordBytes(1, 0xfffffffe, 3, 4, 5, 6, 7, 8)) | |
| 472 | + | if prim != [8]int32{1, -2, 3, 4, 5, 6, 7, 8} { | |
| 473 | + | t.Fatalf("primaries %v", prim) | |
| 474 | + | } | |
| 475 | + | e.eventFD(info.ID(), 0, nil) | |
| 476 | + | if doneCalls != 1 { | |
| 477 | + | t.Fatal(doneCalls) | |
| 478 | + | } | |
| 479 | + | send(t, e.p, msg(info.ID(), 0)) | |
| 480 | + | if err := e.d.Dispatch(); !errors.Is(err, wlturbo.ErrUnknownObject) { | |
| 481 | + | t.Fatalf("event after done = %v", err) | |
| 482 | + | } | |
| 483 | + | ||
| 484 | + | // A descriptor no handler takes is closed when dispatch returns. | |
| 485 | + | info2, err := created.GetInformation() | |
| 486 | + | noerr(t, err) | |
| 487 | + | rxWant(t, e.p, created.ID(), 1, info2.ID()) | |
| 488 | + | info2.OnIccFile(func(f *wlturbo.OwnedFD, n uint32) {}) | |
| 489 | + | before = rxOpenFDs(t) | |
| 490 | + | e.eventFD(info2.ID(), 1, wordBytes(19), int(src2.Fd())) | |
| 491 | + | if now := rxOpenFDs(t); now != before { | |
| 492 | + | t.Fatalf("unclaimed descriptor leaked: %d -> %d", before, now) | |
| 493 | + | } | |
| 494 | + | // An icc_file event with no descriptor is a protocol error. | |
| 495 | + | send(t, e.p, payload(info2.ID(), 1, wordBytes(19)...)) | |
| 496 | + | if err := e.d.Dispatch(); !errors.Is(err, wlturbo.ErrMalformedFrame) { | |
| 497 | + | t.Fatalf("icc_file without fd = %v", err) | |
| 498 | + | } | |
| 499 | + | } | |
| 500 | + | ||
| 501 | + | func TestDRMLeaseDescriptorsAndLifecycle(t *testing.T) { | |
| 502 | + | e := rxNew(t) | |
| 503 | + | dev := drmlease.NewWpDrmLeaseDevice(e.d.Context()) | |
| 504 | + | bind(t, e.d, e.p, 1, drmlease.WpDrmLeaseDeviceInterface, 1, 1, dev) | |
| 505 | + | ||
| 506 | + | var seq []string | |
| 507 | + | var drm, drm2 *wlturbo.OwnedFD | |
| 508 | + | var drmFD int | |
| 509 | + | dev.OnDrmFd(func(f *wlturbo.OwnedFD) { | |
| 510 | + | drm = f | |
| 511 | + | var err error | |
| 512 | + | drmFD, err = f.Take() | |
| 513 | + | noerr(t, err) | |
| 514 | + | seq = append(seq, "drm_fd") | |
| 515 | + | }) | |
| 516 | + | dev.OnDrmFd(func(f *wlturbo.OwnedFD) { drm2 = f }) | |
| 517 | + | var conn *drmlease.WpDrmLeaseConnector | |
| 518 | + | dev.OnConnector(func(c *drmlease.WpDrmLeaseConnector) { conn = c; seq = append(seq, "connector") }) | |
| 519 | + | dev.OnDone(func() { seq = append(seq, "done") }) | |
| 520 | + | ||
| 521 | + | node := rxTempFile(t, "DRM-NODE") | |
| 522 | + | before := rxOpenFDs(t) | |
| 523 | + | e.eventFD(dev.ID(), 0, nil, int(node.Fd())) | |
| 524 | + | if drm == nil || drm2 != nil { | |
| 525 | + | t.Fatalf("drm_fd owners: first=%v second=%v", drm, drm2) | |
| 526 | + | } | |
| 527 | + | if now := rxOpenFDs(t); now != before+1 { | |
| 528 | + | t.Fatalf("taken drm_fd not live: %d -> %d", before, now) | |
| 529 | + | } | |
| 530 | + | rxReadFD(t, drmFD, "DRM-NODE") | |
| 531 | + | if now := rxOpenFDs(t); now != before { | |
| 532 | + | t.Fatalf("drm_fd leaked: %d -> %d", before, now) | |
| 533 | + | } | |
| 534 | + | ||
| 535 | + | // new_id event: the child is created at the server-chosen ID and | |
| 536 | + | // inherits the device version. | |
| 537 | + | e.eventFD(dev.ID(), 1, wordBytes(serverID)) | |
| 538 | + | if conn == nil || conn.ID() != serverID || conn.Version() != 1 { | |
| 539 | + | t.Fatalf("connector %+v", conn) | |
| 540 | + | } | |
| 541 | + | var name, desc string | |
| 542 | + | var connID uint32 | |
| 543 | + | withdrawn := 0 | |
| 544 | + | conn.OnName(func(s string) { name = s }) | |
| 545 | + | conn.OnDescription(func(s string) { desc = s }) | |
| 546 | + | conn.OnConnectorId(func(v uint32) { connID = v }) | |
| 547 | + | conn.OnDone(func() { seq = append(seq, "conn_done") }) | |
| 548 | + | conn.OnWithdrawn(func() { withdrawn++ }) | |
| 549 | + | e.eventFD(conn.ID(), 0, str("HDMI-A-1")) | |
| 550 | + | e.eventFD(conn.ID(), 1, str("Acme 4K")) | |
| 551 | + | e.eventFD(conn.ID(), 2, wordBytes(77)) | |
| 552 | + | e.eventFD(conn.ID(), 3, nil) | |
| 553 | + | e.eventFD(dev.ID(), 2, nil) | |
| 554 | + | if name != "HDMI-A-1" || desc != "Acme 4K" || connID != 77 || len(seq) != 4 || seq[3] != "done" { | |
| 555 | + | t.Fatalf("connector %q %q %d seq %v", name, desc, connID, seq) | |
| 556 | + | } | |
| 557 | + | ||
| 558 | + | req, err := dev.CreateLeaseRequest() | |
| 559 | + | noerr(t, err) | |
| 560 | + | rxWant(t, e.p, dev.ID(), 0, req.ID()) | |
| 561 | + | noerr(t, req.RequestConnector(conn)) | |
| 562 | + | rxWant(t, e.p, req.ID(), 0, conn.ID()) | |
| 563 | + | lease, err := req.Submit() | |
| 564 | + | noerr(t, err) | |
| 565 | + | rxWant(t, e.p, req.ID(), 1, lease.ID()) | |
| 566 | + | // submit is a destructor: the request is spent. | |
| 567 | + | if err := req.RequestConnector(conn); err == nil { | |
| 568 | + | t.Fatal("request after submit accepted") | |
| 569 | + | } | |
| 570 | + | if _, err := req.Submit(); err == nil { | |
| 571 | + | t.Fatal("second submit accepted") | |
| 572 | + | } | |
| 573 | + | requireNoWrite(t, e.p) | |
| 574 | + | ||
| 575 | + | var leased *wlturbo.OwnedFD | |
| 576 | + | var leasedFD int | |
| 577 | + | finished := 0 | |
| 578 | + | lease.OnLeaseFd(func(f *wlturbo.OwnedFD) { | |
| 579 | + | leased = f | |
| 580 | + | var err error | |
| 581 | + | leasedFD, err = f.Take() | |
| 582 | + | noerr(t, err) | |
| 583 | + | }) | |
| 584 | + | lease.OnFinished(func() { finished++ }) | |
| 585 | + | lfile := rxTempFile(t, "LEASED") | |
| 586 | + | e.eventFD(lease.ID(), 0, nil, int(lfile.Fd())) | |
| 587 | + | if leased == nil { | |
| 588 | + | t.Fatal("lease_fd not delivered") | |
| 589 | + | } | |
| 590 | + | rxReadFD(t, leasedFD, "LEASED") | |
| 591 | + | e.eventFD(lease.ID(), 1, nil) | |
| 592 | + | if finished != 1 { | |
| 593 | + | t.Fatal(finished) | |
| 594 | + | } | |
| 595 | + | noerr(t, lease.Destroy()) | |
| 596 | + | rxWant(t, e.p, lease.ID(), 0) | |
| 597 | + | ||
| 598 | + | // A denied lease sends finished with no descriptor at all. | |
| 599 | + | req2, err := dev.CreateLeaseRequest() | |
| 600 | + | noerr(t, err) | |
| 601 | + | rxWant(t, e.p, dev.ID(), 0, req2.ID()) | |
| 602 | + | noerr(t, req2.RequestConnector(conn)) | |
| 603 | + | rxWant(t, e.p, req2.ID(), 0, conn.ID()) | |
| 604 | + | denied, err := req2.Submit() | |
| 605 | + | noerr(t, err) | |
| 606 | + | rxWant(t, e.p, req2.ID(), 1, denied.ID()) | |
| 607 | + | deniedFD := 0 | |
| 608 | + | deniedDone := 0 | |
| 609 | + | denied.OnLeaseFd(func(*wlturbo.OwnedFD) { deniedFD++ }) | |
| 610 | + | denied.OnFinished(func() { deniedDone++ }) | |
| 611 | + | e.eventFD(denied.ID(), 1, nil) | |
| 612 | + | if deniedFD != 0 || deniedDone != 1 { | |
| 613 | + | t.Fatalf("denied lease fd=%d finished=%d", deniedFD, deniedDone) | |
| 614 | + | } | |
| 615 | + | ||
| 616 | + | // An unclaimed lease descriptor is closed by the dispatcher. | |
| 617 | + | req3, err := dev.CreateLeaseRequest() | |
| 618 | + | noerr(t, err) | |
| 619 | + | rxWant(t, e.p, dev.ID(), 0, req3.ID()) | |
| 620 | + | noerr(t, req3.RequestConnector(conn)) | |
| 621 | + | rxWant(t, e.p, req3.ID(), 0, conn.ID()) | |
| 622 | + | l3, err := req3.Submit() | |
| 623 | + | noerr(t, err) | |
| 624 | + | rxWant(t, e.p, req3.ID(), 1, l3.ID()) | |
| 625 | + | l3.OnLeaseFd(func(*wlturbo.OwnedFD) {}) | |
| 626 | + | before = rxOpenFDs(t) | |
| 627 | + | e.eventFD(l3.ID(), 0, nil, int(lfile.Fd())) | |
| 628 | + | if now := rxOpenFDs(t); now != before { | |
| 629 | + | t.Fatalf("unclaimed lease fd leaked: %d -> %d", before, now) | |
| 630 | + | } | |
| 631 | + | // lease_fd without SCM_RIGHTS is malformed. | |
| 632 | + | send(t, e.p, msg(l3.ID(), 0)) | |
| 633 | + | if err := e.d.Dispatch(); !errors.Is(err, wlturbo.ErrMalformedFrame) { | |
| 634 | + | t.Fatalf("lease_fd without fd = %v", err) | |
| 635 | + | } | |
| 636 | + | ||
| 637 | + | e.eventFD(conn.ID(), 4, nil) | |
| 638 | + | if withdrawn != 1 { | |
| 639 | + | t.Fatal(withdrawn) | |
| 640 | + | } | |
| 641 | + | noerr(t, conn.Destroy()) | |
| 642 | + | rxWant(t, e.p, conn.ID(), 0) | |
| 643 | + | ||
| 644 | + | // release is not a destructor: the device stays alive, and keeps | |
| 645 | + | // receiving events, until the compositor answers with released. | |
| 646 | + | noerr(t, dev.Release()) | |
| 647 | + | rxWant(t, e.p, dev.ID(), 1) | |
| 648 | + | e.eventFD(dev.ID(), 2, nil) | |
| 649 | + | released := 0 | |
| 650 | + | dev.OnReleased(func() { released++ }) | |
| 651 | + | e.eventFD(dev.ID(), 3, nil) | |
| 652 | + | if released != 1 { | |
| 653 | + | t.Fatal(released) | |
| 654 | + | } | |
| 655 | + | if _, err := dev.CreateLeaseRequest(); err == nil { | |
| 656 | + | t.Fatal("request on a released device accepted") | |
| 657 | + | } | |
| 658 | + | requireNoWrite(t, e.p) | |
| 659 | + | send(t, e.p, msg(dev.ID(), 2)) | |
| 660 | + | if err := e.d.Dispatch(); !errors.Is(err, wlturbo.ErrUnknownObject) { | |
| 661 | + | t.Fatalf("event after released = %v", err) | |
| 662 | + | } | |
| 663 | + | } | |
| 664 | + | ||
| 665 | + | func TestDRMLeaseDeviceWithoutDescriptorIsMalformed(t *testing.T) { | |
| 666 | + | e := rxNew(t) | |
| 667 | + | dev := drmlease.NewWpDrmLeaseDevice(e.d.Context()) | |
| 668 | + | bind(t, e.d, e.p, 1, drmlease.WpDrmLeaseDeviceInterface, 1, 1, dev) | |
| 669 | + | called := false | |
| 670 | + | dev.OnDrmFd(func(*wlturbo.OwnedFD) { called = true }) | |
| 671 | + | send(t, e.p, msg(dev.ID(), 0)) | |
| 672 | + | if err := e.d.Dispatch(); !errors.Is(err, wlturbo.ErrMalformedFrame) { | |
| 673 | + | t.Fatalf("drm_fd without fd = %v", err) | |
| 674 | + | } | |
| 675 | + | if called { | |
| 676 | + | t.Fatal("handler ran without a descriptor") | |
| 677 | + | } | |
| 678 | + | } | |
| 679 | + | ||
| 680 | + | func TestSurfaceHintProtocolsWire(t *testing.T) { | |
| 681 | + | e := rxNew(t) | |
| 682 | + | ||
| 683 | + | // alpha modifier | |
| 684 | + | am := alphamodifier.NewWpAlphaModifier(e.d.Context()) | |
| 685 | + | bind(t, e.d, e.p, 1, alphamodifier.WpAlphaModifierInterface, 1, 1, am) | |
| 686 | + | as, err := am.GetSurface(e.surface) | |
| 687 | + | noerr(t, err) | |
| 688 | + | rxWant(t, e.p, am.ID(), 1, as.ID(), e.surface.ID()) | |
| 689 | + | noerr(t, as.SetMultiplier(0xffffffff)) | |
| 690 | + | rxWant(t, e.p, as.ID(), 1, 0xffffffff) | |
| 691 | + | noerr(t, as.SetMultiplier(0x80000000)) | |
| 692 | + | rxWant(t, e.p, as.ID(), 1, 0x80000000) | |
| 693 | + | // Destroying the manager leaves its children usable. | |
| 694 | + | noerr(t, am.Destroy()) | |
| 695 | + | rxWant(t, e.p, am.ID(), 0) | |
| 696 | + | noerr(t, as.SetMultiplier(0)) | |
| 697 | + | rxWant(t, e.p, as.ID(), 1, 0) | |
| 698 | + | noerr(t, as.Destroy()) | |
| 699 | + | rxWant(t, e.p, as.ID(), 0) | |
| 700 | + | if err := as.SetMultiplier(1); err == nil { | |
| 701 | + | t.Fatal("request after destroy accepted") | |
| 702 | + | } | |
| 703 | + | requireNoWrite(t, e.p) | |
| 704 | + | ||
| 705 | + | // commit timing | |
| 706 | + | ct := committiming.NewWpCommitTimingManager(e.d.Context()) | |
| 707 | + | bind(t, e.d, e.p, 2, committiming.WpCommitTimingManagerInterface, 1, 1, ct) | |
| 708 | + | timer, err := ct.GetTimer(e.surface) | |
| 709 | + | noerr(t, err) | |
| 710 | + | rxWant(t, e.p, ct.ID(), 1, timer.ID(), e.surface.ID()) | |
| 711 | + | noerr(t, timer.SetTimestamp(1, 0xfffffffe, 999999999)) | |
| 712 | + | rxWant(t, e.p, timer.ID(), 0, 1, 0xfffffffe, 999999999) | |
| 713 | + | noerr(t, timer.Destroy()) | |
| 714 | + | rxWant(t, e.p, timer.ID(), 1) | |
| 715 | + | noerr(t, ct.Destroy()) | |
| 716 | + | rxWant(t, e.p, ct.ID(), 0) | |
| 717 | + | ||
| 718 | + | // fifo: argument-less requests are bare 8-byte headers | |
| 719 | + | ff := fifo.NewWpFifoManager(e.d.Context()) | |
| 720 | + | bind(t, e.d, e.p, 3, fifo.WpFifoManagerInterface, 1, 1, ff) | |
| 721 | + | f, err := ff.GetFifo(e.surface) | |
| 722 | + | noerr(t, err) | |
| 723 | + | rxWant(t, e.p, ff.ID(), 1, f.ID(), e.surface.ID()) | |
| 724 | + | noerr(t, f.SetBarrier()) | |
| 725 | + | rxWant(t, e.p, f.ID(), 0) | |
| 726 | + | noerr(t, f.WaitBarrier()) | |
| 727 | + | rxWant(t, e.p, f.ID(), 1) | |
| 728 | + | noerr(t, f.Destroy()) | |
| 729 | + | rxWant(t, e.p, f.ID(), 2) | |
| 730 | + | noerr(t, ff.Destroy()) | |
| 731 | + | rxWant(t, e.p, ff.ID(), 0) | |
| 732 | + | ||
| 733 | + | // tearing control | |
| 734 | + | tc := tearingcontrol.NewWpTearingControlManager(e.d.Context()) | |
| 735 | + | bind(t, e.d, e.p, 4, tearingcontrol.WpTearingControlManagerInterface, 1, 1, tc) | |
| 736 | + | tear, err := tc.GetTearingControl(e.surface) | |
| 737 | + | noerr(t, err) | |
| 738 | + | rxWant(t, e.p, tc.ID(), 1, tear.ID(), e.surface.ID()) | |
| 739 | + | noerr(t, tear.SetPresentationHint(tearingcontrol.PRESENTATION_HINT_ASYNC)) | |
| 740 | + | rxWant(t, e.p, tear.ID(), 0, 1) | |
| 741 | + | noerr(t, tear.SetPresentationHint(tearingcontrol.PRESENTATION_HINT_VSYNC)) | |
| 742 | + | rxWant(t, e.p, tear.ID(), 0, 0) | |
| 743 | + | noerr(t, tear.Destroy()) | |
| 744 | + | rxWant(t, e.p, tear.ID(), 1) | |
| 745 | + | noerr(t, tc.Destroy()) | |
| 746 | + | rxWant(t, e.p, tc.ID(), 0) | |
| 747 | + | } | |
| 748 | + | ||
| 749 | + | func TestContentTypeSurfaceHintWire(t *testing.T) { | |
| 750 | + | e := rxNew(t) | |
| 751 | + | mgr := contenttype.NewWpContentTypeManager(e.d.Context()) | |
| 752 | + | bind(t, e.d, e.p, 1, contenttype.WpContentTypeManagerInterface, 1, 1, mgr) | |
| 753 | + | ct, err := mgr.GetSurfaceContentType(e.surface) | |
| 754 | + | noerr(t, err) | |
| 755 | + | rxWant(t, e.p, mgr.ID(), 1, ct.ID(), e.surface.ID()) | |
| 756 | + | for _, typ := range []uint32{contenttype.TYPE_GAME, contenttype.TYPE_VIDEO, contenttype.TYPE_PHOTO, contenttype.TYPE_NONE} { | |
| 757 | + | noerr(t, ct.SetContentType(typ)) | |
| 758 | + | rxWant(t, e.p, ct.ID(), 1, typ) | |
| 759 | + | } | |
| 760 | + | // The manager may go first; its child keeps working. | |
| 761 | + | noerr(t, mgr.Destroy()) | |
| 762 | + | rxWant(t, e.p, mgr.ID(), 0) | |
| 763 | + | noerr(t, ct.SetContentType(contenttype.TYPE_GAME)) | |
| 764 | + | rxWant(t, e.p, ct.ID(), 1, 3) | |
| 765 | + | noerr(t, ct.Destroy()) | |
| 766 | + | rxWant(t, e.p, ct.ID(), 0) | |
| 767 | + | if err := ct.SetContentType(1); err == nil { | |
| 768 | + | t.Fatal("request after destroy accepted") | |
| 769 | + | } | |
| 770 | + | requireNoWrite(t, e.p) | |
| 771 | + | // The interface has no events: any event is an unknown opcode. | |
| 772 | + | ct2 := contenttype.NewWpContentType(e.d.Context()) | |
| 773 | + | ct2.SetID(e.d.AllocateID()) | |
| 774 | + | e.d.Context().Register(ct2) | |
| 775 | + | send(t, e.p, msg(ct2.ID(), 0)) | |
| 776 | + | if err := e.d.Dispatch(); !errors.Is(err, wlturbo.ErrUnknownOpcode) { | |
| 777 | + | t.Fatalf("event on eventless interface = %v", err) | |
| 778 | + | } | |
| 779 | + | } | |
| 780 | + | ||
| 781 | + | func TestXdgActivationTokenWireAndDoneEvent(t *testing.T) { | |
| 782 | + | e := rxNew(t) | |
| 783 | + | act := xdgactivation.NewXdgActivation(e.d.Context()) | |
| 784 | + | bind(t, e.d, e.p, 1, xdgactivation.XdgActivationInterface, 1, 1, act) | |
| 785 | + | tok, err := act.GetActivationToken() | |
| 786 | + | noerr(t, err) | |
| 787 | + | rxWant(t, e.p, act.ID(), 1, tok.ID()) | |
| 788 | + | noerr(t, tok.SetSerial(0x01020304, e.seat)) | |
| 789 | + | rxWant(t, e.p, tok.ID(), 0, 0x01020304, e.seat.ID()) | |
| 790 | + | noerr(t, tok.SetAppId("org.example.App")) | |
| 791 | + | rxWantRaw(t, e.p, tok.ID(), 1, str("org.example.App")) | |
| 792 | + | noerr(t, tok.SetSurface(e.surface)) | |
| 793 | + | rxWant(t, e.p, tok.ID(), 2, e.surface.ID()) | |
| 794 | + | noerr(t, tok.Commit()) | |
| 795 | + | rxWant(t, e.p, tok.ID(), 3) | |
| 796 | + | ||
| 797 | + | var got string | |
| 798 | + | tok.OnDone(func(s string) { got = s }) | |
| 799 | + | e.eventFD(tok.ID(), 0, str("activation-token-é")) | |
| 800 | + | if got != "activation-token-é" { | |
| 801 | + | t.Fatalf("done token %q", got) | |
| 802 | + | } | |
| 803 | + | // A string missing its NUL terminator is rejected before any handler. | |
| 804 | + | got = "" | |
| 805 | + | send(t, e.p, payload(tok.ID(), 0, arr([]byte("abc"))...)) | |
| 806 | + | if err := e.d.Dispatch(); !errors.Is(err, wlturbo.ErrMalformedFrame) || got != "" { | |
| 807 | + | t.Fatalf("unterminated string = %v handler=%q", err, got) | |
| 808 | + | } | |
| 809 | + | ||
| 810 | + | noerr(t, act.Activate("activation-token-é", e.surface)) | |
| 811 | + | rxWantRaw(t, e.p, act.ID(), 2, cat(str("activation-token-é"), wordBytes(e.surface.ID()))) | |
| 812 | + | noerr(t, tok.Destroy()) | |
| 813 | + | rxWant(t, e.p, tok.ID(), 4) | |
| 814 | + | noerr(t, act.Destroy()) | |
| 815 | + | rxWant(t, e.p, act.ID(), 0) | |
| 816 | + | } | |
| 817 | + | ||
| 818 | + | func TestPointerWarpFixedWire(t *testing.T) { | |
| 819 | + | e := rxNew(t) | |
| 820 | + | pw := pointerwarp.NewWpPointerWarp(e.d.Context()) | |
| 821 | + | bind(t, e.d, e.p, 1, pointerwarp.WpPointerWarpInterface, 1, 1, pw) | |
| 822 | + | noerr(t, pw.WarpPointer(e.surface, e.pointer, wlturbo.NewFixed(10.5), wlturbo.NewFixed(-3.25), 0xabcdef01)) | |
| 823 | + | rxWant(t, e.p, pw.ID(), 1, e.surface.ID(), e.pointer.ID(), 2688, uint32(0xfffffcc0), 0xabcdef01) | |
| 824 | + | noerr(t, pw.Destroy()) | |
| 825 | + | rxWant(t, e.p, pw.ID(), 0) | |
| 826 | + | if err := pw.WarpPointer(e.surface, e.pointer, 0, 0, 1); err == nil { | |
| 827 | + | t.Fatal("warp after destroy accepted") | |
| 828 | + | } | |
| 829 | + | requireNoWrite(t, e.p) | |
| 830 | + | } | |
| 831 | + | ||
| 832 | + | func TestColorRepresentationWireAndCapabilityEvents(t *testing.T) { | |
| 833 | + | e := rxNew(t) | |
| 834 | + | mgr := colorrepresentation.NewWpColorRepresentationManager(e.d.Context()) | |
| 835 | + | bind(t, e.d, e.p, 1, colorrepresentation.WpColorRepresentationManagerInterface, 1, 1, mgr) | |
| 836 | + | ||
| 837 | + | var alphas []uint32 | |
| 838 | + | var combos [][2]uint32 | |
| 839 | + | done := 0 | |
| 840 | + | mgr.OnSupportedAlphaMode(func(v uint32) { alphas = append(alphas, v) }) | |
| 841 | + | mgr.OnSupportedCoefficientsAndRanges(func(c, r uint32) { combos = append(combos, [2]uint32{c, r}) }) | |
| 842 | + | mgr.OnDone(func() { done++ }) | |
| 843 | + | e.eventFD(mgr.ID(), 0, wordBytes(colorrepresentation.ALPHA_MODE_STRAIGHT)) | |
| 844 | + | e.eventFD(mgr.ID(), 1, wordBytes(colorrepresentation.COEFFICIENTS_BT709, colorrepresentation.RANGE_LIMITED)) | |
| 845 | + | e.eventFD(mgr.ID(), 1, wordBytes(colorrepresentation.COEFFICIENTS_ICTCP, colorrepresentation.RANGE_FULL)) | |
| 846 | + | e.eventFD(mgr.ID(), 2, nil) | |
| 847 | + | if len(alphas) != 1 || alphas[0] != 2 || len(combos) != 2 || combos[0] != [2]uint32{2, 2} || combos[1] != [2]uint32{8, 1} || done != 1 { | |
| 848 | + | t.Fatalf("capabilities %v %v %d", alphas, combos, done) | |
| 849 | + | } | |
| 850 | + | ||
| 851 | + | s, err := mgr.GetSurface(e.surface) | |
| 852 | + | noerr(t, err) | |
| 853 | + | rxWant(t, e.p, mgr.ID(), 1, s.ID(), e.surface.ID()) | |
| 854 | + | noerr(t, s.SetAlphaMode(colorrepresentation.ALPHA_MODE_PREMULTIPLIED_OPTICAL)) | |
| 855 | + | rxWant(t, e.p, s.ID(), 1, 1) | |
| 856 | + | noerr(t, s.SetCoefficientsAndRange(colorrepresentation.COEFFICIENTS_BT2020, colorrepresentation.RANGE_LIMITED)) | |
| 857 | + | rxWant(t, e.p, s.ID(), 2, 6, 2) | |
| 858 | + | noerr(t, s.SetChromaLocation(colorrepresentation.CHROMA_LOCATION_TYPE_5)) | |
| 859 | + | rxWant(t, e.p, s.ID(), 3, 6) | |
| 860 | + | noerr(t, s.Destroy()) | |
| 861 | + | rxWant(t, e.p, s.ID(), 0) | |
| 862 | + | noerr(t, mgr.Destroy()) | |
| 863 | + | rxWant(t, e.p, mgr.ID(), 0) | |
| 864 | + | } | |
A client/securitycontext/securitycontext_generated.go +166 -0
| @@ -0,0 +1,166 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: security_context_v1 | |
| 3 | + | // Source: security-context-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2021 Simon Ser | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package securitycontext | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | "github.com/bnema/wlturbo/wl" | |
| 31 | + | ) | |
| 32 | + | ||
| 33 | + | // ERROR_INVALID_LISTEN_FD is the error invalid_listen_fd value. | |
| 34 | + | const ERROR_INVALID_LISTEN_FD = 1 | |
| 35 | + | ||
| 36 | + | // ERROR_NESTED is the error nested value. | |
| 37 | + | const ERROR_NESTED = 2 | |
| 38 | + | ||
| 39 | + | // ERROR_ALREADY_USED is the error already_used value. | |
| 40 | + | const ERROR_ALREADY_USED = 1 | |
| 41 | + | ||
| 42 | + | // ERROR_ALREADY_SET is the error already_set value. | |
| 43 | + | const ERROR_ALREADY_SET = 2 | |
| 44 | + | ||
| 45 | + | // ERROR_INVALID_METADATA is the error invalid_metadata value. | |
| 46 | + | const ERROR_INVALID_METADATA = 3 | |
| 47 | + | ||
| 48 | + | // WpSecurityContextManagerInterface is the protocol interface name. | |
| 49 | + | const WpSecurityContextManagerInterface = "wp_security_context_manager_v1" | |
| 50 | + | ||
| 51 | + | // WpSecurityContextManager is the generated binding for wp_security_context_manager_v1 version 1. | |
| 52 | + | type WpSecurityContextManager struct { | |
| 53 | + | wl.BaseProxy | |
| 54 | + | } | |
| 55 | + | ||
| 56 | + | // NewWpSecurityContextManager returns an unbound WpSecurityContextManager. | |
| 57 | + | func NewWpSecurityContextManager(ctx *wl.Context) *WpSecurityContextManager { | |
| 58 | + | obj := &WpSecurityContextManager{} | |
| 59 | + | obj.SetContext(ctx) | |
| 60 | + | ctx.Register(obj) | |
| 61 | + | return obj | |
| 62 | + | } | |
| 63 | + | ||
| 64 | + | // Destroy the manager. This doesn't destroy objects created with the manager. | |
| 65 | + | func (o *WpSecurityContextManager) Destroy() error { | |
| 66 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_security_context_manager_v1.destroy", Destructor: true}); err != nil { | |
| 67 | + | return err | |
| 68 | + | } | |
| 69 | + | return nil | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | // Creates a new security context with a socket listening FD. The compositor will accept new client connections on listen_fd. listen_fd must be ready to accept new connections when this request is sent by the client. In other words, the client must call bind(2) and listen(2) before sending the FD. close_fd is a FD that will signal hangup when the compositor should stop accepting new connections on listen_fd. The compositor must continue to accept connections on listen_fd when the Wayland client which created the security context disconnects. After sending this request, closing listen_fd and close_fd remains the only valid operation on them. | |
| 73 | + | func (o *WpSecurityContextManager) CreateListener(listenFd int, closeFd int) (*WpSecurityContext, error) { | |
| 74 | + | child := &WpSecurityContext{} | |
| 75 | + | child.SetContext(o.Context()) | |
| 76 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_security_context_manager_v1.create_listener", Child: child, FDs: []int{listenFd, closeFd}}, wl.ArgObject(child), wl.ArgFD(), wl.ArgFD()); err != nil { | |
| 77 | + | return nil, err | |
| 78 | + | } | |
| 79 | + | return child, nil | |
| 80 | + | } | |
| 81 | + | ||
| 82 | + | // EventSignature returns the declared event argument types in wire order. | |
| 83 | + | func (o *WpSecurityContextManager) EventSignature(opcode uint16) (string, bool) { | |
| 84 | + | switch opcode { | |
| 85 | + | default: | |
| 86 | + | return "", false | |
| 87 | + | } | |
| 88 | + | } | |
| 89 | + | ||
| 90 | + | // Dispatch decodes one event on wp_security_context_manager_v1 and calls the registered handlers. | |
| 91 | + | func (o *WpSecurityContextManager) Dispatch(event *wl.Event) { | |
| 92 | + | switch event.Opcode { | |
| 93 | + | default: | |
| 94 | + | } | |
| 95 | + | } | |
| 96 | + | ||
| 97 | + | // WpSecurityContextInterface is the protocol interface name. | |
| 98 | + | const WpSecurityContextInterface = "wp_security_context_v1" | |
| 99 | + | ||
| 100 | + | // WpSecurityContext is the generated binding for wp_security_context_v1 version 1. | |
| 101 | + | type WpSecurityContext struct { | |
| 102 | + | wl.BaseProxy | |
| 103 | + | } | |
| 104 | + | ||
| 105 | + | // NewWpSecurityContext returns an unbound WpSecurityContext. | |
| 106 | + | func NewWpSecurityContext(ctx *wl.Context) *WpSecurityContext { | |
| 107 | + | obj := &WpSecurityContext{} | |
| 108 | + | obj.SetContext(ctx) | |
| 109 | + | ctx.Register(obj) | |
| 110 | + | return obj | |
| 111 | + | } | |
| 112 | + | ||
| 113 | + | // Destroy the security context object. | |
| 114 | + | func (o *WpSecurityContext) Destroy() error { | |
| 115 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_security_context_v1.destroy", Destructor: true}); err != nil { | |
| 116 | + | return err | |
| 117 | + | } | |
| 118 | + | return nil | |
| 119 | + | } | |
| 120 | + | ||
| 121 | + | // Attach a unique sandbox engine name to the security context. The name should follow the reverse-DNS style (e.g. "org.flatpak"). A list of well-known engines is maintained at: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/main/staging/security-context/engines.md It is a protocol error to call this request twice. The already_set error is sent in this case. | |
| 122 | + | func (o *WpSecurityContext) SetSandboxEngine(name string) error { | |
| 123 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_security_context_v1.set_sandbox_engine"}, wl.ArgString(name)); err != nil { | |
| 124 | + | return err | |
| 125 | + | } | |
| 126 | + | return nil | |
| 127 | + | } | |
| 128 | + | ||
| 129 | + | // Attach an application ID to the security context. The application ID is an opaque, sandbox-specific identifier for an application. See the well-known engines document for more details: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/main/staging/security-context/engines.md The compositor may use the application ID to group clients belonging to the same security context application. Whether this request is optional or not depends on the sandbox engine used. It is a protocol error to call this request twice. The already_set error is sent in this case. | |
| 130 | + | func (o *WpSecurityContext) SetAppId(appId string) error { | |
| 131 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wp_security_context_v1.set_app_id"}, wl.ArgString(appId)); err != nil { | |
| 132 | + | return err | |
| 133 | + | } | |
| 134 | + | return nil | |
| 135 | + | } | |
| 136 | + | ||
| 137 | + | // Attach an instance ID to the security context. The instance ID is an opaque, sandbox-specific identifier for a running instance of an application. See the well-known engines document for more details: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/main/staging/security-context/engines.md Whether this request is optional or not depends on the sandbox engine used. It is a protocol error to call this request twice. The already_set error is sent in this case. | |
| 138 | + | func (o *WpSecurityContext) SetInstanceId(instanceId string) error { | |
| 139 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "wp_security_context_v1.set_instance_id"}, wl.ArgString(instanceId)); err != nil { | |
| 140 | + | return err | |
| 141 | + | } | |
| 142 | + | return nil | |
| 143 | + | } | |
| 144 | + | ||
| 145 | + | // Atomically register the new client and attach the security context metadata. If the provided metadata is inconsistent or does not match with out of band metadata (see https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/main/staging/security-context/engines.md), the invalid_metadata error may be sent eventually. It's a protocol error to send any request other than "destroy" after this request. In this case, the already_used error is sent. | |
| 146 | + | func (o *WpSecurityContext) Commit() error { | |
| 147 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 4, Name: "wp_security_context_v1.commit"}); err != nil { | |
| 148 | + | return err | |
| 149 | + | } | |
| 150 | + | return nil | |
| 151 | + | } | |
| 152 | + | ||
| 153 | + | // EventSignature returns the declared event argument types in wire order. | |
| 154 | + | func (o *WpSecurityContext) EventSignature(opcode uint16) (string, bool) { | |
| 155 | + | switch opcode { | |
| 156 | + | default: | |
| 157 | + | return "", false | |
| 158 | + | } | |
| 159 | + | } | |
| 160 | + | ||
| 161 | + | // Dispatch decodes one event on wp_security_context_v1 and calls the registered handlers. | |
| 162 | + | func (o *WpSecurityContext) Dispatch(event *wl.Event) { | |
| 163 | + | switch event.Opcode { | |
| 164 | + | default: | |
| 165 | + | } | |
| 166 | + | } | |
A client/serverdecoration/serverdecoration_generated.go +197 -0
| @@ -0,0 +1,197 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: server_decoration | |
| 3 | + | // Source: server-decoration.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // SPDX-FileCopyrightText: 2015 Martin Gräßlin | |
| 7 | + | // | |
| 8 | + | // SPDX-License-Identifier: LGPL-2.1-or-later | |
| 9 | + | ||
| 10 | + | package serverdecoration | |
| 11 | + | ||
| 12 | + | import ( | |
| 13 | + | "sync" | |
| 14 | + | ||
| 15 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 16 | + | "github.com/bnema/wlturbo/wl" | |
| 17 | + | ) | |
| 18 | + | ||
| 19 | + | // ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_NONE is the mode None value. | |
| 20 | + | const ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_NONE = 0 | |
| 21 | + | ||
| 22 | + | // ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT is the mode Client value. | |
| 23 | + | const ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT = 1 | |
| 24 | + | ||
| 25 | + | // ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER is the mode Server value. | |
| 26 | + | const ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER = 2 | |
| 27 | + | ||
| 28 | + | // ORG_KDE_KWIN_SERVER_DECORATION_MODE_NONE is the mode None value. | |
| 29 | + | const ORG_KDE_KWIN_SERVER_DECORATION_MODE_NONE = 0 | |
| 30 | + | ||
| 31 | + | // ORG_KDE_KWIN_SERVER_DECORATION_MODE_CLIENT is the mode Client value. | |
| 32 | + | const ORG_KDE_KWIN_SERVER_DECORATION_MODE_CLIENT = 1 | |
| 33 | + | ||
| 34 | + | // ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER is the mode Server value. | |
| 35 | + | const ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER = 2 | |
| 36 | + | ||
| 37 | + | // OrgKdeKwinServerDecorationManagerInterface is the protocol interface name. | |
| 38 | + | const OrgKdeKwinServerDecorationManagerInterface = "org_kde_kwin_server_decoration_manager" | |
| 39 | + | ||
| 40 | + | // OrgKdeKwinServerDecorationManager is the generated binding for org_kde_kwin_server_decoration_manager version 1. | |
| 41 | + | type OrgKdeKwinServerDecorationManager struct { | |
| 42 | + | wl.BaseProxy | |
| 43 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 44 | + | // handlers while another goroutine dispatches events. | |
| 45 | + | handlersMu sync.Mutex | |
| 46 | + | onDefaultMode []func(mode uint32) | |
| 47 | + | } | |
| 48 | + | ||
| 49 | + | // NewOrgKdeKwinServerDecorationManager returns an unbound OrgKdeKwinServerDecorationManager. | |
| 50 | + | func NewOrgKdeKwinServerDecorationManager(ctx *wl.Context) *OrgKdeKwinServerDecorationManager { | |
| 51 | + | obj := &OrgKdeKwinServerDecorationManager{} | |
| 52 | + | obj.SetContext(ctx) | |
| 53 | + | ctx.Register(obj) | |
| 54 | + | return obj | |
| 55 | + | } | |
| 56 | + | ||
| 57 | + | // When a client creates a server-side decoration object it indicates that it supports the protocol. The client is supposed to tell the server whether it wants server-side decorations or will provide client-side decorations. If the client does not create a server-side decoration object for a surface the server interprets this as lack of support for this protocol and considers it as client-side decorated. Nevertheless a client-side decorated surface should use this protocol to indicate to the server that it does not want a server-side deco. | |
| 58 | + | func (o *OrgKdeKwinServerDecorationManager) Create(surface *cross_wl_surface.Surface) (*OrgKdeKwinServerDecoration, error) { | |
| 59 | + | var arg1 wl.Object | |
| 60 | + | if surface != nil { | |
| 61 | + | arg1 = surface | |
| 62 | + | } | |
| 63 | + | child := &OrgKdeKwinServerDecoration{} | |
| 64 | + | child.SetContext(o.Context()) | |
| 65 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "org_kde_kwin_server_decoration_manager.create", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 66 | + | return nil, err | |
| 67 | + | } | |
| 68 | + | return child, nil | |
| 69 | + | } | |
| 70 | + | ||
| 71 | + | // OnDefaultMode registers a handler for the default_mode event. | |
| 72 | + | // | |
| 73 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 74 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 75 | + | func (o *OrgKdeKwinServerDecorationManager) OnDefaultMode(handler func(mode uint32)) { | |
| 76 | + | if handler == nil { | |
| 77 | + | return | |
| 78 | + | } | |
| 79 | + | o.handlersMu.Lock() | |
| 80 | + | defer o.handlersMu.Unlock() | |
| 81 | + | o.onDefaultMode = append(o.onDefaultMode, handler) | |
| 82 | + | } | |
| 83 | + | ||
| 84 | + | // handlersForDefaultMode returns the handlers registered for default_mode, taken | |
| 85 | + | // under the lock so a handler may register another handler while events are | |
| 86 | + | // being dispatched. | |
| 87 | + | func (o *OrgKdeKwinServerDecorationManager) handlersForDefaultMode() []func(mode uint32) { | |
| 88 | + | o.handlersMu.Lock() | |
| 89 | + | defer o.handlersMu.Unlock() | |
| 90 | + | return o.onDefaultMode | |
| 91 | + | } | |
| 92 | + | ||
| 93 | + | // EventSignature returns the declared event argument types in wire order. | |
| 94 | + | func (o *OrgKdeKwinServerDecorationManager) EventSignature(opcode uint16) (string, bool) { | |
| 95 | + | switch opcode { | |
| 96 | + | case 0: | |
| 97 | + | return "uint,", true | |
| 98 | + | default: | |
| 99 | + | return "", false | |
| 100 | + | } | |
| 101 | + | } | |
| 102 | + | ||
| 103 | + | // Dispatch decodes one event on org_kde_kwin_server_decoration_manager and calls the registered handlers. | |
| 104 | + | func (o *OrgKdeKwinServerDecorationManager) Dispatch(event *wl.Event) { | |
| 105 | + | switch event.Opcode { | |
| 106 | + | case 0: // default_mode | |
| 107 | + | mode := event.Uint32() | |
| 108 | + | ||
| 109 | + | for i, handler := range o.handlersForDefaultMode() { | |
| 110 | + | _ = i | |
| 111 | + | handler(mode) | |
| 112 | + | } | |
| 113 | + | default: | |
| 114 | + | } | |
| 115 | + | } | |
| 116 | + | ||
| 117 | + | // OrgKdeKwinServerDecorationInterface is the protocol interface name. | |
| 118 | + | const OrgKdeKwinServerDecorationInterface = "org_kde_kwin_server_decoration" | |
| 119 | + | ||
| 120 | + | // OrgKdeKwinServerDecoration is the generated binding for org_kde_kwin_server_decoration version 1. | |
| 121 | + | type OrgKdeKwinServerDecoration struct { | |
| 122 | + | wl.BaseProxy | |
| 123 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 124 | + | // handlers while another goroutine dispatches events. | |
| 125 | + | handlersMu sync.Mutex | |
| 126 | + | onMode []func(mode uint32) | |
| 127 | + | } | |
| 128 | + | ||
| 129 | + | // NewOrgKdeKwinServerDecoration returns an unbound OrgKdeKwinServerDecoration. | |
| 130 | + | func NewOrgKdeKwinServerDecoration(ctx *wl.Context) *OrgKdeKwinServerDecoration { | |
| 131 | + | obj := &OrgKdeKwinServerDecoration{} | |
| 132 | + | obj.SetContext(ctx) | |
| 133 | + | ctx.Register(obj) | |
| 134 | + | return obj | |
| 135 | + | } | |
| 136 | + | ||
| 137 | + | // release the server decoration object | |
| 138 | + | func (o *OrgKdeKwinServerDecoration) Release() error { | |
| 139 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "org_kde_kwin_server_decoration.release", Destructor: true}); err != nil { | |
| 140 | + | return err | |
| 141 | + | } | |
| 142 | + | return nil | |
| 143 | + | } | |
| 144 | + | ||
| 145 | + | // The decoration mode the surface wants to use. | |
| 146 | + | func (o *OrgKdeKwinServerDecoration) RequestMode(mode uint32) error { | |
| 147 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "org_kde_kwin_server_decoration.request_mode"}, wl.ArgUint(mode)); err != nil { | |
| 148 | + | return err | |
| 149 | + | } | |
| 150 | + | return nil | |
| 151 | + | } | |
| 152 | + | ||
| 153 | + | // OnMode registers a handler for the mode event. | |
| 154 | + | // | |
| 155 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 156 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 157 | + | func (o *OrgKdeKwinServerDecoration) OnMode(handler func(mode uint32)) { | |
| 158 | + | if handler == nil { | |
| 159 | + | return | |
| 160 | + | } | |
| 161 | + | o.handlersMu.Lock() | |
| 162 | + | defer o.handlersMu.Unlock() | |
| 163 | + | o.onMode = append(o.onMode, handler) | |
| 164 | + | } | |
| 165 | + | ||
| 166 | + | // handlersForMode returns the handlers registered for mode, taken | |
| 167 | + | // under the lock so a handler may register another handler while events are | |
| 168 | + | // being dispatched. | |
| 169 | + | func (o *OrgKdeKwinServerDecoration) handlersForMode() []func(mode uint32) { | |
| 170 | + | o.handlersMu.Lock() | |
| 171 | + | defer o.handlersMu.Unlock() | |
| 172 | + | return o.onMode | |
| 173 | + | } | |
| 174 | + | ||
| 175 | + | // EventSignature returns the declared event argument types in wire order. | |
| 176 | + | func (o *OrgKdeKwinServerDecoration) EventSignature(opcode uint16) (string, bool) { | |
| 177 | + | switch opcode { | |
| 178 | + | case 0: | |
| 179 | + | return "uint,", true | |
| 180 | + | default: | |
| 181 | + | return "", false | |
| 182 | + | } | |
| 183 | + | } | |
| 184 | + | ||
| 185 | + | // Dispatch decodes one event on org_kde_kwin_server_decoration and calls the registered handlers. | |
| 186 | + | func (o *OrgKdeKwinServerDecoration) Dispatch(event *wl.Event) { | |
| 187 | + | switch event.Opcode { | |
| 188 | + | case 0: // mode | |
| 189 | + | mode := event.Uint32() | |
| 190 | + | ||
| 191 | + | for i, handler := range o.handlersForMode() { | |
| 192 | + | _ = i | |
| 193 | + | handler(mode) | |
| 194 | + | } | |
| 195 | + | default: | |
| 196 | + | } | |
| 197 | + | } | |
A client/session_lock_test.go +222 -0
| @@ -0,0 +1,222 @@ | |||
| 1 | + | //go:build linux | |
| 2 | + | ||
| 3 | + | package client_test | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "errors" | |
| 7 | + | "reflect" | |
| 8 | + | "sync" | |
| 9 | + | "testing" | |
| 10 | + | ||
| 11 | + | "github.com/bnema/go-wayland-bindings/client/extsessionlock" | |
| 12 | + | "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 13 | + | "github.com/bnema/wlturbo" | |
| 14 | + | ) | |
| 15 | + | ||
| 16 | + | // These tests use ordinary generated proxies and the production transport on a | |
| 17 | + | // socketpair. Only the server wire peer is scripted; no request/dispatch hooks | |
| 18 | + | // are replaced, and no live compositor or session lock is used. | |
| 19 | + | func TestSessionLockLockedLifetime(t *testing.T) { | |
| 20 | + | s := newWireEnv(t) | |
| 21 | + | ctx := s.d.Context() | |
| 22 | + | compositor := wayland.NewCompositor(ctx) | |
| 23 | + | s.bind(1, wayland.CompositorInterface, 6, 6, compositor) | |
| 24 | + | surface, err := compositor.CreateSurface() | |
| 25 | + | noerr(t, err) | |
| 26 | + | wantWords(t, "create_surface", s.req(compositor.ID(), 0), surface.ID()) | |
| 27 | + | out := wayland.NewOutput(ctx) | |
| 28 | + | s.bind(2, wayland.OutputInterface, 4, 4, out) | |
| 29 | + | mgr := extsessionlock.NewExtSessionLockManager(ctx) | |
| 30 | + | s.bind(3, extsessionlock.ExtSessionLockManagerInterface, 1, 1, mgr) | |
| 31 | + | lock, err := mgr.Lock() | |
| 32 | + | noerr(t, err) | |
| 33 | + | wantWords(t, "lock", s.req(mgr.ID(), 1), lock.ID()) | |
| 34 | + | if lock.Version() != 1 || lock.Context() != ctx { | |
| 35 | + | t.Fatalf("lock version=%d context=%p", lock.Version(), lock.Context()) | |
| 36 | + | } | |
| 37 | + | noerr(t, ctx.CheckProxy(lock)) | |
| 38 | + | ||
| 39 | + | // The manager destructor must not invalidate its lock children. | |
| 40 | + | noerr(t, mgr.Destroy()) | |
| 41 | + | wantWords(t, "manager.destroy", s.req(mgr.ID(), 0)) | |
| 42 | + | if ctx.CheckProxy(mgr) == nil { | |
| 43 | + | t.Fatal("destroyed manager remains registered") | |
| 44 | + | } | |
| 45 | + | s.event(1, 1, wordBytes(mgr.ID())...) // wl_display.delete_id | |
| 46 | + | noerr(t, ctx.CheckProxy(lock)) | |
| 47 | + | ls, err := lock.GetLockSurface(surface, out) | |
| 48 | + | noerr(t, err) | |
| 49 | + | wantWords(t, "get_lock_surface", s.req(lock.ID(), 1), ls.ID(), surface.ID(), out.ID()) | |
| 50 | + | if ls.Version() != 1 || ls.Context() != ctx { | |
| 51 | + | t.Fatalf("lock surface version=%d context=%p", ls.Version(), ls.Context()) | |
| 52 | + | } | |
| 53 | + | noerr(t, ctx.CheckProxy(ls)) | |
| 54 | + | ||
| 55 | + | var events []string | |
| 56 | + | lock.OnLocked(func() { events = append(events, "locked") }) | |
| 57 | + | lock.OnFinished(func() { events = append(events, "finished") }) | |
| 58 | + | var configures [][3]uint32 | |
| 59 | + | ls.OnConfigure(func(serial, width, height uint32) { | |
| 60 | + | configures = append(configures, [3]uint32{serial, width, height}) | |
| 61 | + | noerr(t, ls.AckConfigure(serial)) | |
| 62 | + | }) | |
| 63 | + | s.event(ls.ID(), 0, wordBytes(0x89abcdef, 1920, 1080)...) | |
| 64 | + | wantWords(t, "ack_configure", s.req(ls.ID(), 1), 0x89abcdef) | |
| 65 | + | s.event(lock.ID(), 0) | |
| 66 | + | s.event(lock.ID(), 1) // finished after locked still requires unlock_and_destroy | |
| 67 | + | if !reflect.DeepEqual(events, []string{"locked", "finished"}) || | |
| 68 | + | !reflect.DeepEqual(configures, [][3]uint32{{0x89abcdef, 1920, 1080}}) { | |
| 69 | + | t.Fatalf("events=%v configures=%v", events, configures) | |
| 70 | + | } | |
| 71 | + | // Neither event is a destructor; the application must choose the request. | |
| 72 | + | noerr(t, ctx.CheckProxy(lock)) | |
| 73 | + | noerr(t, lock.UnlockAndDestroy()) | |
| 74 | + | wantWords(t, "unlock_and_destroy", s.req(lock.ID(), 2)) | |
| 75 | + | if ctx.CheckProxy(lock) == nil { | |
| 76 | + | t.Fatal("unlocked lock remains registered") | |
| 77 | + | } | |
| 78 | + | s.event(1, 1, wordBytes(lock.ID())...) | |
| 79 | + | ||
| 80 | + | // Lock destruction also leaves its children and core objects valid. | |
| 81 | + | noerr(t, ctx.CheckProxy(ls)) | |
| 82 | + | noerr(t, ctx.CheckProxy(surface)) | |
| 83 | + | noerr(t, ctx.CheckProxy(out)) | |
| 84 | + | s.event(ls.ID(), 0, wordBytes(0xffffffff, 800, 600)...) | |
| 85 | + | wantWords(t, "ack after parent destruction", s.req(ls.ID(), 1), 0xffffffff) | |
| 86 | + | if len(configures) != 2 || configures[1] != [3]uint32{0xffffffff, 800, 600} { | |
| 87 | + | t.Fatal(configures) | |
| 88 | + | } | |
| 89 | + | noerr(t, ls.Destroy()) | |
| 90 | + | wantWords(t, "surface.destroy", s.req(ls.ID(), 0)) | |
| 91 | + | if ctx.CheckProxy(ls) == nil { | |
| 92 | + | t.Fatal("destroyed lock surface remains registered") | |
| 93 | + | } | |
| 94 | + | // Events in flight on a destroyed object are dropped until delete_id. | |
| 95 | + | s.event(ls.ID(), 0, wordBytes(12, 640, 480)...) | |
| 96 | + | if len(configures) != 2 { | |
| 97 | + | t.Fatal("configure delivered to destroyed surface") | |
| 98 | + | } | |
| 99 | + | s.event(1, 1, wordBytes(ls.ID())...) | |
| 100 | + | if err := ls.AckConfigure(12); err == nil { | |
| 101 | + | t.Fatal("ack on destroyed surface succeeded") | |
| 102 | + | } | |
| 103 | + | if err := ls.Destroy(); err == nil { | |
| 104 | + | t.Fatal("second surface destructor succeeded") | |
| 105 | + | } | |
| 106 | + | if err := lock.Destroy(); err == nil { | |
| 107 | + | t.Fatal("second lock destructor succeeded") | |
| 108 | + | } | |
| 109 | + | if child, err := mgr.Lock(); err == nil || child != nil { | |
| 110 | + | t.Fatal("destroyed manager created a child", child, err) | |
| 111 | + | } | |
| 112 | + | if child, err := lock.GetLockSurface(surface, out); err == nil || child != nil { | |
| 113 | + | t.Fatal("destroyed lock created a child", child, err) | |
| 114 | + | } | |
| 115 | + | s.noRequest() | |
| 116 | + | noerr(t, surface.Destroy()) | |
| 117 | + | wantWords(t, "wl_surface.destroy", s.req(surface.ID(), 0)) | |
| 118 | + | noerr(t, out.Release()) | |
| 119 | + | wantWords(t, "wl_output.release", s.req(out.ID(), 0)) | |
| 120 | + | } | |
| 121 | + | ||
| 122 | + | func TestSessionLockDeniedDestroy(t *testing.T) { | |
| 123 | + | s := newWireEnv(t) | |
| 124 | + | mgr := extsessionlock.NewExtSessionLockManager(s.d.Context()) | |
| 125 | + | s.bind(1, extsessionlock.ExtSessionLockManagerInterface, 1, 1, mgr) | |
| 126 | + | lock, err := mgr.Lock() | |
| 127 | + | noerr(t, err) | |
| 128 | + | wantWords(t, "lock", s.req(mgr.ID(), 1), lock.ID()) | |
| 129 | + | var locked, finished bool | |
| 130 | + | lock.OnLocked(func() { locked = true }) | |
| 131 | + | lock.OnFinished(func() { finished = true }) | |
| 132 | + | s.event(lock.ID(), 1) | |
| 133 | + | if locked || !finished { | |
| 134 | + | t.Fatalf("locked=%t finished=%t", locked, finished) | |
| 135 | + | } | |
| 136 | + | noerr(t, s.d.Context().CheckProxy(lock)) | |
| 137 | + | noerr(t, lock.Destroy()) // never locked: destroy, not unlock_and_destroy | |
| 138 | + | wantWords(t, "denied.destroy", s.req(lock.ID(), 0)) | |
| 139 | + | if err := lock.UnlockAndDestroy(); err == nil { | |
| 140 | + | t.Fatal("second destructor succeeded") | |
| 141 | + | } | |
| 142 | + | s.noRequest() | |
| 143 | + | // Destroying one child must not invalidate the manager or its next child. | |
| 144 | + | noerr(t, s.d.Context().CheckProxy(mgr)) | |
| 145 | + | next, err := mgr.Lock() | |
| 146 | + | noerr(t, err) | |
| 147 | + | wantWords(t, "next lock", s.req(mgr.ID(), 1), next.ID()) | |
| 148 | + | noerr(t, next.Destroy()) | |
| 149 | + | wantWords(t, "next.destroy", s.req(next.ID(), 0)) | |
| 150 | + | noerr(t, mgr.Destroy()) | |
| 151 | + | wantWords(t, "manager.destroy", s.req(mgr.ID(), 0)) | |
| 152 | + | } | |
| 153 | + | ||
| 154 | + | func TestSessionLockConcurrentDestructors(t *testing.T) { | |
| 155 | + | s := newWireEnv(t) | |
| 156 | + | mgr := extsessionlock.NewExtSessionLockManager(s.d.Context()) | |
| 157 | + | s.bind(1, extsessionlock.ExtSessionLockManagerInterface, 1, 1, mgr) | |
| 158 | + | lock, err := mgr.Lock() | |
| 159 | + | noerr(t, err) | |
| 160 | + | wantWords(t, "lock", s.req(mgr.ID(), 1), lock.ID()) | |
| 161 | + | s.event(lock.ID(), 1) | |
| 162 | + | var wg sync.WaitGroup | |
| 163 | + | results := make(chan error, 8) | |
| 164 | + | for range 8 { | |
| 165 | + | wg.Add(1) | |
| 166 | + | go func() { defer wg.Done(); results <- lock.Destroy() }() | |
| 167 | + | } | |
| 168 | + | wg.Wait() | |
| 169 | + | close(results) | |
| 170 | + | successes := 0 | |
| 171 | + | for err := range results { | |
| 172 | + | if err == nil { | |
| 173 | + | successes++ | |
| 174 | + | } | |
| 175 | + | } | |
| 176 | + | if successes != 1 { | |
| 177 | + | t.Fatalf("successful destructors=%d, want 1", successes) | |
| 178 | + | } | |
| 179 | + | wantWords(t, "single destructor", s.req(lock.ID(), 0)) | |
| 180 | + | s.noRequest() | |
| 181 | + | } | |
| 182 | + | ||
| 183 | + | func TestSessionLockMalformedEvents(t *testing.T) { | |
| 184 | + | for _, tc := range []struct { | |
| 185 | + | name string | |
| 186 | + | surface bool | |
| 187 | + | op uint16 | |
| 188 | + | body []byte | |
| 189 | + | }{ | |
| 190 | + | {"locked trailing word", false, 0, wordBytes(1)}, | |
| 191 | + | {"finished trailing word", false, 1, wordBytes(1)}, | |
| 192 | + | {"configure missing height", true, 0, wordBytes(1, 800)}, | |
| 193 | + | {"configure trailing word", true, 0, wordBytes(1, 800, 600, 1)}, | |
| 194 | + | } { | |
| 195 | + | t.Run(tc.name, func(t *testing.T) { | |
| 196 | + | s := newWireEnv(t) | |
| 197 | + | mgr := extsessionlock.NewExtSessionLockManager(s.d.Context()) | |
| 198 | + | s.bind(1, extsessionlock.ExtSessionLockManagerInterface, 1, 1, mgr) | |
| 199 | + | lock, err := mgr.Lock() | |
| 200 | + | noerr(t, err) | |
| 201 | + | s.req(mgr.ID(), 1) | |
| 202 | + | id := lock.ID() | |
| 203 | + | called := false | |
| 204 | + | lock.OnLocked(func() { called = true }) | |
| 205 | + | lock.OnFinished(func() { called = true }) | |
| 206 | + | if tc.surface { | |
| 207 | + | ls, err := lock.GetLockSurface(s.surface(), s.output()) | |
| 208 | + | noerr(t, err) | |
| 209 | + | s.req(lock.ID(), 1) | |
| 210 | + | ls.OnConfigure(func(_, _, _ uint32) { called = true }) | |
| 211 | + | id = ls.ID() | |
| 212 | + | } | |
| 213 | + | send(t, s.p, payload(id, tc.op, tc.body...)) | |
| 214 | + | if err := s.d.Dispatch(); !errors.Is(err, wlturbo.ErrMalformedFrame) { | |
| 215 | + | t.Fatalf("malformed event: %v", err) | |
| 216 | + | } | |
| 217 | + | if called { | |
| 218 | + | t.Fatal("malformed event reached a handler") | |
| 219 | + | } | |
| 220 | + | }) | |
| 221 | + | } | |
| 222 | + | } | |
A client/singlepixelbuffer/singlepixelbuffer_generated.go +80 -0
| @@ -0,0 +1,80 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: single_pixel_buffer_v1 | |
| 3 | + | // Source: single-pixel-buffer-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2022 Simon Ser | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package singlepixelbuffer | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | cross_wl_buffer "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 31 | + | "github.com/bnema/wlturbo/wl" | |
| 32 | + | ) | |
| 33 | + | ||
| 34 | + | // WpSinglePixelBufferManagerInterface is the protocol interface name. | |
| 35 | + | const WpSinglePixelBufferManagerInterface = "wp_single_pixel_buffer_manager_v1" | |
| 36 | + | ||
| 37 | + | // WpSinglePixelBufferManager is the generated binding for wp_single_pixel_buffer_manager_v1 version 1. | |
| 38 | + | type WpSinglePixelBufferManager struct { | |
| 39 | + | wl.BaseProxy | |
| 40 | + | } | |
| 41 | + | ||
| 42 | + | // NewWpSinglePixelBufferManager returns an unbound WpSinglePixelBufferManager. | |
| 43 | + | func NewWpSinglePixelBufferManager(ctx *wl.Context) *WpSinglePixelBufferManager { | |
| 44 | + | obj := &WpSinglePixelBufferManager{} | |
| 45 | + | obj.SetContext(ctx) | |
| 46 | + | ctx.Register(obj) | |
| 47 | + | return obj | |
| 48 | + | } | |
| 49 | + | ||
| 50 | + | // Destroy the wp_single_pixel_buffer_manager_v1 object. The child objects created via this interface are unaffected. | |
| 51 | + | func (o *WpSinglePixelBufferManager) Destroy() error { | |
| 52 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_single_pixel_buffer_manager_v1.destroy", Destructor: true}); err != nil { | |
| 53 | + | return err | |
| 54 | + | } | |
| 55 | + | return nil | |
| 56 | + | } | |
| 57 | + | ||
| 58 | + | // Create a single-pixel buffer from four 32-bit RGBA values. Unless specified in another protocol extension, the RGBA values use pre-multiplied alpha. The width and height of the buffer are 1. The r, g, b and a arguments valid range is from UINT32_MIN (0) to UINT32_MAX (0xffffffff). These arguments should be interpreted as a percentage, i.e. - UINT32_MIN = 0% of the given color component - UINT32_MAX = 100% of the given color component | |
| 59 | + | func (o *WpSinglePixelBufferManager) CreateU32RgbaBuffer(r uint32, g uint32, b uint32, a uint32) (*cross_wl_buffer.Buffer, error) { | |
| 60 | + | child := cross_wl_buffer.NewBuffer(o.Context()) | |
| 61 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_single_pixel_buffer_manager_v1.create_u32_rgba_buffer", Child: child}, wl.ArgObject(child), wl.ArgUint(r), wl.ArgUint(g), wl.ArgUint(b), wl.ArgUint(a)); err != nil { | |
| 62 | + | return nil, err | |
| 63 | + | } | |
| 64 | + | return child, nil | |
| 65 | + | } | |
| 66 | + | ||
| 67 | + | // EventSignature returns the declared event argument types in wire order. | |
| 68 | + | func (o *WpSinglePixelBufferManager) EventSignature(opcode uint16) (string, bool) { | |
| 69 | + | switch opcode { | |
| 70 | + | default: | |
| 71 | + | return "", false | |
| 72 | + | } | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | // Dispatch decodes one event on wp_single_pixel_buffer_manager_v1 and calls the registered handlers. | |
| 76 | + | func (o *WpSinglePixelBufferManager) Dispatch(event *wl.Event) { | |
| 77 | + | switch event.Opcode { | |
| 78 | + | default: | |
| 79 | + | } | |
| 80 | + | } | |
A client/tablet/tablet_generated.go +2286 -0 large diff (2286 lines changed): collapsed
A client/tearingcontrol/tearingcontrol_generated.go +141 -0
| @@ -0,0 +1,141 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: tearing_control_v1 | |
| 3 | + | // Source: tearing-control-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2021 Xaver Hugl | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package tearingcontrol | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 31 | + | "github.com/bnema/wlturbo/wl" | |
| 32 | + | ) | |
| 33 | + | ||
| 34 | + | // ERROR_TEARING_CONTROL_EXISTS is the error tearing_control_exists value. | |
| 35 | + | const ERROR_TEARING_CONTROL_EXISTS = 0 | |
| 36 | + | ||
| 37 | + | // PRESENTATION_HINT_VSYNC is the presentation_hint vsync value. | |
| 38 | + | const PRESENTATION_HINT_VSYNC = 0 | |
| 39 | + | ||
| 40 | + | // PRESENTATION_HINT_ASYNC is the presentation_hint async value. | |
| 41 | + | const PRESENTATION_HINT_ASYNC = 1 | |
| 42 | + | ||
| 43 | + | // WpTearingControlManagerInterface is the protocol interface name. | |
| 44 | + | const WpTearingControlManagerInterface = "wp_tearing_control_manager_v1" | |
| 45 | + | ||
| 46 | + | // WpTearingControlManager is the generated binding for wp_tearing_control_manager_v1 version 1. | |
| 47 | + | type WpTearingControlManager struct { | |
| 48 | + | wl.BaseProxy | |
| 49 | + | } | |
| 50 | + | ||
| 51 | + | // NewWpTearingControlManager returns an unbound WpTearingControlManager. | |
| 52 | + | func NewWpTearingControlManager(ctx *wl.Context) *WpTearingControlManager { | |
| 53 | + | obj := &WpTearingControlManager{} | |
| 54 | + | obj.SetContext(ctx) | |
| 55 | + | ctx.Register(obj) | |
| 56 | + | return obj | |
| 57 | + | } | |
| 58 | + | ||
| 59 | + | // Destroy this tearing control factory object. Other objects, including wp_tearing_control_v1 objects created by this factory, are not affected by this request. | |
| 60 | + | func (o *WpTearingControlManager) Destroy() error { | |
| 61 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_tearing_control_manager_v1.destroy", Destructor: true}); err != nil { | |
| 62 | + | return err | |
| 63 | + | } | |
| 64 | + | return nil | |
| 65 | + | } | |
| 66 | + | ||
| 67 | + | // Instantiate an interface extension for the given wl_surface to request asynchronous page flips for presentation. If the given wl_surface already has a wp_tearing_control_v1 object associated, the tearing_control_exists protocol error is raised. | |
| 68 | + | func (o *WpTearingControlManager) GetTearingControl(surface *cross_wl_surface.Surface) (*WpTearingControl, error) { | |
| 69 | + | var arg1 wl.Object | |
| 70 | + | if surface != nil { | |
| 71 | + | arg1 = surface | |
| 72 | + | } | |
| 73 | + | child := &WpTearingControl{} | |
| 74 | + | child.SetContext(o.Context()) | |
| 75 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_tearing_control_manager_v1.get_tearing_control", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 76 | + | return nil, err | |
| 77 | + | } | |
| 78 | + | return child, nil | |
| 79 | + | } | |
| 80 | + | ||
| 81 | + | // EventSignature returns the declared event argument types in wire order. | |
| 82 | + | func (o *WpTearingControlManager) EventSignature(opcode uint16) (string, bool) { | |
| 83 | + | switch opcode { | |
| 84 | + | default: | |
| 85 | + | return "", false | |
| 86 | + | } | |
| 87 | + | } | |
| 88 | + | ||
| 89 | + | // Dispatch decodes one event on wp_tearing_control_manager_v1 and calls the registered handlers. | |
| 90 | + | func (o *WpTearingControlManager) Dispatch(event *wl.Event) { | |
| 91 | + | switch event.Opcode { | |
| 92 | + | default: | |
| 93 | + | } | |
| 94 | + | } | |
| 95 | + | ||
| 96 | + | // WpTearingControlInterface is the protocol interface name. | |
| 97 | + | const WpTearingControlInterface = "wp_tearing_control_v1" | |
| 98 | + | ||
| 99 | + | // WpTearingControl is the generated binding for wp_tearing_control_v1 version 1. | |
| 100 | + | type WpTearingControl struct { | |
| 101 | + | wl.BaseProxy | |
| 102 | + | } | |
| 103 | + | ||
| 104 | + | // NewWpTearingControl returns an unbound WpTearingControl. | |
| 105 | + | func NewWpTearingControl(ctx *wl.Context) *WpTearingControl { | |
| 106 | + | obj := &WpTearingControl{} | |
| 107 | + | obj.SetContext(ctx) | |
| 108 | + | ctx.Register(obj) | |
| 109 | + | return obj | |
| 110 | + | } | |
| 111 | + | ||
| 112 | + | // Set the presentation hint for the associated wl_surface. This state is double-buffered, see wl_surface.commit. The compositor is free to dynamically respect or ignore this hint based on various conditions like hardware capabilities, surface state and user preferences. | |
| 113 | + | func (o *WpTearingControl) SetPresentationHint(hint uint32) error { | |
| 114 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_tearing_control_v1.set_presentation_hint"}, wl.ArgUint(hint)); err != nil { | |
| 115 | + | return err | |
| 116 | + | } | |
| 117 | + | return nil | |
| 118 | + | } | |
| 119 | + | ||
| 120 | + | // Destroy this surface tearing object and revert the presentation hint to vsync. The change will be applied on the next wl_surface.commit. | |
| 121 | + | func (o *WpTearingControl) Destroy() error { | |
| 122 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_tearing_control_v1.destroy", Destructor: true}); err != nil { | |
| 123 | + | return err | |
| 124 | + | } | |
| 125 | + | return nil | |
| 126 | + | } | |
| 127 | + | ||
| 128 | + | // EventSignature returns the declared event argument types in wire order. | |
| 129 | + | func (o *WpTearingControl) EventSignature(opcode uint16) (string, bool) { | |
| 130 | + | switch opcode { | |
| 131 | + | default: | |
| 132 | + | return "", false | |
| 133 | + | } | |
| 134 | + | } | |
| 135 | + | ||
| 136 | + | // Dispatch decodes one event on wp_tearing_control_v1 and calls the registered handlers. | |
| 137 | + | func (o *WpTearingControl) Dispatch(event *wl.Event) { | |
| 138 | + | switch event.Opcode { | |
| 139 | + | default: | |
| 140 | + | } | |
| 141 | + | } | |
A client/textinput/textinput_generated.go +628 -0
| @@ -0,0 +1,628 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: text_input_unstable_v3 | |
| 3 | + | // Source: text-input-unstable-v3.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2012, 2013 Intel Corporation | |
| 7 | + | // Copyright © 2015, 2016 Jan Arne Petersen | |
| 8 | + | // Copyright © 2017, 2018 Red Hat, Inc. | |
| 9 | + | // Copyright © 2018 Purism SPC | |
| 10 | + | // | |
| 11 | + | // Permission to use, copy, modify, distribute, and sell this | |
| 12 | + | // software and its documentation for any purpose is hereby granted | |
| 13 | + | // without fee, provided that the above copyright notice appear in | |
| 14 | + | // all copies and that both that copyright notice and this permission | |
| 15 | + | // notice appear in supporting documentation, and that the name of | |
| 16 | + | // the copyright holders not be used in advertising or publicity | |
| 17 | + | // pertaining to distribution of the software without specific, | |
| 18 | + | // written prior permission. The copyright holders make no | |
| 19 | + | // representations about the suitability of this software for any | |
| 20 | + | // purpose. It is provided "as is" without express or implied | |
| 21 | + | // warranty. | |
| 22 | + | // | |
| 23 | + | // THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
| 24 | + | // SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| 25 | + | // FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| 26 | + | // SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 27 | + | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
| 28 | + | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
| 29 | + | // ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| 30 | + | // THIS SOFTWARE. | |
| 31 | + | ||
| 32 | + | package textinput | |
| 33 | + | ||
| 34 | + | import ( | |
| 35 | + | "sync" | |
| 36 | + | ||
| 37 | + | cross_wl_seat "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 38 | + | "github.com/bnema/wlturbo/wl" | |
| 39 | + | ) | |
| 40 | + | ||
| 41 | + | // CHANGE_CAUSE_INPUT_METHOD is the change_cause input_method value. | |
| 42 | + | const CHANGE_CAUSE_INPUT_METHOD = 0 | |
| 43 | + | ||
| 44 | + | // CHANGE_CAUSE_OTHER is the change_cause other value. | |
| 45 | + | const CHANGE_CAUSE_OTHER = 1 | |
| 46 | + | ||
| 47 | + | // CONTENT_HINT_NONE is the content_hint none value. | |
| 48 | + | const CONTENT_HINT_NONE = 0x0 | |
| 49 | + | ||
| 50 | + | // CONTENT_HINT_COMPLETION is the content_hint completion value. | |
| 51 | + | const CONTENT_HINT_COMPLETION = 0x1 | |
| 52 | + | ||
| 53 | + | // CONTENT_HINT_SPELLCHECK is the content_hint spellcheck value. | |
| 54 | + | const CONTENT_HINT_SPELLCHECK = 0x2 | |
| 55 | + | ||
| 56 | + | // CONTENT_HINT_AUTO_CAPITALIZATION is the content_hint auto_capitalization value. | |
| 57 | + | const CONTENT_HINT_AUTO_CAPITALIZATION = 0x4 | |
| 58 | + | ||
| 59 | + | // CONTENT_HINT_LOWERCASE is the content_hint lowercase value. | |
| 60 | + | const CONTENT_HINT_LOWERCASE = 0x8 | |
| 61 | + | ||
| 62 | + | // CONTENT_HINT_UPPERCASE is the content_hint uppercase value. | |
| 63 | + | const CONTENT_HINT_UPPERCASE = 0x10 | |
| 64 | + | ||
| 65 | + | // CONTENT_HINT_TITLECASE is the content_hint titlecase value. | |
| 66 | + | const CONTENT_HINT_TITLECASE = 0x20 | |
| 67 | + | ||
| 68 | + | // CONTENT_HINT_HIDDEN_TEXT is the content_hint hidden_text value. | |
| 69 | + | const CONTENT_HINT_HIDDEN_TEXT = 0x40 | |
| 70 | + | ||
| 71 | + | // CONTENT_HINT_SENSITIVE_DATA is the content_hint sensitive_data value. | |
| 72 | + | const CONTENT_HINT_SENSITIVE_DATA = 0x80 | |
| 73 | + | ||
| 74 | + | // CONTENT_HINT_LATIN is the content_hint latin value. | |
| 75 | + | const CONTENT_HINT_LATIN = 0x100 | |
| 76 | + | ||
| 77 | + | // CONTENT_HINT_MULTILINE is the content_hint multiline value. | |
| 78 | + | const CONTENT_HINT_MULTILINE = 0x200 | |
| 79 | + | ||
| 80 | + | // CONTENT_HINT_ON_SCREEN_INPUT_PROVIDED is the content_hint on_screen_input_provided value. | |
| 81 | + | const CONTENT_HINT_ON_SCREEN_INPUT_PROVIDED = 0x400 | |
| 82 | + | ||
| 83 | + | // CONTENT_HINT_NO_EMOJI is the content_hint no_emoji value. | |
| 84 | + | const CONTENT_HINT_NO_EMOJI = 0x800 | |
| 85 | + | ||
| 86 | + | // CONTENT_HINT_PREEDIT_SHOWN is the content_hint preedit_shown value. | |
| 87 | + | const CONTENT_HINT_PREEDIT_SHOWN = 0x1000 | |
| 88 | + | ||
| 89 | + | // CONTENT_PURPOSE_NORMAL is the content_purpose normal value. | |
| 90 | + | const CONTENT_PURPOSE_NORMAL = 0 | |
| 91 | + | ||
| 92 | + | // CONTENT_PURPOSE_ALPHA is the content_purpose alpha value. | |
| 93 | + | const CONTENT_PURPOSE_ALPHA = 1 | |
| 94 | + | ||
| 95 | + | // CONTENT_PURPOSE_DIGITS is the content_purpose digits value. | |
| 96 | + | const CONTENT_PURPOSE_DIGITS = 2 | |
| 97 | + | ||
| 98 | + | // CONTENT_PURPOSE_NUMBER is the content_purpose number value. | |
| 99 | + | const CONTENT_PURPOSE_NUMBER = 3 | |
| 100 | + | ||
| 101 | + | // CONTENT_PURPOSE_PHONE is the content_purpose phone value. | |
| 102 | + | const CONTENT_PURPOSE_PHONE = 4 | |
| 103 | + | ||
| 104 | + | // CONTENT_PURPOSE_URL is the content_purpose url value. | |
| 105 | + | const CONTENT_PURPOSE_URL = 5 | |
| 106 | + | ||
| 107 | + | // CONTENT_PURPOSE_EMAIL is the content_purpose email value. | |
| 108 | + | const CONTENT_PURPOSE_EMAIL = 6 | |
| 109 | + | ||
| 110 | + | // CONTENT_PURPOSE_NAME is the content_purpose name value. | |
| 111 | + | const CONTENT_PURPOSE_NAME = 7 | |
| 112 | + | ||
| 113 | + | // CONTENT_PURPOSE_PASSWORD is the content_purpose password value. | |
| 114 | + | const CONTENT_PURPOSE_PASSWORD = 8 | |
| 115 | + | ||
| 116 | + | // CONTENT_PURPOSE_PIN is the content_purpose pin value. | |
| 117 | + | const CONTENT_PURPOSE_PIN = 9 | |
| 118 | + | ||
| 119 | + | // CONTENT_PURPOSE_DATE is the content_purpose date value. | |
| 120 | + | const CONTENT_PURPOSE_DATE = 10 | |
| 121 | + | ||
| 122 | + | // CONTENT_PURPOSE_TIME is the content_purpose time value. | |
| 123 | + | const CONTENT_PURPOSE_TIME = 11 | |
| 124 | + | ||
| 125 | + | // CONTENT_PURPOSE_DATETIME is the content_purpose datetime value. | |
| 126 | + | const CONTENT_PURPOSE_DATETIME = 12 | |
| 127 | + | ||
| 128 | + | // CONTENT_PURPOSE_TERMINAL is the content_purpose terminal value. | |
| 129 | + | const CONTENT_PURPOSE_TERMINAL = 13 | |
| 130 | + | ||
| 131 | + | // ERROR_INVALID_ACTION is the error invalid_action value. | |
| 132 | + | const ERROR_INVALID_ACTION = 0 | |
| 133 | + | ||
| 134 | + | // ACTION_NONE is the action none value. | |
| 135 | + | const ACTION_NONE = 0 | |
| 136 | + | ||
| 137 | + | // ACTION_SUBMIT is the action submit value. | |
| 138 | + | const ACTION_SUBMIT = 1 | |
| 139 | + | ||
| 140 | + | // PREEDIT_HINT_WHOLE is the preedit_hint whole value. | |
| 141 | + | const PREEDIT_HINT_WHOLE = 1 | |
| 142 | + | ||
| 143 | + | // PREEDIT_HINT_SELECTION is the preedit_hint selection value. | |
| 144 | + | const PREEDIT_HINT_SELECTION = 2 | |
| 145 | + | ||
| 146 | + | // PREEDIT_HINT_PREDICTION is the preedit_hint prediction value. | |
| 147 | + | const PREEDIT_HINT_PREDICTION = 3 | |
| 148 | + | ||
| 149 | + | // PREEDIT_HINT_PREFIX is the preedit_hint prefix value. | |
| 150 | + | const PREEDIT_HINT_PREFIX = 4 | |
| 151 | + | ||
| 152 | + | // PREEDIT_HINT_SUFFIX is the preedit_hint suffix value. | |
| 153 | + | const PREEDIT_HINT_SUFFIX = 5 | |
| 154 | + | ||
| 155 | + | // PREEDIT_HINT_SPELLING_ERROR is the preedit_hint spelling_error value. | |
| 156 | + | const PREEDIT_HINT_SPELLING_ERROR = 6 | |
| 157 | + | ||
| 158 | + | // PREEDIT_HINT_COMPOSE_ERROR is the preedit_hint compose_error value. | |
| 159 | + | const PREEDIT_HINT_COMPOSE_ERROR = 7 | |
| 160 | + | ||
| 161 | + | // TextInputV3Interface is the protocol interface name. | |
| 162 | + | const TextInputV3Interface = "zwp_text_input_v3" | |
| 163 | + | ||
| 164 | + | // TextInputV3 is the generated binding for zwp_text_input_v3 version 2. | |
| 165 | + | type TextInputV3 struct { | |
| 166 | + | wl.BaseProxy | |
| 167 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 168 | + | // handlers while another goroutine dispatches events. | |
| 169 | + | handlersMu sync.Mutex | |
| 170 | + | onEnter []func(surfaceID uint32) | |
| 171 | + | onLeave []func(surfaceID uint32) | |
| 172 | + | onPreeditString []func(text string, cursorBegin int32, cursorEnd int32) | |
| 173 | + | onCommitString []func(text string) | |
| 174 | + | onDeleteSurroundingText []func(beforeLength uint32, afterLength uint32) | |
| 175 | + | onDone []func(serial uint32) | |
| 176 | + | onAction []func(action uint32, serial uint32) | |
| 177 | + | onLanguage []func(language string) | |
| 178 | + | onPreeditHint []func(start uint32, end uint32, hint uint32) | |
| 179 | + | } | |
| 180 | + | ||
| 181 | + | // NewTextInputV3 returns an unbound TextInputV3. | |
| 182 | + | func NewTextInputV3(ctx *wl.Context) *TextInputV3 { | |
| 183 | + | obj := &TextInputV3{} | |
| 184 | + | obj.SetContext(ctx) | |
| 185 | + | ctx.Register(obj) | |
| 186 | + | return obj | |
| 187 | + | } | |
| 188 | + | ||
| 189 | + | // Destroy the wp_text_input object. Also disables all surfaces enabled through this wp_text_input object. | |
| 190 | + | func (o *TextInputV3) Destroy() error { | |
| 191 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_text_input_v3.destroy", Destructor: true}); err != nil { | |
| 192 | + | return err | |
| 193 | + | } | |
| 194 | + | return nil | |
| 195 | + | } | |
| 196 | + | ||
| 197 | + | // Requests text input on the surface previously obtained from the enter event. This request must be issued every time the focused text input changes to a new one, including within the current surface. Use zwp_text_input_v3.disable when there is no longer any input focus on the current surface. Clients must not enable more than one text input on the single seat and should disable the current text input before enabling the new one. Requests to enable a text input when another text input is enabled on the same seat must be ignored by compositor. This request resets all state associated with previous enable, disable, set_surrounding_text, set_text_change_cause, set_content_type, and set_cursor_rectangle requests, as well as the state associated with preedit_string, commit_string, and delete_surrounding_text events. The set_surrounding_text, set_content_type and set_cursor_rectangle requests must follow if the text input supports the necessary functionality. State set with this request is double-buffered. It will get applied on the next zwp_text_input_v3.commit request, and stay valid until the next committed enable or disable request. The changes must be applied by the compositor after issuing a zwp_text_input_v3.commit request. | |
| 198 | + | func (o *TextInputV3) Enable() error { | |
| 199 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_text_input_v3.enable"}); err != nil { | |
| 200 | + | return err | |
| 201 | + | } | |
| 202 | + | return nil | |
| 203 | + | } | |
| 204 | + | ||
| 205 | + | // Explicitly disable text input on the current surface (typically when there is no focus on any text entry inside the surface). State set with this request is double-buffered. It will get applied on the next zwp_text_input_v3.commit request. | |
| 206 | + | func (o *TextInputV3) Disable() error { | |
| 207 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_text_input_v3.disable"}); err != nil { | |
| 208 | + | return err | |
| 209 | + | } | |
| 210 | + | return nil | |
| 211 | + | } | |
| 212 | + | ||
| 213 | + | // Sets the surrounding plain text around the input, excluding the preedit text. The client should notify the compositor of any changes in any of the values carried with this request, including changes caused by handling incoming text-input events as well as changes caused by other mechanisms like keyboard typing. If the client is unaware of the text around the cursor, it should not issue this request, to signify lack of support to the compositor. Text is UTF-8 encoded, and should include the cursor position, the complete selection and additional characters before and after them. There is a maximum length of wayland messages, so text can not be longer than 4000 bytes. Cursor is the byte offset of the cursor within text buffer. Anchor is the byte offset of the selection anchor within text buffer. If there is no selected text, anchor is the same as cursor. If any preedit text is present, it is replaced with a cursor for the purpose of this event. Values set with this request are double-buffered. They will get applied on the next zwp_text_input_v3.commit request, and stay valid until the next committed enable or disable request. The initial state for affected fields is empty, meaning that the text input does not support sending surrounding text. If the empty values get applied, subsequent attempts to change them may have no effect. | |
| 214 | + | func (o *TextInputV3) SetSurroundingText(text string, cursor int32, anchor int32) error { | |
| 215 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "zwp_text_input_v3.set_surrounding_text"}, wl.ArgString(text), wl.ArgInt(cursor), wl.ArgInt(anchor)); err != nil { | |
| 216 | + | return err | |
| 217 | + | } | |
| 218 | + | return nil | |
| 219 | + | } | |
| 220 | + | ||
| 221 | + | // Tells the compositor why the text surrounding the cursor changed. Whenever the client detects an external change in text, cursor, or anchor posision, it must issue this request to the compositor. This request is intended to give the input method a chance to update the preedit text in an appropriate way, e.g. by removing it when the user starts typing with a keyboard. cause describes the source of the change. The value set with this request is double-buffered. It must be applied and reset to initial at the next zwp_text_input_v3.commit request. The initial value of cause is input_method. | |
| 222 | + | func (o *TextInputV3) SetTextChangeCause(cause uint32) error { | |
| 223 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 4, Name: "zwp_text_input_v3.set_text_change_cause"}, wl.ArgUint(cause)); err != nil { | |
| 224 | + | return err | |
| 225 | + | } | |
| 226 | + | return nil | |
| 227 | + | } | |
| 228 | + | ||
| 229 | + | // Sets the content purpose and content hint. While the purpose is the basic purpose of an input field, the hint flags allow to modify some of the behavior. Values set with this request are double-buffered. They will get applied on the next zwp_text_input_v3.commit request. Subsequent attempts to update them may have no effect. The values remain valid until the next committed enable or disable request. The initial value for hint is none, and the initial value for purpose is normal. | |
| 230 | + | func (o *TextInputV3) SetContentType(hint uint32, purpose uint32) error { | |
| 231 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 5, Name: "zwp_text_input_v3.set_content_type"}, wl.ArgUint(hint), wl.ArgUint(purpose)); err != nil { | |
| 232 | + | return err | |
| 233 | + | } | |
| 234 | + | return nil | |
| 235 | + | } | |
| 236 | + | ||
| 237 | + | // Marks an area around the cursor as a x, y, width, height rectangle in surface local coordinates. Allows the compositor to put a window with word suggestions near the cursor, without obstructing the text being input. If the client is unaware of the position of edited text, it should not issue this request, to signify lack of support to the compositor. Values set with this request are double-buffered. They will get applied on the next zwp_text_input_v3.commit request, and stay valid until the next committed enable or disable request. The initial values describing a cursor rectangle are empty. That means the text input does not support describing the cursor area. If the empty values get applied, subsequent attempts to change them may have no effect. As of version 2, the zwp_text_input_v3.commit request does not apply values sent with this request. Instead, it stores them in a separate "committed" area. The committed values, if still valid, get applied on the next wl_surface.commit request on the surface with text-input focus. Both committed and applied values get invalidated on: - the next committed enable or disable request, or - a change of the focused surface of the text-input (leave or enter events). This double stage application allows the compositor to position the input method popup in the same frame as the contents of the text on the surface are updated. | |
| 238 | + | func (o *TextInputV3) SetCursorRectangle(x int32, y int32, width int32, height int32) error { | |
| 239 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 6, Name: "zwp_text_input_v3.set_cursor_rectangle"}, wl.ArgInt(x), wl.ArgInt(y), wl.ArgInt(width), wl.ArgInt(height)); err != nil { | |
| 240 | + | return err | |
| 241 | + | } | |
| 242 | + | return nil | |
| 243 | + | } | |
| 244 | + | ||
| 245 | + | // Atomically applies state changes recently sent to the compositor. The commit request establishes and updates the state of the client, and must be issued after any changes to apply them. Text input state (enabled status, content purpose, content hint, surrounding text and change cause, cursor rectangle) is conceptually double-buffered within the context of a text input, i.e. between a committed enable request and the following committed enable or disable request. Protocol requests modify the pending state, as opposed to the current state in use by the input method. A commit request atomically applies all pending state, replacing the current state. After commit, the new pending state is as documented for each related request. Requests are applied in the order of arrival. Neither current nor pending state are modified unless noted otherwise. The compositor must count the number of commit requests coming from each zwp_text_input_v3 object and use the count as the serial in done events. | |
| 246 | + | func (o *TextInputV3) Commit() error { | |
| 247 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 7, Name: "zwp_text_input_v3.commit"}); err != nil { | |
| 248 | + | return err | |
| 249 | + | } | |
| 250 | + | return nil | |
| 251 | + | } | |
| 252 | + | ||
| 253 | + | // Set the actions available for this text input. Values set with this request are double-buffered. They will get applied on the next zwp_text_input_v3.commit request. If the available_actions array contains the none action, or contains the same action multiple times, the compositor must raise the invalid_action protocol error. Initially, no actions are available. | |
| 254 | + | func (o *TextInputV3) SetAvailableActions(availableActions []byte) error { | |
| 255 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 8, Name: "zwp_text_input_v3.set_available_actions", Since: 2}, wl.ArgArray(availableActions)); err != nil { | |
| 256 | + | return err | |
| 257 | + | } | |
| 258 | + | return nil | |
| 259 | + | } | |
| 260 | + | ||
| 261 | + | // Requests an input panel to be shown (e.g. a on-screen keyboard). This request only hints the desired interaction pattern from the client side, and its effect may be ignored by compositors given other environmental factors. Repeated calls will be ignored. | |
| 262 | + | func (o *TextInputV3) ShowInputPanel() error { | |
| 263 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 9, Name: "zwp_text_input_v3.show_input_panel", Since: 2}); err != nil { | |
| 264 | + | return err | |
| 265 | + | } | |
| 266 | + | return nil | |
| 267 | + | } | |
| 268 | + | ||
| 269 | + | // Requests an input panel to be hidden. This request only hints the desired interaction pattern from the client side, and its effect may be ignored by compositors given other environmental factors. Repeated calls will be ignored. | |
| 270 | + | func (o *TextInputV3) HideInputPanel() error { | |
| 271 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 10, Name: "zwp_text_input_v3.hide_input_panel", Since: 2}); err != nil { | |
| 272 | + | return err | |
| 273 | + | } | |
| 274 | + | return nil | |
| 275 | + | } | |
| 276 | + | ||
| 277 | + | // OnEnter registers a handler for the enter event. | |
| 278 | + | // | |
| 279 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 280 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 281 | + | func (o *TextInputV3) OnEnter(handler func(surfaceID uint32)) { | |
| 282 | + | if handler == nil { | |
| 283 | + | return | |
| 284 | + | } | |
| 285 | + | o.handlersMu.Lock() | |
| 286 | + | defer o.handlersMu.Unlock() | |
| 287 | + | o.onEnter = append(o.onEnter, handler) | |
| 288 | + | } | |
| 289 | + | ||
| 290 | + | // handlersForEnter returns the handlers registered for enter, taken | |
| 291 | + | // under the lock so a handler may register another handler while events are | |
| 292 | + | // being dispatched. | |
| 293 | + | func (o *TextInputV3) handlersForEnter() []func(surfaceID uint32) { | |
| 294 | + | o.handlersMu.Lock() | |
| 295 | + | defer o.handlersMu.Unlock() | |
| 296 | + | return o.onEnter | |
| 297 | + | } | |
| 298 | + | ||
| 299 | + | // OnLeave registers a handler for the leave event. | |
| 300 | + | // | |
| 301 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 302 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 303 | + | func (o *TextInputV3) OnLeave(handler func(surfaceID uint32)) { | |
| 304 | + | if handler == nil { | |
| 305 | + | return | |
| 306 | + | } | |
| 307 | + | o.handlersMu.Lock() | |
| 308 | + | defer o.handlersMu.Unlock() | |
| 309 | + | o.onLeave = append(o.onLeave, handler) | |
| 310 | + | } | |
| 311 | + | ||
| 312 | + | // handlersForLeave returns the handlers registered for leave, taken | |
| 313 | + | // under the lock so a handler may register another handler while events are | |
| 314 | + | // being dispatched. | |
| 315 | + | func (o *TextInputV3) handlersForLeave() []func(surfaceID uint32) { | |
| 316 | + | o.handlersMu.Lock() | |
| 317 | + | defer o.handlersMu.Unlock() | |
| 318 | + | return o.onLeave | |
| 319 | + | } | |
| 320 | + | ||
| 321 | + | // OnPreeditString registers a handler for the preedit_string event. | |
| 322 | + | // | |
| 323 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 324 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 325 | + | func (o *TextInputV3) OnPreeditString(handler func(text string, cursorBegin int32, cursorEnd int32)) { | |
| 326 | + | if handler == nil { | |
| 327 | + | return | |
| 328 | + | } | |
| 329 | + | o.handlersMu.Lock() | |
| 330 | + | defer o.handlersMu.Unlock() | |
| 331 | + | o.onPreeditString = append(o.onPreeditString, handler) | |
| 332 | + | } | |
| 333 | + | ||
| 334 | + | // handlersForPreeditString returns the handlers registered for preedit_string, taken | |
| 335 | + | // under the lock so a handler may register another handler while events are | |
| 336 | + | // being dispatched. | |
| 337 | + | func (o *TextInputV3) handlersForPreeditString() []func(text string, cursorBegin int32, cursorEnd int32) { | |
| 338 | + | o.handlersMu.Lock() | |
| 339 | + | defer o.handlersMu.Unlock() | |
| 340 | + | return o.onPreeditString | |
| 341 | + | } | |
| 342 | + | ||
| 343 | + | // OnCommitString registers a handler for the commit_string event. | |
| 344 | + | // | |
| 345 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 346 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 347 | + | func (o *TextInputV3) OnCommitString(handler func(text string)) { | |
| 348 | + | if handler == nil { | |
| 349 | + | return | |
| 350 | + | } | |
| 351 | + | o.handlersMu.Lock() | |
| 352 | + | defer o.handlersMu.Unlock() | |
| 353 | + | o.onCommitString = append(o.onCommitString, handler) | |
| 354 | + | } | |
| 355 | + | ||
| 356 | + | // handlersForCommitString returns the handlers registered for commit_string, taken | |
| 357 | + | // under the lock so a handler may register another handler while events are | |
| 358 | + | // being dispatched. | |
| 359 | + | func (o *TextInputV3) handlersForCommitString() []func(text string) { | |
| 360 | + | o.handlersMu.Lock() | |
| 361 | + | defer o.handlersMu.Unlock() | |
| 362 | + | return o.onCommitString | |
| 363 | + | } | |
| 364 | + | ||
| 365 | + | // OnDeleteSurroundingText registers a handler for the delete_surrounding_text event. | |
| 366 | + | // | |
| 367 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 368 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 369 | + | func (o *TextInputV3) OnDeleteSurroundingText(handler func(beforeLength uint32, afterLength uint32)) { | |
| 370 | + | if handler == nil { | |
| 371 | + | return | |
| 372 | + | } | |
| 373 | + | o.handlersMu.Lock() | |
| 374 | + | defer o.handlersMu.Unlock() | |
| 375 | + | o.onDeleteSurroundingText = append(o.onDeleteSurroundingText, handler) | |
| 376 | + | } | |
| 377 | + | ||
| 378 | + | // handlersForDeleteSurroundingText returns the handlers registered for delete_surrounding_text, taken | |
| 379 | + | // under the lock so a handler may register another handler while events are | |
| 380 | + | // being dispatched. | |
| 381 | + | func (o *TextInputV3) handlersForDeleteSurroundingText() []func(beforeLength uint32, afterLength uint32) { | |
| 382 | + | o.handlersMu.Lock() | |
| 383 | + | defer o.handlersMu.Unlock() | |
| 384 | + | return o.onDeleteSurroundingText | |
| 385 | + | } | |
| 386 | + | ||
| 387 | + | // OnDone registers a handler for the done event. | |
| 388 | + | // | |
| 389 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 390 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 391 | + | func (o *TextInputV3) OnDone(handler func(serial uint32)) { | |
| 392 | + | if handler == nil { | |
| 393 | + | return | |
| 394 | + | } | |
| 395 | + | o.handlersMu.Lock() | |
| 396 | + | defer o.handlersMu.Unlock() | |
| 397 | + | o.onDone = append(o.onDone, handler) | |
| 398 | + | } | |
| 399 | + | ||
| 400 | + | // handlersForDone returns the handlers registered for done, taken | |
| 401 | + | // under the lock so a handler may register another handler while events are | |
| 402 | + | // being dispatched. | |
| 403 | + | func (o *TextInputV3) handlersForDone() []func(serial uint32) { | |
| 404 | + | o.handlersMu.Lock() | |
| 405 | + | defer o.handlersMu.Unlock() | |
| 406 | + | return o.onDone | |
| 407 | + | } | |
| 408 | + | ||
| 409 | + | // OnAction registers a handler for the action event. | |
| 410 | + | // | |
| 411 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 412 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 413 | + | func (o *TextInputV3) OnAction(handler func(action uint32, serial uint32)) { | |
| 414 | + | if handler == nil { | |
| 415 | + | return | |
| 416 | + | } | |
| 417 | + | o.handlersMu.Lock() | |
| 418 | + | defer o.handlersMu.Unlock() | |
| 419 | + | o.onAction = append(o.onAction, handler) | |
| 420 | + | } | |
| 421 | + | ||
| 422 | + | // handlersForAction returns the handlers registered for action, taken | |
| 423 | + | // under the lock so a handler may register another handler while events are | |
| 424 | + | // being dispatched. | |
| 425 | + | func (o *TextInputV3) handlersForAction() []func(action uint32, serial uint32) { | |
| 426 | + | o.handlersMu.Lock() | |
| 427 | + | defer o.handlersMu.Unlock() | |
| 428 | + | return o.onAction | |
| 429 | + | } | |
| 430 | + | ||
| 431 | + | // OnLanguage registers a handler for the language event. | |
| 432 | + | // | |
| 433 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 434 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 435 | + | func (o *TextInputV3) OnLanguage(handler func(language string)) { | |
| 436 | + | if handler == nil { | |
| 437 | + | return | |
| 438 | + | } | |
| 439 | + | o.handlersMu.Lock() | |
| 440 | + | defer o.handlersMu.Unlock() | |
| 441 | + | o.onLanguage = append(o.onLanguage, handler) | |
| 442 | + | } | |
| 443 | + | ||
| 444 | + | // handlersForLanguage returns the handlers registered for language, taken | |
| 445 | + | // under the lock so a handler may register another handler while events are | |
| 446 | + | // being dispatched. | |
| 447 | + | func (o *TextInputV3) handlersForLanguage() []func(language string) { | |
| 448 | + | o.handlersMu.Lock() | |
| 449 | + | defer o.handlersMu.Unlock() | |
| 450 | + | return o.onLanguage | |
| 451 | + | } | |
| 452 | + | ||
| 453 | + | // OnPreeditHint registers a handler for the preedit_hint event. | |
| 454 | + | // | |
| 455 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 456 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 457 | + | func (o *TextInputV3) OnPreeditHint(handler func(start uint32, end uint32, hint uint32)) { | |
| 458 | + | if handler == nil { | |
| 459 | + | return | |
| 460 | + | } | |
| 461 | + | o.handlersMu.Lock() | |
| 462 | + | defer o.handlersMu.Unlock() | |
| 463 | + | o.onPreeditHint = append(o.onPreeditHint, handler) | |
| 464 | + | } | |
| 465 | + | ||
| 466 | + | // handlersForPreeditHint returns the handlers registered for preedit_hint, taken | |
| 467 | + | // under the lock so a handler may register another handler while events are | |
| 468 | + | // being dispatched. | |
| 469 | + | func (o *TextInputV3) handlersForPreeditHint() []func(start uint32, end uint32, hint uint32) { | |
| 470 | + | o.handlersMu.Lock() | |
| 471 | + | defer o.handlersMu.Unlock() | |
| 472 | + | return o.onPreeditHint | |
| 473 | + | } | |
| 474 | + | ||
| 475 | + | // EventSignature returns the declared event argument types in wire order. | |
| 476 | + | func (o *TextInputV3) EventSignature(opcode uint16) (string, bool) { | |
| 477 | + | switch opcode { | |
| 478 | + | case 0: | |
| 479 | + | return "object,", true | |
| 480 | + | case 1: | |
| 481 | + | return "object,", true | |
| 482 | + | case 2: | |
| 483 | + | return "string,int,int,", true | |
| 484 | + | case 3: | |
| 485 | + | return "string,", true | |
| 486 | + | case 4: | |
| 487 | + | return "uint,uint,", true | |
| 488 | + | case 5: | |
| 489 | + | return "uint,", true | |
| 490 | + | case 6: | |
| 491 | + | return "uint,uint,", true | |
| 492 | + | case 7: | |
| 493 | + | return "string,", true | |
| 494 | + | case 8: | |
| 495 | + | return "uint,uint,uint,", true | |
| 496 | + | default: | |
| 497 | + | return "", false | |
| 498 | + | } | |
| 499 | + | } | |
| 500 | + | ||
| 501 | + | // Dispatch decodes one event on zwp_text_input_v3 and calls the registered handlers. | |
| 502 | + | func (o *TextInputV3) Dispatch(event *wl.Event) { | |
| 503 | + | switch event.Opcode { | |
| 504 | + | case 0: // enter | |
| 505 | + | surfaceID := event.Uint32() | |
| 506 | + | ||
| 507 | + | for i, handler := range o.handlersForEnter() { | |
| 508 | + | _ = i | |
| 509 | + | handler(surfaceID) | |
| 510 | + | } | |
| 511 | + | case 1: // leave | |
| 512 | + | surfaceID := event.Uint32() | |
| 513 | + | ||
| 514 | + | for i, handler := range o.handlersForLeave() { | |
| 515 | + | _ = i | |
| 516 | + | handler(surfaceID) | |
| 517 | + | } | |
| 518 | + | case 2: // preedit_string | |
| 519 | + | text := event.String() | |
| 520 | + | cursorBegin := event.Int32() | |
| 521 | + | cursorEnd := event.Int32() | |
| 522 | + | ||
| 523 | + | for i, handler := range o.handlersForPreeditString() { | |
| 524 | + | _ = i | |
| 525 | + | handler(text, cursorBegin, cursorEnd) | |
| 526 | + | } | |
| 527 | + | case 3: // commit_string | |
| 528 | + | text := event.String() | |
| 529 | + | ||
| 530 | + | for i, handler := range o.handlersForCommitString() { | |
| 531 | + | _ = i | |
| 532 | + | handler(text) | |
| 533 | + | } | |
| 534 | + | case 4: // delete_surrounding_text | |
| 535 | + | beforeLength := event.Uint32() | |
| 536 | + | afterLength := event.Uint32() | |
| 537 | + | ||
| 538 | + | for i, handler := range o.handlersForDeleteSurroundingText() { | |
| 539 | + | _ = i | |
| 540 | + | handler(beforeLength, afterLength) | |
| 541 | + | } | |
| 542 | + | case 5: // done | |
| 543 | + | serial := event.Uint32() | |
| 544 | + | ||
| 545 | + | for i, handler := range o.handlersForDone() { | |
| 546 | + | _ = i | |
| 547 | + | handler(serial) | |
| 548 | + | } | |
| 549 | + | case 6: // action | |
| 550 | + | action := event.Uint32() | |
| 551 | + | serial := event.Uint32() | |
| 552 | + | ||
| 553 | + | for i, handler := range o.handlersForAction() { | |
| 554 | + | _ = i | |
| 555 | + | handler(action, serial) | |
| 556 | + | } | |
| 557 | + | case 7: // language | |
| 558 | + | language := event.String() | |
| 559 | + | ||
| 560 | + | for i, handler := range o.handlersForLanguage() { | |
| 561 | + | _ = i | |
| 562 | + | handler(language) | |
| 563 | + | } | |
| 564 | + | case 8: // preedit_hint | |
| 565 | + | start := event.Uint32() | |
| 566 | + | end := event.Uint32() | |
| 567 | + | hint := event.Uint32() | |
| 568 | + | ||
| 569 | + | for i, handler := range o.handlersForPreeditHint() { | |
| 570 | + | _ = i | |
| 571 | + | handler(start, end, hint) | |
| 572 | + | } | |
| 573 | + | default: | |
| 574 | + | } | |
| 575 | + | } | |
| 576 | + | ||
| 577 | + | // TextInputManagerV3Interface is the protocol interface name. | |
| 578 | + | const TextInputManagerV3Interface = "zwp_text_input_manager_v3" | |
| 579 | + | ||
| 580 | + | // TextInputManagerV3 is the generated binding for zwp_text_input_manager_v3 version 2. | |
| 581 | + | type TextInputManagerV3 struct { | |
| 582 | + | wl.BaseProxy | |
| 583 | + | } | |
| 584 | + | ||
| 585 | + | // NewTextInputManagerV3 returns an unbound TextInputManagerV3. | |
| 586 | + | func NewTextInputManagerV3(ctx *wl.Context) *TextInputManagerV3 { | |
| 587 | + | obj := &TextInputManagerV3{} | |
| 588 | + | obj.SetContext(ctx) | |
| 589 | + | ctx.Register(obj) | |
| 590 | + | return obj | |
| 591 | + | } | |
| 592 | + | ||
| 593 | + | // Destroy the wp_text_input_manager object. | |
| 594 | + | func (o *TextInputManagerV3) Destroy() error { | |
| 595 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_text_input_manager_v3.destroy", Destructor: true}); err != nil { | |
| 596 | + | return err | |
| 597 | + | } | |
| 598 | + | return nil | |
| 599 | + | } | |
| 600 | + | ||
| 601 | + | // Creates a new text-input object for a given seat. | |
| 602 | + | func (o *TextInputManagerV3) GetTextInput(seat *cross_wl_seat.Seat) (*TextInputV3, error) { | |
| 603 | + | var arg1 wl.Object | |
| 604 | + | if seat != nil { | |
| 605 | + | arg1 = seat | |
| 606 | + | } | |
| 607 | + | child := &TextInputV3{} | |
| 608 | + | child.SetContext(o.Context()) | |
| 609 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_text_input_manager_v3.get_text_input", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 610 | + | return nil, err | |
| 611 | + | } | |
| 612 | + | return child, nil | |
| 613 | + | } | |
| 614 | + | ||
| 615 | + | // EventSignature returns the declared event argument types in wire order. | |
| 616 | + | func (o *TextInputManagerV3) EventSignature(opcode uint16) (string, bool) { | |
| 617 | + | switch opcode { | |
| 618 | + | default: | |
| 619 | + | return "", false | |
| 620 | + | } | |
| 621 | + | } | |
| 622 | + | ||
| 623 | + | // Dispatch decodes one event on zwp_text_input_manager_v3 and calls the registered handlers. | |
| 624 | + | func (o *TextInputManagerV3) Dispatch(event *wl.Event) { | |
| 625 | + | switch event.Opcode { | |
| 626 | + | default: | |
| 627 | + | } | |
| 628 | + | } | |
A client/viewporter/viewporter_generated.go +155 -0
| @@ -0,0 +1,155 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: viewporter | |
| 3 | + | // Source: viewporter.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2013-2016 Collabora, Ltd. | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package viewporter | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 31 | + | "github.com/bnema/wlturbo/wl" | |
| 32 | + | ) | |
| 33 | + | ||
| 34 | + | // ERROR_VIEWPORT_EXISTS is the error viewport_exists value. | |
| 35 | + | const ERROR_VIEWPORT_EXISTS = 0 | |
| 36 | + | ||
| 37 | + | // ERROR_BAD_VALUE is the error bad_value value. | |
| 38 | + | const ERROR_BAD_VALUE = 0 | |
| 39 | + | ||
| 40 | + | // ERROR_BAD_SIZE is the error bad_size value. | |
| 41 | + | const ERROR_BAD_SIZE = 1 | |
| 42 | + | ||
| 43 | + | // ERROR_OUT_OF_BUFFER is the error out_of_buffer value. | |
| 44 | + | const ERROR_OUT_OF_BUFFER = 2 | |
| 45 | + | ||
| 46 | + | // ERROR_NO_SURFACE is the error no_surface value. | |
| 47 | + | const ERROR_NO_SURFACE = 3 | |
| 48 | + | ||
| 49 | + | // WpViewporterInterface is the protocol interface name. | |
| 50 | + | const WpViewporterInterface = "wp_viewporter" | |
| 51 | + | ||
| 52 | + | // WpViewporter is the generated binding for wp_viewporter version 1. | |
| 53 | + | type WpViewporter struct { | |
| 54 | + | wl.BaseProxy | |
| 55 | + | } | |
| 56 | + | ||
| 57 | + | // NewWpViewporter returns an unbound WpViewporter. | |
| 58 | + | func NewWpViewporter(ctx *wl.Context) *WpViewporter { | |
| 59 | + | obj := &WpViewporter{} | |
| 60 | + | obj.SetContext(ctx) | |
| 61 | + | ctx.Register(obj) | |
| 62 | + | return obj | |
| 63 | + | } | |
| 64 | + | ||
| 65 | + | // Informs the server that the client will not be using this protocol object anymore. This does not affect any other objects, wp_viewport objects included. | |
| 66 | + | func (o *WpViewporter) Destroy() error { | |
| 67 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_viewporter.destroy", Destructor: true}); err != nil { | |
| 68 | + | return err | |
| 69 | + | } | |
| 70 | + | return nil | |
| 71 | + | } | |
| 72 | + | ||
| 73 | + | // Instantiate an interface extension for the given wl_surface to crop and scale its content. If the given wl_surface already has a wp_viewport object associated, the viewport_exists protocol error is raised. | |
| 74 | + | func (o *WpViewporter) GetViewport(surface *cross_wl_surface.Surface) (*WpViewport, error) { | |
| 75 | + | var arg1 wl.Object | |
| 76 | + | if surface != nil { | |
| 77 | + | arg1 = surface | |
| 78 | + | } | |
| 79 | + | child := &WpViewport{} | |
| 80 | + | child.SetContext(o.Context()) | |
| 81 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_viewporter.get_viewport", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 82 | + | return nil, err | |
| 83 | + | } | |
| 84 | + | return child, nil | |
| 85 | + | } | |
| 86 | + | ||
| 87 | + | // EventSignature returns the declared event argument types in wire order. | |
| 88 | + | func (o *WpViewporter) EventSignature(opcode uint16) (string, bool) { | |
| 89 | + | switch opcode { | |
| 90 | + | default: | |
| 91 | + | return "", false | |
| 92 | + | } | |
| 93 | + | } | |
| 94 | + | ||
| 95 | + | // Dispatch decodes one event on wp_viewporter and calls the registered handlers. | |
| 96 | + | func (o *WpViewporter) Dispatch(event *wl.Event) { | |
| 97 | + | switch event.Opcode { | |
| 98 | + | default: | |
| 99 | + | } | |
| 100 | + | } | |
| 101 | + | ||
| 102 | + | // WpViewportInterface is the protocol interface name. | |
| 103 | + | const WpViewportInterface = "wp_viewport" | |
| 104 | + | ||
| 105 | + | // WpViewport is the generated binding for wp_viewport version 1. | |
| 106 | + | type WpViewport struct { | |
| 107 | + | wl.BaseProxy | |
| 108 | + | } | |
| 109 | + | ||
| 110 | + | // NewWpViewport returns an unbound WpViewport. | |
| 111 | + | func NewWpViewport(ctx *wl.Context) *WpViewport { | |
| 112 | + | obj := &WpViewport{} | |
| 113 | + | obj.SetContext(ctx) | |
| 114 | + | ctx.Register(obj) | |
| 115 | + | return obj | |
| 116 | + | } | |
| 117 | + | ||
| 118 | + | // The associated wl_surface's crop and scale state is removed. The change is applied on the next wl_surface.commit. | |
| 119 | + | func (o *WpViewport) Destroy() error { | |
| 120 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_viewport.destroy", Destructor: true}); err != nil { | |
| 121 | + | return err | |
| 122 | + | } | |
| 123 | + | return nil | |
| 124 | + | } | |
| 125 | + | ||
| 126 | + | // Set the source rectangle of the associated wl_surface. See wp_viewport for the description, and relation to the wl_buffer size. If all of x, y, width and height are -1.0, the source rectangle is unset instead. Any other set of values where width or height are zero or negative, or x or y are negative, raise the bad_value protocol error. The crop and scale state is double-buffered, see wl_surface.commit. | |
| 127 | + | func (o *WpViewport) SetSource(x wl.Fixed, y wl.Fixed, width wl.Fixed, height wl.Fixed) error { | |
| 128 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_viewport.set_source"}, wl.ArgFixed(x), wl.ArgFixed(y), wl.ArgFixed(width), wl.ArgFixed(height)); err != nil { | |
| 129 | + | return err | |
| 130 | + | } | |
| 131 | + | return nil | |
| 132 | + | } | |
| 133 | + | ||
| 134 | + | // Set the destination size of the associated wl_surface. See wp_viewport for the description, and relation to the wl_buffer size. If width is -1 and height is -1, the destination size is unset instead. Any other pair of values for width and height that contains zero or negative values raises the bad_value protocol error. The crop and scale state is double-buffered, see wl_surface.commit. | |
| 135 | + | func (o *WpViewport) SetDestination(width int32, height int32) error { | |
| 136 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wp_viewport.set_destination"}, wl.ArgInt(width), wl.ArgInt(height)); err != nil { | |
| 137 | + | return err | |
| 138 | + | } | |
| 139 | + | return nil | |
| 140 | + | } | |
| 141 | + | ||
| 142 | + | // EventSignature returns the declared event argument types in wire order. | |
| 143 | + | func (o *WpViewport) EventSignature(opcode uint16) (string, bool) { | |
| 144 | + | switch opcode { | |
| 145 | + | default: | |
| 146 | + | return "", false | |
| 147 | + | } | |
| 148 | + | } | |
| 149 | + | ||
| 150 | + | // Dispatch decodes one event on wp_viewport and calls the registered handlers. | |
| 151 | + | func (o *WpViewport) Dispatch(event *wl.Event) { | |
| 152 | + | switch event.Opcode { | |
| 153 | + | default: | |
| 154 | + | } | |
| 155 | + | } | |
A client/virtualkeyboard/virtualkeyboard_generated.go +149 -0
| @@ -0,0 +1,149 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: virtual_keyboard_unstable_v1 | |
| 3 | + | // Source: virtual-keyboard-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2008-2011 Kristian Høgsberg | |
| 7 | + | // Copyright © 2010-2013 Intel Corporation | |
| 8 | + | // Copyright © 2012-2013 Collabora, Ltd. | |
| 9 | + | // Copyright © 2018 Purism SPC | |
| 10 | + | // | |
| 11 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 12 | + | // copy of this software and associated documentation files (the "Software"), | |
| 13 | + | // to deal in the Software without restriction, including without limitation | |
| 14 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 15 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 16 | + | // Software is furnished to do so, subject to the following conditions: | |
| 17 | + | // | |
| 18 | + | // The above copyright notice and this permission notice (including the next | |
| 19 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 20 | + | // Software. | |
| 21 | + | // | |
| 22 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 23 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 24 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 25 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 26 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 27 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 28 | + | // DEALINGS IN THE SOFTWARE. | |
| 29 | + | ||
| 30 | + | package virtualkeyboard | |
| 31 | + | ||
| 32 | + | import ( | |
| 33 | + | cross_wl_seat "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 34 | + | "github.com/bnema/wlturbo/wl" | |
| 35 | + | ) | |
| 36 | + | ||
| 37 | + | // ERROR_NO_KEYMAP is the error no_keymap value. | |
| 38 | + | const ERROR_NO_KEYMAP = 0 | |
| 39 | + | ||
| 40 | + | // ERROR_UNAUTHORIZED is the error unauthorized value. | |
| 41 | + | const ERROR_UNAUTHORIZED = 0 | |
| 42 | + | ||
| 43 | + | // VirtualKeyboardInterface is the protocol interface name. | |
| 44 | + | const VirtualKeyboardInterface = "zwp_virtual_keyboard_v1" | |
| 45 | + | ||
| 46 | + | // VirtualKeyboard is the generated binding for zwp_virtual_keyboard_v1 version 1. | |
| 47 | + | type VirtualKeyboard struct { | |
| 48 | + | wl.BaseProxy | |
| 49 | + | } | |
| 50 | + | ||
| 51 | + | // NewVirtualKeyboard returns an unbound VirtualKeyboard. | |
| 52 | + | func NewVirtualKeyboard(ctx *wl.Context) *VirtualKeyboard { | |
| 53 | + | obj := &VirtualKeyboard{} | |
| 54 | + | obj.SetContext(ctx) | |
| 55 | + | ctx.Register(obj) | |
| 56 | + | return obj | |
| 57 | + | } | |
| 58 | + | ||
| 59 | + | // Provide a file descriptor to the compositor which can be memory-mapped to provide a keyboard mapping description. Format carries a value from the keymap_format enumeration. | |
| 60 | + | func (o *VirtualKeyboard) Keymap(format uint32, fd int, size uint32) error { | |
| 61 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_virtual_keyboard_v1.keymap", FDs: []int{fd}}, wl.ArgUint(format), wl.ArgFD(), wl.ArgUint(size)); err != nil { | |
| 62 | + | return err | |
| 63 | + | } | |
| 64 | + | return nil | |
| 65 | + | } | |
| 66 | + | ||
| 67 | + | // A key was pressed or released. The time argument is a timestamp with millisecond granularity, with an undefined base. All requests regarding a single object must share the same clock. Keymap must be set before issuing this request. State carries a value from the key_state enumeration. | |
| 68 | + | func (o *VirtualKeyboard) Key(time uint32, key uint32, state uint32) error { | |
| 69 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_virtual_keyboard_v1.key"}, wl.ArgUint(time), wl.ArgUint(key), wl.ArgUint(state)); err != nil { | |
| 70 | + | return err | |
| 71 | + | } | |
| 72 | + | return nil | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | // Notifies the compositor that the modifier and/or group state has changed, and it should update state. The client should use wl_keyboard.modifiers event to synchronize its internal state with seat state. Keymap must be set before issuing this request. | |
| 76 | + | func (o *VirtualKeyboard) Modifiers(modsDepressed uint32, modsLatched uint32, modsLocked uint32, group uint32) error { | |
| 77 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_virtual_keyboard_v1.modifiers"}, wl.ArgUint(modsDepressed), wl.ArgUint(modsLatched), wl.ArgUint(modsLocked), wl.ArgUint(group)); err != nil { | |
| 78 | + | return err | |
| 79 | + | } | |
| 80 | + | return nil | |
| 81 | + | } | |
| 82 | + | ||
| 83 | + | // destroy the virtual keyboard keyboard object | |
| 84 | + | func (o *VirtualKeyboard) Destroy() error { | |
| 85 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "zwp_virtual_keyboard_v1.destroy", Destructor: true}); err != nil { | |
| 86 | + | return err | |
| 87 | + | } | |
| 88 | + | return nil | |
| 89 | + | } | |
| 90 | + | ||
| 91 | + | // EventSignature returns the declared event argument types in wire order. | |
| 92 | + | func (o *VirtualKeyboard) EventSignature(opcode uint16) (string, bool) { | |
| 93 | + | switch opcode { | |
| 94 | + | default: | |
| 95 | + | return "", false | |
| 96 | + | } | |
| 97 | + | } | |
| 98 | + | ||
| 99 | + | // Dispatch decodes one event on zwp_virtual_keyboard_v1 and calls the registered handlers. | |
| 100 | + | func (o *VirtualKeyboard) Dispatch(event *wl.Event) { | |
| 101 | + | switch event.Opcode { | |
| 102 | + | default: | |
| 103 | + | } | |
| 104 | + | } | |
| 105 | + | ||
| 106 | + | // VirtualKeyboardManagerInterface is the protocol interface name. | |
| 107 | + | const VirtualKeyboardManagerInterface = "zwp_virtual_keyboard_manager_v1" | |
| 108 | + | ||
| 109 | + | // VirtualKeyboardManager is the generated binding for zwp_virtual_keyboard_manager_v1 version 1. | |
| 110 | + | type VirtualKeyboardManager struct { | |
| 111 | + | wl.BaseProxy | |
| 112 | + | } | |
| 113 | + | ||
| 114 | + | // NewVirtualKeyboardManager returns an unbound VirtualKeyboardManager. | |
| 115 | + | func NewVirtualKeyboardManager(ctx *wl.Context) *VirtualKeyboardManager { | |
| 116 | + | obj := &VirtualKeyboardManager{} | |
| 117 | + | obj.SetContext(ctx) | |
| 118 | + | ctx.Register(obj) | |
| 119 | + | return obj | |
| 120 | + | } | |
| 121 | + | ||
| 122 | + | // Creates a new virtual keyboard associated to a seat. If the compositor enables a keyboard to perform arbitrary actions, it should present an error when an untrusted client requests a new keyboard. | |
| 123 | + | func (o *VirtualKeyboardManager) CreateVirtualKeyboard(seat *cross_wl_seat.Seat) (*VirtualKeyboard, error) { | |
| 124 | + | var arg0 wl.Object | |
| 125 | + | if seat != nil { | |
| 126 | + | arg0 = seat | |
| 127 | + | } | |
| 128 | + | child := &VirtualKeyboard{} | |
| 129 | + | child.SetContext(o.Context()) | |
| 130 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_virtual_keyboard_manager_v1.create_virtual_keyboard", Child: child}, wl.ArgObject(arg0), wl.ArgObject(child)); err != nil { | |
| 131 | + | return nil, err | |
| 132 | + | } | |
| 133 | + | return child, nil | |
| 134 | + | } | |
| 135 | + | ||
| 136 | + | // EventSignature returns the declared event argument types in wire order. | |
| 137 | + | func (o *VirtualKeyboardManager) EventSignature(opcode uint16) (string, bool) { | |
| 138 | + | switch opcode { | |
| 139 | + | default: | |
| 140 | + | return "", false | |
| 141 | + | } | |
| 142 | + | } | |
| 143 | + | ||
| 144 | + | // Dispatch decodes one event on zwp_virtual_keyboard_manager_v1 and calls the registered handlers. | |
| 145 | + | func (o *VirtualKeyboardManager) Dispatch(event *wl.Event) { | |
| 146 | + | switch event.Opcode { | |
| 147 | + | default: | |
| 148 | + | } | |
| 149 | + | } | |
A client/wayland/doc.go +8 -0
| @@ -0,0 +1,8 @@ | |||
| 1 | + | // Package wayland contains canonical Wayland core protocol bindings generated from | |
| 2 | + | // the pinned wayland.xml. Bind globals with display.Registry().Bind and the | |
| 3 | + | // corresponding New* constructor. Client-created and server-created children | |
| 4 | + | // are registered with their concrete generated types; never replace them with | |
| 5 | + | // transport wrappers. On* handlers receive typed values. Received OwnedFDs | |
| 6 | + | // are closed after the event unless a handler calls Take; request FDs are | |
| 7 | + | // transferred (and closed locally) only after a complete successful send. | |
| 8 | + | package wayland | |
A client/wayland/wayland_generated.go +3995 -0 large diff (3995 lines changed): collapsed
A client/wayland/wayland_test.go +532 -0
| @@ -0,0 +1,532 @@ | |||
| 1 | + | //go:build linux | |
| 2 | + | ||
| 3 | + | package wayland_test | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "encoding/binary" | |
| 7 | + | "errors" | |
| 8 | + | "io" | |
| 9 | + | "net" | |
| 10 | + | "os" | |
| 11 | + | "testing" | |
| 12 | + | "time" | |
| 13 | + | ||
| 14 | + | "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 15 | + | "github.com/bnema/wlturbo" | |
| 16 | + | "golang.org/x/sys/unix" | |
| 17 | + | ) | |
| 18 | + | ||
| 19 | + | func pair(t *testing.T) (*net.UnixConn, *net.UnixConn) { | |
| 20 | + | t.Helper() | |
| 21 | + | f, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0) | |
| 22 | + | if err != nil { | |
| 23 | + | t.Fatal(err) | |
| 24 | + | } | |
| 25 | + | a := os.NewFile(uintptr(f[0]), "a") | |
| 26 | + | b := os.NewFile(uintptr(f[1]), "b") | |
| 27 | + | ca, e := net.FileConn(a) | |
| 28 | + | a.Close() | |
| 29 | + | if e != nil { | |
| 30 | + | t.Fatal(e) | |
| 31 | + | } | |
| 32 | + | cb, e := net.FileConn(b) | |
| 33 | + | b.Close() | |
| 34 | + | if e != nil { | |
| 35 | + | t.Fatal(e) | |
| 36 | + | } | |
| 37 | + | t.Cleanup(func() { ca.Close(); cb.Close() }) | |
| 38 | + | return ca.(*net.UnixConn), cb.(*net.UnixConn) | |
| 39 | + | } | |
| 40 | + | func frame(id uint32, op uint16, body ...uint32) []byte { | |
| 41 | + | p := make([]byte, 8+4*len(body)) | |
| 42 | + | binary.LittleEndian.PutUint32(p, id) | |
| 43 | + | binary.LittleEndian.PutUint32(p[4:], uint32(len(p))<<16|uint32(op)) | |
| 44 | + | for i, v := range body { | |
| 45 | + | binary.LittleEndian.PutUint32(p[8+i*4:], v) | |
| 46 | + | } | |
| 47 | + | return p | |
| 48 | + | } | |
| 49 | + | func receiveRequest(t *testing.T, p *net.UnixConn) { | |
| 50 | + | t.Helper() | |
| 51 | + | p.SetReadDeadline(testDeadline()) | |
| 52 | + | b := make([]byte, 256) | |
| 53 | + | if _, e := p.Read(b); e != nil { | |
| 54 | + | t.Fatal(e) | |
| 55 | + | } | |
| 56 | + | } | |
| 57 | + | func testDeadline() (d time.Time) { return time.Now().Add(2 * time.Second) } | |
| 58 | + | func send(t *testing.T, p *net.UnixConn, msg []byte, fd ...int) { | |
| 59 | + | t.Helper() | |
| 60 | + | var oob []byte | |
| 61 | + | if len(fd) > 0 { | |
| 62 | + | oob = unix.UnixRights(fd...) | |
| 63 | + | } | |
| 64 | + | if _, _, e := p.WriteMsgUnix(msg, oob, nil); e != nil { | |
| 65 | + | t.Fatal(e) | |
| 66 | + | } | |
| 67 | + | } | |
| 68 | + | func TestGeneratedCoreOverSocketpair(t *testing.T) { | |
| 69 | + | c, p := pair(t) | |
| 70 | + | d, err := wlturbo.ConnectFromConn(c) | |
| 71 | + | if err != nil { | |
| 72 | + | t.Fatal(err) | |
| 73 | + | } | |
| 74 | + | defer d.Close() | |
| 75 | + | receiveRequest(t, p) // get_registry | |
| 76 | + | seat := wayland.NewSeat(d.Context()) | |
| 77 | + | if err := d.Registry().Bind(1, wayland.SeatInterface, 1, seat); err != nil { | |
| 78 | + | t.Fatal(err) | |
| 79 | + | } | |
| 80 | + | receiveRequest(t, p) | |
| 81 | + | kb, err := seat.GetKeyboard() | |
| 82 | + | if err != nil { | |
| 83 | + | t.Fatal(err) | |
| 84 | + | } | |
| 85 | + | receiveRequest(t, p) | |
| 86 | + | var key uint32 | |
| 87 | + | kb.OnKey(func(_, _, k, _ uint32) { key = k }) | |
| 88 | + | send(t, p, frame(kb.ID(), 3, 1, 2, 42, 1)) | |
| 89 | + | if err := d.Dispatch(); err != nil { | |
| 90 | + | t.Fatal(err) | |
| 91 | + | } | |
| 92 | + | if key != 42 { | |
| 93 | + | t.Fatalf("key=%d", key) | |
| 94 | + | } | |
| 95 | + | compositor := wayland.NewCompositor(d.Context()) | |
| 96 | + | if err := d.Registry().Bind(2, wayland.CompositorInterface, 1, compositor); err != nil { | |
| 97 | + | t.Fatal(err) | |
| 98 | + | } | |
| 99 | + | receiveRequest(t, p) | |
| 100 | + | surface, err := compositor.CreateSurface() | |
| 101 | + | if err != nil { | |
| 102 | + | t.Fatal(err) | |
| 103 | + | } | |
| 104 | + | receiveRequest(t, p) | |
| 105 | + | callback, err := surface.Frame() | |
| 106 | + | if err != nil { | |
| 107 | + | t.Fatal(err) | |
| 108 | + | } | |
| 109 | + | receiveRequest(t, p) | |
| 110 | + | var done uint32 | |
| 111 | + | callback.OnDone(func(ms uint32) { done = ms }) | |
| 112 | + | send(t, p, frame(callback.ID(), 0, 123)) | |
| 113 | + | if err := d.Dispatch(); err != nil { | |
| 114 | + | t.Fatal(err) | |
| 115 | + | } | |
| 116 | + | if done != 123 { | |
| 117 | + | t.Fatalf("done=%d", done) | |
| 118 | + | } | |
| 119 | + | send(t, p, frame(callback.ID(), 0, 124)) | |
| 120 | + | if err := d.Dispatch(); !errors.Is(err, wlturbo.ErrUnknownObject) { | |
| 121 | + | t.Fatalf("destroyed callback: %v", err) | |
| 122 | + | } | |
| 123 | + | } | |
| 124 | + | func TestKeymapFDNoHandlerAndMultipleHandlers(t *testing.T) { | |
| 125 | + | c, p := pair(t) | |
| 126 | + | d, e := wlturbo.ConnectFromConn(c) | |
| 127 | + | if e != nil { | |
| 128 | + | t.Fatal(e) | |
| 129 | + | } | |
| 130 | + | defer d.Close() | |
| 131 | + | receiveRequest(t, p) | |
| 132 | + | kb := wayland.NewKeyboard(d.Context()) | |
| 133 | + | kb.SetID(d.AllocateID()) | |
| 134 | + | d.Context().Register(kb) | |
| 135 | + | r, w, e := os.Pipe() | |
| 136 | + | if e != nil { | |
| 137 | + | t.Fatal(e) | |
| 138 | + | } | |
| 139 | + | defer r.Close() | |
| 140 | + | send(t, p, frame(kb.ID(), 0, 1, 8), int(w.Fd())) | |
| 141 | + | w.Close() | |
| 142 | + | if e := d.Dispatch(); e != nil { | |
| 143 | + | t.Fatal(e) | |
| 144 | + | } | |
| 145 | + | buf := make([]byte, 1) | |
| 146 | + | if n, e := r.Read(buf); n != 0 || e != io.EOF { | |
| 147 | + | t.Fatalf("unclaimed FD n=%d err=%v", n, e) | |
| 148 | + | } | |
| 149 | + | r2, w2, e := os.Pipe() | |
| 150 | + | if e != nil { | |
| 151 | + | t.Fatal(e) | |
| 152 | + | } | |
| 153 | + | defer r2.Close() | |
| 154 | + | received := 0 | |
| 155 | + | kb.OnKeymap(func(_ uint32, fd *wlturbo.OwnedFD, _ uint32) { | |
| 156 | + | if fd == nil { | |
| 157 | + | t.Fatal("first FD missing") | |
| 158 | + | } | |
| 159 | + | n, e := fd.Take() | |
| 160 | + | if e != nil { | |
| 161 | + | t.Fatal(e) | |
| 162 | + | } | |
| 163 | + | received++ | |
| 164 | + | unix.Close(n) | |
| 165 | + | }) | |
| 166 | + | kb.OnKeymap(func(_ uint32, fd *wlturbo.OwnedFD, _ uint32) { | |
| 167 | + | if fd != nil { | |
| 168 | + | t.Fatal("duplicated owner") | |
| 169 | + | } | |
| 170 | + | received++ | |
| 171 | + | }) | |
| 172 | + | send(t, p, frame(kb.ID(), 0, 1, 8), int(w2.Fd())) | |
| 173 | + | w2.Close() | |
| 174 | + | if e := d.Dispatch(); e != nil { | |
| 175 | + | t.Fatal(e) | |
| 176 | + | } | |
| 177 | + | if received != 2 { | |
| 178 | + | t.Fatalf("handlers=%d", received) | |
| 179 | + | } | |
| 180 | + | } | |
| 181 | + | func TestBufferReleaseAndOfferChild(t *testing.T) { | |
| 182 | + | c, p := pair(t) | |
| 183 | + | d, e := wlturbo.ConnectFromConn(c) | |
| 184 | + | if e != nil { | |
| 185 | + | t.Fatal(e) | |
| 186 | + | } | |
| 187 | + | defer d.Close() | |
| 188 | + | receiveRequest(t, p) | |
| 189 | + | b := wayland.NewBuffer(d.Context()) | |
| 190 | + | b.SetID(d.AllocateID()) | |
| 191 | + | d.Context().Register(b) | |
| 192 | + | releases := 0 | |
| 193 | + | b.OnRelease(func() { releases++ }) | |
| 194 | + | send(t, p, frame(b.ID(), 0)) | |
| 195 | + | if e := d.Dispatch(); e != nil { | |
| 196 | + | t.Fatal(e) | |
| 197 | + | } | |
| 198 | + | if releases != 1 { | |
| 199 | + | t.Fatal("release not dispatched") | |
| 200 | + | } | |
| 201 | + | device := wayland.NewDataDevice(d.Context()) | |
| 202 | + | device.SetID(d.AllocateID()) | |
| 203 | + | d.Context().Register(device) | |
| 204 | + | var offer *wayland.DataOffer | |
| 205 | + | device.OnDataOffer(func(o *wayland.DataOffer) { offer = o }) | |
| 206 | + | send(t, p, frame(device.ID(), 0, 0xff000001)) | |
| 207 | + | if e := d.Dispatch(); e != nil { | |
| 208 | + | t.Fatal(e) | |
| 209 | + | } | |
| 210 | + | if offer == nil || offer.ID() != 0xff000001 { | |
| 211 | + | t.Fatalf("offer=%v", offer) | |
| 212 | + | } | |
| 213 | + | } | |
| 214 | + | ||
| 215 | + | func TestMissingKeymapDescriptor(t *testing.T) { | |
| 216 | + | c, p := pair(t) | |
| 217 | + | d, e := wlturbo.ConnectFromConn(c) | |
| 218 | + | if e != nil { | |
| 219 | + | t.Fatal(e) | |
| 220 | + | } | |
| 221 | + | defer d.Close() | |
| 222 | + | receiveRequest(t, p) | |
| 223 | + | kb := wayland.NewKeyboard(d.Context()) | |
| 224 | + | kb.SetID(d.AllocateID()) | |
| 225 | + | d.Context().Register(kb) | |
| 226 | + | send(t, p, frame(kb.ID(), 0, 1, 8)) | |
| 227 | + | if e := d.Dispatch(); !errors.Is(e, wlturbo.ErrMalformedFrame) { | |
| 228 | + | t.Fatalf("missing FD: %v", e) | |
| 229 | + | } | |
| 230 | + | } | |
| 231 | + | ||
| 232 | + | func TestInterleavedFDAndPlainMessages(t *testing.T) { | |
| 233 | + | c, p := pair(t) | |
| 234 | + | d, e := wlturbo.ConnectFromConn(c) | |
| 235 | + | if e != nil { | |
| 236 | + | t.Fatal(e) | |
| 237 | + | } | |
| 238 | + | defer d.Close() | |
| 239 | + | receiveRequest(t, p) | |
| 240 | + | kb := wayland.NewKeyboard(d.Context()) | |
| 241 | + | kb.SetID(d.AllocateID()) | |
| 242 | + | d.Context().Register(kb) | |
| 243 | + | calls := 0 | |
| 244 | + | kb.OnKeymap(func(_ uint32, fd *wlturbo.OwnedFD, _ uint32) { | |
| 245 | + | if fd == nil { | |
| 246 | + | t.Fatal("FD not assigned") | |
| 247 | + | } | |
| 248 | + | _ = fd.Close() | |
| 249 | + | calls++ | |
| 250 | + | }) | |
| 251 | + | kb.OnKey(func(_, _, key, _ uint32) { | |
| 252 | + | if key != 33 { | |
| 253 | + | t.Errorf("key=%d", key) | |
| 254 | + | } | |
| 255 | + | calls++ | |
| 256 | + | }) | |
| 257 | + | r, w, e := os.Pipe() | |
| 258 | + | if e != nil { | |
| 259 | + | t.Fatal(e) | |
| 260 | + | } | |
| 261 | + | defer r.Close() | |
| 262 | + | send(t, p, frame(kb.ID(), 0, 1, 8), int(w.Fd())) | |
| 263 | + | w.Close() | |
| 264 | + | send(t, p, frame(kb.ID(), 3, 1, 2, 33, 1)) | |
| 265 | + | if e := d.Dispatch(); e != nil { | |
| 266 | + | t.Fatal(e) | |
| 267 | + | } | |
| 268 | + | if e := d.Dispatch(); e != nil { | |
| 269 | + | t.Fatal(e) | |
| 270 | + | } | |
| 271 | + | if calls != 2 { | |
| 272 | + | t.Fatalf("calls=%d", calls) | |
| 273 | + | } | |
| 274 | + | } | |
| 275 | + | func TestMalformedGeneratedPayload(t *testing.T) { | |
| 276 | + | c, p := pair(t) | |
| 277 | + | d, e := wlturbo.ConnectFromConn(c) | |
| 278 | + | if e != nil { | |
| 279 | + | t.Fatal(e) | |
| 280 | + | } | |
| 281 | + | defer d.Close() | |
| 282 | + | receiveRequest(t, p) | |
| 283 | + | kb := wayland.NewKeyboard(d.Context()) | |
| 284 | + | kb.SetID(d.AllocateID()) | |
| 285 | + | d.Context().Register(kb) | |
| 286 | + | send(t, p, frame(kb.ID(), 3, 1, 2)) | |
| 287 | + | if e := d.Dispatch(); !errors.Is(e, wlturbo.ErrMalformedFrame) { | |
| 288 | + | t.Fatalf("truncated key: %v", e) | |
| 289 | + | } | |
| 290 | + | } | |
| 291 | + | ||
| 292 | + | func TestServerChildEventsAfterOffer(t *testing.T) { | |
| 293 | + | c, p := pair(t) | |
| 294 | + | d, e := wlturbo.ConnectFromConn(c) | |
| 295 | + | if e != nil { | |
| 296 | + | t.Fatal(e) | |
| 297 | + | } | |
| 298 | + | defer d.Close() | |
| 299 | + | receiveRequest(t, p) | |
| 300 | + | device := wayland.NewDataDevice(d.Context()) | |
| 301 | + | device.SetID(d.AllocateID()) | |
| 302 | + | d.Context().Register(device) | |
| 303 | + | const offerID = 0xff000011 | |
| 304 | + | var offer *wayland.DataOffer | |
| 305 | + | device.OnDataOffer(func(o *wayland.DataOffer) { offer = o }) | |
| 306 | + | send(t, p, frame(device.ID(), 0, offerID)) | |
| 307 | + | if e := d.Dispatch(); e != nil { | |
| 308 | + | t.Fatal(e) | |
| 309 | + | } | |
| 310 | + | if offer == nil { | |
| 311 | + | t.Fatal("missing concrete child") | |
| 312 | + | } | |
| 313 | + | got := "" | |
| 314 | + | offer.OnOffer(func(mime string) { got = mime }) | |
| 315 | + | payload := append(frame(offerID, 0), 4, 0, 0, 0, 'a', 'b', 'c', 0) | |
| 316 | + | binary.LittleEndian.PutUint32(payload[4:], uint32(len(payload))<<16) | |
| 317 | + | send(t, p, payload) | |
| 318 | + | if e := d.Dispatch(); e != nil { | |
| 319 | + | t.Fatal(e) | |
| 320 | + | } | |
| 321 | + | if got != "abc" { | |
| 322 | + | t.Fatalf("typed child event: %q", got) | |
| 323 | + | } | |
| 324 | + | } | |
| 325 | + | ||
| 326 | + | func TestRegistryBootstrapAnnouncements(t *testing.T) { | |
| 327 | + | c, p := pair(t) | |
| 328 | + | d, e := wlturbo.ConnectFromConn(c) | |
| 329 | + | if e != nil { | |
| 330 | + | t.Fatal(e) | |
| 331 | + | } | |
| 332 | + | defer d.Close() | |
| 333 | + | receiveRequest(t, p) | |
| 334 | + | var got wlturbo.Global | |
| 335 | + | d.Registry().AddHandler("wl_compositor", func(r *wlturbo.Registry, n, v uint32) { got, _ = r.FindGlobalByName(n) }) | |
| 336 | + | name := "wl_compositor" | |
| 337 | + | body := make([]byte, 4+4+((len(name)+1+3)&^3)+4) | |
| 338 | + | binary.LittleEndian.PutUint32(body, 17) | |
| 339 | + | binary.LittleEndian.PutUint32(body[4:], uint32(len(name)+1)) | |
| 340 | + | copy(body[8:], name) | |
| 341 | + | binary.LittleEndian.PutUint32(body[len(body)-4:], 7) | |
| 342 | + | msg := append(frame(d.Registry().ID(), 0), body...) | |
| 343 | + | binary.LittleEndian.PutUint32(msg[4:], uint32(len(msg))<<16) | |
| 344 | + | send(t, p, msg) | |
| 345 | + | if e := d.Dispatch(); e != nil { | |
| 346 | + | t.Fatal(e) | |
| 347 | + | } | |
| 348 | + | if got.Name != 17 || got.Interface != name || got.Version != 7 { | |
| 349 | + | t.Fatalf("global: %+v", got) | |
| 350 | + | } | |
| 351 | + | send(t, p, frame(d.Registry().ID(), 1, 17)) | |
| 352 | + | if e := d.Dispatch(); e != nil { | |
| 353 | + | t.Fatal(e) | |
| 354 | + | } | |
| 355 | + | if _, ok := d.Registry().FindGlobalByName(17); ok { | |
| 356 | + | t.Fatal("global not removed") | |
| 357 | + | } | |
| 358 | + | send(t, p, frame(d.Registry().ID(), 2)) | |
| 359 | + | if e := d.Dispatch(); !errors.Is(e, wlturbo.ErrUnknownOpcode) { | |
| 360 | + | t.Fatalf("unknown registry opcode: %v", e) | |
| 361 | + | } | |
| 362 | + | } | |
| 363 | + | func TestUnclaimedFirstHandlerFDClosed(t *testing.T) { | |
| 364 | + | c, p := pair(t) | |
| 365 | + | d, e := wlturbo.ConnectFromConn(c) | |
| 366 | + | if e != nil { | |
| 367 | + | t.Fatal(e) | |
| 368 | + | } | |
| 369 | + | defer d.Close() | |
| 370 | + | receiveRequest(t, p) | |
| 371 | + | kb := wayland.NewKeyboard(d.Context()) | |
| 372 | + | kb.SetID(d.AllocateID()) | |
| 373 | + | d.Context().Register(kb) | |
| 374 | + | kb.OnKeymap(func(_ uint32, fd *wlturbo.OwnedFD, _ uint32) { | |
| 375 | + | if fd == nil { | |
| 376 | + | t.Fatal("missing first owner") | |
| 377 | + | } | |
| 378 | + | }) | |
| 379 | + | kb.OnKeymap(func(_ uint32, fd *wlturbo.OwnedFD, _ uint32) { | |
| 380 | + | if fd != nil { | |
| 381 | + | t.Fatal("duplicate owner") | |
| 382 | + | } | |
| 383 | + | }) | |
| 384 | + | r, w, e := os.Pipe() | |
| 385 | + | if e != nil { | |
| 386 | + | t.Fatal(e) | |
| 387 | + | } | |
| 388 | + | defer r.Close() | |
| 389 | + | send(t, p, frame(kb.ID(), 0, 1, 8), int(w.Fd())) | |
| 390 | + | w.Close() | |
| 391 | + | if e := d.Dispatch(); e != nil { | |
| 392 | + | t.Fatal(e) | |
| 393 | + | } | |
| 394 | + | if e := r.SetReadDeadline(testDeadline()); e != nil { | |
| 395 | + | t.Fatal(e) | |
| 396 | + | } | |
| 397 | + | var b [1]byte | |
| 398 | + | if n, e := r.Read(b[:]); n != 0 || e != io.EOF { | |
| 399 | + | t.Fatalf("unclaimed FD not closed: %d %v", n, e) | |
| 400 | + | } | |
| 401 | + | } | |
| 402 | + | ||
| 403 | + | func TestDestroyedProxyRejectsRequests(t *testing.T) { | |
| 404 | + | c, p := pair(t) | |
| 405 | + | d, err := wlturbo.ConnectFromConn(c) | |
| 406 | + | if err != nil { | |
| 407 | + | t.Fatal(err) | |
| 408 | + | } | |
| 409 | + | defer d.Close() | |
| 410 | + | receiveRequest(t, p) | |
| 411 | + | surface := wayland.NewSurface(d.Context()) | |
| 412 | + | surface.SetID(d.AllocateID()) | |
| 413 | + | d.Context().Register(surface) | |
| 414 | + | if err := surface.Destroy(); err != nil { | |
| 415 | + | t.Fatal(err) | |
| 416 | + | } | |
| 417 | + | receiveRequest(t, p) | |
| 418 | + | if err := surface.Destroy(); err == nil { | |
| 419 | + | t.Fatal("second destroy succeeded") | |
| 420 | + | } | |
| 421 | + | if err := surface.Commit(); err == nil { | |
| 422 | + | t.Fatal("request on destroyed surface succeeded") | |
| 423 | + | } | |
| 424 | + | if _, err := surface.Frame(); err == nil { | |
| 425 | + | t.Fatal("child request on destroyed surface succeeded") | |
| 426 | + | } | |
| 427 | + | p.SetReadDeadline(time.Now().Add(20 * time.Millisecond)) | |
| 428 | + | _, err = p.Read(make([]byte, 32)) | |
| 429 | + | ne, ok := err.(net.Error) | |
| 430 | + | if !ok || !ne.Timeout() { | |
| 431 | + | t.Fatalf("unexpected bytes on wire: %v", err) | |
| 432 | + | } | |
| 433 | + | } | |
| 434 | + | ||
| 435 | + | func TestConcurrentDestroySendsOnce(t *testing.T) { | |
| 436 | + | c, p := pair(t) | |
| 437 | + | d, err := wlturbo.ConnectFromConn(c) | |
| 438 | + | if err != nil { | |
| 439 | + | t.Fatal(err) | |
| 440 | + | } | |
| 441 | + | defer d.Close() | |
| 442 | + | receiveRequest(t, p) | |
| 443 | + | const rounds, destroyers, committers = 100, 4, 4 | |
| 444 | + | totalCommits := 0 | |
| 445 | + | for round := 0; round < rounds; round++ { | |
| 446 | + | surface := wayland.NewSurface(d.Context()) | |
| 447 | + | surface.SetID(d.AllocateID()) | |
| 448 | + | d.Context().Register(surface) | |
| 449 | + | start := make(chan struct{}) | |
| 450 | + | destroyed := make(chan error, destroyers) | |
| 451 | + | committed := make(chan error, committers) | |
| 452 | + | for i := 0; i < destroyers; i++ { | |
| 453 | + | go func() { <-start; destroyed <- surface.Destroy() }() | |
| 454 | + | } | |
| 455 | + | for i := 0; i < committers; i++ { | |
| 456 | + | go func() { <-start; committed <- surface.Commit() }() | |
| 457 | + | } | |
| 458 | + | close(start) | |
| 459 | + | okDestroy, okCommit := 0, 0 | |
| 460 | + | for i := 0; i < destroyers; i++ { | |
| 461 | + | if <-destroyed == nil { | |
| 462 | + | okDestroy++ | |
| 463 | + | } | |
| 464 | + | } | |
| 465 | + | for i := 0; i < committers; i++ { | |
| 466 | + | if <-committed == nil { | |
| 467 | + | okCommit++ | |
| 468 | + | } | |
| 469 | + | } | |
| 470 | + | if okDestroy != 1 { | |
| 471 | + | t.Fatalf("round %d: %d destroys succeeded, want 1", round, okDestroy) | |
| 472 | + | } | |
| 473 | + | totalCommits += okCommit | |
| 474 | + | // Decode every frame: exactly okCommit commits (opcode 6), then one | |
| 475 | + | // destroy (opcode 0) for this surface, and nothing after it. | |
| 476 | + | frames := readFrames(t, p, okCommit+1) | |
| 477 | + | for i, f := range frames { | |
| 478 | + | if f.id != surface.ID() { | |
| 479 | + | t.Fatalf("round %d: frame %d targets object %d", round, i, f.id) | |
| 480 | + | } | |
| 481 | + | last := i == len(frames)-1 | |
| 482 | + | if last && f.opcode != 0 || !last && f.opcode != 6 { | |
| 483 | + | t.Fatalf("round %d: frame %d opcode %d (last=%v)", round, i, f.opcode, last) | |
| 484 | + | } | |
| 485 | + | } | |
| 486 | + | p.SetReadDeadline(time.Now().Add(2 * time.Millisecond)) | |
| 487 | + | if n, err := p.Read(make([]byte, 8)); n != 0 { | |
| 488 | + | t.Fatalf("round %d: request after destroy (%d bytes, %v)", round, n, err) | |
| 489 | + | } | |
| 490 | + | p.SetReadDeadline(time.Time{}) | |
| 491 | + | } | |
| 492 | + | // Ordering is only exercised when some commits won the race. | |
| 493 | + | if totalCommits == 0 { | |
| 494 | + | t.Fatal("no commit succeeded in any round; ordering was not exercised") | |
| 495 | + | } | |
| 496 | + | } | |
| 497 | + | ||
| 498 | + | type wireFrame struct { | |
| 499 | + | id uint32 | |
| 500 | + | opcode uint16 | |
| 501 | + | } | |
| 502 | + | ||
| 503 | + | func readFrames(t *testing.T, p *net.UnixConn, n int) []wireFrame { | |
| 504 | + | t.Helper() | |
| 505 | + | p.SetReadDeadline(testDeadline()) | |
| 506 | + | defer p.SetReadDeadline(time.Time{}) | |
| 507 | + | var out []wireFrame | |
| 508 | + | var buf []byte | |
| 509 | + | tmp := make([]byte, 4096) | |
| 510 | + | for len(out) < n { | |
| 511 | + | for len(buf) >= 8 { | |
| 512 | + | size := int(binary.LittleEndian.Uint32(buf[4:8]) >> 16) | |
| 513 | + | if size < 8 || len(buf) < size { | |
| 514 | + | break | |
| 515 | + | } | |
| 516 | + | out = append(out, wireFrame{binary.LittleEndian.Uint32(buf[0:4]), uint16(binary.LittleEndian.Uint32(buf[4:8]))}) | |
| 517 | + | buf = buf[size:] | |
| 518 | + | } | |
| 519 | + | if len(out) >= n { | |
| 520 | + | break | |
| 521 | + | } | |
| 522 | + | m, err := p.Read(tmp) | |
| 523 | + | if err != nil { | |
| 524 | + | t.Fatalf("read frames: got %d of %d: %v", len(out), n, err) | |
| 525 | + | } | |
| 526 | + | buf = append(buf, tmp[:m]...) | |
| 527 | + | } | |
| 528 | + | if len(out) != n || len(buf) != 0 { | |
| 529 | + | t.Fatalf("got %d frames (+%d bytes), want %d", len(out), len(buf), n) | |
| 530 | + | } | |
| 531 | + | return out | |
| 532 | + | } | |
A client/wlr_extensions_test.go +652 -0
| @@ -0,0 +1,652 @@ | |||
| 1 | + | //go:build linux | |
| 2 | + | ||
| 3 | + | package client_test | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "bytes" | |
| 7 | + | "encoding/binary" | |
| 8 | + | "errors" | |
| 9 | + | "os" | |
| 10 | + | "reflect" | |
| 11 | + | "testing" | |
| 12 | + | "time" | |
| 13 | + | ||
| 14 | + | "github.com/bnema/go-wayland-bindings/client/inputmethod" | |
| 15 | + | kdeserverdecoration "github.com/bnema/go-wayland-bindings/client/serverdecoration" | |
| 16 | + | "github.com/bnema/go-wayland-bindings/client/textinput" | |
| 17 | + | "github.com/bnema/go-wayland-bindings/client/virtualkeyboard" | |
| 18 | + | "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 19 | + | foreigntoplevel "github.com/bnema/go-wayland-bindings/client/wlrforeigntoplevelmanagement" | |
| 20 | + | layershell "github.com/bnema/go-wayland-bindings/client/wlrlayershell" | |
| 21 | + | outputmanagement "github.com/bnema/go-wayland-bindings/client/wlroutputmanagement" | |
| 22 | + | outputpower "github.com/bnema/go-wayland-bindings/client/wlroutputpowermanagement" | |
| 23 | + | screencopy "github.com/bnema/go-wayland-bindings/client/wlrscreencopy" | |
| 24 | + | "github.com/bnema/go-wayland-bindings/client/xdgshell" | |
| 25 | + | "github.com/bnema/wlturbo" | |
| 26 | + | "golang.org/x/sys/unix" | |
| 27 | + | ) | |
| 28 | + | ||
| 29 | + | // The output head, its modes and configuration objects are all created by | |
| 30 | + | // server events (new_id in an event) or nested client requests. | |
| 31 | + | func TestWlrOutputManagementHeadNewID(t *testing.T) { | |
| 32 | + | s := newWireEnv(t) | |
| 33 | + | mgr := outputmanagement.NewOutputManager(s.d.Context()) | |
| 34 | + | s.bind(1, outputmanagement.OutputManagerInterface, 4, 4, mgr) | |
| 35 | + | ||
| 36 | + | var head *outputmanagement.OutputHead | |
| 37 | + | mgr.OnHead(func(h *outputmanagement.OutputHead) { head = h }) | |
| 38 | + | var serial uint32 | |
| 39 | + | mgr.OnDone(func(v uint32) { serial = v }) | |
| 40 | + | s.event(mgr.ID(), 0, wordBytes(serverID+1)...) | |
| 41 | + | if head == nil || head.ID() != serverID+1 || head.Version() != mgr.Version() || head.Version() != 4 { | |
| 42 | + | t.Fatalf("head %+v", head) | |
| 43 | + | } | |
| 44 | + | ||
| 45 | + | var name string | |
| 46 | + | var mode *outputmanagement.OutputMode | |
| 47 | + | var current uint32 | |
| 48 | + | var scale wlturbo.Fixed | |
| 49 | + | var enabled int32 | |
| 50 | + | head.OnName(func(v string) { name = v }) | |
| 51 | + | head.OnMode(func(m *outputmanagement.OutputMode) { mode = m }) | |
| 52 | + | head.OnCurrentMode(func(id uint32) { current = id }) | |
| 53 | + | head.OnScale(func(v wlturbo.Fixed) { scale = v }) | |
| 54 | + | head.OnEnabled(func(v int32) { enabled = v }) | |
| 55 | + | s.event(head.ID(), 0, str("HDMI-A-1")...) | |
| 56 | + | s.event(head.ID(), 3, wordBytes(serverID+2)...) | |
| 57 | + | if mode == nil || mode.ID() != serverID+2 || mode.Version() != 4 { | |
| 58 | + | t.Fatalf("mode %+v", mode) | |
| 59 | + | } | |
| 60 | + | var w, h, refresh int32 | |
| 61 | + | var preferred bool | |
| 62 | + | mode.OnSize(func(a, b int32) { w, h = a, b }) | |
| 63 | + | mode.OnRefresh(func(v int32) { refresh = v }) | |
| 64 | + | mode.OnPreferred(func() { preferred = true }) | |
| 65 | + | s.event(mode.ID(), 0, wordBytes(1920, 1080)...) | |
| 66 | + | s.event(mode.ID(), 1, wordBytes(60000)...) | |
| 67 | + | s.event(mode.ID(), 2) | |
| 68 | + | s.event(head.ID(), 4, wordBytes(1)...) | |
| 69 | + | s.event(head.ID(), 5, wordBytes(mode.ID())...) | |
| 70 | + | s.event(head.ID(), 8, wordBytes(uint32(wlturbo.NewFixed(1.5)))...) | |
| 71 | + | s.event(mgr.ID(), 1, wordBytes(41)...) | |
| 72 | + | if name != "HDMI-A-1" || w != 1920 || h != 1080 || refresh != 60000 || !preferred || | |
| 73 | + | enabled != 1 || current != mode.ID() || scale.Float64() != 1.5 || serial != 41 { | |
| 74 | + | t.Fatal(name, w, h, refresh, preferred, enabled, current, scale, serial) | |
| 75 | + | } | |
| 76 | + | ||
| 77 | + | // create_configuration -> enable_head (new_id + object) -> setters -> apply. | |
| 78 | + | cfg, e := mgr.CreateConfiguration(serial) | |
| 79 | + | noerr(t, e) | |
| 80 | + | wantWords(t, "create_configuration", s.req(mgr.ID(), 0), cfg.ID(), 41) | |
| 81 | + | ch, e := cfg.EnableHead(head) | |
| 82 | + | noerr(t, e) | |
| 83 | + | wantWords(t, "enable_head", s.req(cfg.ID(), 0), ch.ID(), head.ID()) | |
| 84 | + | noerr(t, ch.SetMode(mode)) | |
| 85 | + | wantWords(t, "set_mode", s.req(ch.ID(), 0), mode.ID()) | |
| 86 | + | noerr(t, ch.SetPosition(-10, 20)) | |
| 87 | + | wantWords(t, "set_position", s.req(ch.ID(), 2), 0xfffffff6, 20) | |
| 88 | + | noerr(t, ch.SetTransform(wayland.TRANSFORM_90)) | |
| 89 | + | wantWords(t, "set_transform", s.req(ch.ID(), 3), wayland.TRANSFORM_90) | |
| 90 | + | noerr(t, ch.SetScale(wlturbo.NewFixed(2))) | |
| 91 | + | wantWords(t, "set_scale", s.req(ch.ID(), 4), uint32(wlturbo.NewFixed(2))) | |
| 92 | + | noerr(t, ch.SetAdaptiveSync(outputmanagement.ADAPTIVE_SYNC_STATE_ENABLED)) | |
| 93 | + | wantWords(t, "set_adaptive_sync", s.req(ch.ID(), 5), 1) | |
| 94 | + | noerr(t, cfg.Test()) | |
| 95 | + | s.req(cfg.ID(), 3) | |
| 96 | + | noerr(t, cfg.Apply()) | |
| 97 | + | s.req(cfg.ID(), 2) | |
| 98 | + | var results []string | |
| 99 | + | cfg.OnSucceeded(func() { results = append(results, "succeeded") }) | |
| 100 | + | cfg.OnFailed(func() { results = append(results, "failed") }) | |
| 101 | + | cfg.OnCancelled(func() { results = append(results, "cancelled") }) | |
| 102 | + | s.event(cfg.ID(), 0) | |
| 103 | + | s.event(cfg.ID(), 1) | |
| 104 | + | s.event(cfg.ID(), 2) | |
| 105 | + | if !reflect.DeepEqual(results, []string{"succeeded", "failed", "cancelled"}) { | |
| 106 | + | t.Fatal(results) | |
| 107 | + | } | |
| 108 | + | noerr(t, cfg.Destroy()) | |
| 109 | + | s.req(cfg.ID(), 4) | |
| 110 | + | ||
| 111 | + | // Release destructors (since 3) and manager finished (destructor event). | |
| 112 | + | var headFinished bool | |
| 113 | + | head.OnFinished(func() { headFinished = true }) | |
| 114 | + | s.event(head.ID(), 9) | |
| 115 | + | if !headFinished { | |
| 116 | + | t.Fatal("head finished not delivered") | |
| 117 | + | } | |
| 118 | + | noerr(t, mode.Release()) | |
| 119 | + | s.req(mode.ID(), 0) | |
| 120 | + | noerr(t, head.Release()) | |
| 121 | + | s.req(head.ID(), 0) | |
| 122 | + | noerr(t, mgr.Stop()) | |
| 123 | + | s.req(mgr.ID(), 1) | |
| 124 | + | var finished bool | |
| 125 | + | mgr.OnFinished(func() { finished = true }) | |
| 126 | + | s.event(mgr.ID(), 2) | |
| 127 | + | if !finished { | |
| 128 | + | t.Fatal("finished not delivered") | |
| 129 | + | } | |
| 130 | + | if e := mgr.Stop(); e == nil { | |
| 131 | + | t.Fatal("request on a finished manager must fail") | |
| 132 | + | } | |
| 133 | + | s.noRequest() | |
| 134 | + | } | |
| 135 | + | ||
| 136 | + | func TestWlrOutputManagementVersionGate(t *testing.T) { | |
| 137 | + | s := newWireEnv(t) | |
| 138 | + | mgr := outputmanagement.NewOutputManager(s.d.Context()) | |
| 139 | + | s.bind(1, outputmanagement.OutputManagerInterface, 4, 2, mgr) | |
| 140 | + | var head *outputmanagement.OutputHead | |
| 141 | + | mgr.OnHead(func(h *outputmanagement.OutputHead) { head = h }) | |
| 142 | + | s.event(mgr.ID(), 0, wordBytes(serverID+1)...) | |
| 143 | + | if head == nil || head.Version() != 2 { | |
| 144 | + | t.Fatalf("head %+v", head) | |
| 145 | + | } | |
| 146 | + | if e := head.Release(); !errors.Is(e, wlturbo.ErrVersionTooLow) { | |
| 147 | + | t.Fatalf("release on v2 head: %v", e) | |
| 148 | + | } | |
| 149 | + | s.noRequest() | |
| 150 | + | } | |
| 151 | + | ||
| 152 | + | func TestWlrScreencopyBufferFlow(t *testing.T) { | |
| 153 | + | s := newWireEnv(t) | |
| 154 | + | out := s.output() | |
| 155 | + | shm := wayland.NewShm(s.d.Context()) | |
| 156 | + | s.bind(1, wayland.ShmInterface, 1, 1, shm) | |
| 157 | + | mgr := screencopy.NewScreencopyManager(s.d.Context()) | |
| 158 | + | s.bind(2, screencopy.ScreencopyManagerInterface, 3, 3, mgr) | |
| 159 | + | ||
| 160 | + | frame, e := mgr.CaptureOutput(1, out) | |
| 161 | + | noerr(t, e) | |
| 162 | + | wantWords(t, "capture_output", s.req(mgr.ID(), 0), frame.ID(), 1, out.ID()) | |
| 163 | + | if frame.Version() != 3 { | |
| 164 | + | t.Fatalf("frame version %d", frame.Version()) | |
| 165 | + | } | |
| 166 | + | var events []string | |
| 167 | + | var shmW, shmH, shmStride, shmFormat uint32 | |
| 168 | + | frame.OnBuffer(func(f, w, h, st uint32) { | |
| 169 | + | shmFormat, shmW, shmH, shmStride = f, w, h, st | |
| 170 | + | events = append(events, "buffer") | |
| 171 | + | }) | |
| 172 | + | frame.OnLinuxDmabuf(func(f, w, h uint32) { events = append(events, "dmabuf") }) | |
| 173 | + | frame.OnBufferDone(func() { events = append(events, "done") }) | |
| 174 | + | frame.OnFlags(func(f uint32) { | |
| 175 | + | if f != screencopy.FLAGS_Y_INVERT { | |
| 176 | + | t.Fatalf("flags %d", f) | |
| 177 | + | } | |
| 178 | + | events = append(events, "flags") | |
| 179 | + | }) | |
| 180 | + | var sec uint64 | |
| 181 | + | var nsec uint32 | |
| 182 | + | frame.OnReady(func(hi, lo, ns uint32) { sec, nsec = uint64(hi)<<32|uint64(lo), ns; events = append(events, "ready") }) | |
| 183 | + | s.event(frame.ID(), 0, wordBytes(wayland.FORMAT_XRGB8888, 4, 2, 16)...) | |
| 184 | + | s.event(frame.ID(), 5, wordBytes(0x34325258, 4, 2)...) | |
| 185 | + | s.event(frame.ID(), 6) | |
| 186 | + | if shmFormat != wayland.FORMAT_XRGB8888 || shmW != 4 || shmH != 2 || shmStride != 16 { | |
| 187 | + | t.Fatal(shmFormat, shmW, shmH, shmStride) | |
| 188 | + | } | |
| 189 | + | ||
| 190 | + | // Build the wl_shm buffer the compositor asked for; the pool descriptor is | |
| 191 | + | // duplicated by the kernel and the client's copy is closed by the binding. | |
| 192 | + | memfd, e := unix.MemfdCreate("wlturbo-shm", unix.MFD_CLOEXEC) | |
| 193 | + | noerr(t, e) | |
| 194 | + | noerr(t, unix.Ftruncate(memfd, 32)) | |
| 195 | + | pool, e := shm.CreatePool(memfd, 32) | |
| 196 | + | noerr(t, e) | |
| 197 | + | requireFDClosed(t, memfd) | |
| 198 | + | body, fd := s.reqFD(shm.ID(), 0) | |
| 199 | + | unix.Close(fd) | |
| 200 | + | wantWords(t, "create_pool", body, pool.ID(), 32) | |
| 201 | + | buf, e := pool.CreateBuffer(0, 4, 2, 16, wayland.FORMAT_XRGB8888) | |
| 202 | + | noerr(t, e) | |
| 203 | + | wantWords(t, "create_buffer", s.req(pool.ID(), 0), buf.ID(), 0, 4, 2, 16, wayland.FORMAT_XRGB8888) | |
| 204 | + | ||
| 205 | + | noerr(t, frame.Copy(buf)) | |
| 206 | + | wantWords(t, "copy", s.req(frame.ID(), 0), buf.ID()) | |
| 207 | + | s.event(frame.ID(), 1, wordBytes(screencopy.FLAGS_Y_INVERT)...) | |
| 208 | + | s.event(frame.ID(), 2, wordBytes(1, 2, 999999999)...) | |
| 209 | + | if sec != 1<<32|2 || nsec != 999999999 { | |
| 210 | + | t.Fatal(sec, nsec) | |
| 211 | + | } | |
| 212 | + | want := []string{"buffer", "dmabuf", "done", "flags", "ready"} | |
| 213 | + | if !reflect.DeepEqual(events, want) { | |
| 214 | + | t.Fatalf("events %v, want %v", events, want) | |
| 215 | + | } | |
| 216 | + | noerr(t, frame.Destroy()) | |
| 217 | + | s.req(frame.ID(), 1) | |
| 218 | + | ||
| 219 | + | // Region capture + damage + failure on a second frame. | |
| 220 | + | f2, e := mgr.CaptureOutputRegion(0, out, -1, 2, 30, 40) | |
| 221 | + | noerr(t, e) | |
| 222 | + | wantWords(t, "capture_output_region", s.req(mgr.ID(), 1), f2.ID(), 0, out.ID(), 0xffffffff, 2, 30, 40) | |
| 223 | + | noerr(t, f2.CopyWithDamage(buf)) | |
| 224 | + | wantWords(t, "copy_with_damage", s.req(f2.ID(), 2), buf.ID()) | |
| 225 | + | var damage []uint32 | |
| 226 | + | var failed bool | |
| 227 | + | f2.OnDamage(func(x, y, w, h uint32) { damage = []uint32{x, y, w, h} }) | |
| 228 | + | f2.OnFailed(func() { failed = true }) | |
| 229 | + | s.event(f2.ID(), 4, wordBytes(1, 2, 3, 4)...) | |
| 230 | + | s.event(f2.ID(), 3) | |
| 231 | + | if !reflect.DeepEqual(damage, []uint32{1, 2, 3, 4}) || !failed { | |
| 232 | + | t.Fatal(damage, failed) | |
| 233 | + | } | |
| 234 | + | noerr(t, f2.Destroy()) | |
| 235 | + | s.req(f2.ID(), 1) | |
| 236 | + | noerr(t, buf.Destroy()) | |
| 237 | + | s.req(buf.ID(), 0) | |
| 238 | + | noerr(t, mgr.Destroy()) | |
| 239 | + | s.req(mgr.ID(), 2) | |
| 240 | + | } | |
| 241 | + | ||
| 242 | + | func TestWlrScreencopyVersionGate(t *testing.T) { | |
| 243 | + | s := newWireEnv(t) | |
| 244 | + | out := s.output() | |
| 245 | + | mgr := screencopy.NewScreencopyManager(s.d.Context()) | |
| 246 | + | s.bind(1, screencopy.ScreencopyManagerInterface, 3, 1, mgr) | |
| 247 | + | frame, e := mgr.CaptureOutput(0, out) | |
| 248 | + | noerr(t, e) | |
| 249 | + | s.req(mgr.ID(), 0) | |
| 250 | + | buf := wayland.NewBuffer(s.d.Context()) | |
| 251 | + | buf.SetID(s.d.AllocateID()) | |
| 252 | + | s.d.Context().Register(buf) | |
| 253 | + | if e := frame.CopyWithDamage(buf); !errors.Is(e, wlturbo.ErrVersionTooLow) { | |
| 254 | + | t.Fatalf("copy_with_damage on v1 frame: %v", e) | |
| 255 | + | } | |
| 256 | + | s.noRequest() | |
| 257 | + | noerr(t, frame.Copy(buf)) | |
| 258 | + | s.req(frame.ID(), 0) | |
| 259 | + | } | |
| 260 | + | ||
| 261 | + | func TestWlrInputMethodFDAndCrossPackageEnums(t *testing.T) { | |
| 262 | + | s := newWireEnv(t) | |
| 263 | + | seat, surf := s.seat(), s.surface() | |
| 264 | + | mgr := inputmethod.NewInputMethodManager(s.d.Context()) | |
| 265 | + | s.bind(1, inputmethod.InputMethodManagerInterface, 1, 1, mgr) | |
| 266 | + | im, e := mgr.GetInputMethod(seat) | |
| 267 | + | noerr(t, e) | |
| 268 | + | wantWords(t, "get_input_method", s.req(mgr.ID(), 0), seat.ID(), im.ID()) | |
| 269 | + | ||
| 270 | + | var seq []string | |
| 271 | + | var text string | |
| 272 | + | var cursor, anchor, cause, hint, purpose uint32 | |
| 273 | + | im.OnActivate(func() { seq = append(seq, "activate") }) | |
| 274 | + | im.OnSurroundingText(func(tx string, c, a uint32) { text, cursor, anchor = tx, c, a; seq = append(seq, "surrounding") }) | |
| 275 | + | im.OnTextChangeCause(func(c uint32) { cause = c; seq = append(seq, "cause") }) | |
| 276 | + | im.OnContentType(func(h, p uint32) { hint, purpose = h, p; seq = append(seq, "content") }) | |
| 277 | + | im.OnDone(func() { seq = append(seq, "done") }) | |
| 278 | + | s.event(im.ID(), 0) | |
| 279 | + | s.event(im.ID(), 2, cat(str("héllo"), wordBytes(3, 3))...) | |
| 280 | + | s.event(im.ID(), 3, wordBytes(textinput.CHANGE_CAUSE_OTHER)...) | |
| 281 | + | s.event(im.ID(), 4, wordBytes(textinput.CONTENT_HINT_SPELLCHECK, textinput.CONTENT_PURPOSE_EMAIL)...) | |
| 282 | + | s.event(im.ID(), 5) | |
| 283 | + | if !reflect.DeepEqual(seq, []string{"activate", "surrounding", "cause", "content", "done"}) || | |
| 284 | + | text != "héllo" || cursor != 3 || anchor != 3 || cause != textinput.CHANGE_CAUSE_OTHER || | |
| 285 | + | hint != textinput.CONTENT_HINT_SPELLCHECK || purpose != textinput.CONTENT_PURPOSE_EMAIL { | |
| 286 | + | t.Fatal(seq, text, cursor, anchor, cause, hint, purpose) | |
| 287 | + | } | |
| 288 | + | ||
| 289 | + | noerr(t, im.CommitString("ok")) | |
| 290 | + | if b := s.req(im.ID(), 0); !bytes.Equal(b, str("ok")) { | |
| 291 | + | t.Fatalf("commit_string %x", b) | |
| 292 | + | } | |
| 293 | + | noerr(t, im.SetPreeditString("pre", -1, -1)) | |
| 294 | + | if b := s.req(im.ID(), 1); !bytes.Equal(b, cat(str("pre"), wordBytes(0xffffffff, 0xffffffff))) { | |
| 295 | + | t.Fatalf("set_preedit_string %x", b) | |
| 296 | + | } | |
| 297 | + | noerr(t, im.DeleteSurroundingText(2, 1)) | |
| 298 | + | wantWords(t, "delete_surrounding_text", s.req(im.ID(), 2), 2, 1) | |
| 299 | + | noerr(t, im.Commit(1)) | |
| 300 | + | wantWords(t, "commit", s.req(im.ID(), 3), 1) | |
| 301 | + | ||
| 302 | + | popup, e := im.GetInputPopupSurface(surf) | |
| 303 | + | noerr(t, e) | |
| 304 | + | wantWords(t, "get_input_popup_surface", s.req(im.ID(), 4), popup.ID(), surf.ID()) | |
| 305 | + | var rect []int32 | |
| 306 | + | popup.OnTextInputRectangle(func(x, y, w, h int32) { rect = []int32{x, y, w, h} }) | |
| 307 | + | s.event(popup.ID(), 0, wordBytes(0xfffffffe, 5, 30, 12)...) | |
| 308 | + | if !reflect.DeepEqual(rect, []int32{-2, 5, 30, 12}) { | |
| 309 | + | t.Fatal(rect) | |
| 310 | + | } | |
| 311 | + | ||
| 312 | + | grab, e := im.GrabKeyboard() | |
| 313 | + | noerr(t, e) | |
| 314 | + | wantWords(t, "grab_keyboard", s.req(im.ID(), 5), grab.ID()) | |
| 315 | + | ||
| 316 | + | // keymap carries a descriptor: the first handler may take ownership, the | |
| 317 | + | // second sees nil, and an unclaimed descriptor is closed by the transport. | |
| 318 | + | var claim = true | |
| 319 | + | var first, second []*wlturbo.OwnedFD | |
| 320 | + | var format, size uint32 | |
| 321 | + | var got []byte | |
| 322 | + | grab.OnKeymap(func(f uint32, fd *wlturbo.OwnedFD, sz uint32) { | |
| 323 | + | first = append(first, fd) | |
| 324 | + | format, size = f, sz | |
| 325 | + | if !claim { | |
| 326 | + | return | |
| 327 | + | } | |
| 328 | + | n, e := fd.Take() | |
| 329 | + | noerr(t, e) | |
| 330 | + | buf := make([]byte, 16) | |
| 331 | + | m, e := unix.Read(n, buf) | |
| 332 | + | noerr(t, e) | |
| 333 | + | got = buf[:m] | |
| 334 | + | unix.Close(n) | |
| 335 | + | }) | |
| 336 | + | grab.OnKeymap(func(f uint32, fd *wlturbo.OwnedFD, sz uint32) { second = append(second, fd) }) | |
| 337 | + | pr, pw, e := os.Pipe() | |
| 338 | + | noerr(t, e) | |
| 339 | + | _, e = pw.Write([]byte("xkb-keymap")) | |
| 340 | + | noerr(t, e) | |
| 341 | + | send(t, s.p, payload(grab.ID(), 0, wordBytes(wayland.KEYMAP_FORMAT_XKB_V1, 10)...), int(pr.Fd())) | |
| 342 | + | pr.Close() | |
| 343 | + | pw.Close() | |
| 344 | + | s.dispatch() | |
| 345 | + | if string(got) != "xkb-keymap" || format != wayland.KEYMAP_FORMAT_XKB_V1 || size != 10 || len(second) != 1 || second[0] != nil { | |
| 346 | + | t.Fatalf("keymap got=%q format=%d size=%d second=%v", got, format, size, second) | |
| 347 | + | } | |
| 348 | + | ||
| 349 | + | claim = false | |
| 350 | + | pr2, pw2, e := os.Pipe() | |
| 351 | + | noerr(t, e) | |
| 352 | + | defer pr2.Close() | |
| 353 | + | send(t, s.p, payload(grab.ID(), 0, wordBytes(wayland.KEYMAP_FORMAT_XKB_V1, 0)...), int(pw2.Fd())) | |
| 354 | + | pw2.Close() // only the in-flight duplicate keeps the write end alive | |
| 355 | + | s.dispatch() | |
| 356 | + | pr2.SetReadDeadline(time.Now().Add(2 * time.Second)) | |
| 357 | + | if n, e := pr2.Read(make([]byte, 4)); n != 0 || e == nil { | |
| 358 | + | t.Fatalf("unclaimed descriptor still open: n=%d err=%v", n, e) | |
| 359 | + | } | |
| 360 | + | ||
| 361 | + | var key, mods, repeat []uint32 | |
| 362 | + | grab.OnKey(func(serial, tm, k, st uint32) { key = []uint32{serial, tm, k, st} }) | |
| 363 | + | grab.OnModifiers(func(serial, d, l, lk, g uint32) { mods = []uint32{serial, d, l, lk, g} }) | |
| 364 | + | grab.OnRepeatInfo(func(rate, delay int32) { repeat = []uint32{uint32(rate), uint32(delay)} }) | |
| 365 | + | s.event(grab.ID(), 1, wordBytes(7, 100, 30, wayland.KEY_STATE_PRESSED)...) | |
| 366 | + | s.event(grab.ID(), 2, wordBytes(8, 1, 2, 4, 1)...) | |
| 367 | + | s.event(grab.ID(), 3, wordBytes(25, 600)...) | |
| 368 | + | if !reflect.DeepEqual(key, []uint32{7, 100, 30, wayland.KEY_STATE_PRESSED}) || | |
| 369 | + | !reflect.DeepEqual(mods, []uint32{8, 1, 2, 4, 1}) || !reflect.DeepEqual(repeat, []uint32{25, 600}) { | |
| 370 | + | t.Fatal(key, mods, repeat) | |
| 371 | + | } | |
| 372 | + | ||
| 373 | + | noerr(t, grab.Release()) | |
| 374 | + | s.req(grab.ID(), 0) | |
| 375 | + | noerr(t, popup.Destroy()) | |
| 376 | + | s.req(popup.ID(), 0) | |
| 377 | + | var unavailable bool | |
| 378 | + | im.OnUnavailable(func() { unavailable = true }) | |
| 379 | + | s.event(im.ID(), 6) | |
| 380 | + | if !unavailable { | |
| 381 | + | t.Fatal("unavailable not delivered") | |
| 382 | + | } | |
| 383 | + | noerr(t, im.Destroy()) | |
| 384 | + | s.req(im.ID(), 6) | |
| 385 | + | noerr(t, mgr.Destroy()) | |
| 386 | + | s.req(mgr.ID(), 1) | |
| 387 | + | } | |
| 388 | + | ||
| 389 | + | func TestWlrVirtualKeyboardKeymapFD(t *testing.T) { | |
| 390 | + | s := newWireEnv(t) | |
| 391 | + | seat := s.seat() | |
| 392 | + | mgr := virtualkeyboard.NewVirtualKeyboardManager(s.d.Context()) | |
| 393 | + | s.bind(1, virtualkeyboard.VirtualKeyboardManagerInterface, 1, 1, mgr) | |
| 394 | + | kb, e := mgr.CreateVirtualKeyboard(seat) | |
| 395 | + | noerr(t, e) | |
| 396 | + | wantWords(t, "create_virtual_keyboard", s.req(mgr.ID(), 0), seat.ID(), kb.ID()) | |
| 397 | + | ||
| 398 | + | r, w, e := os.Pipe() | |
| 399 | + | noerr(t, e) | |
| 400 | + | defer r.Close() | |
| 401 | + | // Hand the write end to the binding as a plain descriptor. | |
| 402 | + | fd, e := unix.Dup(int(w.Fd())) | |
| 403 | + | noerr(t, e) | |
| 404 | + | w.Close() | |
| 405 | + | noerr(t, kb.Keymap(wayland.KEYMAP_FORMAT_XKB_V1, fd, 6)) | |
| 406 | + | requireFDClosed(t, fd) | |
| 407 | + | body, got := s.reqFD(kb.ID(), 0) | |
| 408 | + | wantWords(t, "keymap", body, wayland.KEYMAP_FORMAT_XKB_V1, 6) | |
| 409 | + | _, e = unix.Write(got, []byte("keymap")) | |
| 410 | + | noerr(t, e) | |
| 411 | + | unix.Close(got) | |
| 412 | + | buf := make([]byte, 16) | |
| 413 | + | r.SetReadDeadline(time.Now().Add(2 * time.Second)) | |
| 414 | + | n, e := r.Read(buf) | |
| 415 | + | noerr(t, e) | |
| 416 | + | if string(buf[:n]) != "keymap" { | |
| 417 | + | t.Fatalf("keymap payload %q", buf[:n]) | |
| 418 | + | } | |
| 419 | + | ||
| 420 | + | noerr(t, kb.Key(1234, 30, wayland.KEY_STATE_PRESSED)) | |
| 421 | + | wantWords(t, "key", s.req(kb.ID(), 1), 1234, 30, wayland.KEY_STATE_PRESSED) | |
| 422 | + | noerr(t, kb.Modifiers(1, 2, 4, 0)) | |
| 423 | + | wantWords(t, "modifiers", s.req(kb.ID(), 2), 1, 2, 4, 0) | |
| 424 | + | noerr(t, kb.Destroy()) | |
| 425 | + | s.req(kb.ID(), 3) | |
| 426 | + | if e := kb.Key(1, 1, 0); e == nil { | |
| 427 | + | t.Fatal("request after destroy must fail") | |
| 428 | + | } | |
| 429 | + | s.noRequest() | |
| 430 | + | } | |
| 431 | + | ||
| 432 | + | // A layer surface is a wl_surface role defined in layershell, and its popup is | |
| 433 | + | // an xdg_popup from xdgshell; both packages must agree on the same objects. | |
| 434 | + | func TestWlrLayerShellPopupCrossPackage(t *testing.T) { | |
| 435 | + | s := newWireEnv(t) | |
| 436 | + | panel, popupSurf := s.surface(), s.surface() | |
| 437 | + | out := s.output() | |
| 438 | + | ||
| 439 | + | wm := xdgshell.NewXdgWmBase(s.d.Context()) | |
| 440 | + | s.bind(1, xdgshell.XdgWmBaseInterface, 6, 6, wm) | |
| 441 | + | ls := layershell.NewLayerShell(s.d.Context()) | |
| 442 | + | s.bind(2, layershell.LayerShellInterface, 5, 5, ls) | |
| 443 | + | ||
| 444 | + | surf, e := ls.GetLayerSurface(panel, out, layershell.LAYER_TOP, "panel") | |
| 445 | + | noerr(t, e) | |
| 446 | + | if b := s.req(ls.ID(), 0); !bytes.Equal(b, cat(wordBytes(surf.ID(), panel.ID(), out.ID(), layershell.LAYER_TOP), str("panel"))) { | |
| 447 | + | t.Fatalf("get_layer_surface %x", b) | |
| 448 | + | } | |
| 449 | + | if surf.Version() != 5 { | |
| 450 | + | t.Fatalf("layer surface version %d", surf.Version()) | |
| 451 | + | } | |
| 452 | + | // A nullable output is encoded as object 0. | |
| 453 | + | nullOut, e := ls.GetLayerSurface(s.surface(), nil, layershell.LAYER_BACKGROUND, "wallpaper") | |
| 454 | + | noerr(t, e) | |
| 455 | + | if b := s.req(ls.ID(), 0); binary.NativeEndian.Uint32(b[8:]) != 0 || binary.NativeEndian.Uint32(b[:4]) != nullOut.ID() { | |
| 456 | + | t.Fatalf("null output %x", b) | |
| 457 | + | } | |
| 458 | + | ||
| 459 | + | anchors := uint32(layershell.ANCHOR_TOP | layershell.ANCHOR_LEFT | layershell.ANCHOR_RIGHT) | |
| 460 | + | noerr(t, surf.SetSize(0, 30)) | |
| 461 | + | wantWords(t, "set_size", s.req(surf.ID(), 0), 0, 30) | |
| 462 | + | noerr(t, surf.SetAnchor(anchors)) | |
| 463 | + | wantWords(t, "set_anchor", s.req(surf.ID(), 1), anchors) | |
| 464 | + | noerr(t, surf.SetExclusiveZone(-1)) | |
| 465 | + | wantWords(t, "set_exclusive_zone", s.req(surf.ID(), 2), 0xffffffff) | |
| 466 | + | noerr(t, surf.SetMargin(1, 2, 3, 4)) | |
| 467 | + | wantWords(t, "set_margin", s.req(surf.ID(), 3), 1, 2, 3, 4) | |
| 468 | + | noerr(t, surf.SetKeyboardInteractivity(layershell.KEYBOARD_INTERACTIVITY_ON_DEMAND)) | |
| 469 | + | wantWords(t, "set_keyboard_interactivity", s.req(surf.ID(), 4), layershell.KEYBOARD_INTERACTIVITY_ON_DEMAND) | |
| 470 | + | noerr(t, surf.SetLayer(layershell.LAYER_OVERLAY)) | |
| 471 | + | wantWords(t, "set_layer", s.req(surf.ID(), 8), layershell.LAYER_OVERLAY) | |
| 472 | + | noerr(t, surf.SetExclusiveEdge(layershell.ANCHOR_TOP)) | |
| 473 | + | wantWords(t, "set_exclusive_edge", s.req(surf.ID(), 9), layershell.ANCHOR_TOP) | |
| 474 | + | ||
| 475 | + | var cfgSerial, cfgW, cfgH uint32 | |
| 476 | + | surf.OnConfigure(func(serial, w, h uint32) { | |
| 477 | + | cfgSerial, cfgW, cfgH = serial, w, h | |
| 478 | + | noerr(t, surf.AckConfigure(serial)) | |
| 479 | + | }) | |
| 480 | + | s.event(surf.ID(), 0, wordBytes(77, 1920, 30)...) | |
| 481 | + | if cfgSerial != 77 || cfgW != 1920 || cfgH != 30 { | |
| 482 | + | t.Fatal(cfgSerial, cfgW, cfgH) | |
| 483 | + | } | |
| 484 | + | wantWords(t, "ack_configure", s.req(surf.ID(), 6), 77) | |
| 485 | + | ||
| 486 | + | // The popup is created through xdg_shell with a NULL parent, then adopted | |
| 487 | + | // by the layer surface. | |
| 488 | + | xs, e := wm.GetXdgSurface(popupSurf) | |
| 489 | + | noerr(t, e) | |
| 490 | + | s.req(wm.ID(), 2) | |
| 491 | + | pos, e := wm.CreatePositioner() | |
| 492 | + | noerr(t, e) | |
| 493 | + | s.req(wm.ID(), 1) | |
| 494 | + | noerr(t, pos.SetSize(100, 50)) | |
| 495 | + | wantWords(t, "positioner size", s.req(pos.ID(), 1), 100, 50) | |
| 496 | + | noerr(t, pos.SetAnchorRect(0, 0, 10, 30)) | |
| 497 | + | s.req(pos.ID(), 2) | |
| 498 | + | popup, e := xs.GetPopup(nil, pos) | |
| 499 | + | noerr(t, e) | |
| 500 | + | wantWords(t, "get_popup", s.req(xs.ID(), 2), popup.ID(), 0, pos.ID()) | |
| 501 | + | noerr(t, surf.GetPopup(popup)) | |
| 502 | + | wantWords(t, "layer get_popup", s.req(surf.ID(), 5), popup.ID()) | |
| 503 | + | ||
| 504 | + | var popupCfg []int32 | |
| 505 | + | var done bool | |
| 506 | + | popup.OnConfigure(func(x, y, w, h int32) { popupCfg = []int32{x, y, w, h} }) | |
| 507 | + | popup.OnPopupDone(func() { done = true }) | |
| 508 | + | s.event(popup.ID(), 0, wordBytes(4, 30, 100, 50)...) | |
| 509 | + | s.event(popup.ID(), 1) | |
| 510 | + | if !reflect.DeepEqual(popupCfg, []int32{4, 30, 100, 50}) || !done { | |
| 511 | + | t.Fatal(popupCfg, done) | |
| 512 | + | } | |
| 513 | + | ||
| 514 | + | var closed bool | |
| 515 | + | surf.OnClosed(func() { closed = true }) | |
| 516 | + | s.event(surf.ID(), 1) | |
| 517 | + | if !closed { | |
| 518 | + | t.Fatal("closed not delivered") | |
| 519 | + | } | |
| 520 | + | noerr(t, popup.Destroy()) | |
| 521 | + | s.req(popup.ID(), 0) | |
| 522 | + | noerr(t, surf.Destroy()) | |
| 523 | + | s.req(surf.ID(), 7) | |
| 524 | + | noerr(t, ls.Destroy()) | |
| 525 | + | s.req(ls.ID(), 1) | |
| 526 | + | if e := surf.SetSize(1, 1); e == nil { | |
| 527 | + | t.Fatal("request after destroy must fail") | |
| 528 | + | } | |
| 529 | + | s.noRequest() | |
| 530 | + | } | |
| 531 | + | ||
| 532 | + | func TestWlrLayerShellVersionGate(t *testing.T) { | |
| 533 | + | s := newWireEnv(t) | |
| 534 | + | ls := layershell.NewLayerShell(s.d.Context()) | |
| 535 | + | s.bind(1, layershell.LayerShellInterface, 5, 4, ls) | |
| 536 | + | surf, e := ls.GetLayerSurface(s.surface(), nil, layershell.LAYER_TOP, "x") | |
| 537 | + | noerr(t, e) | |
| 538 | + | s.req(ls.ID(), 0) | |
| 539 | + | if e := surf.SetExclusiveEdge(layershell.ANCHOR_TOP); !errors.Is(e, wlturbo.ErrVersionTooLow) { | |
| 540 | + | t.Fatalf("set_exclusive_edge on v4: %v", e) | |
| 541 | + | } | |
| 542 | + | s.noRequest() | |
| 543 | + | noerr(t, surf.SetLayer(layershell.LAYER_BOTTOM)) | |
| 544 | + | s.req(surf.ID(), 8) | |
| 545 | + | } | |
| 546 | + | ||
| 547 | + | func TestWlrForeignToplevelOutputPowerAndKDEDecoration(t *testing.T) { | |
| 548 | + | s := newWireEnv(t) | |
| 549 | + | seat, surf, out := s.seat(), s.surface(), s.output() | |
| 550 | + | ||
| 551 | + | // foreign-toplevel: toplevel is a server new_id event; finished destroys. | |
| 552 | + | tm := foreigntoplevel.NewForeignToplevelManager(s.d.Context()) | |
| 553 | + | s.bind(1, foreigntoplevel.ForeignToplevelManagerInterface, 3, 3, tm) | |
| 554 | + | var top *foreigntoplevel.ForeignToplevelHandle | |
| 555 | + | tm.OnToplevel(func(h *foreigntoplevel.ForeignToplevelHandle) { top = h }) | |
| 556 | + | s.event(tm.ID(), 0, wordBytes(serverID+1)...) | |
| 557 | + | if top == nil || top.ID() != serverID+1 || top.Version() != 3 { | |
| 558 | + | t.Fatalf("toplevel %+v", top) | |
| 559 | + | } | |
| 560 | + | var title, appID string | |
| 561 | + | var states []byte | |
| 562 | + | var enter, parent uint32 | |
| 563 | + | var done, closed bool | |
| 564 | + | top.OnTitle(func(v string) { title = v }) | |
| 565 | + | top.OnAppId(func(v string) { appID = v }) | |
| 566 | + | top.OnState(func(v []byte) { states = append([]byte(nil), v...) }) | |
| 567 | + | top.OnOutputEnter(func(id uint32) { enter = id }) | |
| 568 | + | top.OnParent(func(id uint32) { parent = id }) | |
| 569 | + | top.OnDone(func() { done = true }) | |
| 570 | + | top.OnClosed(func() { closed = true }) | |
| 571 | + | s.event(top.ID(), 0, str("term")...) | |
| 572 | + | s.event(top.ID(), 1, str("org.example.term")...) | |
| 573 | + | s.event(top.ID(), 2, wordBytes(out.ID())...) | |
| 574 | + | s.event(top.ID(), 4, arr(wordBytes(foreigntoplevel.STATE_MAXIMIZED, foreigntoplevel.STATE_ACTIVATED))...) | |
| 575 | + | s.event(top.ID(), 7, wordBytes(0)...) | |
| 576 | + | s.event(top.ID(), 5) | |
| 577 | + | if title != "term" || appID != "org.example.term" || enter != out.ID() || parent != 0 || !done || | |
| 578 | + | !bytes.Equal(states, wordBytes(foreigntoplevel.STATE_MAXIMIZED, foreigntoplevel.STATE_ACTIVATED)) { | |
| 579 | + | t.Fatal(title, appID, enter, parent, done, states) | |
| 580 | + | } | |
| 581 | + | noerr(t, top.SetMaximized()) | |
| 582 | + | s.req(top.ID(), 0) | |
| 583 | + | noerr(t, top.Activate(seat)) | |
| 584 | + | wantWords(t, "activate", s.req(top.ID(), 4), seat.ID()) | |
| 585 | + | noerr(t, top.SetRectangle(surf, 1, 2, 3, 4)) | |
| 586 | + | wantWords(t, "set_rectangle", s.req(top.ID(), 6), surf.ID(), 1, 2, 3, 4) | |
| 587 | + | noerr(t, top.SetFullscreen(nil)) | |
| 588 | + | wantWords(t, "set_fullscreen(nil)", s.req(top.ID(), 8), 0) | |
| 589 | + | noerr(t, top.SetFullscreen(out)) | |
| 590 | + | wantWords(t, "set_fullscreen", s.req(top.ID(), 8), out.ID()) | |
| 591 | + | noerr(t, top.Close()) | |
| 592 | + | s.req(top.ID(), 5) | |
| 593 | + | s.event(top.ID(), 6) | |
| 594 | + | if !closed { | |
| 595 | + | t.Fatal("closed not delivered") | |
| 596 | + | } | |
| 597 | + | noerr(t, top.Destroy()) | |
| 598 | + | s.req(top.ID(), 7) | |
| 599 | + | noerr(t, tm.Stop()) | |
| 600 | + | s.req(tm.ID(), 0) | |
| 601 | + | s.event(tm.ID(), 1) | |
| 602 | + | if e := tm.Stop(); e == nil { | |
| 603 | + | t.Fatal("request on a finished manager must fail") | |
| 604 | + | } | |
| 605 | + | ||
| 606 | + | // output-power: object argument + mode/failed events. | |
| 607 | + | pm := outputpower.NewOutputPowerManager(s.d.Context()) | |
| 608 | + | s.bind(2, outputpower.OutputPowerManagerInterface, 1, 1, pm) | |
| 609 | + | pw, e := pm.GetOutputPower(out) | |
| 610 | + | noerr(t, e) | |
| 611 | + | wantWords(t, "get_output_power", s.req(pm.ID(), 0), pw.ID(), out.ID()) | |
| 612 | + | var modes []uint32 | |
| 613 | + | var failed bool | |
| 614 | + | pw.OnMode(func(m uint32) { modes = append(modes, m) }) | |
| 615 | + | pw.OnFailed(func() { failed = true }) | |
| 616 | + | s.event(pw.ID(), 0, wordBytes(outputpower.MODE_ON)...) | |
| 617 | + | noerr(t, pw.SetMode(outputpower.MODE_OFF)) | |
| 618 | + | wantWords(t, "set_mode", s.req(pw.ID(), 0), outputpower.MODE_OFF) | |
| 619 | + | s.event(pw.ID(), 0, wordBytes(outputpower.MODE_OFF)...) | |
| 620 | + | s.event(pw.ID(), 1) | |
| 621 | + | if !reflect.DeepEqual(modes, []uint32{outputpower.MODE_ON, outputpower.MODE_OFF}) || !failed { | |
| 622 | + | t.Fatal(modes, failed) | |
| 623 | + | } | |
| 624 | + | noerr(t, pw.Destroy()) | |
| 625 | + | s.req(pw.ID(), 1) | |
| 626 | + | noerr(t, pm.Destroy()) | |
| 627 | + | s.req(pm.ID(), 1) | |
| 628 | + | ||
| 629 | + | // KDE server decoration: mode enums are per-interface constants. | |
| 630 | + | dm := kdeserverdecoration.NewOrgKdeKwinServerDecorationManager(s.d.Context()) | |
| 631 | + | s.bind(3, kdeserverdecoration.OrgKdeKwinServerDecorationManagerInterface, 1, 1, dm) | |
| 632 | + | var def uint32 = 99 | |
| 633 | + | dm.OnDefaultMode(func(m uint32) { def = m }) | |
| 634 | + | s.event(dm.ID(), 0, wordBytes(kdeserverdecoration.ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT)...) | |
| 635 | + | if def != kdeserverdecoration.ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT { | |
| 636 | + | t.Fatal(def) | |
| 637 | + | } | |
| 638 | + | dec, e := dm.Create(surf) | |
| 639 | + | noerr(t, e) | |
| 640 | + | wantWords(t, "create", s.req(dm.ID(), 0), dec.ID(), surf.ID()) | |
| 641 | + | var mode uint32 = 99 | |
| 642 | + | dec.OnMode(func(m uint32) { mode = m }) | |
| 643 | + | noerr(t, dec.RequestMode(kdeserverdecoration.ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER)) | |
| 644 | + | wantWords(t, "request_mode", s.req(dec.ID(), 1), kdeserverdecoration.ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER) | |
| 645 | + | s.event(dec.ID(), 0, wordBytes(kdeserverdecoration.ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER)...) | |
| 646 | + | if mode != kdeserverdecoration.ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER { | |
| 647 | + | t.Fatal(mode) | |
| 648 | + | } | |
| 649 | + | noerr(t, dec.Release()) | |
| 650 | + | s.req(dec.ID(), 0) | |
| 651 | + | s.noRequest() | |
| 652 | + | } | |
A client/wlrdatacontrol/wlrdatacontrol_generated.go +504 -0
| @@ -0,0 +1,504 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: wlr_data_control_unstable_v1 | |
| 3 | + | // Source: wlr-data-control-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2018 Simon Ser | |
| 7 | + | // Copyright © 2019 Ivan Molodetskikh | |
| 8 | + | // | |
| 9 | + | // Permission to use, copy, modify, distribute, and sell this | |
| 10 | + | // software and its documentation for any purpose is hereby granted | |
| 11 | + | // without fee, provided that the above copyright notice appear in | |
| 12 | + | // all copies and that both that copyright notice and this permission | |
| 13 | + | // notice appear in supporting documentation, and that the name of | |
| 14 | + | // the copyright holders not be used in advertising or publicity | |
| 15 | + | // pertaining to distribution of the software without specific, | |
| 16 | + | // written prior permission. The copyright holders make no | |
| 17 | + | // representations about the suitability of this software for any | |
| 18 | + | // purpose. It is provided "as is" without express or implied | |
| 19 | + | // warranty. | |
| 20 | + | // | |
| 21 | + | // THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
| 22 | + | // SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| 23 | + | // FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| 24 | + | // SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 25 | + | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
| 26 | + | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
| 27 | + | // ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| 28 | + | // THIS SOFTWARE. | |
| 29 | + | ||
| 30 | + | package wlrdatacontrol | |
| 31 | + | ||
| 32 | + | import ( | |
| 33 | + | "sync" | |
| 34 | + | ||
| 35 | + | cross_wl_seat "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 36 | + | "github.com/bnema/wlturbo/wl" | |
| 37 | + | ) | |
| 38 | + | ||
| 39 | + | // ERROR_USED_SOURCE is the error used_source value. | |
| 40 | + | const ERROR_USED_SOURCE = 1 | |
| 41 | + | ||
| 42 | + | // ERROR_INVALID_OFFER is the error invalid_offer value. | |
| 43 | + | const ERROR_INVALID_OFFER = 1 | |
| 44 | + | ||
| 45 | + | // DataControlManagerInterface is the protocol interface name. | |
| 46 | + | const DataControlManagerInterface = "zwlr_data_control_manager_v1" | |
| 47 | + | ||
| 48 | + | // DataControlManager is the generated binding for zwlr_data_control_manager_v1 version 2. | |
| 49 | + | type DataControlManager struct { | |
| 50 | + | wl.BaseProxy | |
| 51 | + | } | |
| 52 | + | ||
| 53 | + | // NewDataControlManager returns an unbound DataControlManager. | |
| 54 | + | func NewDataControlManager(ctx *wl.Context) *DataControlManager { | |
| 55 | + | obj := &DataControlManager{} | |
| 56 | + | obj.SetContext(ctx) | |
| 57 | + | ctx.Register(obj) | |
| 58 | + | return obj | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | // Create a new data source. | |
| 62 | + | func (o *DataControlManager) CreateDataSource() (*DataControlSource, error) { | |
| 63 | + | child := &DataControlSource{} | |
| 64 | + | child.SetContext(o.Context()) | |
| 65 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_data_control_manager_v1.create_data_source", Child: child}, wl.ArgObject(child)); err != nil { | |
| 66 | + | return nil, err | |
| 67 | + | } | |
| 68 | + | return child, nil | |
| 69 | + | } | |
| 70 | + | ||
| 71 | + | // Create a data device that can be used to manage a seat's selection. | |
| 72 | + | func (o *DataControlManager) GetDataDevice(seat *cross_wl_seat.Seat) (*DataControlDevice, error) { | |
| 73 | + | var arg1 wl.Object | |
| 74 | + | if seat != nil { | |
| 75 | + | arg1 = seat | |
| 76 | + | } | |
| 77 | + | child := &DataControlDevice{} | |
| 78 | + | child.SetContext(o.Context()) | |
| 79 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwlr_data_control_manager_v1.get_data_device", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 80 | + | return nil, err | |
| 81 | + | } | |
| 82 | + | return child, nil | |
| 83 | + | } | |
| 84 | + | ||
| 85 | + | // All objects created by the manager will still remain valid, until their appropriate destroy request has been called. | |
| 86 | + | func (o *DataControlManager) Destroy() error { | |
| 87 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwlr_data_control_manager_v1.destroy", Destructor: true}); err != nil { | |
| 88 | + | return err | |
| 89 | + | } | |
| 90 | + | return nil | |
| 91 | + | } | |
| 92 | + | ||
| 93 | + | // EventSignature returns the declared event argument types in wire order. | |
| 94 | + | func (o *DataControlManager) EventSignature(opcode uint16) (string, bool) { | |
| 95 | + | switch opcode { | |
| 96 | + | default: | |
| 97 | + | return "", false | |
| 98 | + | } | |
| 99 | + | } | |
| 100 | + | ||
| 101 | + | // Dispatch decodes one event on zwlr_data_control_manager_v1 and calls the registered handlers. | |
| 102 | + | func (o *DataControlManager) Dispatch(event *wl.Event) { | |
| 103 | + | switch event.Opcode { | |
| 104 | + | default: | |
| 105 | + | } | |
| 106 | + | } | |
| 107 | + | ||
| 108 | + | // DataControlDeviceInterface is the protocol interface name. | |
| 109 | + | const DataControlDeviceInterface = "zwlr_data_control_device_v1" | |
| 110 | + | ||
| 111 | + | // DataControlDevice is the generated binding for zwlr_data_control_device_v1 version 2. | |
| 112 | + | type DataControlDevice struct { | |
| 113 | + | wl.BaseProxy | |
| 114 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 115 | + | // handlers while another goroutine dispatches events. | |
| 116 | + | handlersMu sync.Mutex | |
| 117 | + | onDataOffer []func(idObject *DataControlOffer) | |
| 118 | + | onSelection []func(idID uint32) | |
| 119 | + | onFinished []func() | |
| 120 | + | onPrimarySelection []func(idID uint32) | |
| 121 | + | } | |
| 122 | + | ||
| 123 | + | // NewDataControlDevice returns an unbound DataControlDevice. | |
| 124 | + | func NewDataControlDevice(ctx *wl.Context) *DataControlDevice { | |
| 125 | + | obj := &DataControlDevice{} | |
| 126 | + | obj.SetContext(ctx) | |
| 127 | + | ctx.Register(obj) | |
| 128 | + | return obj | |
| 129 | + | } | |
| 130 | + | ||
| 131 | + | // This request asks the compositor to set the selection to the data from the source on behalf of the client. The given source may not be used in any further set_selection or set_primary_selection requests. Attempting to use a previously used source is a protocol error. To unset the selection, set the source to NULL. | |
| 132 | + | func (o *DataControlDevice) SetSelection(source *DataControlSource) error { | |
| 133 | + | var arg0 wl.Object | |
| 134 | + | if source != nil { | |
| 135 | + | arg0 = source | |
| 136 | + | } | |
| 137 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_data_control_device_v1.set_selection"}, wl.ArgObject(arg0)); err != nil { | |
| 138 | + | return err | |
| 139 | + | } | |
| 140 | + | return nil | |
| 141 | + | } | |
| 142 | + | ||
| 143 | + | // Destroys the data device object. | |
| 144 | + | func (o *DataControlDevice) Destroy() error { | |
| 145 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwlr_data_control_device_v1.destroy", Destructor: true}); err != nil { | |
| 146 | + | return err | |
| 147 | + | } | |
| 148 | + | return nil | |
| 149 | + | } | |
| 150 | + | ||
| 151 | + | // This request asks the compositor to set the primary selection to the data from the source on behalf of the client. The given source may not be used in any further set_selection or set_primary_selection requests. Attempting to use a previously used source is a protocol error. To unset the primary selection, set the source to NULL. The compositor will ignore this request if it does not support primary selection. | |
| 152 | + | func (o *DataControlDevice) SetPrimarySelection(source *DataControlSource) error { | |
| 153 | + | var arg0 wl.Object | |
| 154 | + | if source != nil { | |
| 155 | + | arg0 = source | |
| 156 | + | } | |
| 157 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwlr_data_control_device_v1.set_primary_selection", Since: 2}, wl.ArgObject(arg0)); err != nil { | |
| 158 | + | return err | |
| 159 | + | } | |
| 160 | + | return nil | |
| 161 | + | } | |
| 162 | + | ||
| 163 | + | // OnDataOffer registers a handler for the data_offer event. | |
| 164 | + | // | |
| 165 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 166 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 167 | + | func (o *DataControlDevice) OnDataOffer(handler func(idObject *DataControlOffer)) { | |
| 168 | + | if handler == nil { | |
| 169 | + | return | |
| 170 | + | } | |
| 171 | + | o.handlersMu.Lock() | |
| 172 | + | defer o.handlersMu.Unlock() | |
| 173 | + | o.onDataOffer = append(o.onDataOffer, handler) | |
| 174 | + | } | |
| 175 | + | ||
| 176 | + | // handlersForDataOffer returns the handlers registered for data_offer, taken | |
| 177 | + | // under the lock so a handler may register another handler while events are | |
| 178 | + | // being dispatched. | |
| 179 | + | func (o *DataControlDevice) handlersForDataOffer() []func(idObject *DataControlOffer) { | |
| 180 | + | o.handlersMu.Lock() | |
| 181 | + | defer o.handlersMu.Unlock() | |
| 182 | + | return o.onDataOffer | |
| 183 | + | } | |
| 184 | + | ||
| 185 | + | // OnSelection registers a handler for the selection event. | |
| 186 | + | // | |
| 187 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 188 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 189 | + | func (o *DataControlDevice) OnSelection(handler func(idID uint32)) { | |
| 190 | + | if handler == nil { | |
| 191 | + | return | |
| 192 | + | } | |
| 193 | + | o.handlersMu.Lock() | |
| 194 | + | defer o.handlersMu.Unlock() | |
| 195 | + | o.onSelection = append(o.onSelection, handler) | |
| 196 | + | } | |
| 197 | + | ||
| 198 | + | // handlersForSelection returns the handlers registered for selection, taken | |
| 199 | + | // under the lock so a handler may register another handler while events are | |
| 200 | + | // being dispatched. | |
| 201 | + | func (o *DataControlDevice) handlersForSelection() []func(idID uint32) { | |
| 202 | + | o.handlersMu.Lock() | |
| 203 | + | defer o.handlersMu.Unlock() | |
| 204 | + | return o.onSelection | |
| 205 | + | } | |
| 206 | + | ||
| 207 | + | // OnFinished registers a handler for the finished event. | |
| 208 | + | // | |
| 209 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 210 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 211 | + | func (o *DataControlDevice) OnFinished(handler func()) { | |
| 212 | + | if handler == nil { | |
| 213 | + | return | |
| 214 | + | } | |
| 215 | + | o.handlersMu.Lock() | |
| 216 | + | defer o.handlersMu.Unlock() | |
| 217 | + | o.onFinished = append(o.onFinished, handler) | |
| 218 | + | } | |
| 219 | + | ||
| 220 | + | // handlersForFinished returns the handlers registered for finished, taken | |
| 221 | + | // under the lock so a handler may register another handler while events are | |
| 222 | + | // being dispatched. | |
| 223 | + | func (o *DataControlDevice) handlersForFinished() []func() { | |
| 224 | + | o.handlersMu.Lock() | |
| 225 | + | defer o.handlersMu.Unlock() | |
| 226 | + | return o.onFinished | |
| 227 | + | } | |
| 228 | + | ||
| 229 | + | // OnPrimarySelection registers a handler for the primary_selection event. | |
| 230 | + | // | |
| 231 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 232 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 233 | + | func (o *DataControlDevice) OnPrimarySelection(handler func(idID uint32)) { | |
| 234 | + | if handler == nil { | |
| 235 | + | return | |
| 236 | + | } | |
| 237 | + | o.handlersMu.Lock() | |
| 238 | + | defer o.handlersMu.Unlock() | |
| 239 | + | o.onPrimarySelection = append(o.onPrimarySelection, handler) | |
| 240 | + | } | |
| 241 | + | ||
| 242 | + | // handlersForPrimarySelection returns the handlers registered for primary_selection, taken | |
| 243 | + | // under the lock so a handler may register another handler while events are | |
| 244 | + | // being dispatched. | |
| 245 | + | func (o *DataControlDevice) handlersForPrimarySelection() []func(idID uint32) { | |
| 246 | + | o.handlersMu.Lock() | |
| 247 | + | defer o.handlersMu.Unlock() | |
| 248 | + | return o.onPrimarySelection | |
| 249 | + | } | |
| 250 | + | ||
| 251 | + | // EventSignature returns the declared event argument types in wire order. | |
| 252 | + | func (o *DataControlDevice) EventSignature(opcode uint16) (string, bool) { | |
| 253 | + | switch opcode { | |
| 254 | + | case 0: | |
| 255 | + | return "new_id,", true | |
| 256 | + | case 1: | |
| 257 | + | return "object,", true | |
| 258 | + | case 2: | |
| 259 | + | return "", true | |
| 260 | + | case 3: | |
| 261 | + | return "object,", true | |
| 262 | + | default: | |
| 263 | + | return "", false | |
| 264 | + | } | |
| 265 | + | } | |
| 266 | + | ||
| 267 | + | // Dispatch decodes one event on zwlr_data_control_device_v1 and calls the registered handlers. | |
| 268 | + | func (o *DataControlDevice) Dispatch(event *wl.Event) { | |
| 269 | + | switch event.Opcode { | |
| 270 | + | case 0: // data_offer | |
| 271 | + | idID := event.Uint32() | |
| 272 | + | idObject := &DataControlOffer{} | |
| 273 | + | idObject.SetContext(o.Context()) | |
| 274 | + | idObject.SetID(idID) | |
| 275 | + | idObject.SetVersion(o.Version()) | |
| 276 | + | o.Context().Register(idObject) | |
| 277 | + | ||
| 278 | + | for i, handler := range o.handlersForDataOffer() { | |
| 279 | + | _ = i | |
| 280 | + | handler(idObject) | |
| 281 | + | } | |
| 282 | + | case 1: // selection | |
| 283 | + | idID := event.Uint32() | |
| 284 | + | ||
| 285 | + | for i, handler := range o.handlersForSelection() { | |
| 286 | + | _ = i | |
| 287 | + | handler(idID) | |
| 288 | + | } | |
| 289 | + | case 2: // finished | |
| 290 | + | ||
| 291 | + | for i, handler := range o.handlersForFinished() { | |
| 292 | + | _ = i | |
| 293 | + | handler() | |
| 294 | + | } | |
| 295 | + | case 3: // primary_selection | |
| 296 | + | idID := event.Uint32() | |
| 297 | + | ||
| 298 | + | for i, handler := range o.handlersForPrimarySelection() { | |
| 299 | + | _ = i | |
| 300 | + | handler(idID) | |
| 301 | + | } | |
| 302 | + | default: | |
| 303 | + | } | |
| 304 | + | } | |
| 305 | + | ||
| 306 | + | // DataControlSourceInterface is the protocol interface name. | |
| 307 | + | const DataControlSourceInterface = "zwlr_data_control_source_v1" | |
| 308 | + | ||
| 309 | + | // DataControlSource is the generated binding for zwlr_data_control_source_v1 version 1. | |
| 310 | + | type DataControlSource struct { | |
| 311 | + | wl.BaseProxy | |
| 312 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 313 | + | // handlers while another goroutine dispatches events. | |
| 314 | + | handlersMu sync.Mutex | |
| 315 | + | onSend []func(mimeType string, fd *wl.OwnedFD) | |
| 316 | + | onCancelled []func() | |
| 317 | + | } | |
| 318 | + | ||
| 319 | + | // NewDataControlSource returns an unbound DataControlSource. | |
| 320 | + | func NewDataControlSource(ctx *wl.Context) *DataControlSource { | |
| 321 | + | obj := &DataControlSource{} | |
| 322 | + | obj.SetContext(ctx) | |
| 323 | + | ctx.Register(obj) | |
| 324 | + | return obj | |
| 325 | + | } | |
| 326 | + | ||
| 327 | + | // This request adds a MIME type to the set of MIME types advertised to targets. Can be called several times to offer multiple types. Calling this after wlr_data_control_device.set_selection is a protocol error. | |
| 328 | + | func (o *DataControlSource) Offer(mimeType string) error { | |
| 329 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_data_control_source_v1.offer"}, wl.ArgString(mimeType)); err != nil { | |
| 330 | + | return err | |
| 331 | + | } | |
| 332 | + | return nil | |
| 333 | + | } | |
| 334 | + | ||
| 335 | + | // Destroys the data source object. | |
| 336 | + | func (o *DataControlSource) Destroy() error { | |
| 337 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwlr_data_control_source_v1.destroy", Destructor: true}); err != nil { | |
| 338 | + | return err | |
| 339 | + | } | |
| 340 | + | return nil | |
| 341 | + | } | |
| 342 | + | ||
| 343 | + | // OnSend registers a handler for the send event. | |
| 344 | + | // | |
| 345 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 346 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 347 | + | func (o *DataControlSource) OnSend(handler func(mimeType string, fd *wl.OwnedFD)) { | |
| 348 | + | if handler == nil { | |
| 349 | + | return | |
| 350 | + | } | |
| 351 | + | o.handlersMu.Lock() | |
| 352 | + | defer o.handlersMu.Unlock() | |
| 353 | + | o.onSend = append(o.onSend, handler) | |
| 354 | + | } | |
| 355 | + | ||
| 356 | + | // handlersForSend returns the handlers registered for send, taken | |
| 357 | + | // under the lock so a handler may register another handler while events are | |
| 358 | + | // being dispatched. | |
| 359 | + | func (o *DataControlSource) handlersForSend() []func(mimeType string, fd *wl.OwnedFD) { | |
| 360 | + | o.handlersMu.Lock() | |
| 361 | + | defer o.handlersMu.Unlock() | |
| 362 | + | return o.onSend | |
| 363 | + | } | |
| 364 | + | ||
| 365 | + | // OnCancelled registers a handler for the cancelled event. | |
| 366 | + | // | |
| 367 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 368 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 369 | + | func (o *DataControlSource) OnCancelled(handler func()) { | |
| 370 | + | if handler == nil { | |
| 371 | + | return | |
| 372 | + | } | |
| 373 | + | o.handlersMu.Lock() | |
| 374 | + | defer o.handlersMu.Unlock() | |
| 375 | + | o.onCancelled = append(o.onCancelled, handler) | |
| 376 | + | } | |
| 377 | + | ||
| 378 | + | // handlersForCancelled returns the handlers registered for cancelled, taken | |
| 379 | + | // under the lock so a handler may register another handler while events are | |
| 380 | + | // being dispatched. | |
| 381 | + | func (o *DataControlSource) handlersForCancelled() []func() { | |
| 382 | + | o.handlersMu.Lock() | |
| 383 | + | defer o.handlersMu.Unlock() | |
| 384 | + | return o.onCancelled | |
| 385 | + | } | |
| 386 | + | ||
| 387 | + | // EventSignature returns the declared event argument types in wire order. | |
| 388 | + | func (o *DataControlSource) EventSignature(opcode uint16) (string, bool) { | |
| 389 | + | switch opcode { | |
| 390 | + | case 0: | |
| 391 | + | return "string,fd,", true | |
| 392 | + | case 1: | |
| 393 | + | return "", true | |
| 394 | + | default: | |
| 395 | + | return "", false | |
| 396 | + | } | |
| 397 | + | } | |
| 398 | + | ||
| 399 | + | // Dispatch decodes one event on zwlr_data_control_source_v1 and calls the registered handlers. | |
| 400 | + | func (o *DataControlSource) Dispatch(event *wl.Event) { | |
| 401 | + | switch event.Opcode { | |
| 402 | + | case 0: // send | |
| 403 | + | mimeType := event.String() | |
| 404 | + | fd := event.FD() | |
| 405 | + | ownedfd := fd | |
| 406 | + | defer ownedfd.Close() | |
| 407 | + | ||
| 408 | + | for i, handler := range o.handlersForSend() { | |
| 409 | + | if i > 0 { | |
| 410 | + | fd = nil | |
| 411 | + | } | |
| 412 | + | handler(mimeType, fd) | |
| 413 | + | } | |
| 414 | + | case 1: // cancelled | |
| 415 | + | ||
| 416 | + | for i, handler := range o.handlersForCancelled() { | |
| 417 | + | _ = i | |
| 418 | + | handler() | |
| 419 | + | } | |
| 420 | + | default: | |
| 421 | + | } | |
| 422 | + | } | |
| 423 | + | ||
| 424 | + | // DataControlOfferInterface is the protocol interface name. | |
| 425 | + | const DataControlOfferInterface = "zwlr_data_control_offer_v1" | |
| 426 | + | ||
| 427 | + | // DataControlOffer is the generated binding for zwlr_data_control_offer_v1 version 1. | |
| 428 | + | type DataControlOffer struct { | |
| 429 | + | wl.BaseProxy | |
| 430 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 431 | + | // handlers while another goroutine dispatches events. | |
| 432 | + | handlersMu sync.Mutex | |
| 433 | + | onOffer []func(mimeType string) | |
| 434 | + | } | |
| 435 | + | ||
| 436 | + | // NewDataControlOffer returns an unbound DataControlOffer. | |
| 437 | + | func NewDataControlOffer(ctx *wl.Context) *DataControlOffer { | |
| 438 | + | obj := &DataControlOffer{} | |
| 439 | + | obj.SetContext(ctx) | |
| 440 | + | ctx.Register(obj) | |
| 441 | + | return obj | |
| 442 | + | } | |
| 443 | + | ||
| 444 | + | // To transfer the offered data, the client issues this request and indicates the MIME type it wants to receive. The transfer happens through the passed file descriptor (typically created with the pipe system call). The source client writes the data in the MIME type representation requested and then closes the file descriptor. The receiving client reads from the read end of the pipe until EOF and then closes its end, at which point the transfer is complete. This request may happen multiple times for different MIME types. | |
| 445 | + | func (o *DataControlOffer) Receive(mimeType string, fd int) error { | |
| 446 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_data_control_offer_v1.receive", FDs: []int{fd}}, wl.ArgString(mimeType), wl.ArgFD()); err != nil { | |
| 447 | + | return err | |
| 448 | + | } | |
| 449 | + | return nil | |
| 450 | + | } | |
| 451 | + | ||
| 452 | + | // Destroys the data offer object. | |
| 453 | + | func (o *DataControlOffer) Destroy() error { | |
| 454 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwlr_data_control_offer_v1.destroy", Destructor: true}); err != nil { | |
| 455 | + | return err | |
| 456 | + | } | |
| 457 | + | return nil | |
| 458 | + | } | |
| 459 | + | ||
| 460 | + | // OnOffer registers a handler for the offer event. | |
| 461 | + | // | |
| 462 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 463 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 464 | + | func (o *DataControlOffer) OnOffer(handler func(mimeType string)) { | |
| 465 | + | if handler == nil { | |
| 466 | + | return | |
| 467 | + | } | |
| 468 | + | o.handlersMu.Lock() | |
| 469 | + | defer o.handlersMu.Unlock() | |
| 470 | + | o.onOffer = append(o.onOffer, handler) | |
| 471 | + | } | |
| 472 | + | ||
| 473 | + | // handlersForOffer returns the handlers registered for offer, taken | |
| 474 | + | // under the lock so a handler may register another handler while events are | |
| 475 | + | // being dispatched. | |
| 476 | + | func (o *DataControlOffer) handlersForOffer() []func(mimeType string) { | |
| 477 | + | o.handlersMu.Lock() | |
| 478 | + | defer o.handlersMu.Unlock() | |
| 479 | + | return o.onOffer | |
| 480 | + | } | |
| 481 | + | ||
| 482 | + | // EventSignature returns the declared event argument types in wire order. | |
| 483 | + | func (o *DataControlOffer) EventSignature(opcode uint16) (string, bool) { | |
| 484 | + | switch opcode { | |
| 485 | + | case 0: | |
| 486 | + | return "string,", true | |
| 487 | + | default: | |
| 488 | + | return "", false | |
| 489 | + | } | |
| 490 | + | } | |
| 491 | + | ||
| 492 | + | // Dispatch decodes one event on zwlr_data_control_offer_v1 and calls the registered handlers. | |
| 493 | + | func (o *DataControlOffer) Dispatch(event *wl.Event) { | |
| 494 | + | switch event.Opcode { | |
| 495 | + | case 0: // offer | |
| 496 | + | mimeType := event.String() | |
| 497 | + | ||
| 498 | + | for i, handler := range o.handlersForOffer() { | |
| 499 | + | _ = i | |
| 500 | + | handler(mimeType) | |
| 501 | + | } | |
| 502 | + | default: | |
| 503 | + | } | |
| 504 | + | } | |
A client/wlrexportdmabuf/wlrexportdmabuf_generated.go +289 -0
| @@ -0,0 +1,289 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: wlr_export_dmabuf_unstable_v1 | |
| 3 | + | // Source: wlr-export-dmabuf-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2018 Rostislav Pehlivanov | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package wlrexportdmabuf | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | "sync" | |
| 31 | + | ||
| 32 | + | cross_wl_output "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 33 | + | "github.com/bnema/wlturbo/wl" | |
| 34 | + | ) | |
| 35 | + | ||
| 36 | + | // FLAGS_TRANSIENT is the flags transient value. | |
| 37 | + | const FLAGS_TRANSIENT = 0x1 | |
| 38 | + | ||
| 39 | + | // CANCEL_REASON_TEMPORARY is the cancel_reason temporary value. | |
| 40 | + | const CANCEL_REASON_TEMPORARY = 0 | |
| 41 | + | ||
| 42 | + | // CANCEL_REASON_PERMANENT is the cancel_reason permanent value. | |
| 43 | + | const CANCEL_REASON_PERMANENT = 1 | |
| 44 | + | ||
| 45 | + | // CANCEL_REASON_RESIZING is the cancel_reason resizing value. | |
| 46 | + | const CANCEL_REASON_RESIZING = 2 | |
| 47 | + | ||
| 48 | + | // ExportDmabufManagerInterface is the protocol interface name. | |
| 49 | + | const ExportDmabufManagerInterface = "zwlr_export_dmabuf_manager_v1" | |
| 50 | + | ||
| 51 | + | // ExportDmabufManager is the generated binding for zwlr_export_dmabuf_manager_v1 version 1. | |
| 52 | + | type ExportDmabufManager struct { | |
| 53 | + | wl.BaseProxy | |
| 54 | + | } | |
| 55 | + | ||
| 56 | + | // NewExportDmabufManager returns an unbound ExportDmabufManager. | |
| 57 | + | func NewExportDmabufManager(ctx *wl.Context) *ExportDmabufManager { | |
| 58 | + | obj := &ExportDmabufManager{} | |
| 59 | + | obj.SetContext(ctx) | |
| 60 | + | ctx.Register(obj) | |
| 61 | + | return obj | |
| 62 | + | } | |
| 63 | + | ||
| 64 | + | // Capture the next frame of an entire output. | |
| 65 | + | func (o *ExportDmabufManager) CaptureOutput(overlayCursor int32, output *cross_wl_output.Output) (*ExportDmabufFrame, error) { | |
| 66 | + | var arg2 wl.Object | |
| 67 | + | if output != nil { | |
| 68 | + | arg2 = output | |
| 69 | + | } | |
| 70 | + | child := &ExportDmabufFrame{} | |
| 71 | + | child.SetContext(o.Context()) | |
| 72 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_export_dmabuf_manager_v1.capture_output", Child: child}, wl.ArgObject(child), wl.ArgInt(overlayCursor), wl.ArgObject(arg2)); err != nil { | |
| 73 | + | return nil, err | |
| 74 | + | } | |
| 75 | + | return child, nil | |
| 76 | + | } | |
| 77 | + | ||
| 78 | + | // All objects created by the manager will still remain valid, until their appropriate destroy request has been called. | |
| 79 | + | func (o *ExportDmabufManager) Destroy() error { | |
| 80 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwlr_export_dmabuf_manager_v1.destroy", Destructor: true}); err != nil { | |
| 81 | + | return err | |
| 82 | + | } | |
| 83 | + | return nil | |
| 84 | + | } | |
| 85 | + | ||
| 86 | + | // EventSignature returns the declared event argument types in wire order. | |
| 87 | + | func (o *ExportDmabufManager) EventSignature(opcode uint16) (string, bool) { | |
| 88 | + | switch opcode { | |
| 89 | + | default: | |
| 90 | + | return "", false | |
| 91 | + | } | |
| 92 | + | } | |
| 93 | + | ||
| 94 | + | // Dispatch decodes one event on zwlr_export_dmabuf_manager_v1 and calls the registered handlers. | |
| 95 | + | func (o *ExportDmabufManager) Dispatch(event *wl.Event) { | |
| 96 | + | switch event.Opcode { | |
| 97 | + | default: | |
| 98 | + | } | |
| 99 | + | } | |
| 100 | + | ||
| 101 | + | // ExportDmabufFrameInterface is the protocol interface name. | |
| 102 | + | const ExportDmabufFrameInterface = "zwlr_export_dmabuf_frame_v1" | |
| 103 | + | ||
| 104 | + | // ExportDmabufFrame is the generated binding for zwlr_export_dmabuf_frame_v1 version 1. | |
| 105 | + | type ExportDmabufFrame struct { | |
| 106 | + | wl.BaseProxy | |
| 107 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 108 | + | // handlers while another goroutine dispatches events. | |
| 109 | + | handlersMu sync.Mutex | |
| 110 | + | onFrame []func(width uint32, height uint32, offsetX uint32, offsetY uint32, bufferFlags uint32, flags uint32, format uint32, modHigh uint32, modLow uint32, numObjects uint32) | |
| 111 | + | onObject []func(index uint32, fd *wl.OwnedFD, size uint32, offset uint32, stride uint32, planeIndex uint32) | |
| 112 | + | onReady []func(tvSecHi uint32, tvSecLo uint32, tvNsec uint32) | |
| 113 | + | onCancel []func(reason uint32) | |
| 114 | + | } | |
| 115 | + | ||
| 116 | + | // NewExportDmabufFrame returns an unbound ExportDmabufFrame. | |
| 117 | + | func NewExportDmabufFrame(ctx *wl.Context) *ExportDmabufFrame { | |
| 118 | + | obj := &ExportDmabufFrame{} | |
| 119 | + | obj.SetContext(ctx) | |
| 120 | + | ctx.Register(obj) | |
| 121 | + | return obj | |
| 122 | + | } | |
| 123 | + | ||
| 124 | + | // Unreferences the frame. This request must be called as soon as it's no longer used. It can be called at any time by the client. The client will still have to close any FDs it has been given. | |
| 125 | + | func (o *ExportDmabufFrame) Destroy() error { | |
| 126 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_export_dmabuf_frame_v1.destroy", Destructor: true}); err != nil { | |
| 127 | + | return err | |
| 128 | + | } | |
| 129 | + | return nil | |
| 130 | + | } | |
| 131 | + | ||
| 132 | + | // OnFrame registers a handler for the frame event. | |
| 133 | + | // | |
| 134 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 135 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 136 | + | func (o *ExportDmabufFrame) OnFrame(handler func(width uint32, height uint32, offsetX uint32, offsetY uint32, bufferFlags uint32, flags uint32, format uint32, modHigh uint32, modLow uint32, numObjects uint32)) { | |
| 137 | + | if handler == nil { | |
| 138 | + | return | |
| 139 | + | } | |
| 140 | + | o.handlersMu.Lock() | |
| 141 | + | defer o.handlersMu.Unlock() | |
| 142 | + | o.onFrame = append(o.onFrame, handler) | |
| 143 | + | } | |
| 144 | + | ||
| 145 | + | // handlersForFrame returns the handlers registered for frame, taken | |
| 146 | + | // under the lock so a handler may register another handler while events are | |
| 147 | + | // being dispatched. | |
| 148 | + | func (o *ExportDmabufFrame) handlersForFrame() []func(width uint32, height uint32, offsetX uint32, offsetY uint32, bufferFlags uint32, flags uint32, format uint32, modHigh uint32, modLow uint32, numObjects uint32) { | |
| 149 | + | o.handlersMu.Lock() | |
| 150 | + | defer o.handlersMu.Unlock() | |
| 151 | + | return o.onFrame | |
| 152 | + | } | |
| 153 | + | ||
| 154 | + | // OnObject registers a handler for the object event. | |
| 155 | + | // | |
| 156 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 157 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 158 | + | func (o *ExportDmabufFrame) OnObject(handler func(index uint32, fd *wl.OwnedFD, size uint32, offset uint32, stride uint32, planeIndex uint32)) { | |
| 159 | + | if handler == nil { | |
| 160 | + | return | |
| 161 | + | } | |
| 162 | + | o.handlersMu.Lock() | |
| 163 | + | defer o.handlersMu.Unlock() | |
| 164 | + | o.onObject = append(o.onObject, handler) | |
| 165 | + | } | |
| 166 | + | ||
| 167 | + | // handlersForObject returns the handlers registered for object, taken | |
| 168 | + | // under the lock so a handler may register another handler while events are | |
| 169 | + | // being dispatched. | |
| 170 | + | func (o *ExportDmabufFrame) handlersForObject() []func(index uint32, fd *wl.OwnedFD, size uint32, offset uint32, stride uint32, planeIndex uint32) { | |
| 171 | + | o.handlersMu.Lock() | |
| 172 | + | defer o.handlersMu.Unlock() | |
| 173 | + | return o.onObject | |
| 174 | + | } | |
| 175 | + | ||
| 176 | + | // OnReady registers a handler for the ready event. | |
| 177 | + | // | |
| 178 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 179 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 180 | + | func (o *ExportDmabufFrame) OnReady(handler func(tvSecHi uint32, tvSecLo uint32, tvNsec uint32)) { | |
| 181 | + | if handler == nil { | |
| 182 | + | return | |
| 183 | + | } | |
| 184 | + | o.handlersMu.Lock() | |
| 185 | + | defer o.handlersMu.Unlock() | |
| 186 | + | o.onReady = append(o.onReady, handler) | |
| 187 | + | } | |
| 188 | + | ||
| 189 | + | // handlersForReady returns the handlers registered for ready, taken | |
| 190 | + | // under the lock so a handler may register another handler while events are | |
| 191 | + | // being dispatched. | |
| 192 | + | func (o *ExportDmabufFrame) handlersForReady() []func(tvSecHi uint32, tvSecLo uint32, tvNsec uint32) { | |
| 193 | + | o.handlersMu.Lock() | |
| 194 | + | defer o.handlersMu.Unlock() | |
| 195 | + | return o.onReady | |
| 196 | + | } | |
| 197 | + | ||
| 198 | + | // OnCancel registers a handler for the cancel event. | |
| 199 | + | // | |
| 200 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 201 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 202 | + | func (o *ExportDmabufFrame) OnCancel(handler func(reason uint32)) { | |
| 203 | + | if handler == nil { | |
| 204 | + | return | |
| 205 | + | } | |
| 206 | + | o.handlersMu.Lock() | |
| 207 | + | defer o.handlersMu.Unlock() | |
| 208 | + | o.onCancel = append(o.onCancel, handler) | |
| 209 | + | } | |
| 210 | + | ||
| 211 | + | // handlersForCancel returns the handlers registered for cancel, taken | |
| 212 | + | // under the lock so a handler may register another handler while events are | |
| 213 | + | // being dispatched. | |
| 214 | + | func (o *ExportDmabufFrame) handlersForCancel() []func(reason uint32) { | |
| 215 | + | o.handlersMu.Lock() | |
| 216 | + | defer o.handlersMu.Unlock() | |
| 217 | + | return o.onCancel | |
| 218 | + | } | |
| 219 | + | ||
| 220 | + | // EventSignature returns the declared event argument types in wire order. | |
| 221 | + | func (o *ExportDmabufFrame) EventSignature(opcode uint16) (string, bool) { | |
| 222 | + | switch opcode { | |
| 223 | + | case 0: | |
| 224 | + | return "uint,uint,uint,uint,uint,uint,uint,uint,uint,uint,", true | |
| 225 | + | case 1: | |
| 226 | + | return "uint,fd,uint,uint,uint,uint,", true | |
| 227 | + | case 2: | |
| 228 | + | return "uint,uint,uint,", true | |
| 229 | + | case 3: | |
| 230 | + | return "uint,", true | |
| 231 | + | default: | |
| 232 | + | return "", false | |
| 233 | + | } | |
| 234 | + | } | |
| 235 | + | ||
| 236 | + | // Dispatch decodes one event on zwlr_export_dmabuf_frame_v1 and calls the registered handlers. | |
| 237 | + | func (o *ExportDmabufFrame) Dispatch(event *wl.Event) { | |
| 238 | + | switch event.Opcode { | |
| 239 | + | case 0: // frame | |
| 240 | + | width := event.Uint32() | |
| 241 | + | height := event.Uint32() | |
| 242 | + | offsetX := event.Uint32() | |
| 243 | + | offsetY := event.Uint32() | |
| 244 | + | bufferFlags := event.Uint32() | |
| 245 | + | flags := event.Uint32() | |
| 246 | + | format := event.Uint32() | |
| 247 | + | modHigh := event.Uint32() | |
| 248 | + | modLow := event.Uint32() | |
| 249 | + | numObjects := event.Uint32() | |
| 250 | + | ||
| 251 | + | for i, handler := range o.handlersForFrame() { | |
| 252 | + | _ = i | |
| 253 | + | handler(width, height, offsetX, offsetY, bufferFlags, flags, format, modHigh, modLow, numObjects) | |
| 254 | + | } | |
| 255 | + | case 1: // object | |
| 256 | + | index := event.Uint32() | |
| 257 | + | fd := event.FD() | |
| 258 | + | size := event.Uint32() | |
| 259 | + | offset := event.Uint32() | |
| 260 | + | stride := event.Uint32() | |
| 261 | + | planeIndex := event.Uint32() | |
| 262 | + | ownedfd := fd | |
| 263 | + | defer ownedfd.Close() | |
| 264 | + | ||
| 265 | + | for i, handler := range o.handlersForObject() { | |
| 266 | + | if i > 0 { | |
| 267 | + | fd = nil | |
| 268 | + | } | |
| 269 | + | handler(index, fd, size, offset, stride, planeIndex) | |
| 270 | + | } | |
| 271 | + | case 2: // ready | |
| 272 | + | tvSecHi := event.Uint32() | |
| 273 | + | tvSecLo := event.Uint32() | |
| 274 | + | tvNsec := event.Uint32() | |
| 275 | + | ||
| 276 | + | for i, handler := range o.handlersForReady() { | |
| 277 | + | _ = i | |
| 278 | + | handler(tvSecHi, tvSecLo, tvNsec) | |
| 279 | + | } | |
| 280 | + | case 3: // cancel | |
| 281 | + | reason := event.Uint32() | |
| 282 | + | ||
| 283 | + | for i, handler := range o.handlersForCancel() { | |
| 284 | + | _ = i | |
| 285 | + | handler(reason) | |
| 286 | + | } | |
| 287 | + | default: | |
| 288 | + | } | |
| 289 | + | } | |
A client/wlrforeigntoplevelmanagement/wlrforeigntoplevelmanagement_generated.go +544 -0
| @@ -0,0 +1,544 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: wlr_foreign_toplevel_management_unstable_v1 | |
| 3 | + | // Source: wlr-foreign-toplevel-management-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2018 Ilia Bozhinov | |
| 7 | + | // | |
| 8 | + | // Permission to use, copy, modify, distribute, and sell this | |
| 9 | + | // software and its documentation for any purpose is hereby granted | |
| 10 | + | // without fee, provided that the above copyright notice appear in | |
| 11 | + | // all copies and that both that copyright notice and this permission | |
| 12 | + | // notice appear in supporting documentation, and that the name of | |
| 13 | + | // the copyright holders not be used in advertising or publicity | |
| 14 | + | // pertaining to distribution of the software without specific, | |
| 15 | + | // written prior permission. The copyright holders make no | |
| 16 | + | // representations about the suitability of this software for any | |
| 17 | + | // purpose. It is provided "as is" without express or implied | |
| 18 | + | // warranty. | |
| 19 | + | // | |
| 20 | + | // THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
| 21 | + | // SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| 22 | + | // FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| 23 | + | // SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 24 | + | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
| 25 | + | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
| 26 | + | // ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| 27 | + | // THIS SOFTWARE. | |
| 28 | + | ||
| 29 | + | package wlrforeigntoplevelmanagement | |
| 30 | + | ||
| 31 | + | import ( | |
| 32 | + | "sync" | |
| 33 | + | ||
| 34 | + | cross_wl_output "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 35 | + | cross_wl_seat "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 36 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 37 | + | "github.com/bnema/wlturbo/wl" | |
| 38 | + | ) | |
| 39 | + | ||
| 40 | + | // STATE_MAXIMIZED is the state maximized value. | |
| 41 | + | const STATE_MAXIMIZED = 0 | |
| 42 | + | ||
| 43 | + | // STATE_MINIMIZED is the state minimized value. | |
| 44 | + | const STATE_MINIMIZED = 1 | |
| 45 | + | ||
| 46 | + | // STATE_ACTIVATED is the state activated value. | |
| 47 | + | const STATE_ACTIVATED = 2 | |
| 48 | + | ||
| 49 | + | // STATE_FULLSCREEN is the state fullscreen value. | |
| 50 | + | const STATE_FULLSCREEN = 3 | |
| 51 | + | ||
| 52 | + | // ERROR_INVALID_RECTANGLE is the error invalid_rectangle value. | |
| 53 | + | const ERROR_INVALID_RECTANGLE = 0 | |
| 54 | + | ||
| 55 | + | // ForeignToplevelManagerInterface is the protocol interface name. | |
| 56 | + | const ForeignToplevelManagerInterface = "zwlr_foreign_toplevel_manager_v1" | |
| 57 | + | ||
| 58 | + | // ForeignToplevelManager is the generated binding for zwlr_foreign_toplevel_manager_v1 version 3. | |
| 59 | + | type ForeignToplevelManager struct { | |
| 60 | + | wl.BaseProxy | |
| 61 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 62 | + | // handlers while another goroutine dispatches events. | |
| 63 | + | handlersMu sync.Mutex | |
| 64 | + | onToplevel []func(toplevelObject *ForeignToplevelHandle) | |
| 65 | + | onFinished []func() | |
| 66 | + | } | |
| 67 | + | ||
| 68 | + | // NewForeignToplevelManager returns an unbound ForeignToplevelManager. | |
| 69 | + | func NewForeignToplevelManager(ctx *wl.Context) *ForeignToplevelManager { | |
| 70 | + | obj := &ForeignToplevelManager{} | |
| 71 | + | obj.SetContext(ctx) | |
| 72 | + | ctx.Register(obj) | |
| 73 | + | return obj | |
| 74 | + | } | |
| 75 | + | ||
| 76 | + | // Indicates the client no longer wishes to receive events for new toplevels. However the compositor may emit further toplevel_created events, until the finished event is emitted. The client must not send any more requests after this one. | |
| 77 | + | func (o *ForeignToplevelManager) Stop() error { | |
| 78 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_foreign_toplevel_manager_v1.stop"}); err != nil { | |
| 79 | + | return err | |
| 80 | + | } | |
| 81 | + | return nil | |
| 82 | + | } | |
| 83 | + | ||
| 84 | + | // OnToplevel registers a handler for the toplevel event. | |
| 85 | + | // | |
| 86 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 87 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 88 | + | func (o *ForeignToplevelManager) OnToplevel(handler func(toplevelObject *ForeignToplevelHandle)) { | |
| 89 | + | if handler == nil { | |
| 90 | + | return | |
| 91 | + | } | |
| 92 | + | o.handlersMu.Lock() | |
| 93 | + | defer o.handlersMu.Unlock() | |
| 94 | + | o.onToplevel = append(o.onToplevel, handler) | |
| 95 | + | } | |
| 96 | + | ||
| 97 | + | // handlersForToplevel returns the handlers registered for toplevel, taken | |
| 98 | + | // under the lock so a handler may register another handler while events are | |
| 99 | + | // being dispatched. | |
| 100 | + | func (o *ForeignToplevelManager) handlersForToplevel() []func(toplevelObject *ForeignToplevelHandle) { | |
| 101 | + | o.handlersMu.Lock() | |
| 102 | + | defer o.handlersMu.Unlock() | |
| 103 | + | return o.onToplevel | |
| 104 | + | } | |
| 105 | + | ||
| 106 | + | // OnFinished registers a handler for the finished event. | |
| 107 | + | // | |
| 108 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 109 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 110 | + | func (o *ForeignToplevelManager) OnFinished(handler func()) { | |
| 111 | + | if handler == nil { | |
| 112 | + | return | |
| 113 | + | } | |
| 114 | + | o.handlersMu.Lock() | |
| 115 | + | defer o.handlersMu.Unlock() | |
| 116 | + | o.onFinished = append(o.onFinished, handler) | |
| 117 | + | } | |
| 118 | + | ||
| 119 | + | // handlersForFinished returns the handlers registered for finished, taken | |
| 120 | + | // under the lock so a handler may register another handler while events are | |
| 121 | + | // being dispatched. | |
| 122 | + | func (o *ForeignToplevelManager) handlersForFinished() []func() { | |
| 123 | + | o.handlersMu.Lock() | |
| 124 | + | defer o.handlersMu.Unlock() | |
| 125 | + | return o.onFinished | |
| 126 | + | } | |
| 127 | + | ||
| 128 | + | // EventSignature returns the declared event argument types in wire order. | |
| 129 | + | func (o *ForeignToplevelManager) EventSignature(opcode uint16) (string, bool) { | |
| 130 | + | switch opcode { | |
| 131 | + | case 0: | |
| 132 | + | return "new_id,", true | |
| 133 | + | case 1: | |
| 134 | + | return "", true | |
| 135 | + | default: | |
| 136 | + | return "", false | |
| 137 | + | } | |
| 138 | + | } | |
| 139 | + | ||
| 140 | + | // Dispatch decodes one event on zwlr_foreign_toplevel_manager_v1 and calls the registered handlers. | |
| 141 | + | func (o *ForeignToplevelManager) Dispatch(event *wl.Event) { | |
| 142 | + | switch event.Opcode { | |
| 143 | + | case 0: // toplevel | |
| 144 | + | toplevelID := event.Uint32() | |
| 145 | + | toplevelObject := &ForeignToplevelHandle{} | |
| 146 | + | toplevelObject.SetContext(o.Context()) | |
| 147 | + | toplevelObject.SetID(toplevelID) | |
| 148 | + | toplevelObject.SetVersion(o.Version()) | |
| 149 | + | o.Context().Register(toplevelObject) | |
| 150 | + | ||
| 151 | + | for i, handler := range o.handlersForToplevel() { | |
| 152 | + | _ = i | |
| 153 | + | handler(toplevelObject) | |
| 154 | + | } | |
| 155 | + | case 1: // finished | |
| 156 | + | ||
| 157 | + | for i, handler := range o.handlersForFinished() { | |
| 158 | + | _ = i | |
| 159 | + | handler() | |
| 160 | + | } | |
| 161 | + | o.Context().Unregister(o) | |
| 162 | + | default: | |
| 163 | + | } | |
| 164 | + | } | |
| 165 | + | ||
| 166 | + | // ForeignToplevelHandleInterface is the protocol interface name. | |
| 167 | + | const ForeignToplevelHandleInterface = "zwlr_foreign_toplevel_handle_v1" | |
| 168 | + | ||
| 169 | + | // ForeignToplevelHandle is the generated binding for zwlr_foreign_toplevel_handle_v1 version 3. | |
| 170 | + | type ForeignToplevelHandle struct { | |
| 171 | + | wl.BaseProxy | |
| 172 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 173 | + | // handlers while another goroutine dispatches events. | |
| 174 | + | handlersMu sync.Mutex | |
| 175 | + | onTitle []func(title string) | |
| 176 | + | onAppId []func(appId string) | |
| 177 | + | onOutputEnter []func(outputID uint32) | |
| 178 | + | onOutputLeave []func(outputID uint32) | |
| 179 | + | onState []func(state []byte) | |
| 180 | + | onDone []func() | |
| 181 | + | onClosed []func() | |
| 182 | + | onParent []func(parentID uint32) | |
| 183 | + | } | |
| 184 | + | ||
| 185 | + | // NewForeignToplevelHandle returns an unbound ForeignToplevelHandle. | |
| 186 | + | func NewForeignToplevelHandle(ctx *wl.Context) *ForeignToplevelHandle { | |
| 187 | + | obj := &ForeignToplevelHandle{} | |
| 188 | + | obj.SetContext(ctx) | |
| 189 | + | ctx.Register(obj) | |
| 190 | + | return obj | |
| 191 | + | } | |
| 192 | + | ||
| 193 | + | // Requests that the toplevel be maximized. If the maximized state actually changes, this will be indicated by the state event. | |
| 194 | + | func (o *ForeignToplevelHandle) SetMaximized() error { | |
| 195 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_foreign_toplevel_handle_v1.set_maximized"}); err != nil { | |
| 196 | + | return err | |
| 197 | + | } | |
| 198 | + | return nil | |
| 199 | + | } | |
| 200 | + | ||
| 201 | + | // Requests that the toplevel be unmaximized. If the maximized state actually changes, this will be indicated by the state event. | |
| 202 | + | func (o *ForeignToplevelHandle) UnsetMaximized() error { | |
| 203 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwlr_foreign_toplevel_handle_v1.unset_maximized"}); err != nil { | |
| 204 | + | return err | |
| 205 | + | } | |
| 206 | + | return nil | |
| 207 | + | } | |
| 208 | + | ||
| 209 | + | // Requests that the toplevel be minimized. If the minimized state actually changes, this will be indicated by the state event. | |
| 210 | + | func (o *ForeignToplevelHandle) SetMinimized() error { | |
| 211 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwlr_foreign_toplevel_handle_v1.set_minimized"}); err != nil { | |
| 212 | + | return err | |
| 213 | + | } | |
| 214 | + | return nil | |
| 215 | + | } | |
| 216 | + | ||
| 217 | + | // Requests that the toplevel be unminimized. If the minimized state actually changes, this will be indicated by the state event. | |
| 218 | + | func (o *ForeignToplevelHandle) UnsetMinimized() error { | |
| 219 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "zwlr_foreign_toplevel_handle_v1.unset_minimized"}); err != nil { | |
| 220 | + | return err | |
| 221 | + | } | |
| 222 | + | return nil | |
| 223 | + | } | |
| 224 | + | ||
| 225 | + | // Request that this toplevel be activated on the given seat. There is no guarantee the toplevel will be actually activated. | |
| 226 | + | func (o *ForeignToplevelHandle) Activate(seat *cross_wl_seat.Seat) error { | |
| 227 | + | var arg0 wl.Object | |
| 228 | + | if seat != nil { | |
| 229 | + | arg0 = seat | |
| 230 | + | } | |
| 231 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 4, Name: "zwlr_foreign_toplevel_handle_v1.activate"}, wl.ArgObject(arg0)); err != nil { | |
| 232 | + | return err | |
| 233 | + | } | |
| 234 | + | return nil | |
| 235 | + | } | |
| 236 | + | ||
| 237 | + | // Send a request to the toplevel to close itself. The compositor would typically use a shell-specific method to carry out this request, for example by sending the xdg_toplevel.close event. However, this gives no guarantees the toplevel will actually be destroyed. If and when this happens, the zwlr_foreign_toplevel_handle_v1.closed event will be emitted. | |
| 238 | + | func (o *ForeignToplevelHandle) Close() error { | |
| 239 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 5, Name: "zwlr_foreign_toplevel_handle_v1.close"}); err != nil { | |
| 240 | + | return err | |
| 241 | + | } | |
| 242 | + | return nil | |
| 243 | + | } | |
| 244 | + | ||
| 245 | + | // The rectangle of the surface specified in this request corresponds to the place where the app using this protocol represents the given toplevel. It can be used by the compositor as a hint for some operations, e.g minimizing. The client is however not required to set this, in which case the compositor is free to decide some default value. If the client specifies more than one rectangle, only the last one is considered. The dimensions are given in surface-local coordinates. Setting width=height=0 removes the already-set rectangle. | |
| 246 | + | func (o *ForeignToplevelHandle) SetRectangle(surface *cross_wl_surface.Surface, x int32, y int32, width int32, height int32) error { | |
| 247 | + | var arg0 wl.Object | |
| 248 | + | if surface != nil { | |
| 249 | + | arg0 = surface | |
| 250 | + | } | |
| 251 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 6, Name: "zwlr_foreign_toplevel_handle_v1.set_rectangle"}, wl.ArgObject(arg0), wl.ArgInt(x), wl.ArgInt(y), wl.ArgInt(width), wl.ArgInt(height)); err != nil { | |
| 252 | + | return err | |
| 253 | + | } | |
| 254 | + | return nil | |
| 255 | + | } | |
| 256 | + | ||
| 257 | + | // Destroys the zwlr_foreign_toplevel_handle_v1 object. This request should be called either when the client does not want to use the toplevel anymore or after the closed event to finalize the destruction of the object. | |
| 258 | + | func (o *ForeignToplevelHandle) Destroy() error { | |
| 259 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 7, Name: "zwlr_foreign_toplevel_handle_v1.destroy", Destructor: true}); err != nil { | |
| 260 | + | return err | |
| 261 | + | } | |
| 262 | + | return nil | |
| 263 | + | } | |
| 264 | + | ||
| 265 | + | // Requests that the toplevel be fullscreened on the given output. If the fullscreen state and/or the outputs the toplevel is visible on actually change, this will be indicated by the state and output_enter/leave events. The output parameter is only a hint to the compositor. Also, if output is NULL, the compositor should decide which output the toplevel will be fullscreened on, if at all. | |
| 266 | + | func (o *ForeignToplevelHandle) SetFullscreen(output *cross_wl_output.Output) error { | |
| 267 | + | var arg0 wl.Object | |
| 268 | + | if output != nil { | |
| 269 | + | arg0 = output | |
| 270 | + | } | |
| 271 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 8, Name: "zwlr_foreign_toplevel_handle_v1.set_fullscreen", Since: 2}, wl.ArgObject(arg0)); err != nil { | |
| 272 | + | return err | |
| 273 | + | } | |
| 274 | + | return nil | |
| 275 | + | } | |
| 276 | + | ||
| 277 | + | // Requests that the toplevel be unfullscreened. If the fullscreen state actually changes, this will be indicated by the state event. | |
| 278 | + | func (o *ForeignToplevelHandle) UnsetFullscreen() error { | |
| 279 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 9, Name: "zwlr_foreign_toplevel_handle_v1.unset_fullscreen", Since: 2}); err != nil { | |
| 280 | + | return err | |
| 281 | + | } | |
| 282 | + | return nil | |
| 283 | + | } | |
| 284 | + | ||
| 285 | + | // OnTitle registers a handler for the title event. | |
| 286 | + | // | |
| 287 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 288 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 289 | + | func (o *ForeignToplevelHandle) OnTitle(handler func(title string)) { | |
| 290 | + | if handler == nil { | |
| 291 | + | return | |
| 292 | + | } | |
| 293 | + | o.handlersMu.Lock() | |
| 294 | + | defer o.handlersMu.Unlock() | |
| 295 | + | o.onTitle = append(o.onTitle, handler) | |
| 296 | + | } | |
| 297 | + | ||
| 298 | + | // handlersForTitle returns the handlers registered for title, taken | |
| 299 | + | // under the lock so a handler may register another handler while events are | |
| 300 | + | // being dispatched. | |
| 301 | + | func (o *ForeignToplevelHandle) handlersForTitle() []func(title string) { | |
| 302 | + | o.handlersMu.Lock() | |
| 303 | + | defer o.handlersMu.Unlock() | |
| 304 | + | return o.onTitle | |
| 305 | + | } | |
| 306 | + | ||
| 307 | + | // OnAppId registers a handler for the app_id event. | |
| 308 | + | // | |
| 309 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 310 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 311 | + | func (o *ForeignToplevelHandle) OnAppId(handler func(appId string)) { | |
| 312 | + | if handler == nil { | |
| 313 | + | return | |
| 314 | + | } | |
| 315 | + | o.handlersMu.Lock() | |
| 316 | + | defer o.handlersMu.Unlock() | |
| 317 | + | o.onAppId = append(o.onAppId, handler) | |
| 318 | + | } | |
| 319 | + | ||
| 320 | + | // handlersForAppId returns the handlers registered for app_id, taken | |
| 321 | + | // under the lock so a handler may register another handler while events are | |
| 322 | + | // being dispatched. | |
| 323 | + | func (o *ForeignToplevelHandle) handlersForAppId() []func(appId string) { | |
| 324 | + | o.handlersMu.Lock() | |
| 325 | + | defer o.handlersMu.Unlock() | |
| 326 | + | return o.onAppId | |
| 327 | + | } | |
| 328 | + | ||
| 329 | + | // OnOutputEnter registers a handler for the output_enter event. | |
| 330 | + | // | |
| 331 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 332 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 333 | + | func (o *ForeignToplevelHandle) OnOutputEnter(handler func(outputID uint32)) { | |
| 334 | + | if handler == nil { | |
| 335 | + | return | |
| 336 | + | } | |
| 337 | + | o.handlersMu.Lock() | |
| 338 | + | defer o.handlersMu.Unlock() | |
| 339 | + | o.onOutputEnter = append(o.onOutputEnter, handler) | |
| 340 | + | } | |
| 341 | + | ||
| 342 | + | // handlersForOutputEnter returns the handlers registered for output_enter, taken | |
| 343 | + | // under the lock so a handler may register another handler while events are | |
| 344 | + | // being dispatched. | |
| 345 | + | func (o *ForeignToplevelHandle) handlersForOutputEnter() []func(outputID uint32) { | |
| 346 | + | o.handlersMu.Lock() | |
| 347 | + | defer o.handlersMu.Unlock() | |
| 348 | + | return o.onOutputEnter | |
| 349 | + | } | |
| 350 | + | ||
| 351 | + | // OnOutputLeave registers a handler for the output_leave event. | |
| 352 | + | // | |
| 353 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 354 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 355 | + | func (o *ForeignToplevelHandle) OnOutputLeave(handler func(outputID uint32)) { | |
| 356 | + | if handler == nil { | |
| 357 | + | return | |
| 358 | + | } | |
| 359 | + | o.handlersMu.Lock() | |
| 360 | + | defer o.handlersMu.Unlock() | |
| 361 | + | o.onOutputLeave = append(o.onOutputLeave, handler) | |
| 362 | + | } | |
| 363 | + | ||
| 364 | + | // handlersForOutputLeave returns the handlers registered for output_leave, taken | |
| 365 | + | // under the lock so a handler may register another handler while events are | |
| 366 | + | // being dispatched. | |
| 367 | + | func (o *ForeignToplevelHandle) handlersForOutputLeave() []func(outputID uint32) { | |
| 368 | + | o.handlersMu.Lock() | |
| 369 | + | defer o.handlersMu.Unlock() | |
| 370 | + | return o.onOutputLeave | |
| 371 | + | } | |
| 372 | + | ||
| 373 | + | // OnState registers a handler for the state event. | |
| 374 | + | // | |
| 375 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 376 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 377 | + | func (o *ForeignToplevelHandle) OnState(handler func(state []byte)) { | |
| 378 | + | if handler == nil { | |
| 379 | + | return | |
| 380 | + | } | |
| 381 | + | o.handlersMu.Lock() | |
| 382 | + | defer o.handlersMu.Unlock() | |
| 383 | + | o.onState = append(o.onState, handler) | |
| 384 | + | } | |
| 385 | + | ||
| 386 | + | // handlersForState returns the handlers registered for state, taken | |
| 387 | + | // under the lock so a handler may register another handler while events are | |
| 388 | + | // being dispatched. | |
| 389 | + | func (o *ForeignToplevelHandle) handlersForState() []func(state []byte) { | |
| 390 | + | o.handlersMu.Lock() | |
| 391 | + | defer o.handlersMu.Unlock() | |
| 392 | + | return o.onState | |
| 393 | + | } | |
| 394 | + | ||
| 395 | + | // OnDone registers a handler for the done event. | |
| 396 | + | // | |
| 397 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 398 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 399 | + | func (o *ForeignToplevelHandle) OnDone(handler func()) { | |
| 400 | + | if handler == nil { | |
| 401 | + | return | |
| 402 | + | } | |
| 403 | + | o.handlersMu.Lock() | |
| 404 | + | defer o.handlersMu.Unlock() | |
| 405 | + | o.onDone = append(o.onDone, handler) | |
| 406 | + | } | |
| 407 | + | ||
| 408 | + | // handlersForDone returns the handlers registered for done, taken | |
| 409 | + | // under the lock so a handler may register another handler while events are | |
| 410 | + | // being dispatched. | |
| 411 | + | func (o *ForeignToplevelHandle) handlersForDone() []func() { | |
| 412 | + | o.handlersMu.Lock() | |
| 413 | + | defer o.handlersMu.Unlock() | |
| 414 | + | return o.onDone | |
| 415 | + | } | |
| 416 | + | ||
| 417 | + | // OnClosed registers a handler for the closed event. | |
| 418 | + | // | |
| 419 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 420 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 421 | + | func (o *ForeignToplevelHandle) OnClosed(handler func()) { | |
| 422 | + | if handler == nil { | |
| 423 | + | return | |
| 424 | + | } | |
| 425 | + | o.handlersMu.Lock() | |
| 426 | + | defer o.handlersMu.Unlock() | |
| 427 | + | o.onClosed = append(o.onClosed, handler) | |
| 428 | + | } | |
| 429 | + | ||
| 430 | + | // handlersForClosed returns the handlers registered for closed, taken | |
| 431 | + | // under the lock so a handler may register another handler while events are | |
| 432 | + | // being dispatched. | |
| 433 | + | func (o *ForeignToplevelHandle) handlersForClosed() []func() { | |
| 434 | + | o.handlersMu.Lock() | |
| 435 | + | defer o.handlersMu.Unlock() | |
| 436 | + | return o.onClosed | |
| 437 | + | } | |
| 438 | + | ||
| 439 | + | // OnParent registers a handler for the parent event. | |
| 440 | + | // | |
| 441 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 442 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 443 | + | func (o *ForeignToplevelHandle) OnParent(handler func(parentID uint32)) { | |
| 444 | + | if handler == nil { | |
| 445 | + | return | |
| 446 | + | } | |
| 447 | + | o.handlersMu.Lock() | |
| 448 | + | defer o.handlersMu.Unlock() | |
| 449 | + | o.onParent = append(o.onParent, handler) | |
| 450 | + | } | |
| 451 | + | ||
| 452 | + | // handlersForParent returns the handlers registered for parent, taken | |
| 453 | + | // under the lock so a handler may register another handler while events are | |
| 454 | + | // being dispatched. | |
| 455 | + | func (o *ForeignToplevelHandle) handlersForParent() []func(parentID uint32) { | |
| 456 | + | o.handlersMu.Lock() | |
| 457 | + | defer o.handlersMu.Unlock() | |
| 458 | + | return o.onParent | |
| 459 | + | } | |
| 460 | + | ||
| 461 | + | // EventSignature returns the declared event argument types in wire order. | |
| 462 | + | func (o *ForeignToplevelHandle) EventSignature(opcode uint16) (string, bool) { | |
| 463 | + | switch opcode { | |
| 464 | + | case 0: | |
| 465 | + | return "string,", true | |
| 466 | + | case 1: | |
| 467 | + | return "string,", true | |
| 468 | + | case 2: | |
| 469 | + | return "object,", true | |
| 470 | + | case 3: | |
| 471 | + | return "object,", true | |
| 472 | + | case 4: | |
| 473 | + | return "array,", true | |
| 474 | + | case 5: | |
| 475 | + | return "", true | |
| 476 | + | case 6: | |
| 477 | + | return "", true | |
| 478 | + | case 7: | |
| 479 | + | return "object,", true | |
| 480 | + | default: | |
| 481 | + | return "", false | |
| 482 | + | } | |
| 483 | + | } | |
| 484 | + | ||
| 485 | + | // Dispatch decodes one event on zwlr_foreign_toplevel_handle_v1 and calls the registered handlers. | |
| 486 | + | func (o *ForeignToplevelHandle) Dispatch(event *wl.Event) { | |
| 487 | + | switch event.Opcode { | |
| 488 | + | case 0: // title | |
| 489 | + | title := event.String() | |
| 490 | + | ||
| 491 | + | for i, handler := range o.handlersForTitle() { | |
| 492 | + | _ = i | |
| 493 | + | handler(title) | |
| 494 | + | } | |
| 495 | + | case 1: // app_id | |
| 496 | + | appId := event.String() | |
| 497 | + | ||
| 498 | + | for i, handler := range o.handlersForAppId() { | |
| 499 | + | _ = i | |
| 500 | + | handler(appId) | |
| 501 | + | } | |
| 502 | + | case 2: // output_enter | |
| 503 | + | outputID := event.Uint32() | |
| 504 | + | ||
| 505 | + | for i, handler := range o.handlersForOutputEnter() { | |
| 506 | + | _ = i | |
| 507 | + | handler(outputID) | |
| 508 | + | } | |
| 509 | + | case 3: // output_leave | |
| 510 | + | outputID := event.Uint32() | |
| 511 | + | ||
| 512 | + | for i, handler := range o.handlersForOutputLeave() { | |
| 513 | + | _ = i | |
| 514 | + | handler(outputID) | |
| 515 | + | } | |
| 516 | + | case 4: // state | |
| 517 | + | state := event.Array() | |
| 518 | + | ||
| 519 | + | for i, handler := range o.handlersForState() { | |
| 520 | + | _ = i | |
| 521 | + | handler(state) | |
| 522 | + | } | |
| 523 | + | case 5: // done | |
| 524 | + | ||
| 525 | + | for i, handler := range o.handlersForDone() { | |
| 526 | + | _ = i | |
| 527 | + | handler() | |
| 528 | + | } | |
| 529 | + | case 6: // closed | |
| 530 | + | ||
| 531 | + | for i, handler := range o.handlersForClosed() { | |
| 532 | + | _ = i | |
| 533 | + | handler() | |
| 534 | + | } | |
| 535 | + | case 7: // parent | |
| 536 | + | parentID := event.Uint32() | |
| 537 | + | ||
| 538 | + | for i, handler := range o.handlersForParent() { | |
| 539 | + | _ = i | |
| 540 | + | handler(parentID) | |
| 541 | + | } | |
| 542 | + | default: | |
| 543 | + | } | |
| 544 | + | } | |
A client/wlrgammacontrol/wlrgammacontrol_generated.go +206 -0
| @@ -0,0 +1,206 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: wlr_gamma_control_unstable_v1 | |
| 3 | + | // Source: wlr-gamma-control-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2015 Giulio camuffo | |
| 7 | + | // Copyright © 2018 Simon Ser | |
| 8 | + | // | |
| 9 | + | // Permission to use, copy, modify, distribute, and sell this | |
| 10 | + | // software and its documentation for any purpose is hereby granted | |
| 11 | + | // without fee, provided that the above copyright notice appear in | |
| 12 | + | // all copies and that both that copyright notice and this permission | |
| 13 | + | // notice appear in supporting documentation, and that the name of | |
| 14 | + | // the copyright holders not be used in advertising or publicity | |
| 15 | + | // pertaining to distribution of the software without specific, | |
| 16 | + | // written prior permission. The copyright holders make no | |
| 17 | + | // representations about the suitability of this software for any | |
| 18 | + | // purpose. It is provided "as is" without express or implied | |
| 19 | + | // warranty. | |
| 20 | + | // | |
| 21 | + | // THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
| 22 | + | // SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| 23 | + | // FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| 24 | + | // SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 25 | + | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
| 26 | + | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
| 27 | + | // ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| 28 | + | // THIS SOFTWARE. | |
| 29 | + | ||
| 30 | + | package wlrgammacontrol | |
| 31 | + | ||
| 32 | + | import ( | |
| 33 | + | "sync" | |
| 34 | + | ||
| 35 | + | cross_wl_output "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 36 | + | "github.com/bnema/wlturbo/wl" | |
| 37 | + | ) | |
| 38 | + | ||
| 39 | + | // ERROR_INVALID_GAMMA is the error invalid_gamma value. | |
| 40 | + | const ERROR_INVALID_GAMMA = 1 | |
| 41 | + | ||
| 42 | + | // GammaControlManagerInterface is the protocol interface name. | |
| 43 | + | const GammaControlManagerInterface = "zwlr_gamma_control_manager_v1" | |
| 44 | + | ||
| 45 | + | // GammaControlManager is the generated binding for zwlr_gamma_control_manager_v1 version 1. | |
| 46 | + | type GammaControlManager struct { | |
| 47 | + | wl.BaseProxy | |
| 48 | + | } | |
| 49 | + | ||
| 50 | + | // NewGammaControlManager returns an unbound GammaControlManager. | |
| 51 | + | func NewGammaControlManager(ctx *wl.Context) *GammaControlManager { | |
| 52 | + | obj := &GammaControlManager{} | |
| 53 | + | obj.SetContext(ctx) | |
| 54 | + | ctx.Register(obj) | |
| 55 | + | return obj | |
| 56 | + | } | |
| 57 | + | ||
| 58 | + | // Create a gamma control that can be used to adjust gamma tables for the provided output. | |
| 59 | + | func (o *GammaControlManager) GetGammaControl(output *cross_wl_output.Output) (*GammaControl, error) { | |
| 60 | + | var arg1 wl.Object | |
| 61 | + | if output != nil { | |
| 62 | + | arg1 = output | |
| 63 | + | } | |
| 64 | + | child := &GammaControl{} | |
| 65 | + | child.SetContext(o.Context()) | |
| 66 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_gamma_control_manager_v1.get_gamma_control", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 67 | + | return nil, err | |
| 68 | + | } | |
| 69 | + | return child, nil | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | // All objects created by the manager will still remain valid, until their appropriate destroy request has been called. | |
| 73 | + | func (o *GammaControlManager) Destroy() error { | |
| 74 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwlr_gamma_control_manager_v1.destroy", Destructor: true}); err != nil { | |
| 75 | + | return err | |
| 76 | + | } | |
| 77 | + | return nil | |
| 78 | + | } | |
| 79 | + | ||
| 80 | + | // EventSignature returns the declared event argument types in wire order. | |
| 81 | + | func (o *GammaControlManager) EventSignature(opcode uint16) (string, bool) { | |
| 82 | + | switch opcode { | |
| 83 | + | default: | |
| 84 | + | return "", false | |
| 85 | + | } | |
| 86 | + | } | |
| 87 | + | ||
| 88 | + | // Dispatch decodes one event on zwlr_gamma_control_manager_v1 and calls the registered handlers. | |
| 89 | + | func (o *GammaControlManager) Dispatch(event *wl.Event) { | |
| 90 | + | switch event.Opcode { | |
| 91 | + | default: | |
| 92 | + | } | |
| 93 | + | } | |
| 94 | + | ||
| 95 | + | // GammaControlInterface is the protocol interface name. | |
| 96 | + | const GammaControlInterface = "zwlr_gamma_control_v1" | |
| 97 | + | ||
| 98 | + | // GammaControl is the generated binding for zwlr_gamma_control_v1 version 1. | |
| 99 | + | type GammaControl struct { | |
| 100 | + | wl.BaseProxy | |
| 101 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 102 | + | // handlers while another goroutine dispatches events. | |
| 103 | + | handlersMu sync.Mutex | |
| 104 | + | onGammaSize []func(size uint32) | |
| 105 | + | onFailed []func() | |
| 106 | + | } | |
| 107 | + | ||
| 108 | + | // NewGammaControl returns an unbound GammaControl. | |
| 109 | + | func NewGammaControl(ctx *wl.Context) *GammaControl { | |
| 110 | + | obj := &GammaControl{} | |
| 111 | + | obj.SetContext(ctx) | |
| 112 | + | ctx.Register(obj) | |
| 113 | + | return obj | |
| 114 | + | } | |
| 115 | + | ||
| 116 | + | // Set the gamma table. The file descriptor can be memory-mapped to provide the raw gamma table, which contains successive gamma ramps for the red, green and blue channels. Each gamma ramp is an array of 16-byte unsigned integers which has the same length as the gamma size. The file descriptor data must have the same length as three times the gamma size. | |
| 117 | + | func (o *GammaControl) SetGamma(fd int) error { | |
| 118 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_gamma_control_v1.set_gamma", FDs: []int{fd}}, wl.ArgFD()); err != nil { | |
| 119 | + | return err | |
| 120 | + | } | |
| 121 | + | return nil | |
| 122 | + | } | |
| 123 | + | ||
| 124 | + | // Destroys the gamma control object. If the object is still valid, this restores the original gamma tables. | |
| 125 | + | func (o *GammaControl) Destroy() error { | |
| 126 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwlr_gamma_control_v1.destroy", Destructor: true}); err != nil { | |
| 127 | + | return err | |
| 128 | + | } | |
| 129 | + | return nil | |
| 130 | + | } | |
| 131 | + | ||
| 132 | + | // OnGammaSize registers a handler for the gamma_size event. | |
| 133 | + | // | |
| 134 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 135 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 136 | + | func (o *GammaControl) OnGammaSize(handler func(size uint32)) { | |
| 137 | + | if handler == nil { | |
| 138 | + | return | |
| 139 | + | } | |
| 140 | + | o.handlersMu.Lock() | |
| 141 | + | defer o.handlersMu.Unlock() | |
| 142 | + | o.onGammaSize = append(o.onGammaSize, handler) | |
| 143 | + | } | |
| 144 | + | ||
| 145 | + | // handlersForGammaSize returns the handlers registered for gamma_size, taken | |
| 146 | + | // under the lock so a handler may register another handler while events are | |
| 147 | + | // being dispatched. | |
| 148 | + | func (o *GammaControl) handlersForGammaSize() []func(size uint32) { | |
| 149 | + | o.handlersMu.Lock() | |
| 150 | + | defer o.handlersMu.Unlock() | |
| 151 | + | return o.onGammaSize | |
| 152 | + | } | |
| 153 | + | ||
| 154 | + | // OnFailed registers a handler for the failed event. | |
| 155 | + | // | |
| 156 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 157 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 158 | + | func (o *GammaControl) OnFailed(handler func()) { | |
| 159 | + | if handler == nil { | |
| 160 | + | return | |
| 161 | + | } | |
| 162 | + | o.handlersMu.Lock() | |
| 163 | + | defer o.handlersMu.Unlock() | |
| 164 | + | o.onFailed = append(o.onFailed, handler) | |
| 165 | + | } | |
| 166 | + | ||
| 167 | + | // handlersForFailed returns the handlers registered for failed, taken | |
| 168 | + | // under the lock so a handler may register another handler while events are | |
| 169 | + | // being dispatched. | |
| 170 | + | func (o *GammaControl) handlersForFailed() []func() { | |
| 171 | + | o.handlersMu.Lock() | |
| 172 | + | defer o.handlersMu.Unlock() | |
| 173 | + | return o.onFailed | |
| 174 | + | } | |
| 175 | + | ||
| 176 | + | // EventSignature returns the declared event argument types in wire order. | |
| 177 | + | func (o *GammaControl) EventSignature(opcode uint16) (string, bool) { | |
| 178 | + | switch opcode { | |
| 179 | + | case 0: | |
| 180 | + | return "uint,", true | |
| 181 | + | case 1: | |
| 182 | + | return "", true | |
| 183 | + | default: | |
| 184 | + | return "", false | |
| 185 | + | } | |
| 186 | + | } | |
| 187 | + | ||
| 188 | + | // Dispatch decodes one event on zwlr_gamma_control_v1 and calls the registered handlers. | |
| 189 | + | func (o *GammaControl) Dispatch(event *wl.Event) { | |
| 190 | + | switch event.Opcode { | |
| 191 | + | case 0: // gamma_size | |
| 192 | + | size := event.Uint32() | |
| 193 | + | ||
| 194 | + | for i, handler := range o.handlersForGammaSize() { | |
| 195 | + | _ = i | |
| 196 | + | handler(size) | |
| 197 | + | } | |
| 198 | + | case 1: // failed | |
| 199 | + | ||
| 200 | + | for i, handler := range o.handlersForFailed() { | |
| 201 | + | _ = i | |
| 202 | + | handler() | |
| 203 | + | } | |
| 204 | + | default: | |
| 205 | + | } | |
| 206 | + | } | |
A client/wlrinputinhibitor/wlrinputinhibitor_generated.go +116 -0
| @@ -0,0 +1,116 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: wlr_input_inhibit_unstable_v1 | |
| 3 | + | // Source: wlr-input-inhibitor-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2018 Drew DeVault | |
| 7 | + | // | |
| 8 | + | // Permission to use, copy, modify, distribute, and sell this | |
| 9 | + | // software and its documentation for any purpose is hereby granted | |
| 10 | + | // without fee, provided that the above copyright notice appear in | |
| 11 | + | // all copies and that both that copyright notice and this permission | |
| 12 | + | // notice appear in supporting documentation, and that the name of | |
| 13 | + | // the copyright holders not be used in advertising or publicity | |
| 14 | + | // pertaining to distribution of the software without specific, | |
| 15 | + | // written prior permission. The copyright holders make no | |
| 16 | + | // representations about the suitability of this software for any | |
| 17 | + | // purpose. It is provided "as is" without express or implied | |
| 18 | + | // warranty. | |
| 19 | + | // | |
| 20 | + | // THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
| 21 | + | // SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| 22 | + | // FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| 23 | + | // SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 24 | + | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
| 25 | + | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
| 26 | + | // ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| 27 | + | // THIS SOFTWARE. | |
| 28 | + | ||
| 29 | + | package wlrinputinhibitor | |
| 30 | + | ||
| 31 | + | import ( | |
| 32 | + | "github.com/bnema/wlturbo/wl" | |
| 33 | + | ) | |
| 34 | + | ||
| 35 | + | // ERROR_ALREADY_INHIBITED is the error already_inhibited value. | |
| 36 | + | const ERROR_ALREADY_INHIBITED = 0 | |
| 37 | + | ||
| 38 | + | // InputInhibitManagerInterface is the protocol interface name. | |
| 39 | + | const InputInhibitManagerInterface = "zwlr_input_inhibit_manager_v1" | |
| 40 | + | ||
| 41 | + | // InputInhibitManager is the generated binding for zwlr_input_inhibit_manager_v1 version 1. | |
| 42 | + | type InputInhibitManager struct { | |
| 43 | + | wl.BaseProxy | |
| 44 | + | } | |
| 45 | + | ||
| 46 | + | // NewInputInhibitManager returns an unbound InputInhibitManager. | |
| 47 | + | func NewInputInhibitManager(ctx *wl.Context) *InputInhibitManager { | |
| 48 | + | obj := &InputInhibitManager{} | |
| 49 | + | obj.SetContext(ctx) | |
| 50 | + | ctx.Register(obj) | |
| 51 | + | return obj | |
| 52 | + | } | |
| 53 | + | ||
| 54 | + | // Activates the input inhibitor. As long as the inhibitor is active, the compositor will not send input events to other clients. | |
| 55 | + | func (o *InputInhibitManager) GetInhibitor() (*InputInhibitor, error) { | |
| 56 | + | child := &InputInhibitor{} | |
| 57 | + | child.SetContext(o.Context()) | |
| 58 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_input_inhibit_manager_v1.get_inhibitor", Child: child}, wl.ArgObject(child)); err != nil { | |
| 59 | + | return nil, err | |
| 60 | + | } | |
| 61 | + | return child, nil | |
| 62 | + | } | |
| 63 | + | ||
| 64 | + | // EventSignature returns the declared event argument types in wire order. | |
| 65 | + | func (o *InputInhibitManager) EventSignature(opcode uint16) (string, bool) { | |
| 66 | + | switch opcode { | |
| 67 | + | default: | |
| 68 | + | return "", false | |
| 69 | + | } | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | // Dispatch decodes one event on zwlr_input_inhibit_manager_v1 and calls the registered handlers. | |
| 73 | + | func (o *InputInhibitManager) Dispatch(event *wl.Event) { | |
| 74 | + | switch event.Opcode { | |
| 75 | + | default: | |
| 76 | + | } | |
| 77 | + | } | |
| 78 | + | ||
| 79 | + | // InputInhibitorInterface is the protocol interface name. | |
| 80 | + | const InputInhibitorInterface = "zwlr_input_inhibitor_v1" | |
| 81 | + | ||
| 82 | + | // InputInhibitor is the generated binding for zwlr_input_inhibitor_v1 version 1. | |
| 83 | + | type InputInhibitor struct { | |
| 84 | + | wl.BaseProxy | |
| 85 | + | } | |
| 86 | + | ||
| 87 | + | // NewInputInhibitor returns an unbound InputInhibitor. | |
| 88 | + | func NewInputInhibitor(ctx *wl.Context) *InputInhibitor { | |
| 89 | + | obj := &InputInhibitor{} | |
| 90 | + | obj.SetContext(ctx) | |
| 91 | + | ctx.Register(obj) | |
| 92 | + | return obj | |
| 93 | + | } | |
| 94 | + | ||
| 95 | + | // Destroy the inhibitor and allow other clients to receive input. | |
| 96 | + | func (o *InputInhibitor) Destroy() error { | |
| 97 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_input_inhibitor_v1.destroy", Destructor: true}); err != nil { | |
| 98 | + | return err | |
| 99 | + | } | |
| 100 | + | return nil | |
| 101 | + | } | |
| 102 | + | ||
| 103 | + | // EventSignature returns the declared event argument types in wire order. | |
| 104 | + | func (o *InputInhibitor) EventSignature(opcode uint16) (string, bool) { | |
| 105 | + | switch opcode { | |
| 106 | + | default: | |
| 107 | + | return "", false | |
| 108 | + | } | |
| 109 | + | } | |
| 110 | + | ||
| 111 | + | // Dispatch decodes one event on zwlr_input_inhibitor_v1 and calls the registered handlers. | |
| 112 | + | func (o *InputInhibitor) Dispatch(event *wl.Event) { | |
| 113 | + | switch event.Opcode { | |
| 114 | + | default: | |
| 115 | + | } | |
| 116 | + | } | |
A client/wlrlayershell/wlrlayershell_generated.go +335 -0 collapsed to keep the page light
A client/wlroutputmanagement/wlroutputmanagement_generated.go +1146 -0 collapsed to keep the page light
A client/wlroutputpowermanagement/wlroutputpowermanagement_generated.go +209 -0
| @@ -0,0 +1,209 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: wlr_output_power_management_unstable_v1 | |
| 3 | + | // Source: wlr-output-power-management-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2019 Purism SPC | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package wlroutputpowermanagement | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | "sync" | |
| 31 | + | ||
| 32 | + | cross_wl_output "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 33 | + | "github.com/bnema/wlturbo/wl" | |
| 34 | + | ) | |
| 35 | + | ||
| 36 | + | // MODE_OFF is the mode off value. | |
| 37 | + | const MODE_OFF = 0 | |
| 38 | + | ||
| 39 | + | // MODE_ON is the mode on value. | |
| 40 | + | const MODE_ON = 1 | |
| 41 | + | ||
| 42 | + | // ERROR_INVALID_MODE is the error invalid_mode value. | |
| 43 | + | const ERROR_INVALID_MODE = 1 | |
| 44 | + | ||
| 45 | + | // OutputPowerManagerInterface is the protocol interface name. | |
| 46 | + | const OutputPowerManagerInterface = "zwlr_output_power_manager_v1" | |
| 47 | + | ||
| 48 | + | // OutputPowerManager is the generated binding for zwlr_output_power_manager_v1 version 1. | |
| 49 | + | type OutputPowerManager struct { | |
| 50 | + | wl.BaseProxy | |
| 51 | + | } | |
| 52 | + | ||
| 53 | + | // NewOutputPowerManager returns an unbound OutputPowerManager. | |
| 54 | + | func NewOutputPowerManager(ctx *wl.Context) *OutputPowerManager { | |
| 55 | + | obj := &OutputPowerManager{} | |
| 56 | + | obj.SetContext(ctx) | |
| 57 | + | ctx.Register(obj) | |
| 58 | + | return obj | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | // Create an output power management mode control that can be used to adjust the power management mode for a given output. | |
| 62 | + | func (o *OutputPowerManager) GetOutputPower(output *cross_wl_output.Output) (*OutputPower, error) { | |
| 63 | + | var arg1 wl.Object | |
| 64 | + | if output != nil { | |
| 65 | + | arg1 = output | |
| 66 | + | } | |
| 67 | + | child := &OutputPower{} | |
| 68 | + | child.SetContext(o.Context()) | |
| 69 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_output_power_manager_v1.get_output_power", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 70 | + | return nil, err | |
| 71 | + | } | |
| 72 | + | return child, nil | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | // All objects created by the manager will still remain valid, until their appropriate destroy request has been called. | |
| 76 | + | func (o *OutputPowerManager) Destroy() error { | |
| 77 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwlr_output_power_manager_v1.destroy", Destructor: true}); err != nil { | |
| 78 | + | return err | |
| 79 | + | } | |
| 80 | + | return nil | |
| 81 | + | } | |
| 82 | + | ||
| 83 | + | // EventSignature returns the declared event argument types in wire order. | |
| 84 | + | func (o *OutputPowerManager) EventSignature(opcode uint16) (string, bool) { | |
| 85 | + | switch opcode { | |
| 86 | + | default: | |
| 87 | + | return "", false | |
| 88 | + | } | |
| 89 | + | } | |
| 90 | + | ||
| 91 | + | // Dispatch decodes one event on zwlr_output_power_manager_v1 and calls the registered handlers. | |
| 92 | + | func (o *OutputPowerManager) Dispatch(event *wl.Event) { | |
| 93 | + | switch event.Opcode { | |
| 94 | + | default: | |
| 95 | + | } | |
| 96 | + | } | |
| 97 | + | ||
| 98 | + | // OutputPowerInterface is the protocol interface name. | |
| 99 | + | const OutputPowerInterface = "zwlr_output_power_v1" | |
| 100 | + | ||
| 101 | + | // OutputPower is the generated binding for zwlr_output_power_v1 version 1. | |
| 102 | + | type OutputPower struct { | |
| 103 | + | wl.BaseProxy | |
| 104 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 105 | + | // handlers while another goroutine dispatches events. | |
| 106 | + | handlersMu sync.Mutex | |
| 107 | + | onMode []func(mode uint32) | |
| 108 | + | onFailed []func() | |
| 109 | + | } | |
| 110 | + | ||
| 111 | + | // NewOutputPower returns an unbound OutputPower. | |
| 112 | + | func NewOutputPower(ctx *wl.Context) *OutputPower { | |
| 113 | + | obj := &OutputPower{} | |
| 114 | + | obj.SetContext(ctx) | |
| 115 | + | ctx.Register(obj) | |
| 116 | + | return obj | |
| 117 | + | } | |
| 118 | + | ||
| 119 | + | // Set an output's power save mode to the given mode. The mode change is effective immediately. If the output does not support the given mode a failed event is sent. | |
| 120 | + | func (o *OutputPower) SetMode(mode uint32) error { | |
| 121 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_output_power_v1.set_mode"}, wl.ArgUint(mode)); err != nil { | |
| 122 | + | return err | |
| 123 | + | } | |
| 124 | + | return nil | |
| 125 | + | } | |
| 126 | + | ||
| 127 | + | // Destroys the output power management mode control object. | |
| 128 | + | func (o *OutputPower) Destroy() error { | |
| 129 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwlr_output_power_v1.destroy", Destructor: true}); err != nil { | |
| 130 | + | return err | |
| 131 | + | } | |
| 132 | + | return nil | |
| 133 | + | } | |
| 134 | + | ||
| 135 | + | // OnMode registers a handler for the mode event. | |
| 136 | + | // | |
| 137 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 138 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 139 | + | func (o *OutputPower) OnMode(handler func(mode uint32)) { | |
| 140 | + | if handler == nil { | |
| 141 | + | return | |
| 142 | + | } | |
| 143 | + | o.handlersMu.Lock() | |
| 144 | + | defer o.handlersMu.Unlock() | |
| 145 | + | o.onMode = append(o.onMode, handler) | |
| 146 | + | } | |
| 147 | + | ||
| 148 | + | // handlersForMode returns the handlers registered for mode, taken | |
| 149 | + | // under the lock so a handler may register another handler while events are | |
| 150 | + | // being dispatched. | |
| 151 | + | func (o *OutputPower) handlersForMode() []func(mode uint32) { | |
| 152 | + | o.handlersMu.Lock() | |
| 153 | + | defer o.handlersMu.Unlock() | |
| 154 | + | return o.onMode | |
| 155 | + | } | |
| 156 | + | ||
| 157 | + | // OnFailed registers a handler for the failed event. | |
| 158 | + | // | |
| 159 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 160 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 161 | + | func (o *OutputPower) OnFailed(handler func()) { | |
| 162 | + | if handler == nil { | |
| 163 | + | return | |
| 164 | + | } | |
| 165 | + | o.handlersMu.Lock() | |
| 166 | + | defer o.handlersMu.Unlock() | |
| 167 | + | o.onFailed = append(o.onFailed, handler) | |
| 168 | + | } | |
| 169 | + | ||
| 170 | + | // handlersForFailed returns the handlers registered for failed, taken | |
| 171 | + | // under the lock so a handler may register another handler while events are | |
| 172 | + | // being dispatched. | |
| 173 | + | func (o *OutputPower) handlersForFailed() []func() { | |
| 174 | + | o.handlersMu.Lock() | |
| 175 | + | defer o.handlersMu.Unlock() | |
| 176 | + | return o.onFailed | |
| 177 | + | } | |
| 178 | + | ||
| 179 | + | // EventSignature returns the declared event argument types in wire order. | |
| 180 | + | func (o *OutputPower) EventSignature(opcode uint16) (string, bool) { | |
| 181 | + | switch opcode { | |
| 182 | + | case 0: | |
| 183 | + | return "uint,", true | |
| 184 | + | case 1: | |
| 185 | + | return "", true | |
| 186 | + | default: | |
| 187 | + | return "", false | |
| 188 | + | } | |
| 189 | + | } | |
| 190 | + | ||
| 191 | + | // Dispatch decodes one event on zwlr_output_power_v1 and calls the registered handlers. | |
| 192 | + | func (o *OutputPower) Dispatch(event *wl.Event) { | |
| 193 | + | switch event.Opcode { | |
| 194 | + | case 0: // mode | |
| 195 | + | mode := event.Uint32() | |
| 196 | + | ||
| 197 | + | for i, handler := range o.handlersForMode() { | |
| 198 | + | _ = i | |
| 199 | + | handler(mode) | |
| 200 | + | } | |
| 201 | + | case 1: // failed | |
| 202 | + | ||
| 203 | + | for i, handler := range o.handlersForFailed() { | |
| 204 | + | _ = i | |
| 205 | + | handler() | |
| 206 | + | } | |
| 207 | + | default: | |
| 208 | + | } | |
| 209 | + | } | |
A client/wlrscreencopy/wlrscreencopy_generated.go +410 -0 collapsed to keep the page light
A client/wlrvirtualpointer/wlrvirtualpointer_generated.go +213 -0 collapsed to keep the page light
A client/xdgactivation/xdgactivation_generated.go +214 -0 collapsed to keep the page light
A client/xdgdecoration/xdgdecoration_generated.go +195 -0 collapsed to keep the page light
A client/xdgdialog/xdgdialog_generated.go +143 -0 collapsed to keep the page light
A client/xdgforeign/xdgforeign_generated.go +301 -0 collapsed to keep the page light
A client/xdgoutput/xdgoutput_generated.go +290 -0 collapsed to keep the page light
A client/xdgsessionmanagement/xdgsessionmanagement_generated.go +376 -0 collapsed to keep the page light
A client/xdgshell/xdgshell_generated.go +1043 -0 collapsed to keep the page light
A client/xdgsystembell/xdgsystembell_generated.go +83 -0
| @@ -0,0 +1,83 @@ | |||
| 1 | + | // Code generated by wlbgen. DO NOT EDIT. | |
| 2 | + | // Protocol: xdg_system_bell_v1 | |
| 3 | + | // Source: xdg-system-bell-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2016, 2023 Red Hat | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package xdgsystembell | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | cross_wl_surface "github.com/bnema/go-wayland-bindings/client/wayland" | |
| 31 | + | "github.com/bnema/wlturbo/wl" | |
| 32 | + | ) | |
| 33 | + | ||
| 34 | + | // XdgSystemBellInterface is the protocol interface name. | |
| 35 | + | const XdgSystemBellInterface = "xdg_system_bell_v1" | |
| 36 | + | ||
| 37 | + | // XdgSystemBell is the generated binding for xdg_system_bell_v1 version 1. | |
| 38 | + | type XdgSystemBell struct { | |
| 39 | + | wl.BaseProxy | |
| 40 | + | } | |
| 41 | + | ||
| 42 | + | // NewXdgSystemBell returns an unbound XdgSystemBell. | |
| 43 | + | func NewXdgSystemBell(ctx *wl.Context) *XdgSystemBell { | |
| 44 | + | obj := &XdgSystemBell{} | |
| 45 | + | obj.SetContext(ctx) | |
| 46 | + | ctx.Register(obj) | |
| 47 | + | return obj | |
| 48 | + | } | |
| 49 | + | ||
| 50 | + | // Notify that the object will no longer be used. | |
| 51 | + | func (o *XdgSystemBell) Destroy() error { | |
| 52 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "xdg_system_bell_v1.destroy", Destructor: true}); err != nil { | |
| 53 | + | return err | |
| 54 | + | } | |
| 55 | + | return nil | |
| 56 | + | } | |
| 57 | + | ||
| 58 | + | // This requests rings the system bell on behalf of a client. How ringing the bell is implemented is up to the compositor. It may be an audible sound, a visual feedback of some kind, or any other thing including nothing. The passed surface should correspond to a toplevel like surface role, or be null, meaning the client doesn't have a particular toplevel it wants to associate the bell ringing with. See the xdg-shell protocol extension for a toplevel like surface role. | |
| 59 | + | func (o *XdgSystemBell) Ring(surface *cross_wl_surface.Surface) error { | |
| 60 | + | var arg0 wl.Object | |
| 61 | + | if surface != nil { | |
| 62 | + | arg0 = surface | |
| 63 | + | } | |
| 64 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "xdg_system_bell_v1.ring"}, wl.ArgObject(arg0)); err != nil { | |
| 65 | + | return err | |
| 66 | + | } | |
| 67 | + | return nil | |
| 68 | + | } | |
| 69 | + | ||
| 70 | + | // EventSignature returns the declared event argument types in wire order. | |
| 71 | + | func (o *XdgSystemBell) EventSignature(opcode uint16) (string, bool) { | |
| 72 | + | switch opcode { | |
| 73 | + | default: | |
| 74 | + | return "", false | |
| 75 | + | } | |
| 76 | + | } | |
| 77 | + | ||
| 78 | + | // Dispatch decodes one event on xdg_system_bell_v1 and calls the registered handlers. | |
| 79 | + | func (o *XdgSystemBell) Dispatch(event *wl.Event) { | |
| 80 | + | switch event.Opcode { | |
| 81 | + | default: | |
| 82 | + | } | |
| 83 | + | } | |
A client/xdgtopleveldrag/xdgtopleveldrag_generated.go +146 -0 collapsed to keep the page light
A client/xdgtoplevelicon/xdgtoplevelicon_generated.go +235 -0 collapsed to keep the page light
A client/xdgtopleveltag/xdgtopleveltag_generated.go +95 -0 collapsed to keep the page light
A client/xwaylandkeyboardgrab/xwaylandkeyboardgrab_generated.go +129 -0 collapsed to keep the page light
A client/xwaylandshell/xwaylandshell_generated.go +141 -0 collapsed to keep the page light
A server/alphamodifier/alphamodifier_generated.go +149 -0 collapsed to keep the page light
A server/colormanagement/colormanagement_generated.go +890 -0 collapsed to keep the page light
A server/colorrepresentation/colorrepresentation_generated.go +228 -0 collapsed to keep the page light
A server/committiming/committiming_generated.go +151 -0 collapsed to keep the page light
A server/contenttype/contenttype_generated.go +152 -0 collapsed to keep the page light
A server/cursorshape/cursorshape_generated.go +190 -0 collapsed to keep the page light
A server/drmlease/drmlease_generated.go +331 -0 collapsed to keep the page light
A server/extbackgroundeffect/extbackgroundeffect_generated.go +164 -0 collapsed to keep the page light
A server/extdatacontrol/extdatacontrol_generated.go +330 -0 collapsed to keep the page light
A server/extforeigntoplevellist/extforeigntoplevellist_generated.go +187 -0 collapsed to keep the page light
A server/extidlenotify/extidlenotify_generated.go +150 -0 collapsed to keep the page light
A server/extimagecapturesource/extimagecapturesource_generated.go +188 -0 collapsed to keep the page light
A server/extimagecopycapture/extimagecopycapture_generated.go +424 -0 collapsed to keep the page light
A server/extsessionlock/extsessionlock_generated.go +242 -0 collapsed to keep the page light
A server/exttransientseat/exttransientseat_generated.go +144 -0 collapsed to keep the page light
A server/extworkspace/extworkspace_generated.go +354 -0 collapsed to keep the page light
A server/fifo/fifo_generated.go +154 -0 collapsed to keep the page light
A server/fractionalscale/fractionalscale_generated.go +145 -0 collapsed to keep the page light
A server/fullscreenshell/fullscreenshell_generated.go +182 -0 collapsed to keep the page light
A server/idleinhibit/idleinhibit_generated.go +130 -0 collapsed to keep the page light
A server/inputmethod/inputmethod_generated.go +361 -0 collapsed to keep the page light
A server/inputtimestamps/inputtimestamps_generated.go +148 -0 collapsed to keep the page light
A server/keyboardshortcutsinhibit/keyboardshortcutsinhibit_generated.go +152 -0 collapsed to keep the page light
A server/linuxdmabuf/linuxdmabuf_generated.go +331 -0 collapsed to keep the page light
A server/linuxdrmsyncobj/linuxdrmsyncobj_generated.go +217 -0 collapsed to keep the page light
A server/linuxexplicitsynchronization/linuxexplicitsynchronization_generated.go +216 -0 collapsed to keep the page light
A server/pointerconstraints/pointerconstraints_generated.go +247 -0 collapsed to keep the page light
A server/pointergestures/pointergestures_generated.go +303 -0 collapsed to keep the page light
A server/pointerwarp/pointerwarp_generated.go +78 -0 collapsed to keep the page light
A server/presentationtime/presentationtime_generated.go +168 -0 collapsed to keep the page light
A server/primaryselection/primaryselection_generated.go +297 -0 collapsed to keep the page light
A server/protocol_test.go +74 -0 collapsed to keep the page light
A server/relativepointer/relativepointer_generated.go +138 -0 collapsed to keep the page light
A server/securitycontext/securitycontext_generated.go +166 -0 collapsed to keep the page light
A server/serverdecoration/serverdecoration_generated.go +163 -0 collapsed to keep the page light
A server/singlepixelbuffer/singlepixelbuffer_generated.go +78 -0 collapsed to keep the page light
A server/tablet/tablet_generated.go +981 -0 collapsed to keep the page light
A server/tearingcontrol/tearingcontrol_generated.go +150 -0 collapsed to keep the page light
A server/textinput/textinput_generated.go +327 -0 collapsed to keep the page light
A server/viewporter/viewporter_generated.go +157 -0 collapsed to keep the page light
A server/virtualkeyboard/virtualkeyboard_generated.go +153 -0 collapsed to keep the page light
A server/wayland/wayland_generated.go +2320 -0 large diff (2320 lines changed): collapsed
A server/wayland/wayland_test.go +25 -0 collapsed to keep the page light
A server/wlrdatacontrol/wlrdatacontrol_generated.go +330 -0 collapsed to keep the page light
A server/wlrexportdmabuf/wlrexportdmabuf_generated.go +175 -0 collapsed to keep the page light
A server/wlrforeigntoplevelmanagement/wlrforeigntoplevelmanagement_generated.go +265 -0 collapsed to keep the page light
A server/wlrgammacontrol/wlrgammacontrol_generated.go +157 -0 collapsed to keep the page light
A server/wlrinputinhibitor/wlrinputinhibitor_generated.go +130 -0 collapsed to keep the page light
A server/wlrlayershell/wlrlayershell_generated.go +240 -0 collapsed to keep the page light
A server/wlrlayershell/wlrlayershell_test.go +20 -0 collapsed to keep the page light
A server/wlroutputmanagement/wlroutputmanagement_generated.go +540 -0 collapsed to keep the page light
A server/wlroutputpowermanagement/wlroutputpowermanagement_generated.go +165 -0 collapsed to keep the page light
A server/wlroutputpowermanagement/wlroutputpowermanagement_test.go +17 -0
| @@ -0,0 +1,17 @@ | |||
| 1 | + | package wlroutputpowermanagement | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "testing" | |
| 5 | + | ||
| 6 | + | "github.com/bnema/go-wayland-bindings/server/wayland" | |
| 7 | + | ) | |
| 8 | + | ||
| 9 | + | func TestImportedInterfaces(t *testing.T) { | |
| 10 | + | req := ZwlrOutputPowerManagerV1Interface.Requests[ZwlrOutputPowerManagerV1RequestGetOutputPower] | |
| 11 | + | if got := req.Types[0]; got != ZwlrOutputPowerV1Interface { | |
| 12 | + | t.Fatalf("new_id type=%v", got) | |
| 13 | + | } | |
| 14 | + | if got := req.Types[1]; got != wayland.OutputInterface { | |
| 15 | + | t.Fatalf("output type=%v", got) | |
| 16 | + | } | |
| 17 | + | } | |