Repository: mmulet/term.everything Branch: main Commit: c8e04be0ae9a Files: 118 Total size: 739.7 KB Directory structure: gitextract_45vhempi/ ├── .github/ │ └── FUNDING.yml ├── .gitignore ├── .vscode/ │ ├── extensions.json │ ├── launch.json │ └── settings.json ├── ChangeLog.md ├── Contributing.md ├── LICENSE.txt ├── Makefile ├── Readme.md ├── distribute.sh ├── escapecodes/ │ └── AsiEscapeCodes.go ├── framebuffertoansi/ │ ├── ChafaInfo.go │ ├── DetectTerminal.go │ ├── DrawState.go │ ├── Readme.md │ └── TermSize.go ├── go.mod ├── main.go ├── resources/ │ ├── HowIDidIt.md │ ├── alpineCompile.sh │ └── multiplatform.sh ├── termeverything/ │ ├── ConvertKeycodeToXbdCode.go │ ├── DisplayServerType.go │ ├── KeycodeSingleCodes.go │ ├── LinuxEventCodes.go │ ├── MainLoop.go │ ├── ParseArgs.go │ ├── PointerCode.go │ ├── RawMode.go │ ├── Readme.md │ ├── RenderMarkdownToTerminal.go │ ├── SetVirtualMonitorSize.go │ ├── StatusLine.go │ ├── TerminalDrawLoop.go │ ├── TerminalWindow.go │ ├── profile.go │ └── resources/ │ ├── LICENSES.txt │ └── help.md └── wayland/ ├── ApplyWlSurfaceDoubleBufferedState.go ├── Client.go ├── ClientGlobal.go ├── CopyBufferToWlSurfaceTexture.go ├── Desktop.go ├── GetMessageAnd_fileDescriptors.go ├── Globals.go ├── InputEvents.go ├── ListenToWaylandSocket.go ├── MemMap.go ├── MessageDecoder.go ├── Readme.md ├── SendMessageAndFileDescriptors.go ├── SocketListener.go ├── SurfaceRole.go ├── SurfaceUpdate.go ├── VirtualMonitorSize.go ├── doc.go ├── generate/ │ ├── Protocol.go │ ├── build_protocol.go │ ├── gen_enums.go │ ├── gen_events.go │ ├── gen_interface_interface.go │ ├── gen_request_handler.go │ ├── protocols.go │ └── resources/ │ ├── wayland.xml │ ├── xdg-decoration-unstable-v1.xml │ ├── xdg-shell.xml │ ├── xwayland-keyboard-grab-unstable-v1.xml │ └── xwayland-shell-v1.xml ├── generate.go ├── mmap.c ├── mmap.h ├── pointerslices/ │ ├── Readme.md │ └── lib.go ├── protocols/ │ ├── GlobalObjects.go │ ├── structs.go │ ├── wayland.xml.go │ ├── wayland_debug.go │ ├── wayland_nodebug.go │ ├── xdg-decoration-unstable-v1.xml.go │ ├── xdg-shell.xml.go │ ├── xwayland-keyboard-grab-unstable-v1.xml.go │ └── xwayland-shell-v1.xml.go ├── resources/ │ └── server-1.xkb ├── types.go ├── wayland.xml.helper.go ├── wl_compositor.go ├── wl_data_device.go ├── wl_data_device_manager.go ├── wl_data_source.go ├── wl_display.go ├── wl_keyboard.go ├── wl_output.go ├── wl_pointer.go ├── wl_region.go ├── wl_registry.go ├── wl_seat.go ├── wl_shm.go ├── wl_shm_pool.go ├── wl_subcompositor.go ├── wl_subsurface.go ├── wl_surface.go ├── wl_tough.go ├── xdg-decoration-unstable-v1.xml.helper.go ├── xdg-shell.xml.helper.go ├── xdg_popup.go ├── xdg_positioner.go ├── xdg_surface.go ├── xdg_toplevel.go ├── xdg_wm_base.go ├── xwayland-keyboard-grab-unstable-v1.xml.helper.go ├── xwayland-shell-v1.xml.helper.go ├── xwayland_shell_v1.go ├── xwayland_surface_v1.go ├── zwp_xwayland_keyboard_grab_manager_v1.go ├── zwp_xwayland_keyboard_grab_v1.go ├── zxdg_decoration_manager_v1.go └── zxdg_toplevel_decoration_v1.go ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: [mmulet] ================================================ FILE: .gitignore ================================================ deps c_interop/*.o c_interop/*.so shaders/spirv c_interop/out .task c_interop/build node_modules src/protocols bin pkg .DS_Store Taskfile.yml taskfile.yml Taskfile.yaml taskfile.yaml Appdir dist resources/npm_licenses.txt .podman .podman-run third_party/chafa_source/build debug.log resources/out/bunterm __debug_bin* term.everything term.everything❗mmulet.com-dont_forget_to_chmod_+x_this_file ================================================ FILE: .vscode/extensions.json ================================================ { "recommendations": [ "ms-vscode.cpptools-extension-pack", "golang.go", "ms-vscode.makefile-tools" ] } ================================================ FILE: .vscode/launch.json ================================================ { // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "Gen protocols", "type": "go", "request": "launch", "mode": "auto", "program": "${workspaceFolder}/cmd/protocols" }, { "name": "Launch term.everything", "type": "go", "request": "launch", "mode": "auto", "program": "${workspaceFolder}", "console": "externalTerminal", "args": [ "alacritty" // "firefox" ], // "buildFlags": ["-tags=debug"], } ] } ================================================ FILE: .vscode/settings.json ================================================ { "files.exclude": { "**/.git": true, "**/.svn": true, "**/.hg": true, "**/CVS": true, "**/.DS_Store": true, "**/Thumbs.db": true, "third_party": false, ".task": false, "deps": false, "scripts": false, ".vscode": false, "bun.lock": false, "package.json": false, "tsconfig.json": false, ".gitmodules": false, ".gitignore": false, "node_modules": false, "c_interop/build": false, "shaders/spirv": false, "bin": false, "pkg": false, "**/Taskfile.dist.yml": false, "tests": false, "Appdir": false, "*.AppImage": false, "dist": false, "patches": false, "LICENSE.txt": false }, "files.associations": { "*.glsl": "glsl", "*.scene": "json", "socket.h": "c", "*.tcc": "cpp", "string": "cpp", "iostream": "cpp", "cctype": "cpp", "clocale": "cpp", "cmath": "cpp", "cstdarg": "cpp", "cstddef": "cpp", "cstdio": "cpp", "cstdlib": "cpp", "cstring": "cpp", "ctime": "cpp", "cwchar": "cpp", "cwctype": "cpp", "array": "cpp", "atomic": "cpp", "strstream": "cpp", "bit": "cpp", "bitset": "cpp", "chrono": "cpp", "compare": "cpp", "complex": "cpp", "concepts": "cpp", "condition_variable": "cpp", "cstdint": "cpp", "deque": "cpp", "list": "cpp", "map": "cpp", "set": "cpp", "unordered_map": "cpp", "unordered_set": "cpp", "vector": "cpp", "exception": "cpp", "algorithm": "cpp", "functional": "cpp", "iterator": "cpp", "memory": "cpp", "memory_resource": "cpp", "numeric": "cpp", "optional": "cpp", "random": "cpp", "ratio": "cpp", "string_view": "cpp", "system_error": "cpp", "tuple": "cpp", "type_traits": "cpp", "utility": "cpp", "fstream": "cpp", "initializer_list": "cpp", "iomanip": "cpp", "iosfwd": "cpp", "istream": "cpp", "limits": "cpp", "mutex": "cpp", "new": "cpp", "numbers": "cpp", "ostream": "cpp", "ranges": "cpp", "shared_mutex": "cpp", "sstream": "cpp", "stdexcept": "cpp", "stop_token": "cpp", "streambuf": "cpp", "thread": "cpp", "cfenv": "cpp", "cinttypes": "cpp", "typeindex": "cpp", "typeinfo": "cpp", "variant": "cpp", "semaphore": "cpp", "csignal": "cpp", "future": "cpp", "span": "cpp", "valarray": "cpp", "*.ipp": "cpp", "csetjmp": "cpp" }, "terminal.integrated.enableImages": true, "typescript.preferences.importModuleSpecifierEnding": "js", "javascript.preferences.importModuleSpecifierEnding": "js", "C_Cpp.default.compilerPath": "/usr/bin/gcc", "C_Cpp.default.includePath": [ "/usr/include/", "/usr/local/include", "/usr/include/chafa", "/usr/lib/x86_64-linux-gnu/chafa/include", "/usr/include/glib-2.0", "/usr/lib/x86_64-linux-gnu/glib-2.0/include", "${workspaceFolder}/c_interop/include", "${workspaceFolder}/deps/**/*", "${workspaceFolder}/third_party/node-v22.14.0-linux-x64/include/node", "${workspaceFolder}/third_party/node-addon-api-8.3.1" ], "mesonbuild.selectRootDir": false, "cSpell.words": [ "Appdir", "appimage", "chafa", "Gwern", "LEFTBRACE", "libinterop", "linuxdeploy", "memcopy", "mmaped", "RIGHTBRACE", "subcompositor", "Xwayland" ], "mesonbuild.configureOnOpen": false, "editor.wordWrap": "off", "editor.rulers": [ 80 ] } ================================================ FILE: ChangeLog.md ================================================ # 0.7.8 - Added support for mouse when really zoomed out by - Adding SGR 1006 support for mouse reporting in terminals that support it. # 0.7.7 - Fixed a bug where the terminal would not output SIXELS even when the override was set. # 0.7.6 - Now it only redraws the screen when there are changes (like frame draw requests from wayland, mouse movement, etc), reducing CPU usage, and network bandwidth for remote sessions. - Moved profiling code behind a build tag to reduce binary size for normal users. # 0.7.5 - Converted code to entriely go (with a tiny bit of c). THis simplifies the build process and reduces dependencies. This lets us easily port to new platforms like arm64. # 0.5.4 - Added environment variables to pass through chafa options. - Added environment variable `TERM_EVERYTHING_PIXEL_TYPE` to workaround certain cases where there is a bgr/rgb swap. - Added `--max-frame-rate` option to ...set the maximum frame rate. - Fixed a build bug with node_canvas's included version of libstdc++.so # 0.5.3 fixed right mouse click and sub menus Set XDG_SESSION_TYPE to wayland so app that have a wayland support will use it. # 0.5.2 fixed scrolling inversion https://github.com/mmulet/term.everything/issues/4 # 0.5.0 First Beta release ================================================ FILE: Contributing.md ================================================ # Easy Distribute and hacking. Want to change just a couple lines? The only dependency you need is `podman - [podman https://podman.io/docs/installation](https://podman.io/docs/installation) On ubuntu just use`sudo apt install podman` and run the distribute script ```sh ./distribute.sh ``` That will use a podman container to build the entire app and it will put the output in `./dist`. Change the `PLATFORM` environment variable to build for different platforms. For example to build for linux aarch64: ```sh PLATFORM=linux/aarch64 ./distribute.sh ``` # Development Below are all the dependencies this app needs. ## Deps: - Download the following dependecies from your system's package manager. On ubuntu use: `sudo apt install pkg-config libchafa-dev build-essential libglib2.0-dev` - Optional: [vscode](https://code.visualstudio.com/) with these recommended extensions: - "ms-vscode.cpptools-extension-pack", - "golang.go", - "ms-vscode.makefile-tools" ### Version map These are the versions of the tools used to build and run the project: - chafa 1.16.0 # Running and building ## run You can just run make ```sh make ``` This will build the app. Or Generate the needed code with ```sh go generate ``` and run with go run. ```sh go run . firefox ``` e, good for local testing or sending to friends ## clean-all Remove all build artifacts. ```sh make clean ``` ## Distribute The distribute script creates an statically linked binary in a alpine linux podman container. ================================================ FILE: LICENSE.txt ================================================ GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 Copyright © 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software. A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public. The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version. An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU Affero General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Remote Network Interaction; Use with the GNU General Public License. Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see . ================================================ FILE: Makefile ================================================ .PHONY: all clean build .DELETE_ON_ERROR: bin_name := dist/$(if $(PLATFORM),$(PLATFORM)/,)$(if $(STATIC_BUILD),static,)/$(ARCH_PREFIX)term.everything❗mmulet.com-dont_forget_to_chmod_+x_this_file protocols_files := $(shell find ./wayland/generate) xml_protocols := $(shell find ./wayland/generate -name "*.xml") generated_protocols := $(patsubst ./wayland/generate/resources/%,./wayland/protocols/%.go,$(xml_protocols)) generated_helpers := $(patsubst ./wayland/generate/resources/%,./wayland/%.helper.go,$(xml_protocols)) build: $(generated_protocols) $(generated_helpers) $(bin_name) # grouped target to generate all protocols and helpers in one go # the & is what does this $(generated_protocols) $(generated_helpers)&: $(protocols_files) ./wayland/generate.go go generate ./wayland STATIC_FLAGS := $(if $(STATIC_BUILD),-ldflags '-extldflags "-static"',) $(bin_name): go.mod main.go $(shell find ./wayland) $(shell find ./termeverything) Makefile $(shell find ./framebuffertoansi) $(shell find ./escapecodes) $(generated_protocols) $(generated_helpers) go build $(STATIC_FLAGS) -o $(bin_name) . clean: @echo cleaning rm __debug_bin* 2>/dev/null || true if [ -z "$$MULTI_PLATFORM" ]; then rm -rf ./dist 2>/dev/null || true; fi rm ./wayland/protocols/*.xml.go 2>/dev/null || true rm ./wayland/*.helper.go 2>/dev/null || true ================================================ FILE: Readme.md ================================================ Term.Everything❗ Download the beta test now! HowIDidIt.md Works on both x11 and Wayland host systems. Now written in go! Typescript version here ## Run every GUI app in the terminal!  ## Even over ssh! Behold as I play a [video game in a font](https://github.com/mmulet/font-game-engine) in a web browser in a terminal transmitted over ssh (with one hand tied behind my back)!  ### Read about how it works! Check out [HowIDidIt.md](./resources/HowIDidIt.md) ## More Examples The quality of the window is limited to the number of rows and columns in your terminal. If you increase the resolution (ctrl - in alacritty, check your terminal) the quality will go up, (but performance may go down). Here I open up the Wing It! movie, and increase the quality until I get both a good frame rate and resolution:  ---------------- If your terminal supports images (like [kitty](https://sw.kovidgoyal.net/kitty/) or [iterm2](https://iterm2.com/)) you can render windows at full resolution (performance may degrade). In this example, on my mac, I open iTerm2 ssh into ubuntu and open firefox at full resolution:  ------------ I feel like every single day I hear about another terminal file viewer. I say, stop making terminal file viewers because you can just use the file viewer you already have! In your terminal!  ------------- Terminal in a terminal in a terminal in a terminal in a terminal.... it's terminals all the way down.  ------------- With only a small amount hacking, it can run Doom (shareware episode)!  ------ Run an entire Desktop in your terminal! [@ismail-yilmaz](https://github.com/ismail-yilmaz) is running Firefox, on [KDE Neon](https://neon.kde.org) in a [VM](https://gitlab.gnome.org/GNOME/gnome-boxes) on [Bobcat](https://github.com/ismail-yilmaz/Bobcat)  And this isn't even full resolution! Checkout the [full vid in in the discussions](https://github.com/mmulet/term.everything/discussions/16#discussioncomment-14390137) ## About `term.everything❗` is a Linux CLI program to run GUI windows in your terminal. Specifically, `term.everything❗` is a built-from-scratch [Wayland](https://wiki.archlinux.org/title/Wayland) compositor that outputs to a terminal rather than your monitor. >Don't know what Wayland is or just want to know more about how this works? Then, head over to [HowIDidIt.md](./resources/HowIDidIt.md) where I will explain how everything works in detail. ## Try it out! [Download the beta test now!](https://github.com/mmulet/term.everything/releases) ## Roadmap 1. [x] Term some things <--- This is where we are at - Some apps or (even most apps) may fail to launch or even crash! Please create [an issue]( https://github.com/mmulet/term.everything/issues) if you have problems. 2. [ ] Term most things 3. [ ] Term everything❗ ## Help and Usage Check out the [help file here](./resources/help.md) for a usage guide on how to use `term.everything❗` ## Contributing term.everything❗ is written in developer friendly [Go](https://go.dev/), with a just a smidge of C. See [./Contributing.md](./Contributing.md). ## Legal: term.everything❗ copyright 2025 Late for Dinner Studios, LLC --- Fontemon copyright 2021 Late for Dinner Studios, LLC --- Wing It! movie is licensed under the Creative Commons Attribution 4.0 license [Wing it licensing page](https://studio.blender.org/projects/wing-it/pages/licensing/) Attribution: (CC) Blender Foundation | studio.blender.org --- Doom shareware episode is copyright 1993 id Software --- ## Bonus: This is Gwerm the Term Worm.  He is doing okay. Thanks for asking. ================================================ FILE: distribute.sh ================================================ #!/bin/bash # This script builds a distributable AppImage # of the term.everything application using Podman. PODMAN="podman " APP_NAME="term.everything❗mmulet.com-dont_forget_to_chmod_+x_this_file" get_distro() { if [ -f /etc/os-release ]; then . /etc/os-release else echo "unknown" return fi # Check ID first, then fall back to ID_LIKE for id in $ID $ID_LIKE; do case $id in ubuntu|debian|linuxmint|pop) echo "sudo apt install -y" return ;; fedora) echo "sudo dnf install -y" return ;; centos|rhel|rocky|almalinux) echo "sudo yum install -y" return ;; arch|manjaro|cachyos|endeavouros|garuda) echo "sudo pacman -S" return ;; opensuse*|suse) echo "sudo zypper install" return ;; alpine) echo "sudo apk add" return ;; void) echo "sudo xbps-install -S" return ;; gentoo) echo "sudo emerge" return ;; nixos) echo "nix-env -iA nixpkgs." return ;; esac done echo "unknown" } if ! command -v podman >/dev/null 2>&1; then if command -v docker >/dev/null 2>&1; then PODMAN="docker " else INSTALL_CMD=$(get_distro) echo "Warning: podman is not installed or not in PATH." echo "To install on your system, try: $INSTALL_CMD podman" echo "Please install podman to proceed, it's literally all you need. Don't even need attention. Just podman. Just get podman. What are you waiting for? Stop reading this and install podman." exit 1 fi fi if [ -z "${PLATFORM+x}" ]; then PLATFORM_ARG="" else PLATFORM_ARG="--platform $PLATFORM -e PLATFORM=$PLATFORM -e MULTI_PLATFORM=1 -e ARCH_PREFIX=$ARCH_PREFIX" fi $PODMAN run \ $PLATFORM_ARG \ -it \ --volume .:/home/mount \ --rm alpine:latest /bin/sh /home/mount/resources/alpineCompile.sh && \ echo "Output is ./dist/$PLATFORM/static/$APP_NAME" ================================================ FILE: escapecodes/AsiEscapeCodes.go ================================================ package escapecodes const ( DisableAlternativeScreenBuffer = "\x1b[?1049l" EnableAlternativeScreenBuffer = "\x1b[?1049h" EnableSGR = "\x1b[?1006h" EnableMouseTracking = "\x1b[?1003h" DisableMouseTracking = "\x1b[?1003l" DisableNormalMouseTracking = "\x1b[?1000l" HideCursor = "\x1b[?25l" ShowCursor = "\x1b[?25h" Reset = "\x1b[0m" FgBlack = "\x1b[30m" BgWhite = "\x1b[47m" FgWhite = "\x1b[37m" BgBlack = "\x1b[40m" FgRed = "\x1b[31m" BgRed = "\x1b[41m" FgGreen = "\x1b[32m" BgGreen = "\x1b[42m" FgYellow = "\x1b[33m" BgYellow = "\x1b[43m" FgBlue = "\x1b[34m" BgBlue = "\x1b[44m" FgMagenta = "\x1b[35m" BgMagenta = "\x1b[45m" FgCyan = "\x1b[36m" BgCyan = "\x1b[46m" Bold = "\x1b[1m" Dim = "\x1b[2m" Italic = "\x1b[3m" Underline = "\x1b[4m" Inverse = "\x1b[7m" Hidden = "\x1b[8m" Strikethrough = "\x1b[9m" MoveCursorToHome = "\x1b[H" ClearScreen = "\x1b[2J" ClearLine = "\x1b[2K" ClearLineAfterCursor = "\x1b[0K" ) ================================================ FILE: framebuffertoansi/ChafaInfo.go ================================================ package framebuffertoansi // #cgo pkg-config: chafa glib-2.0 // #include "chafa.h" // #include // // // Small helpers to safely access GString from Go. // static const char* gstring_str(const GString* s) { return s->str; } // static gsize gstring_len(const GString* s) { return s->len; } // // // Feature test for OCTANT availability to mimic the original #ifdef. // #ifdef CHAFA_VERSION_1_16 // #define HAVE_CHAFA_OCTANT 1 // static ChafaSymbolTags octant_symbol() { return CHAFA_SYMBOL_TAG_OCTANT; } // #else // #define HAVE_CHAFA_OCTANT 0 // static ChafaSymbolTags octant_symbol() { return 0; } // #endif // static int chafa_have_octant() { return HAVE_CHAFA_OCTANT; } // import "C" import ( "os" "runtime" "unsafe" ) type ChafaInfo struct { TermInfo *C.ChafaTermInfo Mode C.ChafaCanvasMode PixelMode C.ChafaPixelMode SymbolMap *C.ChafaSymbolMap Config *C.ChafaCanvasConfig Canvas *C.ChafaCanvas WidthCells int HeightCells int WidthOfACellInPixels int HeightOfACellInPixels int SessionTypeIsX11 bool PixelTypeOverride C.ChafaPixelType } func (ci *ChafaInfo) ConvertImage(texturePixels []byte, textureWidth, textureHeight, textureStride uint32) string { if len(texturePixels) == 0 { return "" } pixelsPtr := (*C.guint8)(unsafe.Pointer(&texturePixels[0])) C.chafa_canvas_draw_all_pixels( ci.Canvas, ci.getPixelType(), pixelsPtr, C.int(textureWidth), C.int(textureHeight), C.int(textureStride), ) runtime.KeepAlive(texturePixels) gstr := C.chafa_canvas_print(ci.Canvas, ci.TermInfo) if gstr == nil { return "" } defer C.g_string_free(gstr, C.gboolean(1)) ptrStr := C.gstring_str(gstr) length := C.gstring_len(gstr) if ptrStr == nil || length == 0 { return "" } return C.GoStringN((*C.char)(unsafe.Pointer(ptrStr)), C.int(length)) } func MakeChafaInfo(widthCells, heightCells, widthOfACellInPixels, heightOfACellInPixels int, sessionTypeIsX11 bool) *ChafaInfo { termInfo, mode, pixelMode := DetectTerminal() ci := &ChafaInfo{ TermInfo: termInfo, Mode: mode, PixelMode: pixelMode, WidthCells: widthCells, HeightCells: heightCells, WidthOfACellInPixels: widthOfACellInPixels, HeightOfACellInPixels: heightOfACellInPixels, SessionTypeIsX11: sessionTypeIsX11, } // Symbol map from env override (or default) ci.SymbolMap = C.chafa_symbol_map_new() C.chafa_symbol_map_add_by_tags(ci.SymbolMap, getChafaSymbolTags()) // Canvas config ci.Config = C.chafa_canvas_config_new() C.chafa_canvas_config_set_canvas_mode(ci.Config, ci.Mode) C.chafa_canvas_config_set_pixel_mode(ci.Config, ci.PixelMode) C.chafa_canvas_config_set_geometry(ci.Config, C.int(widthCells), C.int(heightCells)) C.chafa_canvas_config_set_symbol_map(ci.Config, ci.SymbolMap) // chafa_canvas_config_set_optimizations(config, TRUE); C.chafa_canvas_config_set_work_factor(ci.Config, C.gfloat(0.0)) // C.chafa_canvas_config_set_preprocessing_enabled(ci.Config, C.gboolean(0)) // C.chafa_canvas_config_set_dither_intensity(ci.Config, C.CHAFA_DITHER_MODE_DIFFUSION) if widthOfACellInPixels > 0 && heightOfACellInPixels > 0 { /* We know the pixel dimensions of each cell. Store it in the config. */ C.chafa_canvas_config_set_cell_geometry(ci.Config, C.int(widthOfACellInPixels), C.int(heightOfACellInPixels)) } ci.Canvas = C.chafa_canvas_new(ci.Config) ci.PixelTypeOverride = getChafaPixelType() return ci } func (ci *ChafaInfo) getPixelType() C.ChafaPixelType { if ci.PixelTypeOverride != C.CHAFA_PIXEL_MAX { return ci.PixelTypeOverride } if ci.PixelMode == C.CHAFA_PIXEL_MODE_KITTY && !ci.SessionTypeIsX11 { return C.CHAFA_PIXEL_RGBA8_UNASSOCIATED } return C.CHAFA_PIXEL_BGRA8_UNASSOCIATED } func getChafaPixelType() C.ChafaPixelType { switch os.Getenv("TERM_EVERYTHING_PIXEL_TYPE") { case "": return C.CHAFA_PIXEL_MAX // No override case "RGBA8": return C.CHAFA_PIXEL_RGBA8_UNASSOCIATED case "BGRA8": return C.CHAFA_PIXEL_BGRA8_UNASSOCIATED case "ARGB8": return C.CHAFA_PIXEL_ARGB8_UNASSOCIATED case "ABGR8": return C.CHAFA_PIXEL_ABGR8_UNASSOCIATED case "RGBA8_PREMULTIPLIED": return C.CHAFA_PIXEL_RGBA8_PREMULTIPLIED case "BGRA8_PREMULTIPLIED": return C.CHAFA_PIXEL_BGRA8_PREMULTIPLIED case "ARGB8_PREMULTIPLIED": return C.CHAFA_PIXEL_ARGB8_PREMULTIPLIED case "ABGR8_PREMULTIPLIED": return C.CHAFA_PIXEL_ABGR8_PREMULTIPLIED default: return C.CHAFA_PIXEL_MAX } } var defaultSymbolTags = C.ChafaSymbolTags(C.CHAFA_SYMBOL_TAG_ALL) func getChafaSymbolTags() C.ChafaSymbolTags { switch os.Getenv("TERM_EVERYTHING_SYMBOLS") { case "": return defaultSymbolTags case "NONE": return C.CHAFA_SYMBOL_TAG_NONE case "SPACE": return C.CHAFA_SYMBOL_TAG_SPACE case "SOLID": return C.CHAFA_SYMBOL_TAG_SOLID case "STIPPLE": return C.CHAFA_SYMBOL_TAG_STIPPLE case "BLOCK": return C.CHAFA_SYMBOL_TAG_BLOCK case "BORDER": return C.CHAFA_SYMBOL_TAG_BORDER case "DIAGONAL": return C.CHAFA_SYMBOL_TAG_DIAGONAL case "DOT": return C.CHAFA_SYMBOL_TAG_DOT case "QUAD": return C.CHAFA_SYMBOL_TAG_QUAD case "HHALF": return C.CHAFA_SYMBOL_TAG_HHALF case "VHALF": return C.CHAFA_SYMBOL_TAG_VHALF case "HALF": return C.CHAFA_SYMBOL_TAG_HALF case "INVERTED": return C.CHAFA_SYMBOL_TAG_INVERTED case "BRAILLE": return C.CHAFA_SYMBOL_TAG_BRAILLE case "TECHNICAL": return C.CHAFA_SYMBOL_TAG_TECHNICAL case "GEOMETRIC": return C.CHAFA_SYMBOL_TAG_GEOMETRIC case "ASCII": return C.CHAFA_SYMBOL_TAG_ASCII case "ALPHA": return C.CHAFA_SYMBOL_TAG_ALPHA case "DIGIT": return C.CHAFA_SYMBOL_TAG_DIGIT case "ALNUM": return C.CHAFA_SYMBOL_TAG_ALNUM case "NARROW": return C.CHAFA_SYMBOL_TAG_NARROW case "WIDE": return C.CHAFA_SYMBOL_TAG_WIDE case "AMBIGUOUS": return C.CHAFA_SYMBOL_TAG_AMBIGUOUS case "UGLY": return C.CHAFA_SYMBOL_TAG_UGLY case "LEGACY": return C.CHAFA_SYMBOL_TAG_LEGACY case "SEXTANT": return C.CHAFA_SYMBOL_TAG_SEXTANT case "WEDGE": return C.CHAFA_SYMBOL_TAG_WEDGE case "LATIN": return C.CHAFA_SYMBOL_TAG_LATIN case "IMPORTED": return C.CHAFA_SYMBOL_TAG_IMPORTED case "OCTANT": if C.chafa_have_octant() != 0 { return C.ChafaSymbolTags(C.chafa_have_octant()) } return defaultSymbolTags case "ALL": return C.CHAFA_SYMBOL_TAG_ALL default: return defaultSymbolTags } } func (ci *ChafaInfo) Destroy() { if ci == nil { return } if ci.Canvas != nil { C.chafa_canvas_unref(ci.Canvas) ci.Canvas = nil } if ci.Config != nil { C.chafa_canvas_config_unref(ci.Config) ci.Config = nil } if ci.SymbolMap != nil { C.chafa_symbol_map_unref(ci.SymbolMap) ci.SymbolMap = nil } if ci.TermInfo != nil { C.chafa_term_info_unref(ci.TermInfo) ci.TermInfo = nil } } ================================================ FILE: framebuffertoansi/DetectTerminal.go ================================================ package framebuffertoansi // #cgo pkg-config: chafa glib-2.0 // #include "chafa.h" // #include // // static ChafaTermInfo* detect_term_info_from_env() { // gchar **envp = g_get_environ(); // ChafaTermInfo *term_info = chafa_term_db_detect(chafa_term_db_get_default(), envp); // g_strfreev(envp); // return term_info; // } import "C" import "os" func getDefaultPixelMode(termInfo *C.ChafaTermInfo) C.ChafaPixelMode { if C.chafa_term_info_have_seq(termInfo, C.CHAFA_TERM_SEQ_BEGIN_ITERM2_IMAGE) != 0 { return C.CHAFA_PIXEL_MODE_ITERM2 } else if C.chafa_term_info_have_seq(termInfo, C.CHAFA_TERM_SEQ_BEGIN_KITTY_IMMEDIATE_IMAGE_V1) != 0 { return C.CHAFA_PIXEL_MODE_KITTY } else if C.chafa_term_info_have_seq(termInfo, C.CHAFA_TERM_SEQ_BEGIN_SIXELS) != 0 { return C.CHAFA_PIXEL_MODE_SIXELS } else { return C.CHAFA_PIXEL_MODE_SYMBOLS } } func getPixelModeOverride() string { return os.Getenv("TERM_EVERYTHING_PIXEL_MODE") } func getCanvasModeOverride() string { return os.Getenv("TERM_EVERYTHING_CANVAS_MODE") } func getPixelMode(termInfo *C.ChafaTermInfo) C.ChafaPixelMode { override := getPixelModeOverride() if override == "" { return getDefaultPixelMode(termInfo) } switch override { case "SYMBOLS": return C.CHAFA_PIXEL_MODE_SYMBOLS case "SIXELS": return C.CHAFA_PIXEL_MODE_SIXELS case "KITTY": return C.CHAFA_PIXEL_MODE_KITTY case "ITERM2": return C.CHAFA_PIXEL_MODE_ITERM2 default: return getDefaultPixelMode(termInfo) } } func getDefaultCanvasMode(termInfo *C.ChafaTermInfo, pixelMode C.ChafaPixelMode) C.ChafaCanvasMode { switch pixelMode { case C.CHAFA_PIXEL_MODE_ITERM2, C.CHAFA_PIXEL_MODE_SIXELS, C.CHAFA_PIXEL_MODE_KITTY: return C.CHAFA_CANVAS_MODE_TRUECOLOR case C.CHAFA_PIXEL_MODE_SYMBOLS: fallthrough default: if C.chafa_term_info_have_seq(termInfo, C.CHAFA_TERM_SEQ_SET_COLOR_FGBG_DIRECT) != 0 && C.chafa_term_info_have_seq(termInfo, C.CHAFA_TERM_SEQ_SET_COLOR_FG_DIRECT) != 0 && C.chafa_term_info_have_seq(termInfo, C.CHAFA_TERM_SEQ_SET_COLOR_BG_DIRECT) != 0 { return C.CHAFA_CANVAS_MODE_TRUECOLOR } else if C.chafa_term_info_have_seq(termInfo, C.CHAFA_TERM_SEQ_SET_COLOR_FGBG_256) != 0 && C.chafa_term_info_have_seq(termInfo, C.CHAFA_TERM_SEQ_SET_COLOR_FG_256) != 0 && C.chafa_term_info_have_seq(termInfo, C.CHAFA_TERM_SEQ_SET_COLOR_BG_256) != 0 { return C.CHAFA_CANVAS_MODE_INDEXED_240 } else if C.chafa_term_info_have_seq(termInfo, C.CHAFA_TERM_SEQ_SET_COLOR_FGBG_16) != 0 && C.chafa_term_info_have_seq(termInfo, C.CHAFA_TERM_SEQ_SET_COLOR_FG_16) != 0 && C.chafa_term_info_have_seq(termInfo, C.CHAFA_TERM_SEQ_SET_COLOR_BG_16) != 0 { return C.CHAFA_CANVAS_MODE_INDEXED_16 } else if C.chafa_term_info_have_seq(termInfo, C.CHAFA_TERM_SEQ_INVERT_COLORS) != 0 && C.chafa_term_info_have_seq(termInfo, C.CHAFA_TERM_SEQ_RESET_ATTRIBUTES) != 0 { return C.CHAFA_CANVAS_MODE_FGBG_BGFG } else { return C.CHAFA_CANVAS_MODE_FGBG } } } func getCanvasMode(termInfo *C.ChafaTermInfo, pixelMode C.ChafaPixelMode) C.ChafaCanvasMode { override := getCanvasModeOverride() if override == "" { return getDefaultCanvasMode(termInfo, pixelMode) } switch override { case "TRUECOLOR": return C.CHAFA_CANVAS_MODE_TRUECOLOR case "INDEXED_256": return C.CHAFA_CANVAS_MODE_INDEXED_256 case "INDEXED_240": return C.CHAFA_CANVAS_MODE_INDEXED_240 case "INDEXED_16": return C.CHAFA_CANVAS_MODE_INDEXED_16 case "FGBG_BGFG": return C.CHAFA_CANVAS_MODE_FGBG_BGFG case "FGBG": return C.CHAFA_CANVAS_MODE_FGBG case "INDEXED_8": return C.CHAFA_CANVAS_MODE_INDEXED_8 case "INDEXED_16_8": return C.CHAFA_CANVAS_MODE_INDEXED_16_8 default: return getDefaultCanvasMode(termInfo, pixelMode) } } func DetectTerminal() (termInfo *C.ChafaTermInfo, mode C.ChafaCanvasMode, pixelMode C.ChafaPixelMode) { termInfo = C.detect_term_info_from_env() if getPixelModeOverride() != "" || getCanvasModeOverride() != "" { /* Make sure we have fallback sequences in case the user forces * a mode that's technically unsupported by the terminal. */ fallback_info := C.chafa_term_db_get_fallback_info(C.chafa_term_db_get_default()) C.chafa_term_info_supplement(termInfo, fallback_info) C.chafa_term_info_unref(fallback_info) } pixelMode = getPixelMode(termInfo) mode = getCanvasMode(termInfo, pixelMode) return } ================================================ FILE: framebuffertoansi/DrawState.go ================================================ package framebuffertoansi // #cgo pkg-config: chafa glib-2.0 // #include "chafa.h" import "C" import ( "fmt" "os" "strings" "unsafe" "github.com/mmulet/term.everything/escapecodes" ) type DrawState struct { SessionTypeIsX11 bool ChafaInfo *ChafaInfo } func MakeDrawState(sessionTypeIsX11 bool) *DrawState { return &DrawState{ SessionTypeIsX11: sessionTypeIsX11, } } func (ds *DrawState) ResizeChafaInfoIfNeeded(WidthCells int, HeightCells int, termSize TermSize) { if ds.ChafaInfo != nil && !(ds.ChafaInfo.WidthCells == WidthCells && ds.ChafaInfo.HeightCells == HeightCells && ds.ChafaInfo.WidthOfACellInPixels == termSize.WidthOfACellInPixels && ds.ChafaInfo.HeightOfACellInPixels == termSize.HeightOfACellInPixels) { ds.ChafaInfo.Destroy() ds.ChafaInfo = nil } if ds.ChafaInfo != nil { return } ds.ChafaInfo = MakeChafaInfo(WidthCells, HeightCells, termSize.WidthOfACellInPixels, termSize.HeightOfACellInPixels, ds.SessionTypeIsX11) } func (ds *DrawState) Destroy() { if ds.ChafaInfo != nil { ds.ChafaInfo.Destroy() ds.ChafaInfo = nil } } func (ds *DrawState) DrawDesktop(texturePixels []byte, width, height uint32, statusLine *string) (int, int) { haveStatusLine := statusLine != nil && len(*statusLine) > 0 termSize := MakeTermSize() widthCells := termSize.WidthCells statusLineHeight := 0 if haveStatusLine { statusLineHeight = 1 } heightCells := termSize.HeightCells - statusLineHeight // Adjust geometry preserving aspect ratio. C.chafa_calc_canvas_geometry( C.int(width), C.int(height), (*C.int)(unsafe.Pointer(&widthCells)), (*C.int)(unsafe.Pointer(&heightCells)), C.gfloat(termSize.FontRatio), C.gboolean(1), // preserve aspect C.gboolean(0), // do not upscale ) ds.ResizeChafaInfoIfNeeded(widthCells, heightCells, termSize) printable := ds.ChafaInfo.ConvertImage(texturePixels, width, height, width*4) var sb strings.Builder if haveStatusLine { sb.WriteString(escapecodes.MoveCursorToHome) sb.WriteString(*statusLine) sb.WriteString(escapecodes.ClearLineAfterCursor) sb.WriteString("\n") } sb.WriteString(printable) fmt.Fprint(os.Stdout, sb.String()) _ = os.Stdout.Sync() return widthCells, heightCells } ================================================ FILE: framebuffertoansi/Readme.md ================================================ Convert a framebuffer (bytes) with pixel data into ANSI escape codes for terminal display. ## Usage ```go drawState := framebuffertoansi.MakeDrawState(true) var grid []byte = ... width := 80 height := 24 drawState.DrawDesktop(grid, uint32(width), uint32(height), "Hello, world!") ``` ================================================ FILE: framebuffertoansi/TermSize.go ================================================ package framebuffertoansi import ( "os" "syscall" "unsafe" ) type TermSize struct { WidthCells int HeightCells int WidthPixels int HeightPixels int FontRatio float64 WidthOfACellInPixels int HeightOfACellInPixels int } type WinSize struct { Row uint16 Col uint16 Xpixel uint16 Ypixel uint16 } func MakeTermSize() TermSize { ts := TermSize{ WidthCells: -1, HeightCells: -1, WidthPixels: -1, HeightPixels: -1, WidthOfACellInPixels: -1, HeightOfACellInPixels: -1, FontRatio: 0.5, } tryFDs := []uintptr{os.Stdout.Fd(), os.Stderr.Fd(), os.Stdin.Fd()} for _, fd := range tryFDs { if ws, err := GetWinsize(fd); err == nil { ts.WidthCells = int(ws.Col) ts.HeightCells = int(ws.Row) ts.WidthPixels = int(ws.Xpixel) ts.HeightPixels = int(ws.Ypixel) break } } if ts.WidthCells <= 0 { ts.WidthCells = -1 } if ts.HeightCells <= 2 { ts.HeightCells = -1 } if ts.WidthPixels <= 0 || ts.HeightPixels <= 0 { ts.WidthPixels = -1 ts.HeightPixels = -1 } if ts.WidthCells > 0 && ts.HeightCells > 0 && ts.WidthPixels > 0 && ts.HeightPixels > 0 { ts.WidthOfACellInPixels = ts.WidthPixels / ts.WidthCells ts.HeightOfACellInPixels = ts.HeightPixels / ts.HeightCells if ts.HeightOfACellInPixels > 0 { ts.FontRatio = float64(ts.WidthOfACellInPixels) / float64(ts.HeightOfACellInPixels) } } else { ts.WidthOfACellInPixels = -1 ts.HeightOfACellInPixels = -1 ts.FontRatio = 0.5 } return ts } func GetWinsize(fd uintptr) (WinSize, error) { var ws WinSize _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&ws))) if errno != 0 { return ws, errno } return ws, nil } ================================================ FILE: go.mod ================================================ module github.com/mmulet/term.everything go 1.25.2 ================================================ FILE: main.go ================================================ package main import ( "github.com/mmulet/term.everything/termeverything" ) //go:generate go generate ./wayland func main() { termeverything.MainLoop() } ================================================ FILE: resources/HowIDidIt.md ================================================ # How I Did It! A long long time ago, when a program wanted to draw something to the screen, it could just write to a certain spot in RAM. The screen was a wild west and anyone could draw anywhere anytime. Nowadays, display access is coordinated by a special program called the [Display Server](https://en.wikipedia.org/wiki/Windowing_system#Display_server), which "coordinates the input and output of its clients to and from the rest of the operating system, the hardware and each other". With input being mouse/keyboard/etc and output being graphics, images, anything you see in a "window". On modern linux, for display servers most systems use either the [Wayland (protocol)](https://en.wikipedia.org/wiki/Wayland_(protocol)) or [x11](https://en.wikipedia.org/wiki/X_Window_System). We're going to focus on Wayland, mostly because it's newer and there are systems in place to run older x11 apps in wayland for backwards compatibility. ## Wayland (protocol) Notice that it's Wayland *protocol* not wayland display-server. That's because Wayland is not a display server. It's a [protocol](https://en.wikipedia.org/wiki/Communication_protocol); it'a a way for programs to communicate to a hypothetical display server. When people say that their system is running Wayland, what they really mean is that their system is running a display server that speaks the wayland protocol. What's even better is that Wayland does not have a set [Rendering Model](https://en.wikipedia.org/wiki/Wayland_(protocol)#Rendering_model), the programs decide entirely on their own how they will draw their "windows" or other graphics, then they just hand it over to the display server. ## How to draw The wayland protocol actually has no opinion on what you do with the graphics the programs give you. Sure, they probably expect that you will use [Kernel Mode Setting](https://en.wikipedia.org/wiki/Mode_setting), but really if you wanted to, you could print out the graphics and give them to a league of crochet grandmas to individually tie together every single pixel into the afghan of legend! The programs would never be the wiser. Again, the main benefit of wayland is that the programs don't care how they get input as long as it *gets input*, and it doesn't care what happens to its output. So, this means we can do anything we want, so let's output to the terminal! I take the output given to us by the client and convert the images to terminal output, the utf8 characters with ansi escape codes via the [chafa library](https://github.com/hpjansson/chafa/). For input, I take the keyboard and mouse (yes terminals support mice) from the stdin. And that's it! Of course, there are about 10K lines of code needed to actually do this in practice, but if you're interested in that I invite you to [check out the source code](../termeverything/). ## What else can you do with wayland I have many other crazy ideas of what else to do custom wayland display server, so stay tuned. ================================================ FILE: resources/alpineCompile.sh ================================================ #!/bin/sh cat > /etc/apk/repositories << EOF https://dl-cdn.alpinelinux.org/alpine/edge/main https://dl-cdn.alpinelinux.org/alpine/edge/community EOF apk update apk add chafa-dev go glib-static pcre2-static make # Because I'm paranoid, remove the shared libs # just not to tempt the linker rm /usr/lib/libchafa.so* cd /home/mount make clean STATIC_BUILD=1 make ================================================ FILE: resources/multiplatform.sh ================================================ #!/bin/bash PLATFORM=linux/aarch64 ARCH_PREFIX=ARM- ./distribute.sh PLATFORM=linux/amd64 ARCH_PREFIX= ./distribute.sh ================================================ FILE: termeverything/ConvertKeycodeToXbdCode.go ================================================ package termeverything // /** // - According to sleuthing here are the mod makes // - 1 << 0 Shift // - 1 << 1 Lock // - 1 << 2 Control // - 1 << 3 Alt // - 1 << 4 Mod2 // - 1 << 5 Mod3 // - 1 << 6 Mod4 // - 1 << 7 Mod5 // - 1 << 8 Button1 // - 1 << 9 Button2 // - 1 << 10 Button3 // - 1 << 11 Button4 // - 1 << 12 Button5 const ( ModShift = 1 << 0 ModLock = 1 << 1 ModControl = 1 << 2 ModAlt = 1 << 3 ) // numericKeys and alphaKeys exported here for KeycodeSingleCodes.go var numericKeys = []Linux_Event_Codes{ KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, } var alphaKeys = []Linux_Event_Codes{ KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, } type XkbdCode interface { isXkbdCode() OrModifiers(int) GetModifiers() int } func (*KeyCode) isXkbdCode() {} type KeyCode struct { KeyCode Linux_Event_Codes Modifiers int } func (k *KeyCode) OrModifiers(modifiers int) { k.Modifiers |= modifiers } func (k *KeyCode) GetModifiers() int { return k.Modifiers } func ConvertKeycodeToXbdCode(data []byte) []XkbdCode { if len(data) == 1 { if out := KeycodeSingleCodes(int(data[0])); out != nil { return []XkbdCode{out} } return nil } if len(data) == 2 { return parse_length_2(data) } if len(data) == 3 { return parse_length_3(data) } if data[0] == 27 && data[1] == 91 && data[2] == 60 { return ParseSGRMouseSequences(data) } if len(data) == 4 { return parse_length_4(data) } if len(data) == 5 { if data[0] == 27 && data[1] == 91 && data[4] == 126 { if data[2] == 49 { if keyCode, ok := f5_through_8_codes[data[3]]; ok { return []XkbdCode{&KeyCode{KeyCode: keyCode, Modifiers: 0}} } } if data[2] == 50 { if keyCode, ok := f9_through_12_codes[data[3]]; ok { return []XkbdCode{&KeyCode{KeyCode: keyCode, Modifiers: 0}} } } } } if len(data)%6 == 0 { out := make([]XkbdCode, 0) numEvents := len(data) / 6 for i := range numEvents { slice := data[i*6 : (i+1)*6] if slice[0] == 27 && slice[1] == 91 && slice[3] == 59 { switch slice[2] { case 49: // '1' if modifiers := modifiers_for_arrow_and_page_up_etc(slice[4]); modifiers > 0 { eventOut := parse_length_3([]byte{27, 91, slice[5]}) if len(eventOut) > 0 { for _, e := range eventOut { e.OrModifiers(modifiers) } out = append(out, eventOut...) continue } } case 50, 51, 52, 53, 54: // '2'..'6' if modifiers := modifiers_for_arrow_and_page_up_etc(slice[4]); slice[5] == 126 && modifiers > 0 { eventOut := parse_length_4([]byte{27, 91, slice[2], 126}) if len(eventOut) > 0 { for _, e := range eventOut { e.OrModifiers(modifiers) } out = append(out, eventOut...) continue } } } } // if value := PointerCode(slice); value != nil { // out = append(out, value) // } } return out } if len(data) == 7 { if data[0] == 27 && data[1] == 91 && data[4] == 59 && data[6] == 126 { if modifiers := modifiers_for_arrow_and_page_up_etc(data[5]); modifiers > 0 { if data[2] == 49 { if keyCode, ok := f5_through_8_codes[data[3]]; ok { return []XkbdCode{&KeyCode{KeyCode: keyCode, Modifiers: modifiers}} } } if data[2] == 50 { if keyCode, ok := f9_through_12_codes[data[3]]; ok { return []XkbdCode{&KeyCode{KeyCode: keyCode, Modifiers: modifiers}} } } } } } // Unrecognized // TODO maybe return error here? return nil } func parse_length_2(data []byte) []XkbdCode { if len(data) < 2 { return nil } if data[0] == 27 { out := KeycodeSingleCodes(int(data[1])) if out == nil { return nil } out.Modifiers |= ModAlt return []XkbdCode{out} } out := make([]XkbdCode, 0, 2) if out1 := KeycodeSingleCodes(int(data[0])); out1 != nil { out = append(out, out1) } if out2 := KeycodeSingleCodes(int(data[1])); out2 != nil { out = append(out, out2) } return out } func parse_length_3(data []byte) []XkbdCode { if len(data) < 3 { return nil } if data[0] != 27 { a := KeycodeSingleCodes(int(data[0])) b := parse_length_2(data[1:]) if a != nil { return append([]XkbdCode{a}, b...) } return b } if data[1] == 79 { // 'O' switch data[2] { case 80: // 'P' return []XkbdCode{&KeyCode{KeyCode: KEY_F1, Modifiers: 0}} case 81: // 'Q' return []XkbdCode{&KeyCode{KeyCode: KEY_F2, Modifiers: 0}} case 82: // 'R' return []XkbdCode{&KeyCode{KeyCode: KEY_F3, Modifiers: 0}} case 83: // 'S' return []XkbdCode{&KeyCode{KeyCode: KEY_F4, Modifiers: 0}} } } if data[1] == 91 { // '[' switch data[2] { case 65: // 'A' return []XkbdCode{&KeyCode{KeyCode: KEY_UP, Modifiers: 0}} case 66: // 'B' return []XkbdCode{&KeyCode{KeyCode: KEY_DOWN, Modifiers: 0}} case 67: // 'C' return []XkbdCode{&KeyCode{KeyCode: KEY_RIGHT, Modifiers: 0}} case 68: // 'D' return []XkbdCode{&KeyCode{KeyCode: KEY_LEFT, Modifiers: 0}} case 70: // 'F' return []XkbdCode{&KeyCode{KeyCode: KEY_END, Modifiers: 0}} case 72: // 'H' return []XkbdCode{&KeyCode{KeyCode: KEY_HOME, Modifiers: 0}} case 90: // 'Z' => Shift+Tab return []XkbdCode{&KeyCode{KeyCode: KEY_TAB, Modifiers: ModShift}} // These work for alt+F1, shift+F2, etc in some terminals case 80: // 'P' return []XkbdCode{&KeyCode{KeyCode: KEY_F1, Modifiers: 0}} case 81: // 'Q' return []XkbdCode{&KeyCode{KeyCode: KEY_F2, Modifiers: 0}} case 82: // 'R' return []XkbdCode{&KeyCode{KeyCode: KEY_F3, Modifiers: 0}} case 83: // 'S' return []XkbdCode{&KeyCode{KeyCode: KEY_F4, Modifiers: 0}} } } return nil } func modifiers_for_arrow_and_page_up_etc(slice4 byte) int { switch slice4 { case 50: // '2' return ModShift case 51: // '3' return ModAlt case 52: // '4' return ModShift | ModAlt case 53: // '5' return ModControl case 54: // '6' return ModControl | ModShift default: return -1 } } func parse_length_4(data []byte) []XkbdCode { if len(data) < 4 { return nil } if data[0] != 27 { a := KeycodeSingleCodes(int(data[0])) b := parse_length_3(data[1:]) if a != nil { return append([]XkbdCode{a}, b...) } return b } if data[1] == 91 { // '[' if data[2] == 50 && data[3] == 126 { // "2~" return []XkbdCode{&KeyCode{KeyCode: KEY_INSERT, Modifiers: 0}} } if data[2] == 51 && data[3] == 126 { // "3~" return []XkbdCode{&KeyCode{KeyCode: KEY_DELETE, Modifiers: 0}} } if data[2] == 53 && data[3] == 126 { // "5~" return []XkbdCode{&KeyCode{KeyCode: KEY_PAGEUP, Modifiers: 0}} } if data[2] == 54 && data[3] == 126 { // "6~" return []XkbdCode{&KeyCode{KeyCode: KEY_PAGEDOWN, Modifiers: 0}} } } return nil } var f5_through_8_codes = map[byte]Linux_Event_Codes{ 53: KEY_F5, // '5' 55: KEY_F6, // '7' 56: KEY_F7, // '8' 57: KEY_F8, // '9' } var f9_through_12_codes = map[byte]Linux_Event_Codes{ 48: KEY_F9, // '0' 49: KEY_F10, // '1' 51: KEY_F11, // '3' 52: KEY_F12, // '4' } ================================================ FILE: termeverything/DisplayServerType.go ================================================ package termeverything import "os" type DisplayServerTypeEnum int const ( DisplayServerTypeUnknown DisplayServerTypeEnum = iota DisplayServerTypeX11 DisplayServerTypeWayland ) func DisplayServerType() DisplayServerTypeEnum { if displayType, ok := os.LookupEnv("XDG_SESSION_TYPE"); ok { switch displayType { case "x11": return DisplayServerTypeX11 case "wayland": return DisplayServerTypeWayland } } return DisplayServerTypeUnknown } ================================================ FILE: termeverything/KeycodeSingleCodes.go ================================================ package termeverything import "fmt" func KeycodeSingleCodes(d int) *KeyCode { if d >= 1 && d <= 26 { /** * @TODO not sure what to do about the * ctrl+keys that are shadowed * by these keys */ switch d { case 3, 9, 13: // skip (handled below) default: return &KeyCode{ KeyCode: alphaKeys[d-1], Modifiers: ModControl, } } } if d >= 48 && d <= 57 { return &KeyCode{ KeyCode: numericKeys[d-48], Modifiers: 0, } } if d >= 65 && d <= 90 { return &KeyCode{ KeyCode: alphaKeys[d-65], Modifiers: ModShift, } } if d >= 97 && d <= 122 { return &KeyCode{ KeyCode: alphaKeys[d-97], Modifiers: 0, } } switch d { case 33: // ! return &KeyCode{KeyCode: KEY_1, Modifiers: ModShift} case 64: // @ return &KeyCode{KeyCode: KEY_2, Modifiers: ModShift} case 35: // # return &KeyCode{KeyCode: KEY_3, Modifiers: ModShift} case 36: // $ return &KeyCode{KeyCode: KEY_4, Modifiers: ModShift} case 37: // % return &KeyCode{KeyCode: KEY_5, Modifiers: ModShift} case 34: // " return &KeyCode{KeyCode: KEY_APOSTROPHE, Modifiers: ModShift} case 39: // ' return &KeyCode{KeyCode: KEY_APOSTROPHE, Modifiers: 0} case 94: // ^ return &KeyCode{KeyCode: KEY_6, Modifiers: ModShift} case 38: // & return &KeyCode{KeyCode: KEY_7, Modifiers: ModShift} case 42: // * return &KeyCode{KeyCode: KEY_8, Modifiers: ModShift} case 40: // ( return &KeyCode{KeyCode: KEY_9, Modifiers: ModShift} case 41: // ) return &KeyCode{KeyCode: KEY_0, Modifiers: ModShift} case 3: // escape (as per original TS) return &KeyCode{KeyCode: KEY_ESC, Modifiers: 0} case 27: // escape (shift) return &KeyCode{KeyCode: KEY_ESC, Modifiers: ModShift} case 96: // ` return &KeyCode{KeyCode: KEY_GRAVE, Modifiers: 0} case 126: // ~ return &KeyCode{KeyCode: KEY_GRAVE, Modifiers: ModShift} case 45: // - return &KeyCode{KeyCode: KEY_MINUS, Modifiers: 0} case 95: // _ return &KeyCode{KeyCode: KEY_MINUS, Modifiers: ModShift} case 61: // = return &KeyCode{KeyCode: KEY_EQUAL, Modifiers: 0} case 43: // + return &KeyCode{KeyCode: KEY_EQUAL, Modifiers: ModShift} case 8: // CTRL+backspace (overshadowed by CTRL+H) return &KeyCode{KeyCode: KEY_BACKSPACE, Modifiers: ModControl} case 127: // backspace return &KeyCode{KeyCode: KEY_BACKSPACE, Modifiers: 0} case 9: // tab return &KeyCode{KeyCode: KEY_TAB, Modifiers: 0} case 13: // enter return &KeyCode{KeyCode: KEY_ENTER, Modifiers: 0} case 32: // space return &KeyCode{KeyCode: KEY_SPACE, Modifiers: 0} case 0: // ctrl + space return &KeyCode{KeyCode: KEY_SPACE, Modifiers: ModControl} case 59: // ; return &KeyCode{KeyCode: KEY_SEMICOLON, Modifiers: 0} case 58: // : return &KeyCode{KeyCode: KEY_SEMICOLON, Modifiers: ModShift} case 91: // [ return &KeyCode{KeyCode: KEY_LEFTBRACE, Modifiers: 0} case 123: // { return &KeyCode{KeyCode: KEY_LEFTBRACE, Modifiers: ModShift} case 93: // ] return &KeyCode{KeyCode: KEY_RIGHTBRACE, Modifiers: 0} case 125: // } return &KeyCode{KeyCode: KEY_RIGHTBRACE, Modifiers: ModShift} case 129: // ctrl+] return &KeyCode{KeyCode: KEY_RIGHTBRACE, Modifiers: ModControl} case 92: // \ return &KeyCode{KeyCode: KEY_BACKSLASH, Modifiers: 0} case 124: // | return &KeyCode{KeyCode: KEY_BACKSLASH, Modifiers: ModShift} case 44: // , return &KeyCode{KeyCode: KEY_COMMA, Modifiers: 0} case 60: // < return &KeyCode{KeyCode: KEY_COMMA, Modifiers: ModShift} case 46: // . return &KeyCode{KeyCode: KEY_DOT, Modifiers: 0} case 62: // > return &KeyCode{KeyCode: KEY_DOT, Modifiers: ModShift} case 47: // / return &KeyCode{KeyCode: KEY_SLASH, Modifiers: 0} case 63: // ? return &KeyCode{KeyCode: KEY_SLASH, Modifiers: ModShift} case 31: // ctrl+/ return &KeyCode{KeyCode: KEY_SLASH, Modifiers: ModControl} } fmt.Printf("Unrecognized key code: %d\n", d) return nil } ================================================ FILE: termeverything/LinuxEventCodes.go ================================================ package termeverything /** * @see [input-event-codes.h](https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h) */ type Linux_Event_Codes int const ( KEY_RESERVED Linux_Event_Codes = 0 KEY_ESC Linux_Event_Codes = 1 KEY_1 Linux_Event_Codes = 2 KEY_2 Linux_Event_Codes = 3 KEY_3 Linux_Event_Codes = 4 KEY_4 Linux_Event_Codes = 5 KEY_5 Linux_Event_Codes = 6 KEY_6 Linux_Event_Codes = 7 KEY_7 Linux_Event_Codes = 8 KEY_8 Linux_Event_Codes = 9 KEY_9 Linux_Event_Codes = 10 KEY_0 Linux_Event_Codes = 11 KEY_MINUS Linux_Event_Codes = 12 KEY_EQUAL Linux_Event_Codes = 13 KEY_BACKSPACE Linux_Event_Codes = 14 KEY_TAB Linux_Event_Codes = 15 KEY_Q Linux_Event_Codes = 16 KEY_W Linux_Event_Codes = 17 KEY_E Linux_Event_Codes = 18 KEY_R Linux_Event_Codes = 19 KEY_T Linux_Event_Codes = 20 KEY_Y Linux_Event_Codes = 21 KEY_U Linux_Event_Codes = 22 KEY_I Linux_Event_Codes = 23 KEY_O Linux_Event_Codes = 24 KEY_P Linux_Event_Codes = 25 KEY_LEFTBRACE Linux_Event_Codes = 26 KEY_RIGHTBRACE Linux_Event_Codes = 27 KEY_ENTER Linux_Event_Codes = 28 KEY_LEFTCTRL Linux_Event_Codes = 29 KEY_A Linux_Event_Codes = 30 KEY_S Linux_Event_Codes = 31 KEY_D Linux_Event_Codes = 32 KEY_F Linux_Event_Codes = 33 KEY_G Linux_Event_Codes = 34 KEY_H Linux_Event_Codes = 35 KEY_J Linux_Event_Codes = 36 KEY_K Linux_Event_Codes = 37 KEY_L Linux_Event_Codes = 38 KEY_SEMICOLON Linux_Event_Codes = 39 KEY_APOSTROPHE Linux_Event_Codes = 40 KEY_GRAVE Linux_Event_Codes = 41 KEY_LEFTSHIFT Linux_Event_Codes = 42 KEY_BACKSLASH Linux_Event_Codes = 43 KEY_Z Linux_Event_Codes = 44 KEY_X Linux_Event_Codes = 45 KEY_C Linux_Event_Codes = 46 KEY_V Linux_Event_Codes = 47 KEY_B Linux_Event_Codes = 48 KEY_N Linux_Event_Codes = 49 KEY_M Linux_Event_Codes = 50 KEY_COMMA Linux_Event_Codes = 51 KEY_DOT Linux_Event_Codes = 52 KEY_SLASH Linux_Event_Codes = 53 KEY_RIGHTSHIFT Linux_Event_Codes = 54 KEY_KPASTERISK Linux_Event_Codes = 55 KEY_LEFTALT Linux_Event_Codes = 56 KEY_SPACE Linux_Event_Codes = 57 KEY_CAPSLOCK Linux_Event_Codes = 58 KEY_F1 Linux_Event_Codes = 59 KEY_F2 Linux_Event_Codes = 60 KEY_F3 Linux_Event_Codes = 61 KEY_F4 Linux_Event_Codes = 62 KEY_F5 Linux_Event_Codes = 63 KEY_F6 Linux_Event_Codes = 64 KEY_F7 Linux_Event_Codes = 65 KEY_F8 Linux_Event_Codes = 66 KEY_F9 Linux_Event_Codes = 67 KEY_F10 Linux_Event_Codes = 68 KEY_NUMLOCK Linux_Event_Codes = 69 KEY_SCROLLLOCK Linux_Event_Codes = 70 KEY_KP7 Linux_Event_Codes = 71 KEY_KP8 Linux_Event_Codes = 72 KEY_KP9 Linux_Event_Codes = 73 KEY_KPMINUS Linux_Event_Codes = 74 KEY_KP4 Linux_Event_Codes = 75 KEY_KP5 Linux_Event_Codes = 76 KEY_KP6 Linux_Event_Codes = 77 KEY_KPPLUS Linux_Event_Codes = 78 KEY_KP1 Linux_Event_Codes = 79 KEY_KP2 Linux_Event_Codes = 80 KEY_KP3 Linux_Event_Codes = 81 KEY_KP0 Linux_Event_Codes = 82 KEY_KPDOT Linux_Event_Codes = 83 KEY_ZENKAKUHANKAKU Linux_Event_Codes = 85 KEY_102ND Linux_Event_Codes = 86 KEY_F11 Linux_Event_Codes = 87 KEY_F12 Linux_Event_Codes = 88 KEY_RO Linux_Event_Codes = 89 KEY_KATAKANA Linux_Event_Codes = 90 KEY_HIRAGANA Linux_Event_Codes = 91 KEY_HENKAN Linux_Event_Codes = 92 KEY_KATAKANAHIRAGANA Linux_Event_Codes = 93 KEY_MUHENKAN Linux_Event_Codes = 94 KEY_KPJPCOMMA Linux_Event_Codes = 95 KEY_KPENTER Linux_Event_Codes = 96 KEY_RIGHTCTRL Linux_Event_Codes = 97 KEY_KPSLASH Linux_Event_Codes = 98 KEY_SYSRQ Linux_Event_Codes = 99 KEY_RIGHTALT Linux_Event_Codes = 100 KEY_LINEFEED Linux_Event_Codes = 101 KEY_HOME Linux_Event_Codes = 102 KEY_UP Linux_Event_Codes = 103 KEY_PAGEUP Linux_Event_Codes = 104 KEY_LEFT Linux_Event_Codes = 105 KEY_RIGHT Linux_Event_Codes = 106 KEY_END Linux_Event_Codes = 107 KEY_DOWN Linux_Event_Codes = 108 KEY_PAGEDOWN Linux_Event_Codes = 109 KEY_INSERT Linux_Event_Codes = 110 KEY_DELETE Linux_Event_Codes = 111 KEY_MACRO Linux_Event_Codes = 112 KEY_MUTE Linux_Event_Codes = 113 KEY_VOLUMEDOWN Linux_Event_Codes = 114 KEY_VOLUMEUP Linux_Event_Codes = 115 KEY_POWER Linux_Event_Codes = 116 /* SC System Power Down */ KEY_KPEQUAL Linux_Event_Codes = 117 KEY_KPPLUSMINUS Linux_Event_Codes = 118 KEY_PAUSE Linux_Event_Codes = 119 KEY_SCALE Linux_Event_Codes = 120 /* AL Compiz Scale (Expose) */ KEY_KPCOMMA Linux_Event_Codes = 121 KEY_HANGEUL Linux_Event_Codes = 122 // KEY_HANGUEL same as KEY_HANGEUL KEY_HANJA Linux_Event_Codes = 123 KEY_YEN Linux_Event_Codes = 124 KEY_LEFTMETA Linux_Event_Codes = 125 KEY_RIGHTMETA Linux_Event_Codes = 126 KEY_COMPOSE Linux_Event_Codes = 127 KEY_STOP Linux_Event_Codes = 128 /* AC Stop */ KEY_AGAIN Linux_Event_Codes = 129 KEY_PROPS Linux_Event_Codes = 130 /* AC Properties */ KEY_UNDO Linux_Event_Codes = 131 /* AC Undo */ KEY_FRONT Linux_Event_Codes = 132 KEY_COPY Linux_Event_Codes = 133 /* AC Copy */ KEY_OPEN Linux_Event_Codes = 134 /* AC Open */ KEY_PASTE Linux_Event_Codes = 135 /* AC Paste */ KEY_FIND Linux_Event_Codes = 136 /* AC Search */ KEY_CUT Linux_Event_Codes = 137 /* AC Cut */ KEY_HELP Linux_Event_Codes = 138 /* AL Integrated Help Center */ KEY_MENU Linux_Event_Codes = 139 /* Menu (show menu) */ KEY_CALC Linux_Event_Codes = 140 /* AL Calculator */ KEY_SETUP Linux_Event_Codes = 141 KEY_SLEEP Linux_Event_Codes = 142 /* SC System Sleep */ KEY_WAKEUP Linux_Event_Codes = 143 /* System Wake Up */ KEY_FILE Linux_Event_Codes = 144 /* AL Local Machine Browser */ KEY_SENDFILE Linux_Event_Codes = 145 KEY_DELETEFILE Linux_Event_Codes = 146 KEY_XFER Linux_Event_Codes = 147 KEY_PROG1 Linux_Event_Codes = 148 KEY_PROG2 Linux_Event_Codes = 149 KEY_WWW Linux_Event_Codes = 150 /* AL Internet Browser */ KEY_MSDOS Linux_Event_Codes = 151 KEY_COFFEE Linux_Event_Codes = 152 /* AL Terminal Lock/Screensaver */ // KEY_SCREENLOCK same as KEY_COFFEE KEY_ROTATE_DISPLAY Linux_Event_Codes = 153 /* Display orientation */ // KEY_DIRECTION same as KEY_ROTATE_DISPLAY KEY_CYCLEWINDOWS Linux_Event_Codes = 154 KEY_MAIL Linux_Event_Codes = 155 KEY_BOOKMARKS Linux_Event_Codes = 156 /* AC Bookmarks */ KEY_COMPUTER Linux_Event_Codes = 157 KEY_BACK Linux_Event_Codes = 158 /* AC Back */ KEY_FORWARD Linux_Event_Codes = 159 /* AC Forward */ KEY_CLOSECD Linux_Event_Codes = 160 KEY_EJECTCD Linux_Event_Codes = 161 KEY_EJECTCLOSECD Linux_Event_Codes = 162 KEY_NEXTSONG Linux_Event_Codes = 163 KEY_PLAYPAUSE Linux_Event_Codes = 164 KEY_PREVIOUSSONG Linux_Event_Codes = 165 KEY_STOPCD Linux_Event_Codes = 166 KEY_RECORD Linux_Event_Codes = 167 KEY_REWIND Linux_Event_Codes = 168 KEY_PHONE Linux_Event_Codes = 169 /* Media Select Telephone */ KEY_ISO Linux_Event_Codes = 170 KEY_CONFIG Linux_Event_Codes = 171 /* AL Consumer Control Configuration */ KEY_HOMEPAGE Linux_Event_Codes = 172 /* AC Home */ KEY_REFRESH Linux_Event_Codes = 173 /* AC Refresh */ KEY_EXIT Linux_Event_Codes = 174 /* AC Exit */ KEY_MOVE Linux_Event_Codes = 175 KEY_EDIT Linux_Event_Codes = 176 KEY_SCROLLUP Linux_Event_Codes = 177 KEY_SCROLLDOWN Linux_Event_Codes = 178 KEY_KPLEFTPAREN Linux_Event_Codes = 179 KEY_KPRIGHTPAREN Linux_Event_Codes = 180 KEY_NEW Linux_Event_Codes = 181 /* AC New */ KEY_REDO Linux_Event_Codes = 182 /* AC Redo/Repeat */ KEY_F13 Linux_Event_Codes = 183 KEY_F14 Linux_Event_Codes = 184 KEY_F15 Linux_Event_Codes = 185 KEY_F16 Linux_Event_Codes = 186 KEY_F17 Linux_Event_Codes = 187 KEY_F18 Linux_Event_Codes = 188 KEY_F19 Linux_Event_Codes = 189 KEY_F20 Linux_Event_Codes = 190 KEY_F21 Linux_Event_Codes = 191 KEY_F22 Linux_Event_Codes = 192 KEY_F23 Linux_Event_Codes = 193 KEY_F24 Linux_Event_Codes = 194 KEY_PLAYCD Linux_Event_Codes = 200 KEY_PAUSECD Linux_Event_Codes = 201 KEY_PROG3 Linux_Event_Codes = 202 KEY_PROG4 Linux_Event_Codes = 203 KEY_ALL_APPLICATIONS Linux_Event_Codes = 204 /* AC Desktop Show All Applications */ // KEY_DASHBOARD same as KEY_ALL_APPLICATIONS KEY_SUSPEND Linux_Event_Codes = 205 KEY_CLOSE Linux_Event_Codes = 206 /* AC Close */ KEY_PLAY Linux_Event_Codes = 207 KEY_FASTFORWARD Linux_Event_Codes = 208 KEY_BASSBOOST Linux_Event_Codes = 209 KEY_PRINT Linux_Event_Codes = 210 /* AC Print */ KEY_HP Linux_Event_Codes = 211 KEY_CAMERA Linux_Event_Codes = 212 KEY_SOUND Linux_Event_Codes = 213 KEY_QUESTION Linux_Event_Codes = 214 KEY_EMAIL Linux_Event_Codes = 215 KEY_CHAT Linux_Event_Codes = 216 KEY_SEARCH Linux_Event_Codes = 217 KEY_CONNECT Linux_Event_Codes = 218 KEY_FINANCE Linux_Event_Codes = 219 /* AL Checkbook/Finance */ KEY_SPORT Linux_Event_Codes = 220 KEY_SHOP Linux_Event_Codes = 221 KEY_ALTERASE Linux_Event_Codes = 222 KEY_CANCEL Linux_Event_Codes = 223 /* AC Cancel */ KEY_BRIGHTNESSDOWN Linux_Event_Codes = 224 KEY_BRIGHTNESSUP Linux_Event_Codes = 225 KEY_MEDIA Linux_Event_Codes = 226 KEY_SWITCHVIDEOMODE Linux_Event_Codes = 227 /* Cycle video outputs */ KEY_KBDILLUMTOGGLE Linux_Event_Codes = 228 KEY_KBDILLUMDOWN Linux_Event_Codes = 229 KEY_KBDILLUMUP Linux_Event_Codes = 230 KEY_SEND Linux_Event_Codes = 231 /* AC Send */ KEY_REPLY Linux_Event_Codes = 232 /* AC Reply */ KEY_FORWARDMAIL Linux_Event_Codes = 233 /* AC Forward Msg */ KEY_SAVE Linux_Event_Codes = 234 /* AC Save */ KEY_DOCUMENTS Linux_Event_Codes = 235 KEY_BATTERY Linux_Event_Codes = 236 KEY_BLUETOOTH Linux_Event_Codes = 237 KEY_WLAN Linux_Event_Codes = 238 KEY_UWB Linux_Event_Codes = 239 KEY_UNKNOWN Linux_Event_Codes = 240 KEY_VIDEO_NEXT Linux_Event_Codes = 241 KEY_VIDEO_PREV Linux_Event_Codes = 242 KEY_BRIGHTNESS_CYCLE Linux_Event_Codes = 243 KEY_BRIGHTNESS_AUTO Linux_Event_Codes = 244 // KEY_BRIGHTNESS_ZERO same as KEY_BRIGHTNESS_AUTO KEY_DISPLAY_OFF Linux_Event_Codes = 245 KEY_WWAN Linux_Event_Codes = 246 // KEY_WIMAX same as KEY_WWAN KEY_RFKILL Linux_Event_Codes = 247 KEY_MICMUTE Linux_Event_Codes = 248 ) // LINUX_BUTTON_CODES corresponds to Linux button codes. // @see input-event-codes.h type LINUX_BUTTON_CODES int const ( BTN_MISC LINUX_BUTTON_CODES = 0x100 BTN_0 LINUX_BUTTON_CODES = 0x100 BTN_1 LINUX_BUTTON_CODES = 0x101 BTN_2 LINUX_BUTTON_CODES = 0x102 BTN_3 LINUX_BUTTON_CODES = 0x103 BTN_4 LINUX_BUTTON_CODES = 0x104 BTN_5 LINUX_BUTTON_CODES = 0x105 BTN_6 LINUX_BUTTON_CODES = 0x106 BTN_7 LINUX_BUTTON_CODES = 0x107 BTN_8 LINUX_BUTTON_CODES = 0x108 BTN_9 LINUX_BUTTON_CODES = 0x109 BTN_MOUSE LINUX_BUTTON_CODES = 0x110 BTN_LEFT LINUX_BUTTON_CODES = 0x110 BTN_RIGHT LINUX_BUTTON_CODES = 0x111 BTN_MIDDLE LINUX_BUTTON_CODES = 0x112 BTN_SIDE LINUX_BUTTON_CODES = 0x113 BTN_EXTRA LINUX_BUTTON_CODES = 0x114 BTN_FORWARD LINUX_BUTTON_CODES = 0x115 BTN_BACK LINUX_BUTTON_CODES = 0x116 BTN_TASK LINUX_BUTTON_CODES = 0x117 BTN_JOYSTICK LINUX_BUTTON_CODES = 0x120 BTN_TRIGGER LINUX_BUTTON_CODES = 0x120 BTN_THUMB LINUX_BUTTON_CODES = 0x121 BTN_THUMB2 LINUX_BUTTON_CODES = 0x122 BTN_TOP LINUX_BUTTON_CODES = 0x123 BTN_TOP2 LINUX_BUTTON_CODES = 0x124 BTN_PINKIE LINUX_BUTTON_CODES = 0x125 BTN_BASE LINUX_BUTTON_CODES = 0x126 BTN_BASE2 LINUX_BUTTON_CODES = 0x127 BTN_BASE3 LINUX_BUTTON_CODES = 0x128 BTN_BASE4 LINUX_BUTTON_CODES = 0x129 BTN_BASE5 LINUX_BUTTON_CODES = 0x12a BTN_BASE6 LINUX_BUTTON_CODES = 0x12b BTN_DEAD LINUX_BUTTON_CODES = 0x12f BTN_GAMEPAD LINUX_BUTTON_CODES = 0x130 BTN_SOUTH LINUX_BUTTON_CODES = 0x130 BTN_A LINUX_BUTTON_CODES = BTN_SOUTH BTN_EAST LINUX_BUTTON_CODES = 0x131 BTN_B LINUX_BUTTON_CODES = BTN_EAST BTN_C LINUX_BUTTON_CODES = 0x132 BTN_NORTH LINUX_BUTTON_CODES = 0x133 BTN_X LINUX_BUTTON_CODES = BTN_NORTH BTN_WEST LINUX_BUTTON_CODES = 0x134 BTN_Y LINUX_BUTTON_CODES = BTN_WEST BTN_Z LINUX_BUTTON_CODES = 0x135 BTN_TL LINUX_BUTTON_CODES = 0x136 BTN_TR LINUX_BUTTON_CODES = 0x137 BTN_TL2 LINUX_BUTTON_CODES = 0x138 BTN_TR2 LINUX_BUTTON_CODES = 0x139 BTN_SELECT LINUX_BUTTON_CODES = 0x13a BTN_START LINUX_BUTTON_CODES = 0x13b BTN_MODE LINUX_BUTTON_CODES = 0x13c BTN_THUMBL LINUX_BUTTON_CODES = 0x13d BTN_THUMBR LINUX_BUTTON_CODES = 0x13e BTN_DIGI LINUX_BUTTON_CODES = 0x140 BTN_TOOL_PEN LINUX_BUTTON_CODES = 0x140 BTN_TOOL_RUBBER LINUX_BUTTON_CODES = 0x141 BTN_TOOL_BRUSH LINUX_BUTTON_CODES = 0x142 BTN_TOOL_PENCIL LINUX_BUTTON_CODES = 0x143 BTN_TOOL_AIRBRUSH LINUX_BUTTON_CODES = 0x144 BTN_TOOL_FINGER LINUX_BUTTON_CODES = 0x145 BTN_TOOL_MOUSE LINUX_BUTTON_CODES = 0x146 BTN_TOOL_LENS LINUX_BUTTON_CODES = 0x147 BTN_TOOL_QUINTTAP LINUX_BUTTON_CODES = 0x148 /* Five fingers on trackpad */ BTN_STYLUS3 LINUX_BUTTON_CODES = 0x149 BTN_TOUCH LINUX_BUTTON_CODES = 0x14a BTN_STYLUS LINUX_BUTTON_CODES = 0x14b BTN_STYLUS2 LINUX_BUTTON_CODES = 0x14c BTN_TOOL_DOUBLETAP LINUX_BUTTON_CODES = 0x14d BTN_TOOL_TRIPLETAP LINUX_BUTTON_CODES = 0x14e BTN_TOOL_QUADTAP LINUX_BUTTON_CODES = 0x14f /* Four fingers on trackpad */ BTN_WHEEL LINUX_BUTTON_CODES = 0x150 BTN_GEAR_DOWN LINUX_BUTTON_CODES = 0x150 BTN_GEAR_UP LINUX_BUTTON_CODES = 0x151 ) ================================================ FILE: termeverything/MainLoop.go ================================================ package termeverything import ( "fmt" "os" "os/exec" "strings" "github.com/mmulet/term.everything/wayland" ) func MainLoop() { args := ParseArgs() SetVirtualMonitorSize(args.VirtualMonitorSize) listener, err := wayland.MakeSocketListener(&args) if err != nil { fmt.Fprintf(os.Stderr, "Failed to create socket listener: %v\n", err) os.Exit(1) } displaySize := wayland.Size{ Width: uint32(wayland.VirtualMonitorSize.Width), Height: uint32(wayland.VirtualMonitorSize.Height), } terminalWindow := MakeTerminalWindow(listener, displaySize, &args, ) terminanDrawLoop := MakeTerminalDrawLoop( displaySize, args.HideStatusBar, len(args.Positionals) > 0, terminalWindow.SharedRenderedScreenSize, terminalWindow.FrameEvents, &args, ) go listener.MainLoopThenClose() go terminalWindow.InputLoop() go terminanDrawLoop.MainLoop() done := make(chan struct{}) go func() { for { conn := <-listener.OnConnection client := wayland.MakeClient(conn) terminalWindow.GetClients <- client terminanDrawLoop.GetClients <- client go client.MainLoop() } }() if len(args.Positionals) > 0 { cmdStr := strings.Join(args.Positionals, " ") shell := args.Shell cmd := exec.Command(shell, "-c", cmdStr) baseEnv := os.Environ() filtered := make([]string, 0, len(baseEnv)) for _, e := range baseEnv { if strings.HasPrefix(e, "DISPLAY=") { continue } if !args.SupportOldApps && strings.HasPrefix(e, "XDG_SESSION_TYPE=") { continue } filtered = append(filtered, e) } filtered = append(filtered, fmt.Sprintf("WAYLAND_DISPLAY=%s", listener.WaylandDisplayName)) if !args.SupportOldApps { filtered = append(filtered, "XDG_SESSION_TYPE=wayland") } cmd.Env = filtered // cmd.Stdout = os.Stdout // cmd.Stderr = os.Stderr // cmd.Stdin = os.Stdin if err := cmd.Start(); err != nil { fmt.Fprintf(os.Stderr, "Failed to start command: %v\n", err) } else { go func() { _ = cmd.Wait() }() } } <-done //TODO start xwaylnd_if_neccessary // // Wait for SigInt, TODO something different // sig := make(chan os.Signal, 1) // signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM) // <-sig // _ = listener.Close() // fmt.Println("Shutdown complete") } ================================================ FILE: termeverything/ParseArgs.go ================================================ package termeverything import ( "flag" "fmt" "os" _ "embed" ) //go:embed resources/help.md var helpFile string //go:embed resources/LICENSES.txt var licensesFile string const version = "0.7.6" type CommandLineArgs struct { WaylandDisplayNameArg string SupportOldApps bool Xwayland string XwaylandWM string Shell string HideStatusBar bool VirtualMonitorSize string DebugLog bool ReverseScroll bool MaxFrameRate string Positionals []string } func (args *CommandLineArgs) WaylandDisplayName() string { return args.WaylandDisplayNameArg } func ParseArgs() CommandLineArgs { var args CommandLineArgs flag.StringVar(&args.WaylandDisplayNameArg, "wayland-display-name", "", "") flag.BoolVar(&args.SupportOldApps, "support-old-apps", false, "") flag.StringVar(&args.Xwayland, "xwayland", "", "") flag.StringVar(&args.XwaylandWM, "xwayland-wm", "", "") flag.StringVar(&args.Shell, "shell", "/bin/bash", "") flag.BoolVar(&args.HideStatusBar, "hide-status-bar", false, "") flag.StringVar(&args.VirtualMonitorSize, "virtual-monitor-size", "", "") versionFlag := flag.Bool("version", false, "") flag.BoolVar(&args.DebugLog, "debug-log", false, "") helpFlag := flag.Bool("help", false, "") hFlag := flag.Bool("h", false, "help") // short option for help licensesFlag := flag.Bool("licenses", false, "") flag.BoolVar(&args.ReverseScroll, "reverse-scroll", false, "") flag.StringVar(&args.MaxFrameRate, "max-frame-rate", "", "") flag.Parse() if *versionFlag { fmt.Println(version) os.Exit(0) } if *helpFlag || *hFlag { fmt.Println(RenderMarkdownToTerminal(helpFile)) os.Exit(0) } if *licensesFlag { fmt.Println(licensesFile) os.Exit(0) } args.Positionals = flag.Args() return args } ================================================ FILE: termeverything/PointerCode.go ================================================ package termeverything import ( "strconv" "strings" ) type PointerEvent interface { isPointerEvent() isXkbdCode() OrModifiers(int) GetModifiers() int } type PointerMove struct { Row int Col int Modifiers int } func (*PointerMove) isPointerEvent() {} func (*PointerMove) isXkbdCode() {} func (p *PointerMove) OrModifiers(modifiers int) { p.Modifiers |= modifiers } func (p *PointerMove) GetModifiers() int { return p.Modifiers } type PointerButtonPress struct { Modifiers int NeedToReleaseOtherButtons bool Button LINUX_BUTTON_CODES } func (*PointerButtonPress) isPointerEvent() {} func (*PointerButtonPress) isXkbdCode() {} func (p *PointerButtonPress) OrModifiers(modifiers int) { p.Modifiers |= modifiers } func (p *PointerButtonPress) GetModifiers() int { return p.Modifiers } /** * Pointer button release is special * because we can't be sure of which * button is being released */ type PointerButtonRelease struct { Button LINUX_BUTTON_CODES NeedsButtonGuessing bool Modifiers int } func (*PointerButtonRelease) isPointerEvent() {} func (*PointerButtonRelease) isXkbdCode() {} func (p *PointerButtonRelease) OrModifiers(modifiers int) { p.Modifiers |= modifiers } func (p *PointerButtonRelease) GetModifiers() int { return p.Modifiers } type PointerWheel struct { Up bool Modifiers int } func (*PointerWheel) isPointerEvent() {} func (*PointerWheel) isXkbdCode() {} func (p *PointerWheel) OrModifiers(modifiers int) { p.Modifiers |= modifiers } func (p *PointerWheel) GetModifiers() int { return p.Modifiers } func MouseModifiers(code, base int) int { modeType := code - base modifiers := 0 if (modeType & 0b1000) != 0 { modifiers |= ModControl } if (modeType & 0b1_0000) != 0 { modifiers |= ModAlt } return modifiers } func ParseMouseCode(code string) XkbdCode { parts := strings.Split(code, ";") if len(parts) != 3 { return nil } buttonPart := parts[0] colPart := parts[1] rowAndTermPart := parts[2] pressRelease := rowAndTermPart[len(rowAndTermPart)-1] rowPart := rowAndTermPart[:len(rowAndTermPart)-1] button, err := strconv.Atoi(buttonPart) if err != nil { return nil } col, err := strconv.Atoi(colPart) if err != nil { return nil } col = col - 1 row, err := strconv.Atoi(rowPart) if err != nil { return nil } row = row - 1 press := false switch pressRelease { case 'M': press = true case 'm': press = false default: return nil } d := button + 32 /** * Mouse time! */ switch d { case 67, 75, 83, 91: modifiers := MouseModifiers(d, 67) return &PointerMove{ Row: row, Col: col, Modifiers: modifiers, } case 64, 72, 80, 88: /** * This is pointer moving while * holding left mouse button down * * so far it has always followed * a button down event, * so I'm just sending a pointer move * rather than a button followed by a move */ modifiers := MouseModifiers(d, 64) return &PointerMove{ Row: row, Col: col, Modifiers: modifiers, } case 65, 73, 81, 89: /** * Move while holding middle mouse button down */ modifiers := MouseModifiers(d, 65) return &PointerMove{ Row: row, Col: col, Modifiers: modifiers, } case 66, 74, 82, 90: /** * Move while holding right mouse button down */ modifiers := MouseModifiers(d, 66) return &PointerMove{ Row: row, Col: col, Modifiers: modifiers, } // Mouse button left down case 32, 40, 48, 56: if press { return &PointerButtonPress{ Button: BTN_LEFT, NeedToReleaseOtherButtons: false, Modifiers: MouseModifiers(d, 32), } } return &PointerButtonRelease{ Button: BTN_LEFT, Modifiers: MouseModifiers(d, 32), } // Mouse button middle down case 33, 41, 49, 57: if press { return &PointerButtonPress{ Button: BTN_MIDDLE, NeedToReleaseOtherButtons: false, Modifiers: MouseModifiers(d, 33), } } return &PointerButtonRelease{ Button: BTN_MIDDLE, Modifiers: MouseModifiers(d, 33), } // Mouse button right down case 34, 42, 50, 58: if press { return &PointerButtonPress{ Button: BTN_RIGHT, NeedToReleaseOtherButtons: false, Modifiers: MouseModifiers(d, 34), } } return &PointerButtonRelease{ Button: BTN_RIGHT, Modifiers: MouseModifiers(d, 34), } // Mouse wheel up case 96, 104, 112, 120: return &PointerWheel{ Up: true, Modifiers: MouseModifiers(d, 96), } // Mouse wheel down case 97, 105, 113, 121: return &PointerWheel{ Up: false, Modifiers: MouseModifiers(d, 97), } } return nil } func ParseSGRMouseSequences(data []byte) []XkbdCode { codes := strings.Split(string(data), "\x1b[<") if len(codes) < 2 { return nil } codes = codes[1:] // First split is empty string before first ESC[< out := make([]XkbdCode, 0) for _, code := range codes { buttonCode := ParseMouseCode(code) if buttonCode == nil { continue } out = append(out, buttonCode) } return out } func PointerCode(data []byte) PointerEvent { if !(len(data) >= 3 && data[0] == 27 && data[1] == 91 && data[2] == 77) { return nil } d := int(data[3]) /** * Mouse time! */ switch d { case 67, 75, 83, 91: // @TODO why 33 if len(data) < 6 { return nil } col := int(data[4]) - 33 row := int(data[5]) - 33 modifiers := MouseModifiers(d, 67) return &PointerMove{ Row: row, Col: col, Modifiers: modifiers, } case 64, 72, 80, 88: // @again why 33 if len(data) < 6 { return nil } col := int(data[4]) - 33 row := int(data[5]) - 33 /** * This is pointer moving while * holding a button down * * so far it has always followed * a button down event, * so I'm just sending a pointer move * rather than a button followed by a move */ modifiers := MouseModifiers(d, 64) return &PointerMove{ Row: row, Col: col, Modifiers: modifiers, } // Mouse button left down case 32, 40, 48, 56: return &PointerButtonPress{ Button: BTN_LEFT, NeedToReleaseOtherButtons: true, Modifiers: MouseModifiers(d, 32), } // Mouse button middle down case 33, 41, 49, 57: return &PointerButtonPress{ Button: BTN_MIDDLE, NeedToReleaseOtherButtons: true, Modifiers: MouseModifiers(d, 33), } // Mouse button right down case 34, 42, 50, 58: return &PointerButtonPress{ Button: BTN_RIGHT, NeedToReleaseOtherButtons: true, Modifiers: MouseModifiers(d, 34), } // Mouse button up (cannot be sure which button) case 35, 43, 51, 59: return &PointerButtonRelease{ NeedsButtonGuessing: true, Modifiers: MouseModifiers(d, 35), } // Mouse wheel up case 96, 104, 112, 120: return &PointerWheel{ Up: true, Modifiers: MouseModifiers(d, 96), } // Mouse wheel down case 97, 105, 113, 121: return &PointerWheel{ Up: false, Modifiers: MouseModifiers(d, 97), } } return nil } ================================================ FILE: termeverything/RawMode.go ================================================ package termeverything /* #cgo CFLAGS: -Wall #include #include static int get_termios(int fd, struct termios *t) { return tcgetattr(fd, t); } static int set_termios_now(int fd, const struct termios *t) { return tcsetattr(fd, TCSANOW, t); } // Put TTY into "raw-ish" mode for input, but keep output processing so stdout isn't garbled. static void make_raw(struct termios *t) { cfmakeraw(t); // disable canonical, echo, signals, etc. t->c_cc[VMIN] = 1; t->c_cc[VTIME] = 0; // Preserve output post-processing (NL -> CRNL), like the shell default. t->c_oflag |= OPOST; #ifdef ONLCR t->c_oflag |= ONLCR; #endif } */ import "C" import "fmt" func EnableRawModeFD(fd int) (func() error, error) { if C.isatty(C.int(fd)) == 0 { return func() error { return nil }, nil } var orig C.struct_termios if C.get_termios(C.int(fd), &orig) != 0 { return nil, fmt.Errorf("tcgetattr failed") } raw := orig C.make_raw(&raw) if C.set_termios_now(C.int(fd), &raw) != 0 { return nil, fmt.Errorf("tcsetattr (raw) failed") } restored := false restore := func() error { if restored { return nil } restored = true if C.set_termios_now(C.int(fd), &orig) != 0 { return fmt.Errorf("tcsetattr (restore) failed") } return nil } return restore, nil } ================================================ FILE: termeverything/Readme.md ================================================ In this package we do everything you need to interact with a Wayland compositor from a terminal application. This includes handling input events, rendering to surfaces, and managing windows. ================================================ FILE: termeverything/RenderMarkdownToTerminal.go ================================================ package termeverything import ( "strings" "github.com/mmulet/term.everything/escapecodes" ) func RenderMarkdownToTerminal(markdown string) string { var outLines []string for _, line := range strings.Split(markdown, "\n") { if strings.HasPrefix(line, "# ") { outLines = append(outLines, escapecodes.FgGreen+escapecodes.Underline+renderCode(line[2:])+escapecodes.Reset) continue } if strings.HasPrefix(line, "## ") { outLines = append(outLines, escapecodes.FgCyan+escapecodes.Underline+renderCode(line[3:])+escapecodes.Reset) continue } outLines = append(outLines, renderCode(line)) } return strings.Join(outLines, "\n") } func renderCode(line string) string { var outLine strings.Builder inCode := false for _, char := range line { if char != '`' { outLine.WriteRune(char) continue } if inCode { outLine.WriteString(escapecodes.Reset) inCode = false continue } inCode = true outLine.WriteString(escapecodes.FgYellow) } return outLine.String() } ================================================ FILE: termeverything/SetVirtualMonitorSize.go ================================================ package termeverything import ( "fmt" "os" "strconv" "strings" "github.com/mmulet/term.everything/wayland" ) func SetVirtualMonitorSize(newVirtualMonitorSize string) { if newVirtualMonitorSize == "" { return } parts := strings.Split(newVirtualMonitorSize, "x") if len(parts) != 2 { fmt.Fprintf(os.Stderr, "Invalid virtual monitor size %s, expected x\n", newVirtualMonitorSize) os.Exit(1) } width, err1 := strconv.Atoi(parts[0]) height, err2 := strconv.Atoi(parts[1]) if err1 != nil || err2 != nil { fmt.Fprintf(os.Stderr, "Invalid virtual monitor size %s, expected x\n", newVirtualMonitorSize) os.Exit(1) } if width <= 0 || height <= 0 { fmt.Fprintf(os.Stderr, "Invalid virtual monitor size %s, expected x\n", newVirtualMonitorSize) os.Exit(1) } wayland.VirtualMonitorSize.Width = wayland.Pixels(width) wayland.VirtualMonitorSize.Height = wayland.Pixels(height) } ================================================ FILE: termeverything/StatusLine.go ================================================ package termeverything import ( "fmt" "net/url" "os" "os/exec" "strings" "github.com/mmulet/term.everything/escapecodes" "github.com/mmulet/term.everything/framebuffertoansi" ) type LineButton struct { String string Callback func() Keycode *Linux_Event_Codes } type StatusLineTextOrButton interface { IsStatusLineTextOrButton() } type StatusLineText struct { String string } func (s *StatusLineText) IsStatusLineTextOrButton() {} type StatusLineButton struct { Button LineButton } func (s *StatusLineButton) IsStatusLineTextOrButton() {} type Status_Line struct { TextLoopTime float64 ShowStatusLine bool TerminalMousePosition struct { x int y int } TerminalMouseButton struct { pressed bool frame_held_time float64 } b map[string]*StatusLineButton Sponsor *StatusLineButton Bugs *StatusLineButton } func (s *Status_Line) UpdateMousePosition(code *PointerMove) { if code == nil { return } s.TerminalMousePosition.x = code.Col s.TerminalMousePosition.y = code.Row } func (s *Status_Line) HandleTerminalMousePress(pressed bool) { if pressed { if s.TerminalMouseButton.pressed { /** * Mouse state has not changed * do nothing */ return } s.TerminalMouseButton.pressed = true s.TerminalMouseButton.frame_held_time = 0 return } s.TerminalMouseButton.pressed = false s.TerminalMouseButton.frame_held_time = 0 } func (s *Status_Line) PostFrame(delta_time float64) { if s.TerminalMouseButton.pressed { s.TerminalMouseButton.frame_held_time += delta_time } } func MakeStatusLine() *Status_Line { sl := &Status_Line{ ShowStatusLine: true, } sl.TerminalMousePosition.x = -1 sl.TerminalMousePosition.y = -1 escape := KEY_ESC sl.b = map[string]*StatusLineButton{ "escape": &StatusLineButton{ Button: LineButton{ Keycode: &escape, String: "[ESC] to quit", Callback: func() { GlobalExitChan <- 0 }, }, }, "left": &StatusLineButton{ Button: LineButton{ String: "[]", Callback: func() { fmt.Println("left") }, }, }, } sl.Sponsor = &StatusLineButton{ Button: LineButton{ String: "[Sponsor this project]", Callback: func() { _ = exec.Command("xdg-open", "https://github.com/sponsors/mmulet").Start() }, }, } sl.Bugs = &StatusLineButton{ Button: LineButton{ String: "[Report bugs here]", Callback: func() { title := url.QueryEscape("Bug Report") body := url.QueryEscape(sl.buildBugBody()) _ = exec.Command("xdg-open", "https://github.com/mmulet/term.everything/issues/new?title="+title+"&body="+body).Start() }, }, } return sl } func (s *Status_Line) Draw(delta_time float64, app_title *string, keys_pressed_this_frame map[Linux_Event_Codes]bool) string { if !s.ShowStatusLine { return "" } text := s.Line(keys_pressed_this_frame, s.b["escape"], &StatusLineText{" "}, s.Sponsor, &StatusLineText{" | "}, s.ChooseAppTitle(app_title), &StatusLineText{" | "}, ) s.TextLoopTime += delta_time width := 0 if winsize, err := framebuffertoansi.GetWinsize(os.Stdout.Fd()); err == nil { width = int(winsize.Col) } if width > 1 && len(text) >= width { return text[:width-1] } return text } func (s *Status_Line) buildBugBody() string { return fmt.Sprintf(` Quick question before you fill this out: Is your app opening a new window instead of opening in the terminal? If so, do you have any other windows of the current app open? For example, firefox likes to open a new window (not in the terminal) if you already have at least one firefox window open. Close all other windows, and see if the problem still happens. ## Describe the bug A clear and concise description of what the bug is. ## To Reproduce Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error ## Expected behavior A clear and concise description of what you expected to happen. ## Screenshots If applicable, add screenshots to help explain your problem. ## Additional context Add any other context about the problem here. ## System Information Generated from your system, please include this information in your report: - Platform: %s - Architecture: %s - Terminal: %s - OS: %s - OS Details: %s - XDG_SESSION_TYPE: %s - Wayland Display: %s - X11 Display: %s - term.everything version: %s `, os.Getenv("GOOS"), os.Getenv("GOARCH"), getEnvOr("TERM", "N/A"), os.Getenv("GOOS"), s.GetOsDetails(), getEnvOr("XDG_SESSION_TYPE", "N/A"), getEnvOr("WAYLAND_DISPLAY", "N/A"), getEnvOr("DISPLAY", "N/A"), version, ) } func getEnvOr(k, def string) string { v := os.Getenv(k) if v == "" { return def } return v } func (s *Status_Line) ChooseAppTitle(appTitle *string) StatusLineTextOrButton { if appTitle == nil || *appTitle == "" { return s.Bugs } return &StatusLineText{*appTitle} } func (s *Status_Line) KeyboardKeyHitButton(button LineButton, keys_pressed_this_frame map[Linux_Event_Codes]bool) LineButton { if button.Keycode == nil { return button } if _, ok := keys_pressed_this_frame[*button.Keycode]; ok { button.Callback() // Replace callback with no-op button.Callback = func() {} return button } return button } func (s *Status_Line) Line(keys_pressed_this_frame map[Linux_Event_Codes]bool, parts ...StatusLineTextOrButton) string { position := 0 var out strings.Builder for _, v := range parts { switch it := v.(type) { case *StatusLineText: out.WriteString(it.String) position += len(it.String) case *StatusLineButton: btn := s.KeyboardKeyHitButton(it.Button, keys_pressed_this_frame) nextString := btn.String /** * for the rare case where * both click on button and * hold key at the same time */ already_called_callback := false if s.TerminalMousePosition.y == 0 && int(s.TerminalMousePosition.x) >= position && int(s.TerminalMousePosition.x) < position+len(nextString) { out.WriteString(escapecodes.BgWhite + escapecodes.FgBlack + nextString + escapecodes.Reset) if s.TerminalMouseButton.pressed && s.TerminalMouseButton.frame_held_time == 0 { if !already_called_callback { btn.Callback() } } } else { out.WriteString(nextString) } position += len(nextString) } } return out.String() } func (s *Status_Line) GetOsDetails() string { data, err := os.ReadFile("/etc/os-release") if err != nil { return "Unable to determine OS details" } lines := strings.Split(string(data), "\n") osInfo := make(map[string]string) for _, line := range lines { parts := strings.SplitN(line, "=", 2) if len(parts) != 2 { continue } key := parts[0] value := strings.Trim(parts[1], `"`) osInfo[key] = value } return fmt.Sprintf("%s (ID: %s, VERSION: %s)", firstOr(osInfo["PRETTY_NAME"], "Unknown"), firstOr(osInfo["ID"], "N/A"), firstOr(osInfo["VERSION"], "N/A"), ) } func firstOr(a, b string) string { if a == "" { return b } return a } ================================================ FILE: termeverything/TerminalDrawLoop.go ================================================ package termeverything import ( _ "embed" "os" "slices" "strconv" "time" "github.com/mmulet/term.everything/framebuffertoansi" "github.com/mmulet/term.everything/wayland" "github.com/mmulet/term.everything/wayland/protocols" ) //go:embed resources/icon.png var iconPNG []byte type FrameInputState struct { KeysPressedThisFrame map[Linux_Event_Codes]bool MouseMoveThisFrame bool } func MakeFrameInputState() FrameInputState { return FrameInputState{ KeysPressedThisFrame: make(map[Linux_Event_Codes]bool), MouseMoveThisFrame: false, } } type TerminalDrawLoop struct { VirtualMonitorSize wayland.Size Clients []*wayland.Client TimeOfLastTerminalDraw *float64 HideStatusBar bool /** * Don't draw until at least MinTerminalTimeSeconds has passed * since the last frame has been drawn to the terminal. (Not drawn * to the canvas, that is done as fast as possible) * * This is set from the --max-frame-rate argument. */ MinTerminalTimeSeconds *float64 DrawState *framebuffertoansi.DrawState Desktop *wayland.Desktop SharedRenderedScreenSize *RenderedScreenSize FrameEvents chan XkbdCode TimeOfStartOfLastFrame *float64 DesiredFrameTimeSeconds float64 StatusLine *Status_Line GetClients chan *wayland.Client FirstDrawDone bool LastDrawSize framebuffertoansi.WinSize FrameInputState FrameInputState } func MakeTerminalDrawLoop(desktop_size wayland.Size, hide_status_bar bool, willShowAppRightAtStartup bool, sharedRenderedScreenSize *RenderedScreenSize, frameEvents chan XkbdCode, args *CommandLineArgs, ) *TerminalDrawLoop { tw := &TerminalDrawLoop{ Clients: make([]*wayland.Client, 0), TimeOfLastTerminalDraw: nil, MinTerminalTimeSeconds: nil, SharedRenderedScreenSize: sharedRenderedScreenSize, HideStatusBar: hide_status_bar, DrawState: framebuffertoansi.MakeDrawState( DisplayServerType() == DisplayServerTypeX11, ), VirtualMonitorSize: desktop_size, Desktop: wayland.MakeDesktop(wayland.Size{ Width: desktop_size.Width, Height: desktop_size.Height, }, willShowAppRightAtStartup, iconPNG), TimeOfStartOfLastFrame: nil, DesiredFrameTimeSeconds: 0.016, // ~60 FPS StatusLine: MakeStatusLine(), FrameEvents: frameEvents, GetClients: make(chan *wayland.Client, 32), FrameInputState: MakeFrameInputState(), } if args != nil && args.MaxFrameRate != "" { if fps, err := strconv.ParseFloat(args.MaxFrameRate, 64); err == nil && fps > 0 { v := 1.0 / fps tw.MinTerminalTimeSeconds = &v } } return tw } func (tw *TerminalDrawLoop) GetAppTitle() *string { for _, s := range tw.Clients { for topLevelID := range s.TopLevelSurfaces() { top_level := wayland.GetXdgToplevelObject(s, topLevelID) if top_level == nil { continue } return top_level.Title } } return nil } func (tw *TerminalDrawLoop) DrawToTerminal(status_line string) { // if protocols.DebugRequests { // fmt.Println("Debugging!!!") // } else { // fmt.Println("Not debugging.") // } var statusLine *string if !tw.HideStatusBar { statusLine = &status_line } widthCells, heightCells := tw.DrawState.DrawDesktop( tw.Desktop.Buffer, tw.VirtualMonitorSize.Width, tw.VirtualMonitorSize.Height, statusLine, ) tw.SharedRenderedScreenSize.WidthCells = &widthCells tw.SharedRenderedScreenSize.HeightCells = &heightCells } func (tw *TerminalDrawLoop) MainLoop() { for { tw.DrawClients() timeout := time.After(time.Duration(tw.DesiredFrameTimeSeconds * float64(time.Second))) for { select { case code := <-tw.FrameEvents: switch c := code.(type) { case *KeyCode: tw.FrameInputState.KeysPressedThisFrame[c.KeyCode] = true case *PointerMove: tw.StatusLine.UpdateMousePosition(c) tw.FrameInputState.MouseMoveThisFrame = true case *PointerButtonPress: tw.StatusLine.HandleTerminalMousePress(true) case *PointerButtonRelease: tw.StatusLine.HandleTerminalMousePress(false) case *PointerWheel: } case client := <-tw.GetClients: //TODO removing clients tw.Clients = append(tw.Clients, client) case <-timeout: goto KeyReadLoop } } KeyReadLoop: // /** // * I know sleep is bad for timing. // * @TODO replace with polling later on. // */ // time.Sleep(time.Duration(tw.DesiredFrameTimeSeconds * float64(time.Second))) } } func (tw *TerminalDrawLoop) DrawClients() { defer tw.ResetFrameState() start_of_frame := float64(time.Now().UnixMilli()) / 1000.0 var delta_time float64 if tw.TimeOfStartOfLastFrame != nil { delta_time = start_of_frame - *tw.TimeOfStartOfLastFrame } else { delta_time = tw.DesiredFrameTimeSeconds } num_draw_requests := 0 for _, s := range tw.Clients { for { select { case callback_id := <-s.FrameDrawRequests: protocols.WlCallback_done(s, callback_id, uint32(time.Now().UnixMilli())) num_draw_requests++ default: goto DoneCallbacks } } DoneCallbacks: } clients_to_delete := make([]int, 0) for i, s := range tw.Clients { s.Access.Lock() if s.Status != wayland.ClientStatus_Connected { s.Access.Unlock() clients_to_delete = append(clients_to_delete, i) continue } else { defer s.Access.Unlock() } } for i := len(clients_to_delete) - 1; i >= 0; i-- { index := clients_to_delete[i] tw.Clients = slices.Delete(tw.Clients, index, index+1) } for _, s := range tw.Clients { pointer_surface_id := wayland.Pointer.PointerSurfaceID[s] if pointer_surface_id == nil { continue } surface := wayland.GetWlSurfaceObject(s, *pointer_surface_id) if surface == nil { continue } surface.Position.X = int32(wayland.Pointer.WindowX) surface.Position.Y = int32(wayland.Pointer.WindowY) surface.Position.Z = 1000 } tw.Desktop.DrawClients(tw.Clients) status_line := tw.StatusLine.Draw(delta_time, tw.GetAppTitle(), tw.FrameInputState.KeysPressedThisFrame) if tw.ShouldDrawFrame(start_of_frame, num_draw_requests) { tw.DrawToTerminal(status_line) } // const draw_time = Date.now(); // const time_until_next_frame = Math.max( // 0, // this.desired_frame_time_seconds - (draw_time - start_of_frame) // ); tw.TimeOfStartOfLastFrame = &start_of_frame tw.StatusLine.PostFrame(delta_time) } func (tw *TerminalDrawLoop) ResetFrameState() { tw.FrameInputState.MouseMoveThisFrame = false clear(tw.FrameInputState.KeysPressedThisFrame) } func (tw *TerminalDrawLoop) ShouldDrawFrame(start_of_frame float64, num_draw_requests int) (should_draw bool) { defer func() { if should_draw { tw.FirstDrawDone = true } }() if tw.MinTerminalTimeSeconds != nil { last := 0.0 if tw.TimeOfLastTerminalDraw != nil { last = *tw.TimeOfLastTerminalDraw } if start_of_frame-last < *tw.MinTerminalTimeSeconds { return false } tw.TimeOfLastTerminalDraw = &start_of_frame } if protocols.DebugRequests { return false } if winsize, err := framebuffertoansi.GetWinsize(os.Stdout.Fd()); err == nil { defer func() { tw.LastDrawSize = winsize }() if winsize != tw.LastDrawSize { return true } } if num_draw_requests == 0 { return tw.FrameInputState.MouseMoveThisFrame || !tw.FirstDrawDone } return true } ================================================ FILE: termeverything/TerminalWindow.go ================================================ package termeverything import ( "fmt" "os" "os/signal" "slices" "syscall" "github.com/mmulet/term.everything/escapecodes" "github.com/mmulet/term.everything/framebuffertoansi" "github.com/mmulet/term.everything/wayland" "github.com/mmulet/term.everything/wayland/protocols" ) type RenderedScreenSize struct { WidthCells *int HeightCells *int } type WindowMode int const ( WindowMode_Passthrough WindowMode = iota WindowMode_Capture ) var GlobalExitChan = make(chan int) type TerminalWindow struct { SocketListener *wayland.SocketListener VirtualMonitorSize wayland.Size Mode WindowMode FrameEvents chan XkbdCode Args *CommandLineArgs PressedMouseButton *LINUX_BUTTON_CODES Clients []*wayland.Client GetClients chan *wayland.Client SharedRenderedScreenSize *RenderedScreenSize RestoreTerminalMode func() error } func MakeTerminalWindow( socket_listener *wayland.SocketListener, desktop_size wayland.Size, args *CommandLineArgs, ) *TerminalWindow { restoreTerminalMode, err := EnableRawModeFD(int(os.Stdin.Fd())) if err != nil { panic(err) } tw := &TerminalWindow{ SocketListener: socket_listener, VirtualMonitorSize: desktop_size, Mode: WindowMode_Passthrough, FrameEvents: make(chan XkbdCode, 8192), Args: args, PressedMouseButton: nil, SharedRenderedScreenSize: &RenderedScreenSize{}, Clients: make([]*wayland.Client, 0), // RestoreTerminalMode: func() error { return nil }, RestoreTerminalMode: restoreTerminalMode, GetClients: make(chan *wayland.Client, 32), } if !protocols.DebugRequests { os.Stdout.WriteString(escapecodes.EnableAlternativeScreenBuffer) os.Stdout.WriteString(escapecodes.EnableMouseTracking) os.Stdout.WriteString(escapecodes.EnableSGR) os.Stdout.WriteString(escapecodes.HideCursor) } sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGUSR1, syscall.SIGUSR2, ) go func() { exit_code := 0 select { case exit_code = <-GlobalExitChan: case <-sigCh: } tw.OnExit() os.Exit(exit_code) }() return tw } func (tw *TerminalWindow) OnExit() { for _, s := range tw.Clients { for surface := range s.TopLevelSurfaces() { protocols.XdgToplevel_close(s, surface) } } tw.RestoreTerminalMode() os.Stdout.WriteString(escapecodes.DisableAlternativeScreenBuffer) os.Stdout.WriteString(escapecodes.ShowCursor) // TODO re-enable if enabled above // os.Stdout.WriteString(escapecodes.DisableNormalMouseTracking) os.Stdout.WriteString(escapecodes.DisableMouseTracking) } func (tw *TerminalWindow) InputLoop() { buf := make([]byte, 4096) for { n, err := os.Stdin.Read(buf) if err != nil || n == 0 { fmt.Printf("Error reading stdin: %v\n", err) return } chunk := buf[:n] for { select { case client := <-tw.GetClients: //TODO removing client tw.Clients = append(tw.Clients, client) default: goto GotData } } GotData: codes := ConvertKeycodeToXbdCode(chunk) tw.ProcessCodes(codes) } } func (tw *TerminalWindow) ProcessCodes(codes []XkbdCode) { clients_to_delete := make([]int, 0) for i, s := range tw.Clients { s.Access.Lock() if s.Status != wayland.ClientStatus_Connected { s.Access.Unlock() clients_to_delete = append(clients_to_delete, i) continue } else { defer s.Access.Unlock() } } for i := len(clients_to_delete) - 1; i >= 0; i-- { index := clients_to_delete[i] tw.Clients = slices.Delete(tw.Clients, index, index+1) } for _, code := range codes { tw.FrameEvents <- code for _, s := range tw.Clients { if keyboard_map := protocols.GetGlobalWlKeyboardBinds(s); keyboard_map != nil { modifiers := code.GetModifiers() ser := wayland.GetNextEventSerial() for keyboardID := range keyboard_map { protocols.WlKeyboard_modifiers( s, keyboardID, ser, uint32(modifiers), 0, 0, 0, ) } } } switch c := code.(type) { case *KeyCode: wayland.SendKeyboardKey(tw.Clients, uint32(c.KeyCode), true) // Send key released immediately wayland.SendKeyboardKey(tw.Clients, uint32(c.KeyCode), false) case *PointerMove: cols, rows := tw.CurrentTerminalSize() x := float32(c.Col) * (float32(tw.VirtualMonitorSize.Width) / float32(cols)) y := float32(c.Row) * (float32(tw.VirtualMonitorSize.Height) / float32(rows)) wayland.SendPointerMotion(tw.Clients, x, y) case *PointerButtonPress: release := tw.GetButtonToReleaseAndUpdatePressedMouseButton(c.Button) wayland.SendPointerButton(tw.Clients, uint32(c.Button), true) if c.NeedToReleaseOtherButtons && release != nil { wayland.SendPointerButton(tw.Clients, uint32(*release), false) } case *PointerButtonRelease: buttonToRelease := c.Button if c.NeedsButtonGuessing { if tw.PressedMouseButton == nil { break } buttonToRelease = *tw.PressedMouseButton tw.PressedMouseButton = nil } wayland.SendPointerButton(tw.Clients, uint32(buttonToRelease), false) case *PointerWheel: _, rows := tw.CurrentTerminalSize() var scale float32 = 0.5 if (c.Modifiers & ModAlt) != 0 { scale = 1 } amount := scale * float32(tw.ScrollDirection(c.Up)) * float32(tw.VirtualMonitorSize.Height) / float32(rows) wayland.SendPointerAxis(tw.Clients, protocols.WlPointerAxis_enum_vertical_scroll, amount) default: // literal never_default(code) equivalent: do nothing } } } func (tw *TerminalWindow) ScrollDirection(code_up bool) float32 { var code float32 = 1.0 if code_up { code = -1.0 } var reverse float32 = 1.0 if tw.Args != nil && tw.Args.ReverseScroll { reverse = -1.0 } return code * reverse } /** * Because we only get release updates for one button at a time * assume that when you press another mouse button you will * release the one you already have pressed. */ func (tw *TerminalWindow) GetButtonToReleaseAndUpdatePressedMouseButton(new_pressed_button LINUX_BUTTON_CODES) *LINUX_BUTTON_CODES { old_pressed_mouse_button := tw.PressedMouseButton tw.PressedMouseButton = &new_pressed_button //TODO I think this a bug, but keeping it for now because I dont // want to make any behavior changes while porting if old_pressed_mouse_button == nil || *tw.PressedMouseButton == new_pressed_button { return nil } return old_pressed_mouse_button } func (tw *TerminalWindow) CurrentTerminalSize() (cols, rows int) { if tw.SharedRenderedScreenSize != nil && tw.SharedRenderedScreenSize.WidthCells != nil && tw.SharedRenderedScreenSize.HeightCells != nil { return *tw.SharedRenderedScreenSize.WidthCells, *tw.SharedRenderedScreenSize.HeightCells } ws, err := framebuffertoansi.GetWinsize(1) if err != nil || ws.Col <= 0 || ws.Row <= 0 { return 80, 24 } return int(ws.Col), int(ws.Row) } ================================================ FILE: termeverything/profile.go ================================================ //go:build profile // +build profile package termeverything import ( _ "net/http/pprof" "log" "net/http" ) func init() { go func() { log.Println("pprof at http://127.0.0.1:6060/debug/pprof/") _ = http.ListenAndServe("127.0.0.1:6060", nil) }() } ================================================ FILE: termeverything/resources/LICENSES.txt ================================================ This app (term.everything❗mmulet.com) is copyright 2025 Late for Dinner Studios, LLC Licensed under the GNU Affero General Public License v3.0 licenses: AGPL-3.0-only repository: https://github.com/mmulet/term.everything licenseFile: https://github.com/mmulet/term.everything/blob/main/LICENSE.txt publisher: Late for Dinner Studios, LLC lead developer: Michael Mulet maintainer: Michael Mulet email: m@mmulet.com Third-party Dependencies: ├─ Go Standard Library │ ├─ licenses: BSD-3-Clause │ ├─ repository: https://github.com/golang/go │ └─ licenseFile: https://github.com/golang/go/blob/master/LICENSE ├─ musl libc (including libm. and pthread) │ ├─ licenses: MIT │ ├─ repository: https://git.musl-libc.org/cgit/musl/ │ └─ licenseFile: https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT └─ libchafa ├─ licenses: LGPL-3.0 ├─ repository: https://github.com/hpjansson/chafa └─ licenseFile: https://github.com/hpjansson/chafa?tab=LGPL-3.0-1-ov-file ├─ GLib – 2.0 | ├─ licenses: LGPL-2.1-or-later | ├─ repository: https://gitlab.gnome.org/GNOME/glib/ | └─ licenseFile: https://gitlab.gnome.org/GNOME/glib/-/blob/main/LICENSES/LGPL-2.1-or-later.txt ├─ pcre2-8 | ├─ licenses: BSD | ├─ repository: https://github.com/PCRE2Project/pcre2 | └─ licenseFile: https://github.com/PCRE2Project/pcre2/blob/main/LICENCE.md ├─ libatomic │ ├─ licenses: GPL-3.0-with-GCC-exception │ ├─ repository: https://gcc.gnu.org/ │ └─ licenseFile: https://gcc.gnu.org/onlinedocs/libstdc++/manual/license.html (GCC Runtime Library Exception) ├─ libintl (from GNU gettext) │ ├─ licenses: LGPL-2.1-or-later │ ├─ repository: https://www.gnu.org/software/gettext/ │ └─ licenseFile: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html ================================================ FILE: termeverything/resources/help.md ================================================ Usage: ``` term.everything❗mmulet.com-dont_forget_to_chmod_+x_this_file [options] [-- some_app_to_term [some_app_args]] ``` ## Typical Usage: - Navigate to the directory containing the app: `cd ` - Ensure the app has execute permissions: `chmod +x ./term.everything❗mmulet.com-dont_forget_to_chmod_+x_this_file` - Then run (if you want to run firefox for example): `./term.everything❗mmulet.com-dont_forget_to_chmod_+x_this_file firefox` ## App didn't open in the terminal? If that app already has a window open, try closing all the existing windows. Or try using `--support-old-apps` to add support for older applications: - `term.everything❗mmulet.com-dont_forget_to_chmod_+x_this_file --support-old-apps \ -- firefox` ## Advanced Usage: Set a custom Wayland display name along with a custom Xwayland display name: `./term.everything❗mmulet.com-dont_forget_to_chmod_+x_this_file --wayland-display-name \ wayland-3--xwayland ":2 -retro" -- firefox` ## Galaxy Brain Usage: - Boot up 5 terminals (A, Bob, Cob, Dobby, E-obby). - Run the app in terminal A: `./term.everything❗mmulet.com-dont_forget_to_chmod_+x_this_file --wayland-display-name \` `wayland-2` - Then in terminal Bob run: `WAYLAND_DISPLAY=wayland-2 Xwayland :2 -retro` - In terminal Cob run: `matchbox-window-manager -display :2` - In terminal Dobby run: `DISPLAY=:2 ` - In terminal E-obby run: `WAYLAND_DISPLAY=wayland-2 ` The app in terminal A hosts a Wayland display (a virtual desktop). Terminal Bob runs Xwayland for X11 apps, pointing to terminal A. Terminal Cob runs the X11 window manager for terminal Bob. Terminal Dobby is an X11 app connecting to Bob, and terminal E-obby runs a Wayland app connecting to terminal A. ## Options: `--wayland-display-name ` The Wayland display name. @default to wayland-2 (or wayland-3 if wayland-2 is in use,etc). `--xwayland ""` Run an Xwayland display for X11 compatibility (if installed and on the PATH). term.everything does not support a rootless X11 server. Default is empty. `--xwayland-wm ""` Specifies the window manager for Xwayland. Default is: "matchbox-window-manager -display " `--virtual-monitor-size x` Sets the virtual monitor size in pixels (the display size for all apps). A small size is recommended to prevent performance issues. Default is 640x480. `--support-old-apps` Alias for `--xwayland ":5 -retro" --xwayland-wm \ "matchbox-window-manager -display :5"`. Enables support for older apps. `--` Everything after `--` is executed inside the terminal with these environment variables: WAYLAND_DISPLAY= DISPLAY= `--shell ` The shell used to launch the app. Default is `/bin/bash`. `--hide-status-bar` Hides the status bar at the top of the terminal. Default is false. `--version` Print the version number. `-h, --help` Show this help message. `--licenses` Print the open source licenses of libraries used in this app. `--reverse-scroll` Reverse scroll direction. It's great if you ssh into a linux machine from a mac. `--max-frame-rate` Limit drawing to the terminal to $N frames per second. Accepts float. `--debug-log` Log most debug statements to debug.log instead of printing to console # Environment Variables `TERM_EVERYTHING_PIXEL_MODE` Values: - ITERM2 - KITTY - SIXELS - SYMBOLS `TERM_EVERYTHING_CANVAS_MODE` Values: - TRUECOLOR - INDEXED_256 - INDEXED_240 - INDEXED_16 - FGBG_BGFG - FGBG - INDEXED_8 - INDEXED_16_8 `TERM_EVERYTHING_PIXEL_TYPE` Values: - RGBA8 - BGRA8 - ARGB8 - ABGR8 - RGBA8_PREMULTIPLIED - BGRA8_PREMULTIPLIED - ARGB8_PREMULTIPLIED - ABGR8_PREMULTIPLIED `TERM_EVERYTHING_SYMBOLS` Values: see https://github.com/hpjansson/chafa/blob/b790c7e365f6a95aaa9cce985ff16a1c1f914482/chafa/chafa-symbol-map.h#L36 Remove CHAFA_SYMBOL_TAG. For example: `CHAFA_SYMBOL_TAG_ALL` -> `ALL` ================================================ FILE: wayland/ApplyWlSurfaceDoubleBufferedState.go ================================================ package wayland import ( "github.com/mmulet/term.everything/wayland/pointerslices" "github.com/mmulet/term.everything/wayland/protocols" ) type PendingBufferUpdates struct { Surface protocols.ObjectID[protocols.WlSurface] Buffer *protocols.ObjectID[protocols.WlBuffer] ZIndex int } func ApplyWlSurfaceDoubleBufferedState( s protocols.ClientState, surfaceObjectID protocols.ObjectID[protocols.WlSurface], syncSetByParent bool, accumulator []PendingBufferUpdates, zIndex int, ) []PendingBufferUpdates { /** * Could be a child surface */ surface := GetWlSurfaceObject(s, surfaceObjectID) if surface == nil { return accumulator } update := &surface.PendingUpdate if update.Buffer != nil { accumulator = append(accumulator, PendingBufferUpdates{ Surface: surfaceObjectID, Buffer: update.Buffer, ZIndex: zIndex, }) } if update.BufferScale != nil { surface.BufferScale = *update.BufferScale } if update.BufferTransform != nil { surface.BufferTransform = *update.BufferTransform } if update.Damage != nil || update.DamageBuffer != nil { surface.Damaged = true } else { surface.Damaged = false } // offset: add to current offset (doc semantics) if update.Offset != nil { /** * @TODO Docs say: * The x and y arguments specify the location of the new pending * buffer's upper left corner, * relative to the current buffer's upper left corner, * in surface-local coordinates. * In other words, the x and y, * combined with the new surface size define in * which directions the surface's size changes. * * So I think this means I should add the offset to the current offset * of the surface, not just set it to the offset. */ surface.Offset.X += update.Offset.X surface.Offset.Y += update.Offset.Y /** * From the docs: * On wl_surface.offset requests to the pointer surface, hotspot_x and hotspot_y are decremented by the x and y parameters passed to the request. The offset must be applied by wl_surface.commit as usual. */ // if (surface.role?.type === "cursor" && surface.role.data) { // surface.role.data.hotspot.x -= update.offset.x; // surface.role.data.hotspot.y -= update.offset.y; // } } if update.InputRegion != nil { if surface.InputRegion != nil && !AreSame(surface.InputRegion, update.InputRegion) { RemoveObject(s, *surface.InputRegion) } surface.InputRegion = update.InputRegion } if update.OpaqueRegion != nil { if surface.OpaqueRegion != nil && !AreSame(surface.OpaqueRegion, update.OpaqueRegion) { RemoveObject(s, *surface.OpaqueRegion) } surface.OpaqueRegion = update.OpaqueRegion } if update.AddSubSurface != nil { for _, subID := range update.AddSubSurface { surface.ChildrenInDrawOrder = append( []*protocols.ObjectID[protocols.WlSurface]{&subID}, surface.ChildrenInDrawOrder..., ) } } if update.SetChildPosition != nil { for _, childPosition := range update.SetChildPosition { if !pointerslices.Contains(surface.ChildrenInDrawOrder, childPosition.Child) { continue } childSurface := GetWlSurfaceObject(s, childPosition.Child) if childSurface == nil { continue } role, ok := childSurface.Role.(*SurfaceRoleSubSurface) if !ok || role.Data == nil { continue } sub := GetWlSubsurfaceObject(s, *role.Data) if sub == nil { continue } sub.Position = Point{ X: childPosition.X, Y: childPosition.Y, } } } if update.ZOrderSubsurfaces != nil { for _, zUpdate := range update.ZOrderSubsurfaces { index_of_child := pointerslices.Index(surface.ChildrenInDrawOrder, zUpdate.ChildToMove) if index_of_child == -1 { continue } index_of_relative_to := pointerslices.IndexOfItemOrNil(surface.ChildrenInDrawOrder, zUpdate.RelativeTo) if index_of_relative_to == -1 { continue } /** * Remove the child from the list * then reinsert it at the correct index * either above or below the relative_to child * Since it is drawn in order, above means it will * be added to the array after the relative_to child * and below means it will be added before the relative_to child */ surface.ChildrenInDrawOrder = pointerslices.Delete(surface.ChildrenInDrawOrder, index_of_child, index_of_child+1) var offset int if zUpdate.Type == ZOrderTypeAbove { offset = 1 } else { offset = 0 } surface.ChildrenInDrawOrder = pointerslices.Insert(surface.ChildrenInDrawOrder, index_of_relative_to+offset, &zUpdate.ChildToMove) } } if update.XdgSurfaceWindowGeometry != nil { if xdg_surface_state_id := surface.XdgSurfaceState; xdg_surface_state_id != nil { if xdg_surface_state := GetXdgSurfaceObject(s, *xdg_surface_state_id); xdg_surface_state != nil { xdg_surface_state.WindowGeometry = *update.XdgSurfaceWindowGeometry } } } if role, ok := surface.Role.(*SurfaceRoleXdgToplevel); ok && role.Data != nil { top := GetXdgToplevelObject(s, *role.Data) if top != nil && top.PendingState != nil { if top.PendingState.MaxSize != nil { top.MaxSize = top.PendingState.MaxSize } if top.PendingState.MinSize != nil { top.MinSize = top.PendingState.MinSize } top.PendingState = nil } } // if ( // surface.has_role_data_of_type("xdg_toplevel") && // surface.role.data.pending_state // ) { // if (surface.role.data.pending_state.max_size) { // surface.role.data.max_size = surface.role.data.pending_state.max_size; // } // if (surface.role.data.pending_state.min_size) { // surface.role.data.min_size = surface.role.data.pending_state.min_size; // } // delete surface.role.data.pending_state; // } if update.XwaylandSurfarfaceV1Serial != nil { if role, ok := surface.Role.(*SurfaceRoleXWaylandSurface); ok { if role.Data == nil { role.Data = &SurfaceRoleWaylandSurfaceData{} } (*role.Data).Serial = update.XwaylandSurfarfaceV1Serial } } surface.ResetPendingUpdate() for _, childSurfaceObjectID := range surface.ChildrenInDrawOrder { if childSurfaceObjectID == nil { continue } if syncSetByParent { accumulator = ApplyWlSurfaceDoubleBufferedState( s, *childSurfaceObjectID, syncSetByParent, accumulator, zIndex+1, ) continue } childSurface := GetWlSurfaceObject(s, *childSurfaceObjectID) if childSurface == nil { continue } role, ok := childSurface.Role.(*SurfaceRoleSubSurface) if !ok || role.Data == nil { continue } sub := GetWlSubsurfaceObject(s, *role.Data) if sub == nil { continue } // if ( // child_surface.role.type !== "sub_surface" || // child_surface.role.data === null // ) { // continue; // } // if (!child_surface.role.data.sync) { if !sub.Sync { /** * The child is not set to sync with the parent * so do not apply state changes now */ continue } accumulator = ApplyWlSurfaceDoubleBufferedState( s, *childSurfaceObjectID, true, accumulator, zIndex+1, ) } return accumulator } ================================================ FILE: wayland/Client.go ================================================ package wayland import ( "encoding/binary" "fmt" "log" "net" "slices" "sync" "time" "github.com/mmulet/term.everything/wayland/protocols" ) type ClientStatus int const ( ClientStatus_Connected ClientStatus = 0 ClientStatus_Disconnected ClientStatus = 2 ) type Client struct { Status ClientStatus drawableSurfaces map[protocols.ObjectID[protocols.WlSurface]]bool topLevelSurfaces map[protocols.ObjectID[protocols.XdgToplevel]]bool UnixConnection *net.UnixConn CompositorVersion uint32 DisplayID protocols.ObjectID[protocols.WlDisplay] messageBuffer []byte OutgoingChannel chan protocols.OutgoingEvent Decoder *MessageDecoder UnclaimedFDs []protocols.FileDescriptor Objects map[protocols.AnyObjectID]any RolesToSurfaces map[protocols.AnyObjectID]protocols.ObjectID[protocols.WlSurface] FrameDrawRequests chan protocols.ObjectID[protocols.WlCallback] GlobalBinds map[protocols.GlobalID]any LastGetMessageTime time.Time Access sync.Mutex } func (c *Client) AddFrameDrawRequest(cb protocols.ObjectID[protocols.WlCallback]) { c.FrameDrawRequests <- cb } func (c *Client) GetSurfaceIDFromRole(roleObjectID protocols.AnyObjectID) *protocols.ObjectID[protocols.WlSurface] { if sid, ok := c.RolesToSurfaces[roleObjectID]; ok { return &sid } return nil } func (c *Client) GetSurfaceFromRole(roleObjectID protocols.AnyObjectID) any { sidAny := c.GetSurfaceIDFromRole(roleObjectID) if sidAny == nil { return nil } surface := GetWlSurfaceObject(c, *sidAny) return surface } func (c *Client) UnregisterRoleToSurface(roleID protocols.AnyObjectID) { delete(c.RolesToSurfaces, roleID) } func (c *Client) RegisterRoleToSurface(roleID protocols.AnyObjectID, surfaceID protocols.ObjectID[protocols.WlSurface]) { c.RolesToSurfaces[roleID] = surfaceID } /** * Seed if maybe_desceneding_id is a descendant of surface_id * @param s * @param surface_id * @param maybe_descendant_id */ func (c *Client) FindDescendantSurface(surfaceID protocols.ObjectID[protocols.WlSurface], maybeDescendantID protocols.ObjectID[protocols.WlSurface]) bool { surface := GetWlSurfaceObject(c, surfaceID) if surface == nil { return false } for _, childID := range surface.ChildrenInDrawOrder { if childID == nil { continue } if *childID == maybeDescendantID { return true } } for _, childID := range surface.ChildrenInDrawOrder { if childID == nil { continue } if c.FindDescendantSurface(*childID, maybeDescendantID) { return true } } return false } func (c *Client) SendError(objectID protocols.AnyObjectID, code uint32, message string) { protocols.WlDisplay_error(c, protocols.ObjectID[protocols.WlDisplay](protocols.GlobalID_WlDisplay), objectID, code, message, ) } func (c *Client) GetGlobalBinds(globalID protocols.GlobalID) any { return c.GlobalBinds[globalID] } /** * Add a bound object_id to a list * of global_ids. SO that you can * ask, What are all the objects bound * to this global for this client? * @param global_id * @param object_id */ // func (c *Client) AddGlobalBind(globalID protocols.GlobalID, objectID protocols.AnyObjectID, version protocols.Version) { // binds, ok := c.GlobalBinds[globalID] // if !ok { // binds = make(map[protocols.AnyObjectID]protocols.Version) // c.GlobalBinds[globalID] = binds // } // binds[objectID] = version // } func (c *Client) AddObject(id protocols.AnyObjectID, v any) { if v == nil { log.Printf("AddObject: object is nil for id %d", uint32(id)) } if _, already_have := c.Objects[id]; already_have { log.Printf("AddObject: object already exists for id %d", uint32(id)) } c.Objects[id] = v } func (c *Client) RemoveObject(id protocols.AnyObjectID) { delete(c.Objects, id) } func (c *Client) GetObject(id protocols.AnyObjectID) any { object, ok := c.Objects[id] if !ok { return c.GetGlobalObjectByID(uint32(id)) } return object } func (c *Client) GetGlobalObjectByID(globalID uint32) any { switch globalID { case uint32(protocols.GlobalID_WlDisplay): return Global_WlDisplay case uint32(protocols.GlobalID_WlOutput): return Global_WlOutput case uint32(protocols.GlobalID_WlSeat): return Global_WlSeat case uint32(protocols.GlobalID_WlShm): return Global_WlShm case uint32(protocols.GlobalID_WlCompositor): return Global_WlCompositor case uint32(protocols.GlobalID_WlSubcompositor): return Global_WlSubcompositor case uint32(protocols.GlobalID_XdgWmBase): return Global_XdgWmBase case uint32(protocols.GlobalID_WlDataDeviceManager): return Global_WlDataDeviceManager case uint32(protocols.GlobalID_WlKeyboard): return Global_WlKeyboard case uint32(protocols.GlobalID_WlPointer): return Global_WlPointer case uint32(protocols.GlobalID_ZwpXwaylandKeyboardGrabManagerV1): return Global_ZwpXwaylandKeyboardGrabManagerV1 case uint32(protocols.GlobalID_XwaylandShellV1): return Global_XwaylandShellV1 case uint32(protocols.GlobalID_WlDataDevice): return Global_WlDataDevice case uint32(protocols.GlobalID_WlTouch): return Global_WlTouch case uint32(protocols.GlobalID_ZxdgDecorationManagerV1): return Global_ZxdgDecorationManagerV1 } return nil } func MakeClient(conn *net.UnixConn) *Client { return &Client{ Status: ClientStatus_Connected, UnixConnection: conn, CompositorVersion: 1, Decoder: MakeMessageDecoder(), DisplayID: protocols.ObjectID[protocols.WlDisplay](1), messageBuffer: make([]byte, 64*1024), OutgoingChannel: make(chan protocols.OutgoingEvent, 8192), UnclaimedFDs: make([]protocols.FileDescriptor, 0, 8), Objects: make(map[protocols.AnyObjectID]any), RolesToSurfaces: make(map[protocols.AnyObjectID]protocols.ObjectID[protocols.WlSurface]), drawableSurfaces: make(map[protocols.ObjectID[protocols.WlSurface]]bool), topLevelSurfaces: make(map[protocols.ObjectID[protocols.XdgToplevel]]bool), GlobalBinds: make(map[protocols.GlobalID]any), FrameDrawRequests: make(chan protocols.ObjectID[protocols.WlCallback], 1024), } } func (c *Client) MainLoop() error { defer func() { c.Status = ClientStatus_Disconnected if c.UnixConnection != nil { if err := c.UnixConnection.Close(); err != nil { } } }() for { for { select { case ev := <-c.OutgoingChannel: if err := c.SendPendingMessage(ev); err != nil { return err } default: goto drained } } drained: // Receive once with short deadline; parse and dispatch. n, fds, err := GetMessageAndFileDescriptors(c.UnixConnection, c.messageBuffer) if err != nil { // treat unexpected read errors as fatal return err } if err := c.ParseMessages(n, fds); err != nil { return err } } } func (c *Client) Send(ev protocols.OutgoingEvent) { // Allow backpressure to naturally block the sender goroutine. c.OutgoingChannel <- ev } /** * * @param message * @returns Returns if we should continue listening or sending on this socket any more * returns falsy mostly if the client has disconnected */ func (c *Client) SendPendingMessage(ev protocols.OutgoingEvent) error { c.Access.Lock() defer c.Access.Unlock() if protocols.DebugRequests { log.Printf("client -> eid=%d opcode=%d len=%d fd=%v", uint32(ev.ObjectID), ev.Opcode, len(ev.Data), ev.FileDescriptor) } // if WaylandDebugTimeOnly() { // log.Printf("client -> eid=%d opcode=%d len=%d fd=%v", // uint32(ev.ObjectID), ev.Opcode, len(ev.Data), ev.FileDescriptor) // } /** * 8 bytes is the header length + the length of the message * #### Header is * - 4 bytes for object_id * - 2 bytes for opcode * - 2 bytes for size */ size := 8 + len(ev.Data) buf := make([]byte, size) // Wayland header: object_id (u32), size (u16), opcode (u16) binary.LittleEndian.PutUint32(buf[0:4], uint32(ev.ObjectID)) binary.LittleEndian.PutUint16(buf[4:6], uint16(ev.Opcode)) binary.LittleEndian.PutUint16(buf[6:8], uint16(size)) copy(buf[8:], ev.Data) var fds []int if ev.FileDescriptor != nil { fds = []int{int(*ev.FileDescriptor)} } return SendMessageAndFileDescriptors(c.UnixConnection, buf, fds) // re // if err != nil { // // if EPIPE or similar => disconnect // if errors.Is(err, syscall.EPIPE) || errors.Is(err, syscall.ECONNRESET) { // return false // } // log.Printf("Send error: %v (n=%d ok=%v)", err, n, ok) // return false // } // return true } func (c *Client) ParseMessages(n int, fds []int) error { c.Access.Lock() defer c.Access.Unlock() // if len(fds) > 0 && WaylandDebugTimeOnly() { // log.Printf("client: received %d file descriptors", len(fds)) // } for _, fd := range fds { c.UnclaimedFDs = append(c.UnclaimedFDs, protocols.FileDescriptor(fd)) } if n < 0 { return fmt.Errorf("negative byte count received: %d", n) } if n == 0 { /** * Time out */ return nil } msgs := c.Decoder.Consume(c.messageBuffer[:n]) for i := range msgs { m := msgs[i] obj := c.GetObject(m.ObjectID) if obj == nil { // if WaylandDebugTimeOnly() { // log.Printf("client: request for unknown object %d", uint32(m.ObjectID)) // } continue } theType, ok := obj.(protocols.OnRequestable) if !ok { log.Printf("client: object %d has unknown type; cannot dispatch", uint32(m.ObjectID)) continue } theType.OnRequest(c, m) } return nil } func (c *Client) ClaimFileDescriptor() *protocols.FileDescriptor { if len(c.UnclaimedFDs) == 0 { return nil } fd := c.UnclaimedFDs[0] c.UnclaimedFDs = slices.Delete(c.UnclaimedFDs, 0, 1) return &fd } func (c *Client) SetCompositorVersion(v uint32) { c.CompositorVersion = v } func (c *Client) GetCompositorVersion() uint32 { return c.CompositorVersion } func (c *Client) DrawableSurfaces() map[protocols.ObjectID[protocols.WlSurface]]bool { return c.drawableSurfaces } func (c *Client) TopLevelSurfaces() map[protocols.ObjectID[protocols.XdgToplevel]]bool { return c.topLevelSurfaces } ================================================ FILE: wayland/ClientGlobal.go ================================================ package wayland import "github.com/mmulet/term.everything/wayland/protocols" func (c *Client) AddGlobalWlShmBind(objectID protocols.ObjectID[protocols.WlShm], version protocols.Version) { binds, ok := c.GlobalBinds[protocols.GlobalID_WlShm] if !ok { binds = make(map[protocols.ObjectID[protocols.WlShm]]protocols.Version) c.GlobalBinds[protocols.GlobalID_WlShm] = binds } binds.(map[protocols.ObjectID[protocols.WlShm]]protocols.Version)[objectID] = version } func (c *Client) AddGlobalWlSeatBind(objectID protocols.ObjectID[protocols.WlSeat], version protocols.Version) { binds, ok := c.GlobalBinds[protocols.GlobalID_WlSeat] if !ok { binds = make(map[protocols.ObjectID[protocols.WlSeat]]protocols.Version) c.GlobalBinds[protocols.GlobalID_WlSeat] = binds } binds.(map[protocols.ObjectID[protocols.WlSeat]]protocols.Version)[objectID] = version } func (c *Client) AddGlobalWlOutputBind(objectID protocols.ObjectID[protocols.WlOutput], version protocols.Version) { binds, ok := c.GlobalBinds[protocols.GlobalID_WlOutput] if !ok { binds = make(map[protocols.ObjectID[protocols.WlOutput]]protocols.Version) c.GlobalBinds[protocols.GlobalID_WlOutput] = binds } binds.(map[protocols.ObjectID[protocols.WlOutput]]protocols.Version)[objectID] = version } func (c *Client) AddGlobalWlKeyboardBind(objectID protocols.ObjectID[protocols.WlKeyboard], version protocols.Version) { binds, ok := c.GlobalBinds[protocols.GlobalID_WlKeyboard] if !ok { binds = make(map[protocols.ObjectID[protocols.WlKeyboard]]protocols.Version) c.GlobalBinds[protocols.GlobalID_WlKeyboard] = binds } binds.(map[protocols.ObjectID[protocols.WlKeyboard]]protocols.Version)[objectID] = version } func (c *Client) AddGlobalWlPointerBind(objectID protocols.ObjectID[protocols.WlPointer], version protocols.Version) { binds, ok := c.GlobalBinds[protocols.GlobalID_WlPointer] if !ok { binds = make(map[protocols.ObjectID[protocols.WlPointer]]protocols.Version) c.GlobalBinds[protocols.GlobalID_WlPointer] = binds } binds.(map[protocols.ObjectID[protocols.WlPointer]]protocols.Version)[objectID] = version } func (c *Client) AddGlobalWlTouchBind(objectID protocols.ObjectID[protocols.WlTouch], version protocols.Version) { binds, ok := c.GlobalBinds[protocols.GlobalID_WlTouch] if !ok { binds = make(map[protocols.ObjectID[protocols.WlTouch]]protocols.Version) c.GlobalBinds[protocols.GlobalID_WlTouch] = binds } binds.(map[protocols.ObjectID[protocols.WlTouch]]protocols.Version)[objectID] = version } func (c *Client) AddGlobalWlDataDeviceBind(objectID protocols.ObjectID[protocols.WlDataDevice], version protocols.Version) { binds, ok := c.GlobalBinds[protocols.GlobalID_WlDataDevice] if !ok { binds = make(map[protocols.ObjectID[protocols.WlDataDevice]]protocols.Version) c.GlobalBinds[protocols.GlobalID_WlDataDevice] = binds } binds.(map[protocols.ObjectID[protocols.WlDataDevice]]protocols.Version)[objectID] = version } func (c *Client) AddGlobalZwpXwaylandKeyboardGrabManagerV1Bind(objectID protocols.ObjectID[protocols.ZwpXwaylandKeyboardGrabManagerV1], version protocols.Version) { binds, ok := c.GlobalBinds[protocols.GlobalID_ZwpXwaylandKeyboardGrabManagerV1] if !ok { binds = make(map[protocols.ObjectID[protocols.ZwpXwaylandKeyboardGrabManagerV1]]protocols.Version) c.GlobalBinds[protocols.GlobalID_ZwpXwaylandKeyboardGrabManagerV1] = binds } binds.(map[protocols.ObjectID[protocols.ZwpXwaylandKeyboardGrabManagerV1]]protocols.Version)[objectID] = version } func (c *Client) RemoveGlobalWlShmBind(objectID protocols.ObjectID[protocols.WlShm]) { binds, ok := c.GlobalBinds[protocols.GlobalID_WlShm] if !ok { return } delete(binds.(map[protocols.ObjectID[protocols.WlShm]]protocols.Version), objectID) } func (c *Client) RemoveGlobalWlSeatBind(objectID protocols.ObjectID[protocols.WlSeat]) { binds, ok := c.GlobalBinds[protocols.GlobalID_WlSeat] if !ok { return } delete(binds.(map[protocols.ObjectID[protocols.WlSeat]]protocols.Version), objectID) } func (c *Client) RemoveGlobalWlOutputBind(objectID protocols.ObjectID[protocols.WlOutput]) { binds, ok := c.GlobalBinds[protocols.GlobalID_WlOutput] if !ok { return } delete(binds.(map[protocols.ObjectID[protocols.WlOutput]]protocols.Version), objectID) } func (c *Client) RemoveGlobalWlKeyboardBind(objectID protocols.ObjectID[protocols.WlKeyboard]) { binds, ok := c.GlobalBinds[protocols.GlobalID_WlKeyboard] if !ok { return } delete(binds.(map[protocols.ObjectID[protocols.WlKeyboard]]protocols.Version), objectID) } func (c *Client) RemoveGlobalWlPointerBind(objectID protocols.ObjectID[protocols.WlPointer]) { binds, ok := c.GlobalBinds[protocols.GlobalID_WlPointer] if !ok { return } delete(binds.(map[protocols.ObjectID[protocols.WlPointer]]protocols.Version), objectID) } func (c *Client) RemoveGlobalWlTouchBind(objectID protocols.ObjectID[protocols.WlTouch]) { binds, ok := c.GlobalBinds[protocols.GlobalID_WlTouch] if !ok { return } delete(binds.(map[protocols.ObjectID[protocols.WlTouch]]protocols.Version), objectID) } func (c *Client) RemoveGlobalWlDataDeviceBind(objectID protocols.ObjectID[protocols.WlDataDevice]) { binds, ok := c.GlobalBinds[protocols.GlobalID_WlDataDevice] if !ok { return } delete(binds.(map[protocols.ObjectID[protocols.WlDataDevice]]protocols.Version), objectID) } func (c *Client) RemoveGlobalZwpXwaylandKeyboardGrabManagerV1Bind(objectID protocols.ObjectID[protocols.ZwpXwaylandKeyboardGrabManagerV1]) { binds, ok := c.GlobalBinds[protocols.GlobalID_ZwpXwaylandKeyboardGrabManagerV1] if !ok { return } delete(binds.(map[protocols.ObjectID[protocols.ZwpXwaylandKeyboardGrabManagerV1]]protocols.Version), objectID) } ================================================ FILE: wayland/CopyBufferToWlSurfaceTexture.go ================================================ package wayland import ( "fmt" "github.com/mmulet/term.everything/wayland/protocols" ) func CopyBufferToWlSurfaceTexture( s protocols.ClientState, surfaceID protocols.ObjectID[protocols.WlSurface], zIndex int, maybebufferID *protocols.ObjectID[protocols.WlBuffer], ) { surface := GetWlSurfaceObject(s, surfaceID) if maybebufferID == nil { delete(s.DrawableSurfaces(), surfaceID) /** * Time to remove the texture from the surface */ if surface == nil { return } surface.Texture = nil return } bufferId := *maybebufferID if surface == nil { return } pool := GetWlPoolObject_FromBuffer(s, bufferId) if pool == nil { fmt.Println("Could not get pool delegate; can't commit") return } if pool.MapState == MapStateDestroyed { fmt.Printf("Could not get pool.buffer_pointer; can't commit! pool %d buffer %d\n", pool.WlShmPoolObjectID, bufferId) return } bufferInfo, ok := pool.Buffers[bufferId] if !ok { fmt.Println("Could not get buffer_info; can't commit") return } x := surface.Offset.X y := surface.Offset.Y if surface.Role == nil { return } switch role := surface.Role.(type) { case *SurfaceRoleXdgPopup: return case *SurfaceRoleSubSurface: if role.Data != nil { sub_surface := GetWlSubsurfaceObject(s, *role.Data) if sub_surface != nil { x = sub_surface.Position.X y = sub_surface.Position.Y } /** * @TODO should this be relative to the parent? */ } case *SurfaceRoleXWaylandSurface: /** * @TODO */ fmt.Println("ON commit xwayland_surface_v1") case *SurfaceRoleXdgToplevel: if surface.XdgSurfaceState != nil { xdg_surface_state := GetXdgSurfaceObject(s, *surface.XdgSurfaceState) if xdg_surface_state != nil { // x = surface.xdg_surface_state.window_geometry.x; // y = surface.xdg_surface_state.window_geometry.y; // console.log( // "reposition xdg_toplevel, ", // x, // y, // "for surface", // surface_id // ); } } case *SurfaceRoleCursor: /** * @TODO is this right? */ if !role.HasData() { /** * From the docs: * When the use as a cursor ends, the wl_surface is unmapped * * So I think that means if it isn't a cursor anymore, * we should not draw it */ return } x += int32(Pointer.WindowX) + role.Data.Hotspot.X y += int32(Pointer.WindowY) + role.Data.Hotspot.Y } surface.Position.X = x surface.Position.Y = y surface.Position.Z = int32(zIndex) if surface.Texture != nil { if surface.Texture.Stride != uint32(bufferInfo.Stride) || surface.Texture.Width != uint32(bufferInfo.Width) || surface.Texture.Height != uint32(bufferInfo.Height) { surface.Texture = nil } } if surface.Texture == nil { size := int(bufferInfo.Stride) * int(bufferInfo.Height) if size < 0 { fmt.Println("Invalid buffer size; can't commit") return } surface.Texture = &Texture{ Stride: uint32(bufferInfo.Stride), Width: uint32(bufferInfo.Width), Height: uint32(bufferInfo.Height), Data: make([]byte, size), } } memMap, ok := pool.MemMaps[pool.WlShmPoolObjectID] if !ok { fmt.Println("No memmap for pool; can't commit") return } total := int(bufferInfo.Stride) * int(bufferInfo.Height) if total < 0 || total > len(surface.Texture.Data) { fmt.Println("Computed copy size out of bounds; can't commit") return } offset := int(bufferInfo.Offset) src := memMap.Bytes if offset < 0 || offset+total > len(src) { fmt.Println("Pool memory bounds error during copy; can't commit") return } copy(surface.Texture.Data, src[offset:offset+total]) s.DrawableSurfaces()[surfaceID] = true } ================================================ FILE: wayland/Desktop.go ================================================ package wayland import ( "bytes" "image" "image/draw" _ "image/png" "sort" "time" "github.com/mmulet/term.everything/wayland/protocols" ) type Desktop struct { Width int Height int Stride int // bytes per row (Width * 4) // Back buffer as image.RGBA (Pix backed by Buffer) Buffer []byte RGBA *image.RGBA IconImg *image.NRGBA CreatedAt time.Time WillShowAppRightAtStartup bool } func MakeDesktop(size Size, willShowAppRightAtStartup bool, iconPNG []byte) *Desktop { w := int(size.Width) h := int(size.Height) buf := make([]byte, w*h*4) cd := &Desktop{ Width: w, Height: h, Stride: w * 4, Buffer: buf, RGBA: &image.RGBA{ Pix: buf, Stride: w * 4, Rect: image.Rect(0, 0, w, h), }, CreatedAt: time.Now(), WillShowAppRightAtStartup: willShowAppRightAtStartup, } cd.IconImg = RgbaToBgra(DecodeIconToNRGBA(iconPNG)) return cd } func RgbaToBgra(src *image.NRGBA) *image.NRGBA { if src == nil { return nil } b := src.Bounds() dst := image.NewNRGBA(b) for y := b.Min.Y; y < b.Max.Y; y++ { for x := b.Min.X; x < b.Max.X; x++ { off := src.PixOffset(x, y) r := src.Pix[off+0] g := src.Pix[off+1] bb := src.Pix[off+2] a := src.Pix[off+3] dstOff := dst.PixOffset(x, y) dst.Pix[dstOff+0] = bb dst.Pix[dstOff+1] = g dst.Pix[dstOff+2] = r dst.Pix[dstOff+3] = a } } return dst } func DecodeIconToNRGBA(data []byte) *image.NRGBA { if len(data) == 0 { return nil } img, _, err := image.Decode(bytes.NewReader(data)) if err != nil { return nil } if rgba, ok := img.(*image.NRGBA); ok { return rgba } b := img.Bounds() rgba := image.NewNRGBA(b) draw.Draw(rgba, b, img, b.Min, draw.Src) return rgba } func (cd *Desktop) DrawImage(src image.Image, dx, dy int) { if src == nil { return } sb := src.Bounds() r := image.Rect(dx, dy, dx+sb.Dx(), dy+sb.Dy()) draw.Draw(cd.RGBA, r, src, sb.Min, draw.Over) } /* * If we will show an app right at startup, * we want to wait a bit before potentially * drawing the icon. Otherwise it will * flash the icon, and the show the app * content which is annoying. * */ func (cd *Desktop) AfterOpeningTimeout() bool { if !cd.WillShowAppRightAtStartup { return true } return time.Since(cd.CreatedAt) >= 500*time.Millisecond } func (cd *Desktop) Clear() { clear(cd.Buffer) } type SortedSurfaceEntry struct { Surface *WlSurface Src *image.RGBA SurfaceID protocols.ObjectID[protocols.WlSurface] } type SortedSurfaceEntryParentLocation struct { parentID protocols.ObjectID[protocols.WlSurface] x, y int } func (cd *Desktop) DrawClients(clients []*Client) { sorted := make([]SortedSurfaceEntry, 0, 64) childToParent := make(map[protocols.ObjectID[protocols.WlSurface]]SortedSurfaceEntryParentLocation) for _, c := range clients { if c == nil { continue } for surface_id := range c.DrawableSurfaces() { surface := GetWlSurfaceObject(c, surface_id) if surface == nil { continue } tex := surface.Texture.AsRGBA() if tex == nil { continue } for _, child := range surface.ChildrenInDrawOrder { if child == nil { continue } childToParent[*child] = SortedSurfaceEntryParentLocation{ parentID: surface_id, x: int(surface.Position.X), y: int(surface.Position.Y), } } sorted = append(sorted, SortedSurfaceEntry{ Surface: surface, Src: tex, SurfaceID: surface_id, }) } } sort.Slice(sorted, func(i, j int) bool { zi := sorted[i].Surface.Position.Z zj := sorted[j].Surface.Position.Z if zi == zj { return sorted[i].SurfaceID < sorted[j].SurfaceID } return zi < zj }) cd.Clear() if len(sorted) == 0 && cd.AfterOpeningTimeout() { cd.DrawImage(cd.IconImg, 0, 0) return } for _, it := range sorted { /** * Recursively get the position by adding * all ancestor position */ x := int(it.Surface.Position.X) y := int(it.Surface.Position.Y) parent, ok := childToParent[it.SurfaceID] for ok { x += parent.x y += parent.y parent, ok = childToParent[parent.parentID] } cd.DrawImage(it.Src, x, y) } } ================================================ FILE: wayland/GetMessageAnd_fileDescriptors.go ================================================ package wayland import ( "errors" "io" "net" "syscall" "time" ) const ( GetMessage_timeout = 1 * time.Millisecond GetMessage_maxFDsInCmsg = 10 // matches C++: CMSG_SPACE(sizeof(int) * 10) GetMessage_hardFDLimit = 255 // matches C++ guard in the copy loop GetMessage_intSizeBytes = 4 // sizeof(int) on Linux ) var oob = make([]byte, syscall.CmsgSpace(GetMessage_intSizeBytes*GetMessage_maxFDsInCmsg)) func GetMessageAndFileDescriptors(conn *net.UnixConn, buf []byte) (n int, fds []int, err error) { // 10ms "select"-style timeout if err := conn.SetReadDeadline(time.Now().Add(GetMessage_timeout)); err != nil { return 0, nil, err } defer conn.SetReadDeadline(time.Time{}) n, oobn, _, _, rerr := conn.ReadMsgUnix(buf, oob) // Timeout -> continue with no data/fds. if ne, ok := rerr.(net.Error); ok && ne.Timeout() { return 0, nil, nil } if rerr != nil { if errors.Is(rerr, io.EOF) { return n, nil, nil } // Treat as terminal like the C++ (returns false). return n, nil, rerr } if n == 0 { // EOF on stream return 0, nil, nil } // Parse as many rights as fit; ignore truncation like the C++. if oobn > 0 { if cmsgs, perr := syscall.ParseSocketControlMessage(oob[:oobn]); perr == nil { for _, cmsg := range cmsgs { if rights, rerr := syscall.ParseUnixRights(&cmsg); rerr == nil && len(rights) > 0 { fds = append(fds, rights...) if len(fds) >= GetMessage_hardFDLimit { fds = fds[:GetMessage_hardFDLimit] break } } } } } return n, fds, nil } ================================================ FILE: wayland/Globals.go ================================================ package wayland import "github.com/mmulet/term.everything/wayland/protocols" var Global_WlDisplay = MakeWLDisplay() var Global_WlOutput = MakeWlOutput() var Global_WlSeat = MakeWLSeat() var Global_WlShm = MakeWlShm() var Global_WlCompositor = MakeWlCompositor() var Global_WlSubcompositor = MakeWlSubcompositor() var Global_XdgWmBase = MakeXdgWmBase() var Global_WlDataDeviceManager = MakeWlDataDeviceManager() var Global_WlKeyboard = MakeWlKeyboard() var Global_WlPointer = &protocols.WlPointer{ Delegate: &Pointer, } var Global_ZwpXwaylandKeyboardGrabManagerV1 = MakeZwpXwaylandKeyboardGrabManagerV1() var Global_XwaylandShellV1 = MakeXwaylandShellV1() var Global_WlDataDevice = Global_WlSeat var Global_WlTouch = MakeWlTouch() var Global_ZxdgDecorationManagerV1 = MakeZxdgDecorationManagerV1() ================================================ FILE: wayland/InputEvents.go ================================================ package wayland import ( "sync" "time" "github.com/mmulet/term.everything/wayland/protocols" ) var ( serialMutex sync.Mutex nextSerial uint32 = 0 ) func GetNextEventSerial() uint32 { serialMutex.Lock() defer serialMutex.Unlock() nextSerial++ return nextSerial } func getNextSerial() uint32 { return GetNextEventSerial() } func SendPointerMotion(clients []*Client, x, y float32) { // Update global pointer position for cursor drawing Pointer.WindowX = x Pointer.WindowY = y timestamp := uint32(time.Now().UnixMilli()) for _, client := range clients { if client.Status != ClientStatus_Connected { continue } if pointerBinds := protocols.GetGlobalWlPointerBinds(client); pointerBinds != nil { for pointerID, version := range pointerBinds { protocols.WlPointer_motion(client, pointerID, timestamp, x, y) protocols.WlPointer_frame(client, uint32(version), pointerID) } } } } func SendPointerButton(clients []*Client, button uint32, pressed bool) { timestamp := uint32(time.Now().UnixMilli()) ser := getNextSerial() state := protocols.WlPointerButtonState_enum_released if pressed { state = protocols.WlPointerButtonState_enum_pressed } for _, client := range clients { if client.Status != ClientStatus_Connected { continue } if pointerBinds := protocols.GetGlobalWlPointerBinds(client); pointerBinds != nil { for pointerID, version := range pointerBinds { protocols.WlPointer_button(client, pointerID, ser, timestamp, button, state) protocols.WlPointer_frame(client, uint32(version), pointerID) } } } } func SendPointerAxis(clients []*Client, axis protocols.WlPointerAxis_enum, value float32) { timestamp := uint32(time.Now().UnixMilli()) for _, client := range clients { if client.Status != ClientStatus_Connected { continue } if pointerBinds := protocols.GetGlobalWlPointerBinds(client); pointerBinds != nil { for pointerID, version := range pointerBinds { protocols.WlPointer_axis(client, pointerID, timestamp, axis, value) protocols.WlPointer_frame(client, uint32(version), pointerID) } } } } func SendKeyboardKey(clients []*Client, key uint32, pressed bool) { timestamp := uint32(time.Now().UnixMilli()) ser := getNextSerial() state := protocols.WlKeyboardKeyState_enum_released if pressed { state = protocols.WlKeyboardKeyState_enum_pressed } for _, client := range clients { if client.Status != ClientStatus_Connected { continue } if keyboardBinds := protocols.GetGlobalWlKeyboardBinds(client); keyboardBinds != nil { for keyboardID := range keyboardBinds { protocols.WlKeyboard_key(client, keyboardID, ser, timestamp, key, state) } } } } ================================================ FILE: wayland/ListenToWaylandSocket.go ================================================ package wayland import ( "fmt" "net" ) func ListenToWaylandSocket(socketName string, socketPath string) (listner *net.UnixListener, fd int, e error) { if err := removeFileIfExists(socketPath); err != nil { return nil, -1, fmt.Errorf("remove existing socket: %w", err) } addr := &net.UnixAddr{ Name: socketPath, Net: "unix", } ln, err := net.ListenUnix("unix", addr) if err != nil { return nil, -1, fmt.Errorf("listen unix: %w", err) } file, err := ln.File() if err != nil { _ = ln.Close() return nil, -1, fmt.Errorf("get listener file: %w", err) } fd = int(file.Fd()) _ = file.Close() return ln, fd, nil } ================================================ FILE: wayland/MemMap.go ================================================ package wayland /* #include "mmap.h" */ import "C" import ( "fmt" "unsafe" ) type MemMapInfo struct { Bytes []byte Addr unsafe.Pointer Size C.size_t FileDescriptor C.int UnMapped bool } func NewMemMapInfo(fd int, size uint64) (MemMapInfo, error) { fdNum := C.int(fd) c_size := C.size_t(size) addr := C.mmap_fd(fdNum, c_size) if addr == C.map_failed() { return MemMapInfo{ Addr: addr, Size: c_size, FileDescriptor: fdNum, UnMapped: true, }, fmt.Errorf("failed to mmap fd %d", fdNum) } info := MemMapInfo{ Addr: addr, Size: c_size, FileDescriptor: fdNum, UnMapped: false, } info.Bytes = unsafe.Slice((*byte)(info.Addr), info.Size) return info, nil } func (m *MemMapInfo) Unmap() { if m.UnMapped { return } C.unmap(m.Addr, m.Size) m.UnMapped = true m.Bytes = nil } ================================================ FILE: wayland/MessageDecoder.go ================================================ package wayland import "github.com/mmulet/term.everything/wayland/protocols" const ( stateObjectID protocols.DecodeStateType = iota stateOpcode stateSize stateData ) func initialDecodeState() protocols.DecodeState { return protocols.DecodeState{ Phase: stateObjectID, I: 0, ObjectID: 0, Opcode: 0, Size: 0, Data: nil, } } type MessageDecoder struct { state protocols.DecodeState } func MakeMessageDecoder() *MessageDecoder { return &MessageDecoder{ state: initialDecodeState(), } } func (d *MessageDecoder) reset() { d.state = initialDecodeState() } func (d *MessageDecoder) nextState() { d.state.I = 0 switch d.state.Phase { case stateObjectID: d.state.Phase = stateOpcode d.state.Opcode = 0 case stateOpcode: d.state.Phase = stateSize d.state.Size = 0 case stateSize: d.state.Phase = stateData d.state.Data = d.state.Data[:0] // 8 is the header size; no payload means return to initial state if d.state.Size == 8 { d.reset() } case stateData: d.reset() } } func (d *MessageDecoder) Consume(buf []byte) []protocols.Message { out := make([]protocols.Message, 0) for _, b := range buf { switch d.state.Phase { case stateObjectID: d.state.ObjectID |= protocols.AnyObjectID(b) << d.state.I d.state.I += 8 if d.state.I == 32 { d.nextState() } case stateOpcode: d.state.Opcode |= uint16(b) << d.state.I d.state.I += 8 if d.state.I == 16 { d.nextState() } case stateSize: d.state.Size |= uint16(b) << d.state.I d.state.I += 8 if d.state.I == 16 { if d.state.Size == 8 { // zero-size payload message (header-only) out = append(out, protocols.Message{ ObjectID: d.state.ObjectID, Opcode: d.state.Opcode, Size: d.state.Size, Data: []byte{}, }) } d.nextState() } case stateData: d.state.Data = append(d.state.Data, b) // size includes 8-byte header, so payload length is size-8 want := int(d.state.Size) - 8 if len(d.state.Data) == want { // copy data to detach from internal buffer payload := make([]byte, want) copy(payload, d.state.Data) out = append(out, protocols.Message{ ObjectID: d.state.ObjectID, Opcode: d.state.Opcode, Size: d.state.Size, Data: payload, }) d.nextState() } } } return out } ================================================ FILE: wayland/Readme.md ================================================ In this package, we provide utilities for working with Wayland protocol over Unix domain sockets. This will hopefully be a reusable package for custom go Wayland compositors (that I will use at least). ================================================ FILE: wayland/SendMessageAndFileDescriptors.go ================================================ package wayland import ( "fmt" "net" "syscall" ) func SendMessageAndFileDescriptors(conn *net.UnixConn, buf []byte, fds []int) error { if len(buf) == 0 { return nil } total := 0 oobFirst := syscall.UnixRights(fds...) for total < len(buf) { chunk := buf[total:] var oob []byte if total == 0 { oob = oobFirst // send FDs only once } n, _, err := conn.WriteMsgUnix(chunk, oob, nil) if err != nil || n == -1 { var out_error error if err != nil { out_error = err } else { out_error = fmt.Errorf("N -1 on send message") } return out_error } total += n } return nil } ================================================ FILE: wayland/SocketListener.go ================================================ package wayland import ( "fmt" "net" "os" "path/filepath" "github.com/mmulet/term.everything/wayland/protocols" ) // SocketListener listens for new Wayland client connections on a Unix socket. // It provides a channel to receive new connections. Whoevere reads from // the channel is responsible for closing the connections when done. type SocketListener struct { WaylandDisplayName string SocketPath string Listener *net.UnixListener OnConnection chan *net.UnixConn } type HasDisplayName interface { WaylandDisplayName() string } func MakeSocketListener(args HasDisplayName) (*SocketListener, error) { displayName := GetWaylandDisplayName(args) socketPath := GetSocketPathFromName(displayName) if protocols.DebugRequests { fmt.Fprintf(os.Stderr, "Wayland socket path: %s\n", socketPath) } ln, fd, err := ListenToWaylandSocket(displayName, socketPath) if err != nil { return nil, fmt.Errorf("failed to listen on wayland socket: %w", err) } _ = fd w := &SocketListener{ WaylandDisplayName: displayName, SocketPath: socketPath, Listener: ln, OnConnection: make(chan *net.UnixConn, 32), } return w, nil } func (w *SocketListener) MainLoop() error { for { conn, err := w.Listener.AcceptUnix() if err != nil { return fmt.Errorf("failed to accept connection: %w", err) } w.OnConnection <- conn } } func (w *SocketListener) MainLoopThenClose() error { defer w.Close() return w.MainLoop() } func (w *SocketListener) Close() error { if w.Listener != nil { w.Listener.Close() } return removeFileIfExists(w.SocketPath) } func GetWaylandDisplayName(args HasDisplayName) string { if args.WaylandDisplayName() != "" { return args.WaylandDisplayName() } if v := os.Getenv("WAYLAND_DISPLAY_NAME"); v != "" { return v } for i := 2; i < 1000; i++ { name := fmt.Sprintf("wayland-%d", i) path := GetSocketPathFromName(name) if _, err := os.Stat(path); err == nil { continue } else if os.IsNotExist(err) { return name } else { continue } } fmt.Fprintf(os.Stderr, "Failed to find an open wayland socket name. Pass one with --wayland-display-name \n") os.Exit(1) return "" } func GetSocketPathFromName(socketName string) string { runtimeDir := os.Getenv("XDG_RUNTIME_DIR") if runtimeDir == "" { runtimeDir = "/tmp" } return filepath.Join(runtimeDir, socketName) } func removeFileIfExists(p string) error { if p == "" { return fmt.Errorf("empty path") } if _, err := os.Lstat(p); err != nil { if os.IsNotExist(err) { return nil } return err } return os.Remove(p) } ================================================ FILE: wayland/SurfaceRole.go ================================================ package wayland import "github.com/mmulet/term.everything/wayland/protocols" /** * Surface roles can be thought of as type. * [source ](https://wayland.app/protocols/wayland#wl_surface) * Things you may do: * 1. if unset you may assign it a role * 2. if assigned a role you may *not* change it to another role * 3. if assigned a role you may *may* assign it the *same* role * 4. The role may destroyed, allowing you assign it to the role again (maybe with different data), but not a different role. * 5. If the surface is destroyed before the role is destroyed, that is an error. */ type SurfaceRole interface { surface_role() HasData() bool ClearData() } type SurfaceRoleXdgPopup struct { Data *protocols.ObjectID[protocols.XdgPopup] } func (r *SurfaceRoleXdgPopup) surface_role() {} func (r *SurfaceRoleXdgPopup) HasData() bool { return r.Data != nil } func (r *SurfaceRoleXdgPopup) ClearData() { r.Data = nil } type CursorHotspot struct { X, Y int32 } type SurfaceRoleCursorData struct { Hotspot CursorHotspot } type SurfaceRoleCursor struct { Data *SurfaceRoleCursorData } func (r *SurfaceRoleCursor) surface_role() {} func (r *SurfaceRoleCursor) HasData() bool { return r.Data != nil } func (r *SurfaceRoleCursor) ClearData() { r.Data = nil } type ToplevelPendingState struct { MinSize *Size MaxSize *Size } type SurfaceRoleXdgToplevel struct { Data *protocols.ObjectID[protocols.XdgToplevel] } func (r *SurfaceRoleXdgToplevel) surface_role() {} func (r *SurfaceRoleXdgToplevel) HasData() bool { return r.Data != nil } func (r *SurfaceRoleXdgToplevel) ClearData() { r.Data = nil } type SurfaceRoleWaylandSurfaceData struct { Serial *XWaylandSurfaceV1Serial } type SurfaceRoleXWaylandSurface struct { Data *SurfaceRoleWaylandSurfaceData } func (r *SurfaceRoleXWaylandSurface) surface_role() {} func (r *SurfaceRoleXWaylandSurface) HasData() bool { return r.Data != nil } func (r *SurfaceRoleXWaylandSurface) ClearData() { r.Data = nil } type SurfaceRoleSubSurface struct { Data *protocols.ObjectID[protocols.WlSubsurface] } func (r *SurfaceRoleSubSurface) surface_role() {} func (r *SurfaceRoleSubSurface) HasData() bool { return r.Data != nil } func (r *SurfaceRoleSubSurface) ClearData() { r.Data = nil } ================================================ FILE: wayland/SurfaceUpdate.go ================================================ package wayland import "github.com/mmulet/term.everything/wayland/protocols" type SurfaceUpdate struct { Offset *Point Damage []Rect DamageBuffer []Rect BufferScale *int32 BufferTransform *protocols.WlOutputTransform_enum InputRegion *protocols.ObjectID[protocols.WlRegion] OpaqueRegion *protocols.ObjectID[protocols.WlRegion] Buffer *protocols.ObjectID[protocols.WlBuffer] /** * You should unshift when adding to * this array so that the objects will * be added in the correct order. (ie * the ones added last will be on top) */ AddSubSurface []protocols.ObjectID[protocols.WlSurface] XdgSurfaceWindowGeometry *XdgWindowGeometry /** * set_child_position and z_oder_subsurfaces * take place whenever the parent surface is committed, * thus they are part of the SurfaceUpdate of the parent */ SetChildPosition []ChildPosition /** * null means above or below the parent. */ ZOrderSubsurfaces []ZOrderSubsurface XwaylandSurfarfaceV1Serial *XWaylandSurfaceV1Serial } type Point struct { X int32 Y int32 } type Rect struct { X int32 Y int32 Width int32 Height int32 } // ChildPosition mirrors { child: Object_ID; x: number; y: number } type ChildPosition struct { Child protocols.ObjectID[protocols.WlSurface] X int32 Y int32 } type ZOrderSubsurface struct { Type ZOrder ChildToMove protocols.ObjectID[protocols.WlSurface] /** * nil means above or below the parent. */ RelativeTo *protocols.ObjectID[protocols.WlSurface] } type ZOrder int const ( ZOrderTypeAbove ZOrder = iota ZOrderTypeBelow ZOrder = iota + 1 ) type XWaylandSurfaceV1Serial struct { Low uint32 Hi uint32 } ================================================ FILE: wayland/VirtualMonitorSize.go ================================================ package wayland type Pixels int type PixelSize struct { Width Pixels Height Pixels } var VirtualMonitorSize = PixelSize{ Width: 640, Height: 480, } ================================================ FILE: wayland/doc.go ================================================ // Package wayland provides a pure Go implementation of a Wayland compositor. // // This package allows you to create Wayland servers that can host Wayland clients // (such as browsers, terminals, and other applications) and render their output // to your own display surface. // // # Basic Usage // // To create a Wayland compositor, you need to: // // 1. Create a socket listener with [MakeSocketListener] // 2. Accept client connections // 3. Handle frame requests and render client surfaces // // # Minimal Example // // First, implement the args interface to provide the display name: // // type Args struct { // DisplayName string // } // // func (a *Args) WaylandDisplayName() string { // return a.DisplayName // empty string auto-generates a name // } // // Create the socket listener and start accepting connections: // // args := &Args{DisplayName: ""} // listener, err := wayland.MakeSocketListener(args) // if err != nil { // log.Fatal(err) // } // go listener.MainLoopThenClose() // // // Track connected clients // var clients []*wayland.Client // var mu sync.Mutex // // // Accept new client connections // go func() { // for conn := range listener.OnConnection { // client := wayland.MakeClient(conn) // mu.Lock() // clients = append(clients, client) // mu.Unlock() // go client.MainLoop() // go handleFrameRequests(client) // } // }() // // Handle frame callbacks to know when clients want to redraw: // // func handleFrameRequests(client *wayland.Client) { // for callbackID := range client.FrameDrawRequests { // protocols.WlCallback_done(client, callbackID, uint32(time.Now().UnixMilli())) // if client.Status != wayland.ClientStatus_Connected { // break // } // // Signal your render loop that a redraw is needed // } // } // // Create a desktop for compositing and render in your main loop: // // desktop := wayland.MakeDesktop( // wayland.Size{Width: 800, Height: 600}, // false, // useLinuxDMABuf // iconPNG, // icon data for the desktop // ) // // // In your render loop: // desktop.DrawClients(clients) // // desktop.Buffer now contains RGBA pixel data // // desktop.Stride is the row stride in bytes // // Forward input events to clients: // // // Mouse movement (x, y in surface coordinates) // wayland.SendPointerMotion(clients, float32(x), float32(y)) // // // Mouse buttons (use Linux BTN_LEFT=0x110, BTN_RIGHT=0x111, etc.) // wayland.SendPointerButton(clients, 0x110, true) // pressed // wayland.SendPointerButton(clients, 0x110, false) // released // // // Mouse scroll (axis: protocols.WlPointerAxis_enum_vertical_scroll) // wayland.SendPointerAxis(clients, protocols.WlPointerAxis_enum_vertical_scroll, 15.0) // // // Keyboard (use Linux evdev keycodes, e.g., 30 for 'A') // wayland.SendKeyboardKey(clients, 30, true) // key down // wayland.SendKeyboardKey(clients, 30, false) // key up // // Launch a Wayland client with the correct environment: // // cmd := exec.Command("weston-terminal") // cmd.Env = append(os.Environ(), // "WAYLAND_DISPLAY="+listener.WaylandDisplayName, // "XDG_SESSION_TYPE=wayland", // ) // cmd.Start() package wayland ================================================ FILE: wayland/generate/Protocol.go ================================================ package main import ( "encoding/xml" "fmt" "strings" ) func ToPascalCase(s string) string { parts := strings.FieldsFunc(s, func(r rune) bool { return r == '_' }) for i, part := range parts { if len(part) > 0 { parts[i] = strings.ToUpper(part[:1]) + strings.ToLower(part[1:]) } } return strings.Join(parts, "") } func enumName(interfaceName, enumNameWithDot string) string { newEnumName := enumNameWithDot if !strings.Contains(enumNameWithDot, ".") { newEnumName = interfaceName + newEnumName } parts := strings.FieldsFunc(newEnumName, func(r rune) bool { return r == '.' }) for i, part := range parts { if len(part) > 0 { parts[i] = strings.ToUpper(part[:1]) + part[1:] } } newEnumName = strings.Join(parts, "") return newEnumName + "_enum" } type Protocol struct { XMLName xml.Name `xml:"protocol"` Name string `xml:"name,attr"` Interfaces []Interface `xml:"interface"` Copyright string `xml:"copyright"` } type InterfaceAttr struct { Name string `xml:"name,attr"` Version string `xml:"version,attr"` } type Interface struct { InterfaceAttr Description any `xml:"description"` Requests []EventOrRequest `xml:"request"` Events []EventOrRequest `xml:"event"` Enums []Enum `xml:"enum"` } type Description struct { Summary string `xml:"summary,attr"` } type Enum struct { Name string `xml:"name,attr"` Entries []Entry `xml:"entry"` } type Entry struct { Name string `xml:"name,attr"` Value string `xml:"value,attr"` Summary string `xml:"summary,attr"` } type EventOrRequestAttr struct { Name string `xml:"name,attr"` Since *string `xml:"since,attr,omitempty"` } type EventOrRequest struct { EventOrRequestAttr Args []Arg `xml:"arg"` Description *Description `xml:"description"` } type Arg interface { ArgKind() string Name() string } type ArgCommon struct { ArgName string } func (c ArgCommon) Name() string { return c.ArgName } type ArgNewID struct { ArgCommon Interface *string } func (*ArgNewID) ArgKind() string { return "new_id" } type ArgObject struct { ArgCommon Interface *string AllowNull *bool } func (*ArgObject) ArgKind() string { return "object" } type ArgUint struct { ArgCommon Enum *string } func (*ArgUint) ArgKind() string { return "uint" } type ArgString struct { ArgCommon AllowNull *bool } func (*ArgString) ArgKind() string { return "string" } type ArgInt struct { ArgCommon } func (*ArgInt) ArgKind() string { return "int" } type ArgFd struct { ArgCommon } func (*ArgFd) ArgKind() string { return "fd" } type ArgFixed struct { ArgCommon } func (*ArgFixed) ArgKind() string { return "fixed" } type ArgArray struct { ArgCommon } func (*ArgArray) ArgKind() string { return "array" } func sanitizedArgName(arg Arg) string { switch arg.Name() { case "interface": return "interface_" case "class": return "class_" case "make": return "make_" default: return arg.Name() } } type argXML struct { Name string `xml:"name,attr"` Type string `xml:"type,attr"` Interface *string `xml:"interface,attr"` AllowNull *bool `xml:"allow-null,attr"` Enum *string `xml:"enum,attr"` } type eventOrRequestXML struct { Name string `xml:"name,attr"` Since *string `xml:"since,attr,omitempty"` Description *Description `xml:"description"` Args []argXML `xml:"arg"` } type interfaceXML struct { InterfaceAttr Description any `xml:"description"` Requests []eventOrRequestXML `xml:"request"` Events []eventOrRequestXML `xml:"event"` Enums []Enum `xml:"enum"` } type protocolXML struct { XMLName xml.Name `xml:"protocol"` Name string `xml:"name,attr"` Interfaces []interfaceXML `xml:"interface"` Copyright string `xml:"copyright"` } func convertEventOrRequestXML(x eventOrRequestXML) (EventOrRequest, error) { out := EventOrRequest{ EventOrRequestAttr: EventOrRequestAttr{ Name: x.Name, Since: x.Since, }, Description: x.Description, Args: make([]Arg, 0, len(x.Args)), } for _, ax := range x.Args { var a Arg switch ax.Type { case "new_id": var iface *string if ax.Interface != nil { ifaceStr := ToPascalCase(*ax.Interface) iface = &ifaceStr } a = &ArgNewID{ ArgCommon: ArgCommon{ArgName: ax.Name}, Interface: iface, } case "object": var iface *string if ax.Interface != nil { ifaceStr := ToPascalCase(*ax.Interface) iface = &ifaceStr } a = &ArgObject{ ArgCommon: ArgCommon{ArgName: ax.Name}, Interface: iface, AllowNull: ax.AllowNull, } case "uint": var enum *string if ax.Enum != nil { enumStr := ToPascalCase(*ax.Enum) enum = &enumStr } a = &ArgUint{ ArgCommon: ArgCommon{ArgName: ax.Name}, Enum: enum, } case "string": a = &ArgString{ ArgCommon: ArgCommon{ArgName: ax.Name}, AllowNull: ax.AllowNull, } case "int": a = &ArgInt{ArgCommon: ArgCommon{ArgName: ax.Name}} case "fd": a = &ArgFd{ArgCommon: ArgCommon{ArgName: ax.Name}} case "fixed": a = &ArgFixed{ArgCommon: ArgCommon{ArgName: ax.Name}} case "array": a = &ArgArray{ArgCommon: ArgCommon{ArgName: ax.Name}} default: return EventOrRequest{}, fmt.Errorf("unknown arg type: %q", ax.Type) } out.Args = append(out.Args, a) } return out, nil } func UnmarshalProtocolXML(data []byte) (*Protocol, error) { var tmp protocolXML if err := xml.Unmarshal(data, &tmp); err != nil { return nil, err } out := &Protocol{ XMLName: tmp.XMLName, Name: tmp.Name, Copyright: tmp.Copyright, } out.Interfaces = make([]Interface, len(tmp.Interfaces)) for i, ix := range tmp.Interfaces { out_enums := make([]Enum, len(ix.Enums)) for j, ex := range ix.Enums { out_enums[j] = Enum{ Name: ToPascalCase(ex.Name), Entries: ex.Entries, } } iface := Interface{ InterfaceAttr: InterfaceAttr{ Name: ToPascalCase(ix.Name), Version: ix.Version, }, Description: ix.Description, Enums: out_enums, Requests: make([]EventOrRequest, len(ix.Requests)), Events: make([]EventOrRequest, len(ix.Events)), } for j, rx := range ix.Requests { ev, err := convertEventOrRequestXML(rx) if err != nil { return nil, fmt.Errorf("interface %q request %d (%s): %w", ix.Name, j, rx.Name, err) } iface.Requests[j] = ev } for j, ex := range ix.Events { ev, err := convertEventOrRequestXML(ex) if err != nil { return nil, fmt.Errorf("interface %q event %d (%s): %w", ix.Name, j, ex.Name, err) } iface.Events[j] = ev } out.Interfaces[i] = iface } return out, nil } func generateGoType(interfaceName string, a Arg, event bool) string { name := sanitizedArgName(a) switch v := a.(type) { case *ArgNewID: if v.Interface != nil { return fmt.Sprintf("%s ObjectID[%s]", name, *v.Interface) } return fmt.Sprintf("%sInterface string, %sVersion uint32, %sID AnyObjectID", name, name, name) case *ArgObject: if v.Interface != nil { if v.AllowNull != nil && *v.AllowNull { return fmt.Sprintf("%s *ObjectID[%s]", name, *v.Interface) } return fmt.Sprintf("%s ObjectID[%s]", name, *v.Interface) } return fmt.Sprintf("%s AnyObjectID", name) case *ArgUint: if v.Enum == nil { return fmt.Sprintf("%s uint32", name) } return fmt.Sprintf("%s %s", name, enumName(interfaceName, *v.Enum)) case *ArgString: return fmt.Sprintf("%s string", name) case *ArgInt: return fmt.Sprintf("%s int32", name) case *ArgFd: if event { return fmt.Sprintf("%s FileDescriptor", name) } return fmt.Sprintf("%s *FileDescriptor", name) case *ArgFixed: if event { // TODO is this right? return fmt.Sprintf("%s float32", name) } return fmt.Sprintf("%s Fixed", name) case *ArgArray: return fmt.Sprintf("%s []byte", name) default: panic(fmt.Errorf("unknown arg kind: %T", a)) } } ================================================ FILE: wayland/generate/build_protocol.go ================================================ package main import ( "bytes" "embed" "fmt" "path/filepath" "slices" "strings" "text/template" ) type BuildProtocolOut struct { ProtocolFile string HelperFile string } func buildProtocol(fs embed.FS, file string, protocolsPackageNameForHelper string, interfacesToGenHelpersFor []string) (BuildProtocolOut, error) { data, err := fs.ReadFile(filepath.Join("resources", file)) if err != nil { return BuildProtocolOut{}, err } proto, err := UnmarshalProtocolXML(data) if err != nil { return BuildProtocolOut{}, fmt.Errorf("unmarshal %s: %w", file, err) } var out strings.Builder var helperOut strings.Builder helperTemplate := template.Must(template.New("helperGetObject").Parse(` func Get{{.Name}}Object(cs {{.Pkg}}ClientState, id {{.Pkg}}ObjectID[{{.Pkg}}{{.Name}}]) *{{.Name}} { v := cs.GetObject({{.Pkg}}AnyObjectID(id)) if v == nil { return nil } o := v.({{.Pkg}}WaylandObject[{{.Pkg}}{{.Name}}_delegate]) d := o.GetDelegate() return d.(*{{.Name}}) } `)) for _, intf := range proto.Interfaces { fmt.Fprintf(&out, "type %s_delegate interface {\n", intf.Name) out.WriteString(genInterfaceInterface(intf)) out.WriteString("}\n\n") fmt.Fprintf(&out, "type %s struct {\n", intf.Name) fmt.Fprintf(&out, " Delegate %s_delegate\n", intf.Name) out.WriteString("}\n\n") get_delegate_template := `func (p *%s) GetDelegate() %s_delegate { return p.Delegate } ` fmt.Fprintf(&out, get_delegate_template, intf.Name, intf.Name) get_bindable_template := `func (p *%s) GetBindable() OnBindable { return p.Delegate } ` fmt.Fprintf(&out, get_bindable_template, intf.Name) // get_object_template := ` // func Get%sObject(cs ClientState, id ObjectID[%s]) WaylandObject[%s_delegate] { // v := cs.GetObject(AnyObjectID(id)) // if v == nil { // return nil // } // return v.(WaylandObject[%s_delegate]) // } // ` // fmt.Fprintf(&out, get_object_template, intf.Name, intf.Name, intf.Name, intf.Name) // out.WriteString("\n") out.WriteString(genEvents(intf)) out.WriteString("\n") requestHandler := genRequestHandler(intf) fmt.Fprintf(&out, "func (p *%s) OnRequest(s FileDescriptorClaimClientState, message Message) {\n", intf.Name) if requestHandler != "" { out.WriteString(" _data_in_offset__ := 0\n") out.WriteString(" _ = _data_in_offset__\n") out.WriteString(" d := p.Delegate\n") } out.WriteString(" switch message.Opcode {\n") out.WriteString(requestHandler) out.WriteString(" default:\n") fmt.Fprintf(&out, " fmt.Println(\"Unknown opcode on %s\", message.Opcode)\n", intf.Name) out.WriteString(" }\n") out.WriteString("}\n\n") out.WriteString(genEnums(intf)) out.WriteString("\n") if len(interfacesToGenHelpersFor) == 0 || slices.Contains(interfacesToGenHelpersFor, intf.Name) { var buf bytes.Buffer _ = helperTemplate.Execute(&buf, struct { Name string Pkg string }{ Name: intf.Name, Pkg: filepath.Base(protocolsPackageNameForHelper) + ".", }) helperOut.WriteString(buf.String()) helperOut.WriteString("\n") } } return BuildProtocolOut{ ProtocolFile: out.String(), HelperFile: helperOut.String(), }, nil } ================================================ FILE: wayland/generate/gen_enums.go ================================================ package main import ( "fmt" "strings" "unicode" ) func genEnums(intf Interface) string { if len(intf.Enums) == 0 { return "" } var b strings.Builder for _, en := range intf.Enums { enumType := enumName(intf.Name, en.Name) fmt.Fprintf(&b, "type %s uint32\n\n", enumType) if len(en.Entries) > 0 { b.WriteString("const (\n") for _, e := range en.Entries { constName := sanitizeConstName(e.Name) fullName := enumType + "_" + constName fmt.Fprintf(&b, " %s %s = %s\n", fullName, enumType, e.Value) } b.WriteString(")\n\n") } } return b.String() } func sanitizeConstName(s string) string { if s == "" { return "_" } var out strings.Builder for i, r := range s { switch { case i == 0 && unicode.IsDigit(r): out.WriteRune('_') out.WriteRune(r) case (i == 0 && (unicode.IsLetter(r) || r == '_')) || (i > 0 && (unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_')): out.WriteRune(r) default: out.WriteRune('_') } } id := out.String() switch id { case "break", "default", "func", "interface", "select", "case", "defer", "go", "map", "struct", "chan", "else", "goto", "package", "switch", "const", "fallthrough", "if", "range", "type", "continue", "for", "import", "return", "var": return id + "_" } return id } ================================================ FILE: wayland/generate/gen_events.go ================================================ package main import ( "fmt" "strings" ) func genEvents(i Interface) string { if len(i.Events) == 0 { return "" } var out strings.Builder for idx, ev := range i.Events { var argSig []string for _, a := range ev.Args { argSig = append(argSig, generateGoType(i.Name, a, true)) } out.WriteString("\n") out.WriteString(fmt.Sprintf("func %s_%s(", i.Name, ev.Name)) out.WriteString("s Sender, ") if ev.Since != nil && *ev.Since != "" { out.WriteString("boundVersion uint32, ") } out.WriteString(fmt.Sprintf("eventObjectID ObjectID[%s]", i.Name)) if len(argSig) > 0 { out.WriteString(", ") out.WriteString(strings.Join(argSig, ", ")) } out.WriteString(") {\n") if ev.Since != nil && *ev.Since != "" { out.WriteString(fmt.Sprintf(" if boundVersion < %s {\n", *ev.Since)) out.WriteString(" // Event not available in this version; skip\n") out.WriteString(" return\n") out.WriteString(" }\n") } needUint32, needInt32 := false, false for _, a := range ev.Args { switch a.(type) { case *ArgFixed: needInt32 = true case *ArgInt: needInt32 = true case *ArgUint, *ArgNewID, *ArgObject: needUint32 = true case *ArgString, *ArgArray: needUint32 = true case *ArgFd: } } out.WriteString(" data := make([]byte, 0)\n") if needUint32 { out.WriteString(" putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) }\n") } if needInt32 { if needUint32 { out.WriteString(" putInt32 := func(v int32) { putUint32(uint32(v)) }\n") } else { out.WriteString(" putInt32 := func(v int32) { uv := uint32(v); data = append(data, byte(uv), byte(uv>>8), byte(uv>>16), byte(uv>>24)) }\n") } } out.WriteString(" var fileDescriptor *FileDescriptor\n") for _, a := range ev.Args { name := sanitizedArgName(a) switch v := a.(type) { case *ArgFixed: out.WriteString(fmt.Sprintf(" // fixed: 24.8\n putInt32(int32(%s * 256.0))\n", name)) case *ArgInt: out.WriteString(fmt.Sprintf(" putInt32(int32(%s))\n", name)) case *ArgUint: out.WriteString(fmt.Sprintf(" putUint32(uint32(%s))\n", name)) case *ArgNewID: out.WriteString(fmt.Sprintf(" putUint32(uint32(%s))\n", name)) case *ArgObject: if v.Interface != nil && v.AllowNull != nil && *v.AllowNull { tmp := "__tmp_" + name out.WriteString(fmt.Sprintf(" var %s uint32\n", tmp)) out.WriteString(fmt.Sprintf(" if %s != nil { %s = uint32(*%s) }\n", name, tmp, name)) out.WriteString(fmt.Sprintf(" putUint32(%s)\n", tmp)) } else { out.WriteString(fmt.Sprintf(" putUint32(uint32(%s))\n", name)) } case *ArgFd: out.WriteString(fmt.Sprintf(" fileDescriptor = &%s\n", name)) case *ArgString: out.WriteString(fmt.Sprintf( " {\n"+ " b := []byte(%s)\n"+ " total := len(b) + 1 // include null terminator\n"+ " putUint32(uint32(total))\n"+ " data = append(data, b...)\n"+ " data = append(data, 0)\n"+ " if pad := (4 - (total %% 4)) %% 4; pad != 0 {\n"+ " data = append(data, make([]byte, pad)...)\n"+ " }\n"+ " }\n", name)) case *ArgArray: out.WriteString(fmt.Sprintf( " {\n"+ " n := len(%s)\n"+ " putUint32(uint32(n))\n"+ " data = append(data, %s...)\n"+ " if pad := (4 - (n %% 4)) %% 4; pad != 0 {\n"+ " data = append(data, make([]byte, pad)...)\n"+ " }\n"+ " }\n", name, name)) default: out.WriteString(fmt.Sprintf(" // TODO: unhandled arg kind: %T\n", a)) } } out.WriteString(" obj := OutgoingEvent{\n") out.WriteString(" ObjectID: AnyObjectID(eventObjectID),\n") out.WriteString(fmt.Sprintf(" Opcode: %d,\n", idx)) out.WriteString(" Data: data,\n") out.WriteString(" FileDescriptor: fileDescriptor,\n") out.WriteString(" }\n") out.WriteString(" s.Send(obj)\n") out.WriteString("}\n") } return out.String() } ================================================ FILE: wayland/generate/gen_interface_interface.go ================================================ package main import ( "fmt" "strings" ) func genInterfaceInterface(iface Interface) string { on_bind_declaration := "OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32)\n" if len(iface.Requests) == 0 { return on_bind_declaration } var b strings.Builder for _, req := range iface.Requests { params := []string{ "s ClientState", fmt.Sprintf("object_id ObjectID[%s]", iface.Name), } for _, a := range req.Args { params = append(params, generateGoType(iface.Name, a, false)) } methodName := fmt.Sprintf("%s_%s", iface.Name, req.Name) signature := fmt.Sprintf("%s(%s)", methodName, strings.Join(params, ", ")) if req.Name == "destroy" || req.Name == "release" { signature += " bool" } b.WriteString(signature) b.WriteByte('\n') } // b.WriteString(fmt.Sprintf( // // "%s_on_bind(s ClientState, name ObjectID[%s], interface_ string, new_id ObjectID[%s], version_number uint32)\n", // "%s_on_bind(s ClientState, name ObjectID[%s], interface_ string, new_id ObjectID[%s], version_number uint32)\n", // iface.Name, iface.Name, iface.Name, // )) b.WriteString(on_bind_declaration) switch iface.Name { case "WlKeyboard": b.WriteString("AfterGetKeyboard(s ClientState, object_id ObjectID[WlKeyboard])\n") case "WlPointer": b.WriteString("AfterGetPointer(s ClientState, object_id ObjectID[WlPointer])\n") } return b.String() } ================================================ FILE: wayland/generate/gen_request_handler.go ================================================ package main import ( "fmt" "strings" ) func argFlatmap(a Arg, postfix string) []string { switch v := a.(type) { case *ArgNewID: if v.Interface == nil { base := sanitizedArgName(a) return []string{ base + "Interface" + postfix, base + "Version" + postfix, base + "ID" + postfix, } } } return []string{sanitizedArgName(a) + postfix} } func genRequestHandler(i Interface) string { if len(i.Requests) == 0 { return "" } var out strings.Builder for idx, req := range i.Requests { var argList []string for _, a := range req.Args { argList = append(argList, argFlatmap(a, "")...) } var debugPieces []string for _, a := range req.Args { for _, nm := range argFlatmap(a, "") { debugPieces = append(debugPieces, fmt.Sprintf("\"%s: \", %s", nm, nm)) } } debugArgs := "" if len(debugPieces) > 0 { debugArgs = strings.Join(debugPieces, ", \", \", ") } else { debugArgs = "\")\"" } isAutoRemove := req.Name == "release" || req.Name == "destroy" fmt.Fprintf(&out, "case %d: {\n\n", idx) for _, a := range req.Args { out.WriteString(genArgParseCode(a, i.Name)) out.WriteString("\n") } out.WriteString("if DebugRequests {\n") fmt.Fprintf(&out, " fmt.Print(\"%s@\", message.ObjectID, \".%s(\")\n", i.Name, req.Name) if len(debugPieces) > 0 { fmt.Fprintf(&out, " fmt.Println(%s, \")\")\n", debugArgs) } else { out.WriteString(" fmt.Println(\")\")\n") } out.WriteString("}\n\n") call := fmt.Sprintf("d.%s_%s(s, ObjectID[%s](message.ObjectID), %s)", i.Name, req.Name, i.Name, strings.Join(argList, ", ")) if isAutoRemove { fmt.Fprintf(&out, "autoRemove := %s\n", call) } else { fmt.Fprintf(&out, "%s\n", call) } if req.Name == "release" { out.WriteString("if autoRemove {\n") out.WriteString(" s.RemoveObject(message.ObjectID)\n") switch i.Name { case "WlShm", "WlSeat", "WlOutput", "WlKeyboard", "WlPointer", "WlTouch", "WlDataDevice", "ZwpXwaylandKeyboardGrabManagerV1": fmt.Fprintf(&out, " s.RemoveGlobal%sBind(ObjectID[%s](message.ObjectID))\n", i.Name, i.Name) } out.WriteString("}\n") } if req.Name == "destroy" { out.WriteString("if autoRemove {\n") out.WriteString(" s.RemoveObject(message.ObjectID)\n") out.WriteString("}\n") } out.WriteString("break\n") out.WriteString("}\n\n") } return out.String() } func genArgParseCode(a Arg, interfaceName string) string { name := sanitizedArgName(a) switch v := a.(type) { case *ArgFixed: return fmt.Sprintf(`%sRaw := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 %s := float64(int32(%sRaw)) / 256.0 _data_in_offset__ += 4 `, name, name, name) case *ArgNewID: if v.Interface == nil { return genArgParseCode(&ArgString{ArgCommon: ArgCommon{ArgName: name + "Interface"}}, interfaceName) + genArgParseCode(&ArgUint{ArgCommon: ArgCommon{ArgName: name + "Version"}}, interfaceName) + genArgParseCode(&ArgObject{ArgCommon: ArgCommon{ArgName: name + "ID"}}, interfaceName) } return fmt.Sprintf(`%sVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 %s := ObjectID[%s](%sVal) _data_in_offset__ += 4 `, name, name, *v.Interface, name) case *ArgUint: if v.Enum != nil { return fmt.Sprintf(`%s := %s(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 `, name, enumName(interfaceName, *v.Enum)) } return fmt.Sprintf(`%s := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 `, name) case *ArgInt: return fmt.Sprintf(`%s := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 `, name) case *ArgObject: if v.Interface != nil { if v.AllowNull != nil && *v.AllowNull { return fmt.Sprintf(`%sTmp := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 var %s *ObjectID[%s] if %sTmp != 0 { tmp := ObjectID[%s](%sTmp) %s = &tmp } `, name, name, *v.Interface, name, *v.Interface, name, name) } return fmt.Sprintf(`%s := ObjectID[%s](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 `, name, *v.Interface) } return fmt.Sprintf(`%s := AnyObjectID(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 `, name) case *ArgString: return fmt.Sprintf(`%sLen := int(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 %s := string(message.Data[_data_in_offset__ : _data_in_offset__+%sLen-1]) // NUL-terminated // 4-byte alignment if %sLen%%4 != 0 { _data_in_offset__ += %sLen + (4 - (%sLen %% 4)) } else { _data_in_offset__ += %sLen } `, name, name, name, name, name, name, name) case *ArgArray: return fmt.Sprintf(`%sLen := int(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 %s := message.Data[_data_in_offset__ : _data_in_offset__+%sLen] if %sLen%%4 != 0 { _data_in_offset__ += %sLen + (4 - (%sLen %% 4)) } else { _data_in_offset__ += %sLen } `, name, name, name, name, name, name, name) case *ArgFd: return fmt.Sprintf(`%s := s.ClaimFileDescriptor() `, name) default: panic(fmt.Errorf("unknown arg kind: %T", a)) } } ================================================ FILE: wayland/generate/protocols.go ================================================ package main import ( "embed" "fmt" "go/format" "log" "os" "path/filepath" "sort" "sync" ) //go:embed resources var protocolsFS embed.FS func main() { var outDir string if len(os.Args) > 1 { outDir = os.Args[1] } else { log.Fatal(`Usage: protocols protocol_out_dir [helpers_out_dir protocols_package ...interfaces] Generates protocol bindings into protocol_out_dir Optionally, generate helper functions into helpers_out_dir Output helper function into helpers_out_dir (usually want this be a different package than protocols) So if so, also provide protocols_package as the package name for protocols package like github.com/mmulet/term.everything/wayland/protocols If you omit this we'll assume the helpers are in the same package as protocols If you provide interfaces, we'll only generate those those helpers. separated by space. `) } var helpersOutDir string if len(os.Args) > 2 { helpersOutDir = os.Args[2] } var currentDirInPackage string if len(os.Args) > 3 { currentDirInPackage = os.Args[3] } else { currentDirInPackage = "wayland/protocols" } fmt.Println(currentDirInPackage) protocolsPackage := filepath.Join(currentDirInPackage, outDir) protocolsPackage = filepath.Clean(protocolsPackage) fmt.Println(protocolsPackage) var interfacesToGenHelpersFor []string if len(os.Args) > 4 { for i := 4; i < len(os.Args); i++ { interfacesToGenHelpersFor = append(interfacesToGenHelpersFor, os.Args[i]) } } entries, err := protocolsFS.ReadDir("resources") if err != nil { log.Fatalf("read embedded dir resources: %v", err) } var files []string for _, e := range entries { if e.IsDir() { continue } files = append(files, e.Name()) } sort.Strings(files) results := make([]BuildProtocolOut, len(files)) var wg sync.WaitGroup errOnce := make(chan error, 1) for i, f := range files { wg.Add(1) go func(idx int, file string) { defer wg.Done() out, err := buildProtocol(protocolsFS, file, protocolsPackage, interfacesToGenHelpersFor) if err != nil { select { case errOnce <- err: default: } return } results[idx] = out }(i, f) } wg.Wait() select { case e := <-errOnce: log.Fatal(e) default: } writeOutputFiles := func(outDir string, results []BuildProtocolOut, helper bool) { pkg := filepath.Base(outDir) var additionalImport string if helper { additionalImport = fmt.Sprintf(`import "%s"`, protocolsPackage) } else { additionalImport = `import "fmt"` } outFile := fmt.Sprintf(`// Code generated by `+"`cmd/protocols`"+`; DO NOT EDIT. package %s `, pkg) if err := os.MkdirAll(outDir, 0755); err != nil { log.Fatalf("create dir %s: %v", outDir, err) } for i, s := range results { var out string var dest string if helper { if s.HelperFile == "" { out = outFile } else { out = outFile + additionalImport + "\n" + s.HelperFile } dest = filepath.Join(outDir, filepath.Base(files[i])+".helper.go") } else { out = outFile + additionalImport + "\n" + s.ProtocolFile dest = filepath.Join(outDir, filepath.Base(files[i])+".go") } formatted, err := format.Source([]byte(out)) if err != nil { log.Fatalf("format %s: %v", dest, err) } if err := os.WriteFile(dest, formatted, 0o644); err != nil { log.Fatalf("write %s: %v", dest, err) } fmt.Println("wrote", dest) } } writeOutputFiles(outDir, results, false) if helpersOutDir == "" { return } helpersOutDir, err = filepath.Abs(helpersOutDir) if err != nil { log.Fatalf("abs path for helpersOutDir: %v", err) } print("Generating helpers into ", helpersOutDir, "\n") writeOutputFiles(helpersOutDir, results, true) } ================================================ FILE: wayland/generate/resources/wayland.xml ================================================ Copyright © 2008-2011 Kristian Høgsberg Copyright © 2010-2011 Intel Corporation Copyright © 2012-2013 Collabora, Ltd. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. The core global object. This is a special singleton object. It is used for internal Wayland protocol features. The sync request asks the server to emit the 'done' event on the returned wl_callback object. Since requests are handled in-order and events are delivered in-order, this can be used as a barrier to ensure all previous requests and the resulting events have been handled. The object returned by this request will be destroyed by the compositor after the callback is fired and as such the client must not attempt to use it after that point. The callback_data passed in the callback is undefined and should be ignored. This request creates a registry object that allows the client to list and bind the global objects available from the compositor. It should be noted that the server side resources consumed in response to a get_registry request can only be released when the client disconnects, not when the client side proxy is destroyed. Therefore, clients should invoke get_registry as infrequently as possible to avoid wasting memory. The error event is sent out when a fatal (non-recoverable) error has occurred. The object_id argument is the object where the error occurred, most often in response to a request to that object. The code identifies the error and is defined by the object interface. As such, each interface defines its own set of error codes. The message is a brief description of the error, for (debugging) convenience. These errors are global and can be emitted in response to any server request. This event is used internally by the object ID management logic. When a client deletes an object that it had created, the server will send this event to acknowledge that it has seen the delete request. When the client receives this event, it will know that it can safely reuse the object ID. The singleton global registry object. The server has a number of global objects that are available to all clients. These objects typically represent an actual object in the server (for example, an input device) or they are singleton objects that provide extension functionality. When a client creates a registry object, the registry object will emit a global event for each global currently in the registry. Globals come and go as a result of device or monitor hotplugs, reconfiguration or other events, and the registry will send out global and global_remove events to keep the client up to date with the changes. To mark the end of the initial burst of events, the client can use the wl_display.sync request immediately after calling wl_display.get_registry. A client can bind to a global object by using the bind request. This creates a client-side handle that lets the object emit events to the client and lets the client invoke requests on the object. Binds a new, client-created object to the server using the specified name as the identifier. Notify the client of global objects. The event notifies the client that a global object with the given name is now available, and it implements the given version of the given interface. Notify the client of removed global objects. This event notifies the client that the global identified by name is no longer available. If the client bound to the global using the bind request, the client should now destroy that object. The object remains valid and requests to the object will be ignored until the client destroys it, to avoid races between the global going away and a client sending a request to it. Clients can handle the 'done' event to get notified when the related request is done. Note, because wl_callback objects are created from multiple independent factory interfaces, the wl_callback interface is frozen at version 1. Notify the client when the related request is done. A compositor. This object is a singleton global. The compositor is in charge of combining the contents of multiple surfaces into one displayable output. Ask the compositor to create a new surface. Ask the compositor to create a new region. The wl_shm_pool object encapsulates a piece of memory shared between the compositor and client. Through the wl_shm_pool object, the client can allocate shared memory wl_buffer objects. All objects created through the same pool share the same underlying mapped memory. Reusing the mapped memory avoids the setup/teardown overhead and is useful when interactively resizing a surface or for many small buffers. Create a wl_buffer object from the pool. The buffer is created offset bytes into the pool and has width and height as specified. The stride argument specifies the number of bytes from the beginning of one row to the beginning of the next. The format is the pixel format of the buffer and must be one of those advertised through the wl_shm.format event. A buffer will keep a reference to the pool it was created from so it is valid to destroy the pool immediately after creating a buffer from it. Destroy the shared memory pool. The mmapped memory will be released when all buffers that have been created from this pool are gone. This request will cause the server to remap the backing memory for the pool from the file descriptor passed when the pool was created, but using the new size. This request can only be used to make the pool bigger. This request only changes the amount of bytes that are mmapped by the server and does not touch the file corresponding to the file descriptor passed at creation time. It is the client's responsibility to ensure that the file is at least as big as the new pool size. A singleton global object that provides support for shared memory. Clients can create wl_shm_pool objects using the create_pool request. On binding the wl_shm object one or more format events are emitted to inform clients about the valid pixel formats that can be used for buffers. These errors can be emitted in response to wl_shm requests. This describes the memory layout of an individual pixel. All renderers should support argb8888 and xrgb8888 but any other formats are optional and may not be supported by the particular renderer in use. The drm format codes match the macros defined in drm_fourcc.h, except argb8888 and xrgb8888. The formats actually supported by the compositor will be reported by the format event. For all wl_shm formats and unless specified in another protocol extension, pre-multiplied alpha is used for pixel values. Create a new wl_shm_pool object. The pool can be used to create shared memory based buffer objects. The server will mmap size bytes of the passed file descriptor, to use as backing memory for the pool. Informs the client about a valid pixel format that can be used for buffers. Known formats include argb8888 and xrgb8888. Using this request a client can tell the server that it is not going to use the shm object anymore. Objects created via this interface remain unaffected. A buffer provides the content for a wl_surface. Buffers are created through factory interfaces such as wl_shm, wp_linux_buffer_params (from the linux-dmabuf protocol extension) or similar. It has a width and a height and can be attached to a wl_surface, but the mechanism by which a client provides and updates the contents is defined by the buffer factory interface. Color channels are assumed to be electrical rather than optical (in other words, encoded with a transfer function) unless otherwise specified. If the buffer uses a format that has an alpha channel, the alpha channel is assumed to be premultiplied into the electrical color channel values (after transfer function encoding) unless otherwise specified. Note, because wl_buffer objects are created from multiple independent factory interfaces, the wl_buffer interface is frozen at version 1. Destroy a buffer. If and how you need to release the backing storage is defined by the buffer factory interface. For possible side-effects to a surface, see wl_surface.attach. Sent when this wl_buffer is no longer used by the compositor. The client is now free to reuse or destroy this buffer and its backing storage. If a client receives a release event before the frame callback requested in the same wl_surface.commit that attaches this wl_buffer to a surface, then the client is immediately free to reuse the buffer and its backing storage, and does not need a second buffer for the next surface content update. Typically this is possible, when the compositor maintains a copy of the wl_surface contents, e.g. as a GL texture. This is an important optimization for GL(ES) compositors with wl_shm clients. A wl_data_offer represents a piece of data offered for transfer by another client (the source client). It is used by the copy-and-paste and drag-and-drop mechanisms. The offer describes the different mime types that the data can be converted to and provides the mechanism for transferring the data directly from the source client. Indicate that the client can accept the given mime type, or NULL for not accepted. For objects of version 2 or older, this request is used by the client to give feedback whether the client can receive the given mime type, or NULL if none is accepted; the feedback does not determine whether the drag-and-drop operation succeeds or not. For objects of version 3 or newer, this request determines the final result of the drag-and-drop operation. If the end result is that no mime types were accepted, the drag-and-drop operation will be cancelled and the corresponding drag source will receive wl_data_source.cancelled. Clients may still use this event in conjunction with wl_data_source.action for feedback. 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, both before and after wl_data_device.drop. Drag-and-drop destination clients may preemptively fetch data or examine it more closely to determine acceptance. Destroy the data offer. Sent immediately after creating the wl_data_offer object. One event per offered mime type. Notifies the compositor that the drag destination successfully finished the drag-and-drop operation. Upon receiving this request, the compositor will emit wl_data_source.dnd_finished on the drag source client. It is a client error to perform other requests than wl_data_offer.destroy after this one. It is also an error to perform this request after a NULL mime type has been set in wl_data_offer.accept or no action was received through wl_data_offer.action. If wl_data_offer.finish request is received for a non drag and drop operation, the invalid_finish protocol error is raised. Sets the actions that the destination side client supports for this operation. This request may trigger the emission of wl_data_source.action and wl_data_offer.action events if the compositor needs to change the selected action. This request can be called multiple times throughout the drag-and-drop operation, typically in response to wl_data_device.enter or wl_data_device.motion events. This request determines the final result of the drag-and-drop operation. If the end result is that no action is accepted, the drag source will receive wl_data_source.cancelled. The dnd_actions argument must contain only values expressed in the wl_data_device_manager.dnd_actions enum, and the preferred_action argument must only contain one of those values set, otherwise it will result in a protocol error. While managing an "ask" action, the destination drag-and-drop client may perform further wl_data_offer.receive requests, and is expected to perform one last wl_data_offer.set_actions request with a preferred action other than "ask" (and optionally wl_data_offer.accept) before requesting wl_data_offer.finish, in order to convey the action selected by the user. If the preferred action is not in the wl_data_offer.source_actions mask, an error will be raised. If the "ask" action is dismissed (e.g. user cancellation), the client is expected to perform wl_data_offer.destroy right away. This request can only be made on drag-and-drop offers, a protocol error will be raised otherwise. This event indicates the actions offered by the data source. It will be sent immediately after creating the wl_data_offer object, or anytime the source side changes its offered actions through wl_data_source.set_actions. This event indicates the action selected by the compositor after matching the source/destination side actions. Only one action (or none) will be offered here. This event can be emitted multiple times during the drag-and-drop operation in response to destination side action changes through wl_data_offer.set_actions. This event will no longer be emitted after wl_data_device.drop happened on the drag-and-drop destination, the client must honor the last action received, or the last preferred one set through wl_data_offer.set_actions when handling an "ask" action. Compositors may also change the selected action on the fly, mainly in response to keyboard modifier changes during the drag-and-drop operation. The most recent action received is always the valid one. Prior to receiving wl_data_device.drop, the chosen action may change (e.g. due to keyboard modifiers being pressed). At the time of receiving wl_data_device.drop the drag-and-drop destination must honor the last action received. Action changes may still happen after wl_data_device.drop, especially on "ask" actions, where the drag-and-drop destination may choose another action afterwards. Action changes happening at this stage are always the result of inter-client negotiation, the compositor shall no longer be able to induce a different action. Upon "ask" actions, it is expected that the drag-and-drop destination may potentially choose a different action and/or mime type, based on wl_data_offer.source_actions and finally chosen by the user (e.g. popping up a menu with the available options). The final wl_data_offer.set_actions and wl_data_offer.accept requests must happen before the call to wl_data_offer.finish. The wl_data_source object is the source side of a wl_data_offer. It is created by the source client in a data transfer and provides a way to describe the offered data and a way to respond to requests to transfer the data. This request adds a mime type to the set of mime types advertised to targets. Can be called several times to offer multiple types. Destroy the data source. Sent when a target accepts pointer_focus or motion events. If a target does not accept any of the offered types, type is NULL. Used for feedback during drag-and-drop. Request for data from the client. Send the data as the specified mime type over the passed file descriptor, then close it. This data source is no longer valid. There are several reasons why this could happen: - The data source has been replaced by another data source. - The drag-and-drop operation was performed, but the drop destination did not accept any of the mime types offered through wl_data_source.target. - The drag-and-drop operation was performed, but the drop destination did not select any of the actions present in the mask offered through wl_data_source.action. - The drag-and-drop operation was performed but didn't happen over a surface. - The compositor cancelled the drag-and-drop operation (e.g. compositor dependent timeouts to avoid stale drag-and-drop transfers). The client should clean up and destroy this data source. For objects of version 2 or older, wl_data_source.cancelled will only be emitted if the data source was replaced by another data source. Sets the actions that the source side client supports for this operation. This request may trigger wl_data_source.action and wl_data_offer.action events if the compositor needs to change the selected action. The dnd_actions argument must contain only values expressed in the wl_data_device_manager.dnd_actions enum, otherwise it will result in a protocol error. This request must be made once only, and can only be made on sources used in drag-and-drop, so it must be performed before wl_data_device.start_drag. Attempting to use the source other than for drag-and-drop will raise a protocol error. The user performed the drop action. This event does not indicate acceptance, wl_data_source.cancelled may still be emitted afterwards if the drop destination does not accept any mime type. However, this event might however not be received if the compositor cancelled the drag-and-drop operation before this event could happen. Note that the data_source may still be used in the future and should not be destroyed here. The drop destination finished interoperating with this data source, so the client is now free to destroy this data source and free all associated data. If the action used to perform the operation was "move", the source can now delete the transferred data. This event indicates the action selected by the compositor after matching the source/destination side actions. Only one action (or none) will be offered here. This event can be emitted multiple times during the drag-and-drop operation, mainly in response to destination side changes through wl_data_offer.set_actions, and as the data device enters/leaves surfaces. It is only possible to receive this event after wl_data_source.dnd_drop_performed if the drag-and-drop operation ended in an "ask" action, in which case the final wl_data_source.action event will happen immediately before wl_data_source.dnd_finished. Compositors may also change the selected action on the fly, mainly in response to keyboard modifier changes during the drag-and-drop operation. The most recent action received is always the valid one. The chosen action may change alongside negotiation (e.g. an "ask" action can turn into a "move" operation), so the effects of the final action must always be applied in wl_data_offer.dnd_finished. Clients can trigger cursor surface changes from this point, so they reflect the current action. There is one wl_data_device per seat which can be obtained from the global wl_data_device_manager singleton. A wl_data_device provides access to inter-client data transfer mechanisms such as copy-and-paste and drag-and-drop. This request asks the compositor to start a drag-and-drop operation on behalf of the client. The source argument is the data source that provides the data for the eventual data transfer. If source is NULL, enter, leave and motion events are sent only to the client that initiated the drag and the client is expected to handle the data passing internally. If source is destroyed, the drag-and-drop session will be cancelled. The origin surface is the surface where the drag originates and the client must have an active implicit grab that matches the serial. The icon surface is an optional (can be NULL) surface that provides an icon to be moved around with the cursor. Initially, the top-left corner of the icon surface is placed at the cursor hotspot, but subsequent wl_surface.offset requests can move the relative position. Attach requests must be confirmed with wl_surface.commit as usual. The icon surface is given the role of a drag-and-drop icon. If the icon surface already has another role, it raises a protocol error. The input region is ignored for wl_surfaces with the role of a drag-and-drop icon. The given source may not be used in any further set_selection or start_drag requests. Attempting to reuse a previously-used source may send a used_source error. This request asks the compositor to set the selection to the data from the source on behalf of the client. To unset the selection, set the source to NULL. The given source may not be used in any further set_selection or start_drag requests. Attempting to reuse a previously-used source may send a used_source error. The data_offer event introduces a new wl_data_offer object, which will subsequently be used in either the data_device.enter event (for drag-and-drop) or the data_device.selection event (for selections). Immediately following the data_device.data_offer event, the new data_offer object will send out data_offer.offer events to describe the mime types it offers. This event is sent when an active drag-and-drop pointer enters a surface owned by the client. The position of the pointer at enter time is provided by the x and y arguments, in surface-local coordinates. This event is sent when the drag-and-drop pointer leaves the surface and the session ends. The client must destroy the wl_data_offer introduced at enter time at this point. This event is sent when the drag-and-drop pointer moves within the currently focused surface. The new position of the pointer is provided by the x and y arguments, in surface-local coordinates. The event is sent when a drag-and-drop operation is ended because the implicit grab is removed. The drag-and-drop destination is expected to honor the last action received through wl_data_offer.action, if the resulting action is "copy" or "move", the destination can still perform wl_data_offer.receive requests, and is expected to end all transfers with a wl_data_offer.finish request. If the resulting action is "ask", the action will not be considered final. The drag-and-drop destination is expected to perform one last wl_data_offer.set_actions request, or wl_data_offer.destroy in order to cancel the operation. The selection event is sent out to notify the client of a new wl_data_offer for the selection for this device. The data_device.data_offer and the data_offer.offer events are sent out immediately before this event to introduce the data offer object. The selection event is sent to a client immediately before receiving keyboard focus and when a new selection is set while the client has keyboard focus. The data_offer is valid until a new data_offer or NULL is received or until the client loses keyboard focus. Switching surface with keyboard focus within the same client doesn't mean a new selection will be sent. The client must destroy the previous selection data_offer, if any, upon receiving this event. This request destroys the data device. The wl_data_device_manager is a singleton global object that provides access to inter-client data transfer mechanisms such as copy-and-paste and drag-and-drop. These mechanisms are tied to a wl_seat and this interface lets a client get a wl_data_device corresponding to a wl_seat. Depending on the version bound, the objects created from the bound wl_data_device_manager object will have different requirements for functioning properly. See wl_data_source.set_actions, wl_data_offer.accept and wl_data_offer.finish for details. Create a new data source. Create a new data device for a given seat. This is a bitmask of the available/preferred actions in a drag-and-drop operation. In the compositor, the selected action is a result of matching the actions offered by the source and destination sides. "action" events with a "none" action will be sent to both source and destination if there is no match. All further checks will effectively happen on (source actions ∩ destination actions). In addition, compositors may also pick different actions in reaction to key modifiers being pressed. One common design that is used in major toolkits (and the behavior recommended for compositors) is: - If no modifiers are pressed, the first match (in bit order) will be used. - Pressing Shift selects "move", if enabled in the mask. - Pressing Control selects "copy", if enabled in the mask. Behavior beyond that is considered implementation-dependent. Compositors may for example bind other modifiers (like Alt/Meta) or drags initiated with other buttons than BTN_LEFT to specific actions (e.g. "ask"). This interface is implemented by servers that provide desktop-style user interfaces. It allows clients to associate a wl_shell_surface with a basic surface. Note! This protocol is deprecated and not intended for production use. For desktop-style user interfaces, use xdg_shell. Compositors and clients should not implement this interface. Create a shell surface for an existing surface. This gives the wl_surface the role of a shell surface. If the wl_surface already has another role, it raises a protocol error. Only one shell surface can be associated with a given surface. An interface that may be implemented by a wl_surface, for implementations that provide a desktop-style user interface. It provides requests to treat surfaces like toplevel, fullscreen or popup windows, move, resize or maximize them, associate metadata like title and class, etc. On the server side the object is automatically destroyed when the related wl_surface is destroyed. On the client side, wl_shell_surface_destroy() must be called before destroying the wl_surface object. A client must respond to a ping event with a pong request or the client may be deemed unresponsive. Start a pointer-driven move of the surface. This request must be used in response to a button press event. The server may ignore move requests depending on the state of the surface (e.g. fullscreen or maximized). These values are used to indicate which edge of a surface is being dragged in a resize operation. The server may use this information to adapt its behavior, e.g. choose an appropriate cursor image. Start a pointer-driven resizing of the surface. This request must be used in response to a button press event. The server may ignore resize requests depending on the state of the surface (e.g. fullscreen or maximized). Map the surface as a toplevel surface. A toplevel surface is not fullscreen, maximized or transient. These flags specify details of the expected behaviour of transient surfaces. Used in the set_transient request. Map the surface relative to an existing surface. The x and y arguments specify the location of the upper left corner of the surface relative to the upper left corner of the parent surface, in surface-local coordinates. The flags argument controls details of the transient behaviour. Hints to indicate to the compositor how to deal with a conflict between the dimensions of the surface and the dimensions of the output. The compositor is free to ignore this parameter. Map the surface as a fullscreen surface. If an output parameter is given then the surface will be made fullscreen on that output. If the client does not specify the output then the compositor will apply its policy - usually choosing the output on which the surface has the biggest surface area. The client may specify a method to resolve a size conflict between the output size and the surface size - this is provided through the method parameter. The framerate parameter is used only when the method is set to "driver", to indicate the preferred framerate. A value of 0 indicates that the client does not care about framerate. The framerate is specified in mHz, that is framerate of 60000 is 60Hz. A method of "scale" or "driver" implies a scaling operation of the surface, either via a direct scaling operation or a change of the output mode. This will override any kind of output scaling, so that mapping a surface with a buffer size equal to the mode can fill the screen independent of buffer_scale. A method of "fill" means we don't scale up the buffer, however any output scale is applied. This means that you may run into an edge case where the application maps a buffer with the same size of the output mode but buffer_scale 1 (thus making a surface larger than the output). In this case it is allowed to downscale the results to fit the screen. The compositor must reply to this request with a configure event with the dimensions for the output on which the surface will be made fullscreen. Map the surface as a popup. A popup surface is a transient surface with an added pointer grab. An existing implicit grab will be changed to owner-events mode, and the popup grab will continue after the implicit grab ends (i.e. releasing the mouse button does not cause the popup to be unmapped). The popup grab continues until the window is destroyed or a mouse button is pressed in any other client's window. A click in any of the client's surfaces is reported as normal, however, clicks in other clients' surfaces will be discarded and trigger the callback. The x and y arguments specify the location of the upper left corner of the surface relative to the upper left corner of the parent surface, in surface-local coordinates. Map the surface as a maximized surface. If an output parameter is given then the surface will be maximized on that output. If the client does not specify the output then the compositor will apply its policy - usually choosing the output on which the surface has the biggest surface area. The compositor will reply with a configure event telling the expected new surface size. The operation is completed on the next buffer attach to this surface. A maximized surface typically fills the entire output it is bound to, except for desktop elements such as panels. This is the main difference between a maximized shell surface and a fullscreen shell surface. The details depend on the compositor implementation. Set a short title for the surface. This string may be used to identify the surface in a task bar, window list, or other user interface elements provided by the compositor. The string must be encoded in UTF-8. Set a class for the surface. The surface class identifies the general class of applications to which the surface belongs. A common convention is to use the file name (or the full path if it is a non-standard location) of the application's .desktop file as the class. Ping a client to check if it is receiving events and sending requests. A client is expected to reply with a pong request. The configure event asks the client to resize its surface. The size is a hint, in the sense that the client is free to ignore it if it doesn't resize, pick a smaller size (to satisfy aspect ratio or resize in steps of NxM pixels). The edges parameter provides a hint about how the surface was resized. The client may use this information to decide how to adjust its content to the new size (e.g. a scrolling area might adjust its content position to leave the viewable content unmoved). The client is free to dismiss all but the last configure event it received. The width and height arguments specify the size of the window in surface-local coordinates. The popup_done event is sent out when a popup grab is broken, that is, when the user clicks a surface that doesn't belong to the client owning the popup surface. A surface is a rectangular area that may be displayed on zero or more outputs, and shown any number of times at the compositor's discretion. They can present wl_buffers, receive user input, and define a local coordinate system. The size of a surface (and relative positions on it) is described in surface-local coordinates, which may differ from the buffer coordinates of the pixel content, in case a buffer_transform or a buffer_scale is used. A surface without a "role" is fairly useless: a compositor does not know where, when or how to present it. The role is the purpose of a wl_surface. Examples of roles are a cursor for a pointer (as set by wl_pointer.set_cursor), a drag icon (wl_data_device.start_drag), a sub-surface (wl_subcompositor.get_subsurface), and a window as defined by a shell protocol (e.g. wl_shell.get_shell_surface). A surface can have only one role at a time. Initially a wl_surface does not have a role. Once a wl_surface is given a role, it is set permanently for the whole lifetime of the wl_surface object. Giving the current role again is allowed, unless explicitly forbidden by the relevant interface specification. Surface roles are given by requests in other interfaces such as wl_pointer.set_cursor. The request should explicitly mention that this request gives a role to a wl_surface. Often, this request also creates a new protocol object that represents the role and adds additional functionality to wl_surface. When a client wants to destroy a wl_surface, they must destroy this role object before the wl_surface, otherwise a defunct_role_object error is sent. Destroying the role object does not remove the role from the wl_surface, but it may stop the wl_surface from "playing the role". For instance, if a wl_subsurface object is destroyed, the wl_surface it was created for will be unmapped and forget its position and z-order. It is allowed to create a wl_subsurface for the same wl_surface again, but it is not allowed to use the wl_surface as a cursor (cursor is a different role than sub-surface, and role switching is not allowed). These errors can be emitted in response to wl_surface requests. Deletes the surface and invalidates its object ID. Set a buffer as the content of this surface. The new size of the surface is calculated based on the buffer size transformed by the inverse buffer_transform and the inverse buffer_scale. This means that at commit time the supplied buffer size must be an integer multiple of the buffer_scale. If that's not the case, an invalid_size error is sent. The x and y arguments specify the location of the new pending buffer's upper left corner, relative to the current buffer's upper left corner, in surface-local coordinates. In other words, the x and y, combined with the new surface size define in which directions the surface's size changes. Setting anything other than 0 as x and y arguments is discouraged, and should instead be replaced with using the separate wl_surface.offset request. When the bound wl_surface version is 5 or higher, passing any non-zero x or y is a protocol violation, and will result in an 'invalid_offset' error being raised. The x and y arguments are ignored and do not change the pending state. To achieve equivalent semantics, use wl_surface.offset. Surface contents are double-buffered state, see wl_surface.commit. The initial surface contents are void; there is no content. wl_surface.attach assigns the given wl_buffer as the pending wl_buffer. wl_surface.commit makes the pending wl_buffer the new surface contents, and the size of the surface becomes the size calculated from the wl_buffer, as described above. After commit, there is no pending buffer until the next attach. Committing a pending wl_buffer allows the compositor to read the pixels in the wl_buffer. The compositor may access the pixels at any time after the wl_surface.commit request. When the compositor will not access the pixels anymore, it will send the wl_buffer.release event. Only after receiving wl_buffer.release, the client may reuse the wl_buffer. A wl_buffer that has been attached and then replaced by another attach instead of committed will not receive a release event, and is not used by the compositor. If a pending wl_buffer has been committed to more than one wl_surface, the delivery of wl_buffer.release events becomes undefined. A well behaved client should not rely on wl_buffer.release events in this case. Alternatively, a client could create multiple wl_buffer objects from the same backing storage or use wp_linux_buffer_release. Destroying the wl_buffer after wl_buffer.release does not change the surface contents. Destroying the wl_buffer before wl_buffer.release is allowed as long as the underlying buffer storage isn't re-used (this can happen e.g. on client process termination). However, if the client destroys the wl_buffer before receiving the wl_buffer.release event and mutates the underlying buffer storage, the surface contents become undefined immediately. If wl_surface.attach is sent with a NULL wl_buffer, the following wl_surface.commit will remove the surface content. If a pending wl_buffer has been destroyed, the result is not specified. Many compositors are known to remove the surface content on the following wl_surface.commit, but this behaviour is not universal. Clients seeking to maximise compatibility should not destroy pending buffers and should ensure that they explicitly remove content from surfaces, even after destroying buffers. This request is used to describe the regions where the pending buffer is different from the current surface contents, and where the surface therefore needs to be repainted. The compositor ignores the parts of the damage that fall outside of the surface. Damage is double-buffered state, see wl_surface.commit. The damage rectangle is specified in surface-local coordinates, where x and y specify the upper left corner of the damage rectangle. The initial value for pending damage is empty: no damage. wl_surface.damage adds pending damage: the new pending damage is the union of old pending damage and the given rectangle. wl_surface.commit assigns pending damage as the current damage, and clears pending damage. The server will clear the current damage as it repaints the surface. Note! New clients should not use this request. Instead damage can be posted with wl_surface.damage_buffer which uses buffer coordinates instead of surface coordinates. Request a notification when it is a good time to start drawing a new frame, by creating a frame callback. This is useful for throttling redrawing operations, and driving animations. When a client is animating on a wl_surface, it can use the 'frame' request to get notified when it is a good time to draw and commit the next frame of animation. If the client commits an update earlier than that, it is likely that some updates will not make it to the display, and the client is wasting resources by drawing too often. The frame request will take effect on the next wl_surface.commit. The notification will only be posted for one frame unless requested again. For a wl_surface, the notifications are posted in the order the frame requests were committed. The server must send the notifications so that a client will not send excessive updates, while still allowing the highest possible update rate for clients that wait for the reply before drawing again. The server should give some time for the client to draw and commit after sending the frame callback events to let it hit the next output refresh. A server should avoid signaling the frame callbacks if the surface is not visible in any way, e.g. the surface is off-screen, or completely obscured by other opaque surfaces. The object returned by this request will be destroyed by the compositor after the callback is fired and as such the client must not attempt to use it after that point. The callback_data passed in the callback is the current time, in milliseconds, with an undefined base. This request sets the region of the surface that contains opaque content. The opaque region is an optimization hint for the compositor that lets it optimize the redrawing of content behind opaque regions. Setting an opaque region is not required for correct behaviour, but marking transparent content as opaque will result in repaint artifacts. The opaque region is specified in surface-local coordinates. The compositor ignores the parts of the opaque region that fall outside of the surface. Opaque region is double-buffered state, see wl_surface.commit. wl_surface.set_opaque_region changes the pending opaque region. wl_surface.commit copies the pending region to the current region. Otherwise, the pending and current regions are never changed. The initial value for an opaque region is empty. Setting the pending opaque region has copy semantics, and the wl_region object can be destroyed immediately. A NULL wl_region causes the pending opaque region to be set to empty. This request sets the region of the surface that can receive pointer and touch events. Input events happening outside of this region will try the next surface in the server surface stack. The compositor ignores the parts of the input region that fall outside of the surface. The input region is specified in surface-local coordinates. Input region is double-buffered state, see wl_surface.commit. wl_surface.set_input_region changes the pending input region. wl_surface.commit copies the pending region to the current region. Otherwise the pending and current regions are never changed, except cursor and icon surfaces are special cases, see wl_pointer.set_cursor and wl_data_device.start_drag. The initial value for an input region is infinite. That means the whole surface will accept input. Setting the pending input region has copy semantics, and the wl_region object can be destroyed immediately. A NULL wl_region causes the input region to be set to infinite. Surface state (input, opaque, and damage regions, attached buffers, etc.) is double-buffered. Protocol requests modify the pending state, as opposed to the active state in use by the compositor. A commit request atomically creates a content update from the pending state, even if the pending state has not been touched. The content update is placed in a queue until it becomes active. After commit, the new pending state is as documented for each related request. When the content update is applied, the wl_buffer is applied before all other state. This means that all coordinates in double-buffered state are relative to the newly attached wl_buffers, except for wl_surface.attach itself. If there is no newly attached wl_buffer, the coordinates are relative to the previous content update. All requests that need a commit to become effective are documented to affect double-buffered state. Other interfaces may add further double-buffered surface state. This is emitted whenever a surface's creation, movement, or resizing results in some part of it being within the scanout region of an output. Note that a surface may be overlapping with zero or more outputs. This is emitted whenever a surface's creation, movement, or resizing results in it no longer having any part of it within the scanout region of an output. Clients should not use the number of outputs the surface is on for frame throttling purposes. The surface might be hidden even if no leave event has been sent, and the compositor might expect new surface content updates even if no enter event has been sent. The frame event should be used instead. This request sets the transformation that the client has already applied to the content of the buffer. The accepted values for the transform parameter are the values for wl_output.transform. The compositor applies the inverse of this transformation whenever it uses the buffer contents. Buffer transform is double-buffered state, see wl_surface.commit. A newly created surface has its buffer transformation set to normal. wl_surface.set_buffer_transform changes the pending buffer transformation. wl_surface.commit copies the pending buffer transformation to the current one. Otherwise, the pending and current values are never changed. The purpose of this request is to allow clients to render content according to the output transform, thus permitting the compositor to use certain optimizations even if the display is rotated. Using hardware overlays and scanning out a client buffer for fullscreen surfaces are examples of such optimizations. Those optimizations are highly dependent on the compositor implementation, so the use of this request should be considered on a case-by-case basis. Note that if the transform value includes 90 or 270 degree rotation, the width of the buffer will become the surface height and the height of the buffer will become the surface width. If transform is not one of the values from the wl_output.transform enum the invalid_transform protocol error is raised. This request sets an optional scaling factor on how the compositor interprets the contents of the buffer attached to the window. Buffer scale is double-buffered state, see wl_surface.commit. A newly created surface has its buffer scale set to 1. wl_surface.set_buffer_scale changes the pending buffer scale. wl_surface.commit copies the pending buffer scale to the current one. Otherwise, the pending and current values are never changed. The purpose of this request is to allow clients to supply higher resolution buffer data for use on high resolution outputs. It is intended that you pick the same buffer scale as the scale of the output that the surface is displayed on. This means the compositor can avoid scaling when rendering the surface on that output. Note that if the scale is larger than 1, then you have to attach a buffer that is larger (by a factor of scale in each dimension) than the desired surface size. If scale is not greater than 0 the invalid_scale protocol error is raised. This request is used to describe the regions where the pending buffer is different from the current surface contents, and where the surface therefore needs to be repainted. The compositor ignores the parts of the damage that fall outside of the surface. Damage is double-buffered state, see wl_surface.commit. The damage rectangle is specified in buffer coordinates, where x and y specify the upper left corner of the damage rectangle. The initial value for pending damage is empty: no damage. wl_surface.damage_buffer adds pending damage: the new pending damage is the union of old pending damage and the given rectangle. wl_surface.commit assigns pending damage as the current damage, and clears pending damage. The server will clear the current damage as it repaints the surface. This request differs from wl_surface.damage in only one way - it takes damage in buffer coordinates instead of surface-local coordinates. While this generally is more intuitive than surface coordinates, it is especially desirable when using wp_viewport or when a drawing library (like EGL) is unaware of buffer scale and buffer transform. Note: Because buffer transformation changes and damage requests may be interleaved in the protocol stream, it is impossible to determine the actual mapping between surface and buffer damage until wl_surface.commit time. Therefore, compositors wishing to take both kinds of damage into account will have to accumulate damage from the two requests separately and only transform from one to the other after receiving the wl_surface.commit. The x and y arguments specify the location of the new pending buffer's upper left corner, relative to the current buffer's upper left corner, in surface-local coordinates. In other words, the x and y, combined with the new surface size define in which directions the surface's size changes. Surface location offset is double-buffered state, see wl_surface.commit. This request is semantically equivalent to and the replaces the x and y arguments in the wl_surface.attach request in wl_surface versions prior to 5. See wl_surface.attach for details. This event indicates the preferred buffer scale for this surface. It is sent whenever the compositor's preference changes. Before receiving this event the preferred buffer scale for this surface is 1. It is intended that scaling aware clients use this event to scale their content and use wl_surface.set_buffer_scale to indicate the scale they have rendered with. This allows clients to supply a higher detail buffer. The compositor shall emit a scale value greater than 0. This event indicates the preferred buffer transform for this surface. It is sent whenever the compositor's preference changes. Before receiving this event the preferred buffer transform for this surface is normal. Applying this transformation to the surface buffer contents and using wl_surface.set_buffer_transform might allow the compositor to use the surface buffer more efficiently. A seat is a group of keyboards, pointer and touch devices. This object is published as a global during start up, or when such a device is hot plugged. A seat typically has a pointer and maintains a keyboard focus and a pointer focus. This is a bitmask of capabilities this seat has; if a member is set, then it is present on the seat. These errors can be emitted in response to wl_seat requests. This is emitted whenever a seat gains or loses the pointer, keyboard or touch capabilities. The argument is a capability enum containing the complete set of capabilities this seat has. When the pointer capability is added, a client may create a wl_pointer object using the wl_seat.get_pointer request. This object will receive pointer events until the capability is removed in the future. When the pointer capability is removed, a client should destroy the wl_pointer objects associated with the seat where the capability was removed, using the wl_pointer.release request. No further pointer events will be received on these objects. In some compositors, if a seat regains the pointer capability and a client has a previously obtained wl_pointer object of version 4 or less, that object may start sending pointer events again. This behavior is considered a misinterpretation of the intended behavior and must not be relied upon by the client. wl_pointer objects of version 5 or later must not send events if created before the most recent event notifying the client of an added pointer capability. The above behavior also applies to wl_keyboard and wl_touch with the keyboard and touch capabilities, respectively. The ID provided will be initialized to the wl_pointer interface for this seat. This request only takes effect if the seat has the pointer capability, or has had the pointer capability in the past. It is a protocol violation to issue this request on a seat that has never had the pointer capability. The missing_capability error will be sent in this case. The ID provided will be initialized to the wl_keyboard interface for this seat. This request only takes effect if the seat has the keyboard capability, or has had the keyboard capability in the past. It is a protocol violation to issue this request on a seat that has never had the keyboard capability. The missing_capability error will be sent in this case. The ID provided will be initialized to the wl_touch interface for this seat. This request only takes effect if the seat has the touch capability, or has had the touch capability in the past. It is a protocol violation to issue this request on a seat that has never had the touch capability. The missing_capability error will be sent in this case. In a multi-seat configuration the seat name can be used by clients to help identify which physical devices the seat represents. The seat name is a UTF-8 string with no convention defined for its contents. Each name is unique among all wl_seat globals. The name is only guaranteed to be unique for the current compositor instance. The same seat names are used for all clients. Thus, the name can be shared across processes to refer to a specific wl_seat global. The name event is sent after binding to the seat global. This event is only sent once per seat object, and the name does not change over the lifetime of the wl_seat global. Compositors may re-use the same seat name if the wl_seat global is destroyed and re-created later. Using this request a client can tell the server that it is not going to use the seat object anymore. The wl_pointer interface represents one or more input devices, such as mice, which control the pointer location and pointer_focus of a seat. The wl_pointer interface generates motion, enter and leave events for the surfaces that the pointer is located over, and button and axis events for button presses, button releases and scrolling. Set the pointer surface, i.e., the surface that contains the pointer image (cursor). This request gives the surface the role of a cursor. If the surface already has another role, it raises a protocol error. The cursor actually changes only if the pointer focus for this device is one of the requesting client's surfaces or the surface parameter is the current pointer surface. If there was a previous surface set with this request it is replaced. If surface is NULL, the pointer image is hidden. The parameters hotspot_x and hotspot_y define the position of the pointer surface relative to the pointer location. Its top-left corner is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the coordinates of the pointer location, in surface-local coordinates. On wl_surface.offset requests to the pointer surface, hotspot_x and hotspot_y are decremented by the x and y parameters passed to the request. The offset must be applied by wl_surface.commit as usual. The hotspot can also be updated by passing the currently set pointer surface to this request with new values for hotspot_x and hotspot_y. The input region is ignored for wl_surfaces with the role of a cursor. When the use as a cursor ends, the wl_surface is unmapped. The serial parameter must match the latest wl_pointer.enter serial number sent to the client. Otherwise the request will be ignored. Notification that this seat's pointer is focused on a certain surface. When a seat's focus enters a surface, the pointer image is undefined and a client should respond to this event by setting an appropriate pointer image with the set_cursor request. Notification that this seat's pointer is no longer focused on a certain surface. The leave notification is sent before the enter notification for the new focus. Notification of pointer location change. The arguments surface_x and surface_y are the location relative to the focused surface. Describes the physical state of a button that produced the button event. Mouse button click and release notifications. The location of the click is given by the last motion or enter event. The time argument is a timestamp with millisecond granularity, with an undefined base. The button is a button code as defined in the Linux kernel's linux/input-event-codes.h header file, e.g. BTN_LEFT. Any 16-bit button code value is reserved for future additions to the kernel's event code list. All other button codes above 0xFFFF are currently undefined but may be used in future versions of this protocol. Describes the axis types of scroll events. Scroll and other axis notifications. For scroll events (vertical and horizontal scroll axes), the value parameter is the length of a vector along the specified axis in a coordinate space identical to those of motion events, representing a relative movement along the specified axis. For devices that support movements non-parallel to axes multiple axis events will be emitted. When applicable, for example for touch pads, the server can choose to emit scroll events where the motion vector is equivalent to a motion event vector. When applicable, a client can transform its content relative to the scroll distance. Using this request a client can tell the server that it is not going to use the pointer object anymore. This request destroys the pointer proxy object, so clients must not call wl_pointer_destroy() after using this request. Indicates the end of a set of events that logically belong together. A client is expected to accumulate the data in all events within the frame before proceeding. All wl_pointer events before a wl_pointer.frame event belong logically together. For example, in a diagonal scroll motion the compositor will send an optional wl_pointer.axis_source event, two wl_pointer.axis events (horizontal and vertical) and finally a wl_pointer.frame event. The client may use this information to calculate a diagonal vector for scrolling. When multiple wl_pointer.axis events occur within the same frame, the motion vector is the combined motion of all events. When a wl_pointer.axis and a wl_pointer.axis_stop event occur within the same frame, this indicates that axis movement in one axis has stopped but continues in the other axis. When multiple wl_pointer.axis_stop events occur within the same frame, this indicates that these axes stopped in the same instance. A wl_pointer.frame event is sent for every logical event group, even if the group only contains a single wl_pointer event. Specifically, a client may get a sequence: motion, frame, button, frame, axis, frame, axis_stop, frame. The wl_pointer.enter and wl_pointer.leave events are logical events generated by the compositor and not the hardware. These events are also grouped by a wl_pointer.frame. When a pointer moves from one surface to another, a compositor should group the wl_pointer.leave event within the same wl_pointer.frame. However, a client must not rely on wl_pointer.leave and wl_pointer.enter being in the same wl_pointer.frame. Compositor-specific policies may require the wl_pointer.leave and wl_pointer.enter event being split across multiple wl_pointer.frame groups. Describes the source types for axis events. This indicates to the client how an axis event was physically generated; a client may adjust the user interface accordingly. For example, scroll events from a "finger" source may be in a smooth coordinate space with kinetic scrolling whereas a "wheel" source may be in discrete steps of a number of lines. The "continuous" axis source is a device generating events in a continuous coordinate space, but using something other than a finger. One example for this source is button-based scrolling where the vertical motion of a device is converted to scroll events while a button is held down. The "wheel tilt" axis source indicates that the actual device is a wheel but the scroll event is not caused by a rotation but a (usually sideways) tilt of the wheel. Source information for scroll and other axes. This event does not occur on its own. It is sent before a wl_pointer.frame event and carries the source information for all events within that frame. The source specifies how this event was generated. If the source is wl_pointer.axis_source.finger, a wl_pointer.axis_stop event will be sent when the user lifts the finger off the device. If the source is wl_pointer.axis_source.wheel, wl_pointer.axis_source.wheel_tilt or wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event may or may not be sent. Whether a compositor sends an axis_stop event for these sources is hardware-specific and implementation-dependent; clients must not rely on receiving an axis_stop event for these scroll sources and should treat scroll sequences from these scroll sources as unterminated by default. This event is optional. If the source is unknown for a particular axis event sequence, no event is sent. Only one wl_pointer.axis_source event is permitted per frame. The order of wl_pointer.axis_discrete and wl_pointer.axis_source is not guaranteed. Stop notification for scroll and other axes. For some wl_pointer.axis_source types, a wl_pointer.axis_stop event is sent to notify a client that the axis sequence has terminated. This enables the client to implement kinetic scrolling. See the wl_pointer.axis_source documentation for information on when this event may be generated. Any wl_pointer.axis events with the same axis_source after this event should be considered as the start of a new axis motion. The timestamp is to be interpreted identical to the timestamp in the wl_pointer.axis event. The timestamp value may be the same as a preceding wl_pointer.axis event. Discrete step information for scroll and other axes. This event carries the axis value of the wl_pointer.axis event in discrete steps (e.g. mouse wheel clicks). This event is deprecated with wl_pointer version 8 - this event is not sent to clients supporting version 8 or later. This event does not occur on its own, it is coupled with a wl_pointer.axis event that represents this axis value on a continuous scale. The protocol guarantees that each axis_discrete event is always followed by exactly one axis event with the same axis number within the same wl_pointer.frame. Note that the protocol allows for other events to occur between the axis_discrete and its coupled axis event, including other axis_discrete or axis events. A wl_pointer.frame must not contain more than one axis_discrete event per axis type. This event is optional; continuous scrolling devices like two-finger scrolling on touchpads do not have discrete steps and do not generate this event. The discrete value carries the directional information. e.g. a value of -2 is two steps towards the negative direction of this axis. The axis number is identical to the axis number in the associated axis event. The order of wl_pointer.axis_discrete and wl_pointer.axis_source is not guaranteed. Discrete high-resolution scroll information. This event carries high-resolution wheel scroll information, with each multiple of 120 representing one logical scroll step (a wheel detent). For example, an axis_value120 of 30 is one quarter of a logical scroll step in the positive direction, a value120 of -240 are two logical scroll steps in the negative direction within the same hardware event. Clients that rely on discrete scrolling should accumulate the value120 to multiples of 120 before processing the event. The value120 must not be zero. This event replaces the wl_pointer.axis_discrete event in clients supporting wl_pointer version 8 or later. Where a wl_pointer.axis_source event occurs in the same wl_pointer.frame, the axis source applies to this event. The order of wl_pointer.axis_value120 and wl_pointer.axis_source is not guaranteed. This specifies the direction of the physical motion that caused a wl_pointer.axis event, relative to the wl_pointer.axis direction. Relative directional information of the entity causing the axis motion. For a wl_pointer.axis event, the wl_pointer.axis_relative_direction event specifies the movement direction of the entity causing the wl_pointer.axis event. For example: - if a user's fingers on a touchpad move down and this causes a wl_pointer.axis vertical_scroll down event, the physical direction is 'identical' - if a user's fingers on a touchpad move down and this causes a wl_pointer.axis vertical_scroll up scroll up event ('natural scrolling'), the physical direction is 'inverted'. A client may use this information to adjust scroll motion of components. Specifically, enabling natural scrolling causes the content to change direction compared to traditional scrolling. Some widgets like volume control sliders should usually match the physical direction regardless of whether natural scrolling is active. This event enables clients to match the scroll direction of a widget to the physical direction. This event does not occur on its own, it is coupled with a wl_pointer.axis event that represents this axis value. The protocol guarantees that each axis_relative_direction event is always followed by exactly one axis event with the same axis number within the same wl_pointer.frame. Note that the protocol allows for other events to occur between the axis_relative_direction and its coupled axis event. The axis number is identical to the axis number in the associated axis event. The order of wl_pointer.axis_relative_direction, wl_pointer.axis_discrete and wl_pointer.axis_source is not guaranteed. The wl_keyboard interface represents one or more keyboards associated with a seat. Each wl_keyboard has the following logical state: - an active surface (possibly null), - the keys currently logically down, - the active modifiers, - the active group. By default, the active surface is null, the keys currently logically down are empty, the active modifiers and the active group are 0. This specifies the format of the keymap provided to the client with the wl_keyboard.keymap event. This event provides a file descriptor to the client which can be memory-mapped in read-only mode to provide a keyboard mapping description. From version 7 onwards, the fd must be mapped with MAP_PRIVATE by the recipient, as MAP_SHARED may fail. Notification that this seat's keyboard focus is on a certain surface. The compositor must send the wl_keyboard.modifiers event after this event. In the wl_keyboard logical state, this event sets the active surface to the surface argument and the keys currently logically down to the keys in the keys argument. The compositor must not send this event if the wl_keyboard already had an active surface immediately before this event. Notification that this seat's keyboard focus is no longer on a certain surface. The leave notification is sent before the enter notification for the new focus. In the wl_keyboard logical state, this event resets all values to their defaults. The compositor must not send this event if the active surface of the wl_keyboard was not equal to the surface argument immediately before this event. Describes the physical state of a key that produced the key event. A key was pressed or released. The time argument is a timestamp with millisecond granularity, with an undefined base. The key is a platform-specific key code that can be interpreted by feeding it to the keyboard mapping (see the keymap event). If this event produces a change in modifiers, then the resulting wl_keyboard.modifiers event must be sent after this event. In the wl_keyboard logical state, this event adds the key to the keys currently logically down (if the state argument is pressed) or removes the key from the keys currently logically down (if the state argument is released). The compositor must not send this event if the wl_keyboard did not have an active surface immediately before this event. The compositor must not send this event if state is pressed (resp. released) and the key was already logically down (resp. was not logically down) immediately before this event. Notifies clients that the modifier and/or group state has changed, and it should update its local state. The compositor may send this event without a surface of the client having keyboard focus, for example to tie modifier information to pointer focus instead. If a modifier event with pressed modifiers is sent without a prior enter event, the client can assume the modifier state is valid until it receives the next wl_keyboard.modifiers event. In order to reset the modifier state again, the compositor can send a wl_keyboard.modifiers event with no pressed modifiers. In the wl_keyboard logical state, this event updates the modifiers and group. Informs the client about the keyboard's repeat rate and delay. This event is sent as soon as the wl_keyboard object has been created, and is guaranteed to be received by the client before any key press event. Negative values for either rate or delay are illegal. A rate of zero will disable any repeating (regardless of the value of delay). This event can be sent later on as well with a new value if necessary, so clients should continue listening for the event past the creation of wl_keyboard. The wl_touch interface represents a touchscreen associated with a seat. Touch interactions can consist of one or more contacts. For each contact, a series of events is generated, starting with a down event, followed by zero or more motion events, and ending with an up event. Events relating to the same contact point can be identified by the ID of the sequence. A new touch point has appeared on the surface. This touch point is assigned a unique ID. Future events from this touch point reference this ID. The ID ceases to be valid after a touch up event and may be reused in the future. The touch point has disappeared. No further events will be sent for this touch point and the touch point's ID is released and may be reused in a future touch down event. A touch point has changed coordinates. Indicates the end of a set of events that logically belong together. A client is expected to accumulate the data in all events within the frame before proceeding. A wl_touch.frame terminates at least one event but otherwise no guarantee is provided about the set of events within a frame. A client must assume that any state not updated in a frame is unchanged from the previously known state. Sent if the compositor decides the touch stream is a global gesture. No further events are sent to the clients from that particular gesture. Touch cancellation applies to all touch points currently active on this client's surface. The client is responsible for finalizing the touch points, future touch points on this surface may reuse the touch point ID. No frame event is required after the cancel event. Sent when a touchpoint has changed its shape. This event does not occur on its own. It is sent before a wl_touch.frame event and carries the new shape information for any previously reported, or new touch points of that frame. Other events describing the touch point such as wl_touch.down, wl_touch.motion or wl_touch.orientation may be sent within the same wl_touch.frame. A client should treat these events as a single logical touch point update. The order of wl_touch.shape, wl_touch.orientation and wl_touch.motion is not guaranteed. A wl_touch.down event is guaranteed to occur before the first wl_touch.shape event for this touch ID but both events may occur within the same wl_touch.frame. A touchpoint shape is approximated by an ellipse through the major and minor axis length. The major axis length describes the longer diameter of the ellipse, while the minor axis length describes the shorter diameter. Major and minor are orthogonal and both are specified in surface-local coordinates. The center of the ellipse is always at the touchpoint location as reported by wl_touch.down or wl_touch.move. This event is only sent by the compositor if the touch device supports shape reports. The client has to make reasonable assumptions about the shape if it did not receive this event. Sent when a touchpoint has changed its orientation. This event does not occur on its own. It is sent before a wl_touch.frame event and carries the new shape information for any previously reported, or new touch points of that frame. Other events describing the touch point such as wl_touch.down, wl_touch.motion or wl_touch.shape may be sent within the same wl_touch.frame. A client should treat these events as a single logical touch point update. The order of wl_touch.shape, wl_touch.orientation and wl_touch.motion is not guaranteed. A wl_touch.down event is guaranteed to occur before the first wl_touch.orientation event for this touch ID but both events may occur within the same wl_touch.frame. The orientation describes the clockwise angle of a touchpoint's major axis to the positive surface y-axis and is normalized to the -180 to +180 degree range. The granularity of orientation depends on the touch device, some devices only support binary rotation values between 0 and 90 degrees. This event is only sent by the compositor if the touch device supports orientation reports. An output describes part of the compositor geometry. The compositor works in the 'compositor coordinate system' and an output corresponds to a rectangular area in that space that is actually visible. This typically corresponds to a monitor that displays part of the compositor space. This object is published as global during start up, or when a monitor is hotplugged. This enumeration describes how the physical pixels on an output are laid out. This describes transformations that clients and compositors apply to buffer contents. The flipped values correspond to an initial flip around a vertical axis followed by rotation. The purpose is mainly to allow clients to render accordingly and tell the compositor, so that for fullscreen surfaces, the compositor will still be able to scan out directly from client surfaces. The geometry event describes geometric properties of the output. The event is sent when binding to the output object and whenever any of the properties change. The physical size can be set to zero if it doesn't make sense for this output (e.g. for projectors or virtual outputs). The geometry event will be followed by a done event (starting from version 2). Clients should use wl_surface.preferred_buffer_transform instead of the transform advertised by this event to find the preferred buffer transform to use for a surface. Note: wl_output only advertises partial information about the output position and identification. Some compositors, for instance those not implementing a desktop-style output layout or those exposing virtual outputs, might fake this information. Instead of using x and y, clients should use xdg_output.logical_position. Instead of using make and model, clients should use name and description. These flags describe properties of an output mode. They are used in the flags bitfield of the mode event. The mode event describes an available mode for the output. The event is sent when binding to the output object and there will always be one mode, the current mode. The event is sent again if an output changes mode, for the mode that is now current. In other words, the current mode is always the last mode that was received with the current flag set. Non-current modes are deprecated. A compositor can decide to only advertise the current mode and never send other modes. Clients should not rely on non-current modes. The size of a mode is given in physical hardware units of the output device. This is not necessarily the same as the output size in the global compositor space. For instance, the output may be scaled, as described in wl_output.scale, or transformed, as described in wl_output.transform. Clients willing to retrieve the output size in the global compositor space should use xdg_output.logical_size instead. The vertical refresh rate can be set to zero if it doesn't make sense for this output (e.g. for virtual outputs). The mode event will be followed by a done event (starting from version 2). Clients should not use the refresh rate to schedule frames. Instead, they should use the wl_surface.frame event or the presentation-time protocol. Note: this information is not always meaningful for all outputs. Some compositors, such as those exposing virtual outputs, might fake the refresh rate or the size. This event is sent after all other properties have been sent after binding to the output object and after any other property changes done after that. This allows changes to the output properties to be seen as atomic, even if they happen via multiple events. This event contains scaling geometry information that is not in the geometry event. It may be sent after binding the output object or if the output scale changes later. The compositor will emit a non-zero, positive value for scale. If it is not sent, the client should assume a scale of 1. A scale larger than 1 means that the compositor will automatically scale surface buffers by this amount when rendering. This is used for very high resolution displays where applications rendering at the native resolution would be too small to be legible. Clients should use wl_surface.preferred_buffer_scale instead of this event to find the preferred buffer scale to use for a surface. The scale event will be followed by a done event. Using this request a client can tell the server that it is not going to use the output object anymore. Many compositors will assign user-friendly names to their outputs, show them to the user, allow the user to refer to an output, etc. The client may wish to know this name as well to offer the user similar behaviors. The name is a UTF-8 string with no convention defined for its contents. Each name is unique among all wl_output globals. The name is only guaranteed to be unique for the compositor instance. The same output name is used for all clients for a given wl_output global. Thus, the name can be shared across processes to refer to a specific wl_output global. The name is not guaranteed to be persistent across sessions, thus cannot be used to reliably identify an output in e.g. configuration files. Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. However, do not assume that the name is a reflection of an underlying DRM connector, X11 connection, etc. The name event is sent after binding the output object. This event is only sent once per output object, and the name does not change over the lifetime of the wl_output global. Compositors may re-use the same output name if the wl_output global is destroyed and re-created later. Compositors should avoid re-using the same name if possible. The name event will be followed by a done event. Many compositors can produce human-readable descriptions of their outputs. The client may wish to know this description as well, e.g. for output selection purposes. The description is a UTF-8 string with no convention defined for its contents. The description is not guaranteed to be unique among all wl_output globals. Examples might include 'Foocorp 11" Display' or 'Virtual X11 output via :1'. The description event is sent after binding the output object and whenever the description changes. The description is optional, and may not be sent at all. The description event will be followed by a done event. A region object describes an area. Region objects are used to describe the opaque and input regions of a surface. Destroy the region. This will invalidate the object ID. Add the specified rectangle to the region. Subtract the specified rectangle from the region. The global interface exposing sub-surface compositing capabilities. A wl_surface, that has sub-surfaces associated, is called the parent surface. Sub-surfaces can be arbitrarily nested and create a tree of sub-surfaces. The root surface in a tree of sub-surfaces is the main surface. The main surface cannot be a sub-surface, because sub-surfaces must always have a parent. A main surface with its sub-surfaces forms a (compound) window. For window management purposes, this set of wl_surface objects is to be considered as a single window, and it should also behave as such. The aim of sub-surfaces is to offload some of the compositing work within a window from clients to the compositor. A prime example is a video player with decorations and video in separate wl_surface objects. This should allow the compositor to pass YUV video buffer processing to dedicated overlay hardware when possible. Informs the server that the client will not be using this protocol object anymore. This does not affect any other objects, wl_subsurface objects included. Create a sub-surface interface for the given surface, and associate it with the given parent surface. This turns a plain wl_surface into a sub-surface. The to-be sub-surface must not already have another role, and it must not have an existing wl_subsurface object. Otherwise the bad_surface protocol error is raised. Adding sub-surfaces to a parent is a double-buffered operation on the parent (see wl_surface.commit). The effect of adding a sub-surface becomes visible on the next time the state of the parent surface is applied. The parent surface must not be one of the child surface's descendants, and the parent must be different from the child surface, otherwise the bad_parent protocol error is raised. This request modifies the behaviour of wl_surface.commit request on the sub-surface, see the documentation on wl_subsurface interface. An additional interface to a wl_surface object, which has been made a sub-surface. A sub-surface has one parent surface. A sub-surface's size and position are not limited to that of the parent. Particularly, a sub-surface is not automatically clipped to its parent's area. A sub-surface becomes mapped, when a non-NULL wl_buffer is applied and the parent surface is mapped. The order of which one happens first is irrelevant. A sub-surface is hidden if the parent becomes hidden, or if a NULL wl_buffer is applied. These rules apply recursively through the tree of surfaces. The behaviour of a wl_surface.commit request on a sub-surface depends on the sub-surface's mode. The possible modes are synchronized and desynchronized, see methods wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized mode caches the wl_surface state to be applied when the parent's state gets applied, and desynchronized mode applies the pending wl_surface state directly. A sub-surface is initially in the synchronized mode. Sub-surfaces also have another kind of state, which is managed by wl_subsurface requests, as opposed to wl_surface requests. This state includes the sub-surface position relative to the parent surface (wl_subsurface.set_position), and the stacking order of the parent and its sub-surfaces (wl_subsurface.place_above and .place_below). This state is applied when the parent surface's wl_surface state is applied, regardless of the sub-surface's mode. As the exception, set_sync and set_desync are effective immediately. The main surface can be thought to be always in desynchronized mode, since it does not have a parent in the sub-surfaces sense. Even if a sub-surface is in desynchronized mode, it will behave as in synchronized mode, if its parent surface behaves as in synchronized mode. This rule is applied recursively throughout the tree of surfaces. This means, that one can set a sub-surface into synchronized mode, and then assume that all its child and grand-child sub-surfaces are synchronized, too, without explicitly setting them. Destroying a sub-surface takes effect immediately. If you need to synchronize the removal of a sub-surface to the parent surface update, unmap the sub-surface first by attaching a NULL wl_buffer, update parent, and then destroy the sub-surface. If the parent wl_surface object is destroyed, the sub-surface is unmapped. A sub-surface never has the keyboard focus of any seat. The wl_surface.offset request is ignored: clients must use set_position instead to move the sub-surface. The sub-surface interface is removed from the wl_surface object that was turned into a sub-surface with a wl_subcompositor.get_subsurface request. The wl_surface's association to the parent is deleted. The wl_surface is unmapped immediately. This schedules a sub-surface position change. The sub-surface will be moved so that its origin (top left corner pixel) will be at the location x, y of the parent surface coordinate system. The coordinates are not restricted to the parent surface area. Negative values are allowed. The scheduled coordinates will take effect whenever the state of the parent surface is applied. If more than one set_position request is invoked by the client before the commit of the parent surface, the position of a new request always replaces the scheduled position from any previous request. The initial position is 0, 0. This sub-surface is taken from the stack, and put back just above the reference surface, changing the z-order of the sub-surfaces. The reference surface must be one of the sibling surfaces, or the parent surface. Using any other surface, including this sub-surface, will cause a protocol error. The z-order is double-buffered. Requests are handled in order and applied immediately to a pending state. The final pending state is copied to the active state the next time the state of the parent surface is applied. A new sub-surface is initially added as the top-most in the stack of its siblings and parent. The sub-surface is placed just below the reference surface. See wl_subsurface.place_above. Change the commit behaviour of the sub-surface to synchronized mode, also described as the parent dependent mode. In synchronized mode, wl_surface.commit on a sub-surface will accumulate the committed state in a cache, but the state will not be applied and hence will not change the compositor output. The cached state is applied to the sub-surface immediately after the parent surface's state is applied. This ensures atomic updates of the parent and all its synchronized sub-surfaces. Applying the cached state will invalidate the cache, so further parent surface commits do not (re-)apply old state. See wl_subsurface for the recursive effect of this mode. Change the commit behaviour of the sub-surface to desynchronized mode, also described as independent or freely running mode. In desynchronized mode, wl_surface.commit on a sub-surface will apply the pending state directly, without caching, as happens normally with a wl_surface. Calling wl_surface.commit on the parent surface has no effect on the sub-surface's wl_surface state. This mode allows a sub-surface to be updated on its own. If cached state exists when wl_surface.commit is called in desynchronized mode, the pending state is added to the cached state, and applied as a whole. This invalidates the cache. Note: even if a sub-surface is set to desynchronized, a parent sub-surface may override it to behave as synchronized. For details, see wl_subsurface. If a surface's parent surface behaves as desynchronized, then the cached state is applied on set_desync. ================================================ FILE: wayland/generate/resources/xdg-decoration-unstable-v1.xml ================================================ Copyright © 2018 Simon Ser Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. This interface allows a compositor to announce support for server-side decorations. A window decoration is a set of window controls as deemed appropriate by the party managing them, such as user interface components used to move, resize and change a window's state. A client can use this protocol to request being decorated by a supporting compositor. If compositor and client do not negotiate the use of a server-side decoration using this protocol, clients continue to self-decorate as they see fit. Warning! The protocol described in this file is experimental and backward incompatible changes may be made. Backward compatible changes may be added together with the corresponding interface version bump. Backward incompatible changes are done by bumping the version number in the protocol and interface names and resetting the interface version. Once the protocol is to be declared stable, the 'z' prefix and the version number in the protocol and interface names are removed and the interface version number is reset. Destroy the decoration manager. This doesn't destroy objects created with the manager. Create a new decoration object associated with the given toplevel. Creating an xdg_toplevel_decoration from an xdg_toplevel which has a buffer attached or committed is a client error, and any attempts by a client to attach or manipulate a buffer prior to the first xdg_toplevel_decoration.configure event must also be treated as errors. The decoration object allows the compositor to toggle server-side window decorations for a toplevel surface. The client can request to switch to another mode. The xdg_toplevel_decoration object must be destroyed before its xdg_toplevel. Switch back to a mode without any server-side decorations at the next commit. These values describe window decoration modes. Set the toplevel surface decoration mode. This informs the compositor that the client prefers the provided decoration mode. After requesting a decoration mode, the compositor will respond by emitting an xdg_surface.configure event. The client should then update its content, drawing it without decorations if the received mode is server-side decorations. The client must also acknowledge the configure when committing the new content (see xdg_surface.ack_configure). The compositor can decide not to use the client's mode and enforce a different mode instead. Clients whose decoration mode depend on the xdg_toplevel state may send a set_mode request in response to an xdg_surface.configure event and wait for the next xdg_surface.configure event to prevent unwanted state. Such clients are responsible for preventing configure loops and must make sure not to send multiple successive set_mode requests with the same decoration mode. If an invalid mode is supplied by the client, the invalid_mode protocol error is raised by the compositor. Unset the toplevel surface decoration mode. This informs the compositor that the client doesn't prefer a particular decoration mode. This request has the same semantics as set_mode. The configure event configures the effective decoration mode. The configured state should not be applied immediately. Clients must send an ack_configure in response to this event. See xdg_surface.configure and xdg_surface.ack_configure for details. A configure event can be sent at any time. The specified mode must be obeyed by the client. ================================================ FILE: wayland/generate/resources/xdg-shell.xml ================================================ Copyright © 2008-2013 Kristian Høgsberg Copyright © 2013 Rafael Antognolli Copyright © 2013 Jasper St. Pierre Copyright © 2010-2013 Intel Corporation Copyright © 2015-2017 Samsung Electronics Co., Ltd Copyright © 2015-2017 Red Hat Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. The xdg_wm_base interface is exposed as a global object enabling clients to turn their wl_surfaces into windows in a desktop environment. It defines the basic functionality needed for clients and the compositor to create windows that can be dragged, resized, maximized, etc, as well as creating transient windows such as popup menus. Destroy this xdg_wm_base object. Destroying a bound xdg_wm_base object while there are surfaces still alive created by this xdg_wm_base object instance is illegal and will result in a defunct_surfaces error. Create a positioner object. A positioner object is used to position surfaces relative to some parent surface. See the interface description and xdg_surface.get_popup for details. This creates an xdg_surface for the given surface. While xdg_surface itself is not a role, the corresponding surface may only be assigned a role extending xdg_surface, such as xdg_toplevel or xdg_popup. It is illegal to create an xdg_surface for a wl_surface which already has an assigned role and this will result in a role error. This creates an xdg_surface for the given surface. An xdg_surface is used as basis to define a role to a given surface, such as xdg_toplevel or xdg_popup. It also manages functionality shared between xdg_surface based surface roles. See the documentation of xdg_surface for more details about what an xdg_surface is and how it is used. A client must respond to a ping event with a pong request or the client may be deemed unresponsive. See xdg_wm_base.ping and xdg_wm_base.error.unresponsive. The ping event asks the client if it's still alive. Pass the serial specified in the event back to the compositor by sending a "pong" request back with the specified serial. See xdg_wm_base.pong. Compositors can use this to determine if the client is still alive. It's unspecified what will happen if the client doesn't respond to the ping request, or in what timeframe. Clients should try to respond in a reasonable amount of time. The “unresponsive” error is provided for compositors that wish to disconnect unresponsive clients. A compositor is free to ping in any way it wants, but a client must always respond to any xdg_wm_base object it created. The xdg_positioner provides a collection of rules for the placement of a child surface relative to a parent surface. Rules can be defined to ensure the child surface remains within the visible area's borders, and to specify how the child surface changes its position, such as sliding along an axis, or flipping around a rectangle. These positioner-created rules are constrained by the requirement that a child surface must intersect with or be at least partially adjacent to its parent surface. See the various requests for details about possible rules. At the time of the request, the compositor makes a copy of the rules specified by the xdg_positioner. Thus, after the request is complete the xdg_positioner object can be destroyed or reused; further changes to the object will have no effect on previous usages. For an xdg_positioner object to be considered complete, it must have a non-zero size set by set_size, and a non-zero anchor rectangle set by set_anchor_rect. Passing an incomplete xdg_positioner object when positioning a surface raises an invalid_positioner error. Notify the compositor that the xdg_positioner will no longer be used. Set the size of the surface that is to be positioned with the positioner object. The size is in surface-local coordinates and corresponds to the window geometry. See xdg_surface.set_window_geometry. If a zero or negative size is set the invalid_input error is raised. Specify the anchor rectangle within the parent surface that the child surface will be placed relative to. The rectangle is relative to the window geometry as defined by xdg_surface.set_window_geometry of the parent surface. When the xdg_positioner object is used to position a child surface, the anchor rectangle may not extend outside the window geometry of the positioned child's parent surface. If a negative size is set the invalid_input error is raised. Defines the anchor point for the anchor rectangle. The specified anchor is used derive an anchor point that the child surface will be positioned relative to. If a corner anchor is set (e.g. 'top_left' or 'bottom_right'), the anchor point will be at the specified corner; otherwise, the derived anchor point will be centered on the specified edge, or in the center of the anchor rectangle if no edge is specified. Defines in what direction a surface should be positioned, relative to the anchor point of the parent surface. If a corner gravity is specified (e.g. 'bottom_right' or 'top_left'), then the child surface will be placed towards the specified gravity; otherwise, the child surface will be centered over the anchor point on any axis that had no gravity specified. If the gravity is not in the ‘gravity’ enum, an invalid_input error is raised. The constraint adjustment value define ways the compositor will adjust the position of the surface, if the unadjusted position would result in the surface being partly constrained. Whether a surface is considered 'constrained' is left to the compositor to determine. For example, the surface may be partly outside the compositor's defined 'work area', thus necessitating the child surface's position be adjusted until it is entirely inside the work area. The adjustments can be combined, according to a defined precedence: 1) Flip, 2) Slide, 3) Resize. Don't alter the surface position even if it is constrained on some axis, for example partially outside the edge of an output. Slide the surface along the x axis until it is no longer constrained. First try to slide towards the direction of the gravity on the x axis until either the edge in the opposite direction of the gravity is unconstrained or the edge in the direction of the gravity is constrained. Then try to slide towards the opposite direction of the gravity on the x axis until either the edge in the direction of the gravity is unconstrained or the edge in the opposite direction of the gravity is constrained. Slide the surface along the y axis until it is no longer constrained. First try to slide towards the direction of the gravity on the y axis until either the edge in the opposite direction of the gravity is unconstrained or the edge in the direction of the gravity is constrained. Then try to slide towards the opposite direction of the gravity on the y axis until either the edge in the direction of the gravity is unconstrained or the edge in the opposite direction of the gravity is constrained. Invert the anchor and gravity on the x axis if the surface is constrained on the x axis. For example, if the left edge of the surface is constrained, the gravity is 'left' and the anchor is 'left', change the gravity to 'right' and the anchor to 'right'. If the adjusted position also ends up being constrained, the resulting position of the flip_x adjustment will be the one before the adjustment. Invert the anchor and gravity on the y axis if the surface is constrained on the y axis. For example, if the bottom edge of the surface is constrained, the gravity is 'bottom' and the anchor is 'bottom', change the gravity to 'top' and the anchor to 'top'. The adjusted position is calculated given the original anchor rectangle and offset, but with the new flipped anchor and gravity values. If the adjusted position also ends up being constrained, the resulting position of the flip_y adjustment will be the one before the adjustment. Resize the surface horizontally so that it is completely unconstrained. Resize the surface vertically so that it is completely unconstrained. Specify how the window should be positioned if the originally intended position caused the surface to be constrained, meaning at least partially outside positioning boundaries set by the compositor. The adjustment is set by constructing a bitmask describing the adjustment to be made when the surface is constrained on that axis. If no bit for one axis is set, the compositor will assume that the child surface should not change its position on that axis when constrained. If more than one bit for one axis is set, the order of how adjustments are applied is specified in the corresponding adjustment descriptions. The default adjustment is none. Specify the surface position offset relative to the position of the anchor on the anchor rectangle and the anchor on the surface. For example if the anchor of the anchor rectangle is at (x, y), the surface has the gravity bottom|right, and the offset is (ox, oy), the calculated surface position will be (x + ox, y + oy). The offset position of the surface is the one used for constraint testing. See set_constraint_adjustment. An example use case is placing a popup menu on top of a user interface element, while aligning the user interface element of the parent surface with some user interface element placed somewhere in the popup surface. When set reactive, the surface is reconstrained if the conditions used for constraining changed, e.g. the parent window moved. If the conditions changed and the popup was reconstrained, an xdg_popup.configure event is sent with updated geometry, followed by an xdg_surface.configure event. Set the parent window geometry the compositor should use when positioning the popup. The compositor may use this information to determine the future state the popup should be constrained using. If this doesn't match the dimension of the parent the popup is eventually positioned against, the behavior is undefined. The arguments are given in the surface-local coordinate space. Set the serial of an xdg_surface.configure event this positioner will be used in response to. The compositor may use this information together with set_parent_size to determine what future state the popup should be constrained using. An interface that may be implemented by a wl_surface, for implementations that provide a desktop-style user interface. It provides a base set of functionality required to construct user interface elements requiring management by the compositor, such as toplevel windows, menus, etc. The types of functionality are split into xdg_surface roles. Creating an xdg_surface does not set the role for a wl_surface. In order to map an xdg_surface, the client must create a role-specific object using, e.g., get_toplevel, get_popup. The wl_surface for any given xdg_surface can have at most one role, and may not be assigned any role not based on xdg_surface. A role must be assigned before any other requests are made to the xdg_surface object. The client must call wl_surface.commit on the corresponding wl_surface for the xdg_surface state to take effect. Creating an xdg_surface from a wl_surface which has a buffer attached or committed is a client error, and any attempts by a client to attach or manipulate a buffer prior to the first xdg_surface.configure call must also be treated as errors. After creating a role-specific object and setting it up (e.g. by sending the title, app ID, size constraints, parent, etc), the client must perform an initial commit without any buffer attached. The compositor will reply with initial wl_surface state such as wl_surface.preferred_buffer_scale followed by an xdg_surface.configure event. The client must acknowledge it and is then allowed to attach a buffer to map the surface. Mapping an xdg_surface-based role surface is defined as making it possible for the surface to be shown by the compositor. Note that a mapped surface is not guaranteed to be visible once it is mapped. For an xdg_surface to be mapped by the compositor, the following conditions must be met: (1) the client has assigned an xdg_surface-based role to the surface (2) the client has set and committed the xdg_surface state and the role-dependent state to the surface (3) the client has committed a buffer to the surface A newly-unmapped surface is considered to have met condition (1) out of the 3 required conditions for mapping a surface if its role surface has not been destroyed, i.e. the client must perform the initial commit again before attaching a buffer. Destroy the xdg_surface object. An xdg_surface must only be destroyed after its role object has been destroyed, otherwise a defunct_role_object error is raised. This creates an xdg_toplevel object for the given xdg_surface and gives the associated wl_surface the xdg_toplevel role. See the documentation of xdg_toplevel for more details about what an xdg_toplevel is and how it is used. This creates an xdg_popup object for the given xdg_surface and gives the associated wl_surface the xdg_popup role. If null is passed as a parent, a parent surface must be specified using some other protocol, before committing the initial state. See the documentation of xdg_popup for more details about what an xdg_popup is and how it is used. The window geometry of a surface is its "visible bounds" from the user's perspective. Client-side decorations often have invisible portions like drop-shadows which should be ignored for the purposes of aligning, placing and constraining windows. The window geometry is double-buffered state, see wl_surface.commit. When maintaining a position, the compositor should treat the (x, y) coordinate of the window geometry as the top left corner of the window. A client changing the (x, y) window geometry coordinate should in general not alter the position of the window. Once the window geometry of the surface is set, it is not possible to unset it, and it will remain the same until set_window_geometry is called again, even if a new subsurface or buffer is attached. If never set, the value is the full bounds of the surface, including any subsurfaces. This updates dynamically on every commit. This unset is meant for extremely simple clients. The arguments are given in the surface-local coordinate space of the wl_surface associated with this xdg_surface, and may extend outside of the wl_surface itself to mark parts of the subsurface tree as part of the window geometry. When applied, the effective window geometry will be the set window geometry clamped to the bounding rectangle of the combined geometry of the surface of the xdg_surface and the associated subsurfaces. The effective geometry will not be recalculated unless a new call to set_window_geometry is done and the new pending surface state is subsequently applied. The width and height of the effective window geometry must be greater than zero. Setting an invalid size will raise an invalid_size error. 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. For instance, for toplevel surfaces the compositor might use this information to move a surface to the top left only when the client has drawn itself for the maximized or fullscreen state. If the client receives multiple configure events before it can respond to one, it only has to ack the last configure event. Acking a configure event that was never sent raises an invalid_serial error. 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 serial number sent with the request, as well as serial numbers sent by all configure events sent on this xdg_surface prior to the configure event referenced by the committed serial. It is an error to issue multiple ack_configure requests referencing a serial from the same configure event, or to issue an ack_configure request referencing a serial from a configure event issued before the event identified by the last ack_configure request for the same xdg_surface. Doing so will raise an invalid_serial error. The configure event marks the end of a configure sequence. A configure sequence is a set of one or more events configuring the state of the xdg_surface, including the final xdg_surface.configure event. Where applicable, xdg_surface surface roles will during a configure sequence extend this event as a latched state sent as events before the xdg_surface.configure event. Such events should be considered to make up a set of atomically applied configuration states, where the xdg_surface.configure commits the accumulated state. Clients should arrange their surface for the new states, and then send an ack_configure request with the serial sent in this configure event at some point before committing the new surface. If the client receives multiple configure events before it can respond to one, it is free to discard all but the last event it received. This interface defines an xdg_surface role which allows a surface to, among other things, set window-like properties such as maximize, fullscreen, and minimize, set application-specific metadata like title and id, and well as trigger user interactive operations such as interactive resize and move. A xdg_toplevel by default is responsible for providing the full intended visual representation of the toplevel, which depending on the window state, may mean things like a title bar, window controls and drop shadow. Unmapping an xdg_toplevel means that the surface cannot be shown by the compositor until it is explicitly mapped again. All active operations (e.g., move, resize) are canceled and all attributes (e.g. title, state, stacking, ...) are discarded for an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to the state it had right after xdg_surface.get_toplevel. The client can re-map the toplevel by performing a commit without any buffer attached, waiting for a configure event and handling it as usual (see xdg_surface description). Attaching a null buffer to a toplevel unmaps the surface. This request destroys the role surface and unmaps the surface; see "Unmapping" behavior in interface section for details. Set the "parent" of this surface. This surface should be stacked above the parent surface and all other ancestor surfaces. Parent surfaces should be set on dialogs, toolboxes, or other "auxiliary" surfaces, so that the parent is raised when the dialog is raised. Setting a null parent for a child surface unsets its parent. Setting a null parent for a surface which currently has no parent is a no-op. Only mapped surfaces can have child surfaces. Setting a parent which is not mapped is equivalent to setting a null parent. If a surface becomes unmapped, its children's parent is set to the parent of the now-unmapped surface. If the now-unmapped surface has no parent, its children's parent is unset. If the now-unmapped surface becomes mapped again, its parent-child relationship is not restored. The parent toplevel must not be one of the child toplevel's descendants, and the parent must be different from the child toplevel, otherwise the invalid_parent protocol error is raised. Set a short title for the surface. This string may be used to identify the surface in a task bar, window list, or other user interface elements provided by the compositor. The string must be encoded in UTF-8. Set an application identifier for the surface. The app ID identifies the general class of applications to which the surface belongs. The compositor can use this to group multiple surfaces together, or to determine how to launch a new application. For D-Bus activatable applications, the app ID is used as the D-Bus service name. The compositor shell will try to group application surfaces together by their app ID. As a best practice, it is suggested to select app ID's that match the basename of the application's .desktop file. For example, "org.freedesktop.FooViewer" where the .desktop file is "org.freedesktop.FooViewer.desktop". Like other properties, a set_app_id request can be sent after the xdg_toplevel has been mapped to update the property. See the desktop-entry specification [0] for more details on application identifiers and how they relate to well-known D-Bus names and .desktop files. [0] https://standards.freedesktop.org/desktop-entry-spec/ Clients implementing client-side decorations might want to show a context menu when right-clicking on the decorations, giving the user a menu that they can use to maximize or minimize the window. This request asks the compositor to pop up such a window menu at the given position, relative to the local surface coordinates of the parent surface. There are no guarantees as to what menu items the window menu contains, or even if a window menu will be drawn at all. This request must be used in response to some sort of user action like a button press, key press, or touch down event. Start an interactive, user-driven move of the surface. This request must be used in response to some sort of user action like a button press, key press, or touch down event. The passed serial is used to determine the type of interactive move (touch, pointer, etc). The server may ignore move requests depending on the state of the surface (e.g. fullscreen or maximized), or if the passed serial is no longer valid. If triggered, the surface will lose the focus of the device (wl_pointer, wl_touch, etc) used for the move. It is up to the compositor to visually indicate that the move is taking place, such as updating a pointer cursor, during the move. There is no guarantee that the device focus will return when the move is completed. These values are used to indicate which edge of a surface is being dragged in a resize operation. Start a user-driven, interactive resize of the surface. This request must be used in response to some sort of user action like a button press, key press, or touch down event. The passed serial is used to determine the type of interactive resize (touch, pointer, etc). The server may ignore resize requests depending on the state of the surface (e.g. fullscreen or maximized). If triggered, the client will receive configure events with the "resize" state enum value and the expected sizes. See the "resize" enum value for more details about what is required. The client must also acknowledge configure events using "ack_configure". After the resize is completed, the client will receive another "configure" event without the resize state. If triggered, the surface also will lose the focus of the device (wl_pointer, wl_touch, etc) used for the resize. It is up to the compositor to visually indicate that the resize is taking place, such as updating a pointer cursor, during the resize. There is no guarantee that the device focus will return when the resize is completed. The edges parameter specifies how the surface should be resized, and is one of the values of the resize_edge enum. Values not matching a variant of the enum will cause the invalid_resize_edge protocol error. The compositor may use this information to update the surface position for example when dragging the top left corner. The compositor may also use this information to adapt its behavior, e.g. choose an appropriate cursor image. The different state values used on the surface. This is designed for state values like maximized, fullscreen. It is paired with the configure event to ensure that both the client and the compositor setting the state can be synchronized. States set in this way are double-buffered, see wl_surface.commit. The surface is maximized. The window geometry specified in the configure event must be obeyed by the client, or the xdg_wm_base.invalid_surface_state error is raised. The client should draw without shadow or other decoration outside of the window geometry. The surface is fullscreen. The window geometry specified in the configure event is a maximum; the client cannot resize beyond it. For a surface to cover the whole fullscreened area, the geometry dimensions must be obeyed by the client. For more details, see xdg_toplevel.set_fullscreen. The surface is being resized. The window geometry specified in the configure event is a maximum; the client cannot resize beyond it. Clients that have aspect ratio or cell sizing configuration can use a smaller size, however. Client window decorations should be painted as if the window is active. Do not assume this means that the window actually has keyboard or pointer focus. The window is currently in a tiled layout and the left edge is considered to be adjacent to another part of the tiling grid. The client should draw without shadow or other decoration outside of the window geometry on the left edge. The window is currently in a tiled layout and the right edge is considered to be adjacent to another part of the tiling grid. The client should draw without shadow or other decoration outside of the window geometry on the right edge. The window is currently in a tiled layout and the top edge is considered to be adjacent to another part of the tiling grid. The client should draw without shadow or other decoration outside of the window geometry on the top edge. The window is currently in a tiled layout and the bottom edge is considered to be adjacent to another part of the tiling grid. The client should draw without shadow or other decoration outside of the window geometry on the bottom edge. The surface is currently not ordinarily being repainted; for example because its content is occluded by another window, or its outputs are switched off due to screen locking. Set a maximum size for the window. The client can specify a maximum size so that the compositor does not try to configure the window beyond this size. The width and height arguments are in window geometry coordinates. See xdg_surface.set_window_geometry. Values set in this way are double-buffered, see wl_surface.commit. The compositor can use this information to allow or disallow different states like maximize or fullscreen and draw accurate animations. Similarly, a tiling window manager may use this information to place and resize client windows in a more effective way. The client should not rely on the compositor to obey the maximum size. The compositor may decide to ignore the values set by the client and request a larger size. If never set, or a value of zero in the request, means that the client has no expected maximum size in the given dimension. As a result, a client wishing to reset the maximum size to an unspecified state can use zero for width and height in the request. Requesting a maximum size to be smaller than the minimum size of a surface is illegal and will result in an invalid_size error. The width and height must be greater than or equal to zero. Using strictly negative values for width or height will result in a invalid_size error. Set a minimum size for the window. The client can specify a minimum size so that the compositor does not try to configure the window below this size. The width and height arguments are in window geometry coordinates. See xdg_surface.set_window_geometry. Values set in this way are double-buffered, see wl_surface.commit. The compositor can use this information to allow or disallow different states like maximize or fullscreen and draw accurate animations. Similarly, a tiling window manager may use this information to place and resize client windows in a more effective way. The client should not rely on the compositor to obey the minimum size. The compositor may decide to ignore the values set by the client and request a smaller size. If never set, or a value of zero in the request, means that the client has no expected minimum size in the given dimension. As a result, a client wishing to reset the minimum size to an unspecified state can use zero for width and height in the request. Requesting a minimum size to be larger than the maximum size of a surface is illegal and will result in an invalid_size error. The width and height must be greater than or equal to zero. Using strictly negative values for width and height will result in a invalid_size error. Maximize the surface. After requesting that the surface should be maximized, the compositor will respond by emitting a configure event. Whether this configure actually sets the window maximized is subject to compositor policies. The client must then update its content, drawing in the configured state. The client must also acknowledge the configure when committing the new content (see ack_configure). It is up to the compositor to decide how and where to maximize the surface, for example which output and what region of the screen should be used. If the surface was already maximized, the compositor will still emit a configure event with the "maximized" state. If the surface is in a fullscreen state, this request has no direct effect. It may alter the state the surface is returned to when unmaximized unless overridden by the compositor. Unmaximize the surface. After requesting that the surface should be unmaximized, the compositor will respond by emitting a configure event. Whether this actually un-maximizes the window is subject to compositor policies. If available and applicable, the compositor will include the window geometry dimensions the window had prior to being maximized in the configure event. The client must then update its content, drawing it in the configured state. The client must also acknowledge the configure when committing the new content (see ack_configure). It is up to the compositor to position the surface after it was unmaximized; usually the position the surface had before maximizing, if applicable. If the surface was already not maximized, the compositor will still emit a configure event without the "maximized" state. If the surface is in a fullscreen state, this request has no direct effect. It may alter the state the surface is returned to when unmaximized unless overridden by the compositor. Make the surface fullscreen. After requesting that the surface should be fullscreened, the compositor will respond by emitting a configure event. Whether the client is actually put into a fullscreen state is subject to compositor policies. The client must also acknowledge the configure when committing the new content (see ack_configure). The output passed by the request indicates the client's preference as to which display it should be set fullscreen on. If this value is NULL, it's up to the compositor to choose which display will be used to map this surface. If the surface doesn't cover the whole output, the compositor will position the surface in the center of the output and compensate with with border fill covering the rest of the output. The content of the border fill is undefined, but should be assumed to be in some way that attempts to blend into the surrounding area (e.g. solid black). If the fullscreened surface is not opaque, the compositor must make sure that other screen content not part of the same surface tree (made up of subsurfaces, popups or similarly coupled surfaces) are not visible below the fullscreened surface. Make the surface no longer fullscreen. After requesting that the surface should be unfullscreened, the compositor will respond by emitting a configure event. Whether this actually removes the fullscreen state of the client is subject to compositor policies. Making a surface unfullscreen sets states for the surface based on the following: * the state(s) it may have had before becoming fullscreen * any state(s) decided by the compositor * any state(s) requested by the client while the surface was fullscreen The compositor may include the previous window geometry dimensions in the configure event, if applicable. The client must also acknowledge the configure when committing the new content (see ack_configure). Request that the compositor minimize your surface. There is no way to know if the surface is currently minimized, nor is there any way to unset minimization on this surface. If you are looking to throttle redrawing when minimized, please instead use the wl_surface.frame event for this, as this will also work with live previews on windows in Alt-Tab, Expose or similar compositor features. This configure event asks the client to resize its toplevel surface or to change its state. The configured state should not be applied immediately. See xdg_surface.configure for details. The width and height arguments specify a hint to the window about how its surface should be resized in window geometry coordinates. See set_window_geometry. If the width or height arguments are zero, it means the client should decide its own window dimension. This may happen when the compositor needs to configure the state of the surface but doesn't have any information about any previous or expected dimension. The states listed in the event specify how the width/height arguments should be interpreted, and possibly how it should be drawn. Clients must send an ack_configure in response to this event. See xdg_surface.configure and xdg_surface.ack_configure for details. The close event is sent by the compositor when the user wants the surface to be closed. This should be equivalent to the user clicking the close button in client-side decorations, if your application has any. This is only a request that the user intends to close the window. The client may choose to ignore this request, or show a dialog to ask the user to save their data, etc. The configure_bounds event may be sent prior to a xdg_toplevel.configure event to communicate the bounds a window geometry size is recommended to constrain to. The passed width and height are in surface coordinate space. If width and height are 0, it means bounds is unknown and equivalent to as if no configure_bounds event was ever sent for this surface. The bounds can for example correspond to the size of a monitor excluding any panels or other shell components, so that a surface isn't created in a way that it cannot fit. The bounds may change at any point, and in such a case, a new xdg_toplevel.configure_bounds will be sent, followed by xdg_toplevel.configure and xdg_surface.configure. This event advertises the capabilities supported by the compositor. If a capability isn't supported, clients should hide or disable the UI elements that expose this functionality. For instance, if the compositor doesn't advertise support for minimized toplevels, a button triggering the set_minimized request should not be displayed. The compositor will ignore requests it doesn't support. For instance, a compositor which doesn't advertise support for minimized will ignore set_minimized requests. Compositors must send this event once before the first xdg_surface.configure event. When the capabilities change, compositors must send this event again and then send an xdg_surface.configure event. The configured state should not be applied immediately. See xdg_surface.configure for details. The capabilities are sent as an array of 32-bit unsigned integers in native endianness. A popup surface is a short-lived, temporary surface. It can be used to implement for example menus, popovers, tooltips and other similar user interface concepts. A popup can be made to take an explicit grab. See xdg_popup.grab for details. When the popup is dismissed, a popup_done event will be sent out, and at the same time the surface will be unmapped. See the xdg_popup.popup_done event for details. Explicitly destroying the xdg_popup object will also dismiss the popup and unmap the surface. Clients that want to dismiss the popup when another surface of their own is clicked should dismiss the popup using the destroy request. A newly created xdg_popup will be stacked on top of all previously created xdg_popup surfaces associated with the same xdg_toplevel. The parent of an xdg_popup must be mapped (see the xdg_surface description) before the xdg_popup itself. The client must call wl_surface.commit on the corresponding wl_surface for the xdg_popup state to take effect. This destroys the popup. Explicitly destroying the xdg_popup object will also dismiss the popup, and unmap the surface. If this xdg_popup is not the "topmost" popup, the xdg_wm_base.not_the_topmost_popup protocol error will be sent. This request makes the created popup take an explicit grab. An explicit grab will be dismissed when the user dismisses the popup, or when the client destroys the xdg_popup. This can be done by the user clicking outside the surface, using the keyboard, or even locking the screen through closing the lid or a timeout. If the compositor denies the grab, the popup will be immediately dismissed. This request must be used in response to some sort of user action like a button press, key press, or touch down event. The serial number of the event should be passed as 'serial'. The parent of a grabbing popup must either be an xdg_toplevel surface or another xdg_popup with an explicit grab. If the parent is another xdg_popup it means that the popups are nested, with this popup now being the topmost popup. Nested popups must be destroyed in the reverse order they were created in, e.g. the only popup you are allowed to destroy at all times is the topmost one. When compositors choose to dismiss a popup, they may dismiss every nested grabbing popup as well. When a compositor dismisses popups, it will follow the same dismissing order as required from the client. If the topmost grabbing popup is destroyed, the grab will be returned to the parent of the popup, if that parent previously had an explicit grab. If the parent is a grabbing popup which has already been dismissed, this popup will be immediately dismissed. If the parent is a popup that did not take an explicit grab, an error will be raised. During a popup grab, the client owning the grab will receive pointer and touch events for all their surfaces as normal (similar to an "owner-events" grab in X11 parlance), while the top most grabbing popup will always have keyboard focus. This event asks the popup surface to configure itself given the configuration. The configured state should not be applied immediately. See xdg_surface.configure for details. The x and y arguments represent the position the popup was placed at given the xdg_positioner rule, relative to the upper left corner of the window geometry of the parent surface. For version 2 or older, the configure event for an xdg_popup is only ever sent once for the initial configuration. Starting with version 3, it may be sent again if the popup is setup with an xdg_positioner with set_reactive requested, or in response to xdg_popup.reposition requests. The popup_done event is sent out when a popup is dismissed by the compositor. The client should destroy the xdg_popup object at this point. Reposition an already-mapped popup. The popup will be placed given the details in the passed xdg_positioner object, and a xdg_popup.repositioned followed by xdg_popup.configure and xdg_surface.configure will be emitted in response. Any parameters set by the previous positioner will be discarded. The passed token will be sent in the corresponding xdg_popup.repositioned event. The new popup position will not take effect until the corresponding configure event is acknowledged by the client. See xdg_popup.repositioned for details. The token itself is opaque, and has no other special meaning. If multiple reposition requests are sent, the compositor may skip all but the last one. If the popup is repositioned in response to a configure event for its parent, the client should send an xdg_positioner.set_parent_configure and possibly an xdg_positioner.set_parent_size request to allow the compositor to properly constrain the popup. If the popup is repositioned together with a parent that is being resized, but not in response to a configure event, the client should send an xdg_positioner.set_parent_size request. The repositioned event is sent as part of a popup configuration sequence, together with xdg_popup.configure and lastly xdg_surface.configure to notify the completion of a reposition request. The repositioned event is to notify about the completion of a xdg_popup.reposition request. The token argument is the token passed in the xdg_popup.reposition request. Immediately after this event is emitted, xdg_popup.configure and xdg_surface.configure will be sent with the updated size and position, as well as a new configure serial. The client should optionally update the content of the popup, but must acknowledge the new popup configuration for the new position to take effect. See xdg_surface.ack_configure for details. ================================================ FILE: wayland/generate/resources/xwayland-keyboard-grab-unstable-v1.xml ================================================ Copyright © 2017 Red Hat Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. This protocol is application-specific to meet the needs of the X11 protocol through Xwayland. It provides a way for Xwayland to request all keyboard events to be forwarded to a surface even when the surface does not have keyboard focus. In the X11 protocol, a client may request an "active grab" on the keyboard. On success, all key events are reported only to the grabbing X11 client. For details, see XGrabKeyboard(3). The core Wayland protocol does not have a notion of an active keyboard grab. When running in Xwayland, X11 applications may acquire an active grab inside Xwayland but that cannot be translated to the Wayland compositor who may set the input focus to some other surface. In doing so, it breaks the X11 client assumption that all key events are reported to the grabbing client. This protocol specifies a way for Xwayland to request all keyboard be directed to the given surface. The protocol does not guarantee that the compositor will honor this request and it does not prescribe user interfaces on how to handle the respond. For example, a compositor may inform the user that all key events are now forwarded to the given client surface, or it may ask the user for permission to do so. Compositors are required to restrict access to this application specific protocol to Xwayland alone. Warning! The protocol described in this file is experimental and backward incompatible changes may be made. Backward compatible changes may be added together with the corresponding interface version bump. Backward incompatible changes are done by bumping the version number in the protocol and interface names and resetting the interface version. Once the protocol is to be declared stable, the 'z' prefix and the version number in the protocol and interface names are removed and the interface version number is reset. A global interface used for grabbing the keyboard. Destroy the keyboard grab manager. The grab_keyboard request asks for a grab of the keyboard, forcing the keyboard focus for the given seat upon the given surface. The protocol provides no guarantee that the grab is ever satisfied, and does not require the compositor to send an error if the grab cannot ever be satisfied. It is thus possible to request a keyboard grab that will never be effective. The protocol: * does not guarantee that the grab itself is applied for a surface, the grab request may be silently ignored by the compositor, * does not guarantee that any events are sent to this client even if the grab is applied to a surface, * does not guarantee that events sent to this client are exhaustive, a compositor may filter some events for its own consumption, * does not guarantee that events sent to this client are continuous, a compositor may change and reroute keyboard events while the grab is nominally active. A global interface used for grabbing the keyboard. Destroy the grabbed keyboard object. If applicable, the compositor will ungrab the keyboard. ================================================ FILE: wayland/generate/resources/xwayland-shell-v1.xml ================================================ Copyright © 2022 Joshua Ashton Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. This protocol adds a xwayland_surface role which allows an Xwayland server to associate an X11 window to a wl_surface. Before this protocol, this would be done via the Xwayland server providing the wl_surface's resource id via the a client message with the WL_SURFACE_ID atom on the X window. This was problematic as a race could occur if the wl_surface associated with a WL_SURFACE_ID for a window was destroyed before the client message was processed by the compositor and another surface (or other object) had taken its id due to recycling. This protocol solves the problem by moving the X11 window to wl_surface association step to the Wayland side, which means that the association cannot happen out-of-sync with the resource lifetime of the wl_surface. This protocol avoids duplicating the race on the other side by adding a non-zero monotonic serial number which is entirely unique that is set on both the wl_surface (via. xwayland_surface_v1's set_serial method) and the X11 window (via. the `WL_SURFACE_SERIAL` client message) that can be used to associate them, and synchronize the two timelines. The key words "must", "must not", "required", "shall", "shall not", "should", "should not", "recommended", "may", and "optional" in this document are to be interpreted as described in IETF RFC 2119. Warning! The protocol described in this file is currently in the testing phase. Backward compatible changes may be added together with the corresponding interface version bump. Backward incompatible changes can only be done by creating a new major version of the extension. xwayland_shell_v1 is a singleton global object that provides the ability to create a xwayland_surface_v1 object for a given wl_surface. This interface is intended to be bound by the Xwayland server. A compositor must not allow clients other than Xwayland to bind to this interface. A compositor should hide this global from other clients' wl_registry. A client the compositor does not consider to be an Xwayland server attempting to bind this interface will result in an implementation-defined error. An Xwayland server that has bound this interface must not set the `WL_SURFACE_ID` atom on a window. Destroy the xwayland_shell_v1 object. The child objects created via this interface are unaffected. Create an xwayland_surface_v1 interface for a given wl_surface object and gives it the xwayland_surface role. It is illegal to create an xwayland_surface_v1 for a wl_surface which already has an assigned role and this will result in the `role` protocol error. See the documentation of xwayland_surface_v1 for more details about what an xwayland_surface_v1 is and how it is used. An Xwayland surface is a surface managed by an Xwayland server. It is used for associating surfaces to Xwayland windows. The Xwayland server associated with actions in this interface is determined by the Wayland client making the request. The client must call wl_surface.commit on the corresponding wl_surface for the xwayland_surface_v1 state to take effect. Associates an Xwayland window to a wl_surface. The association state is double-buffered, see wl_surface.commit. The `serial_lo` and `serial_hi` parameters specify a non-zero monotonic serial number which is entirely unique and provided by the Xwayland server equal to the serial value provided by a client message with a message type of the `WL_SURFACE_SERIAL` atom on the X11 window for this surface to be associated to. The serial value in the `WL_SURFACE_SERIAL` client message is specified as having the lo-bits specified in `l[0]` and the hi-bits specified in `l[1]`. If the serial value provided by `serial_lo` and `serial_hi` is not valid, the `invalid_serial` protocol error will be raised. An X11 window may be associated with multiple surfaces throughout its lifespan. (eg. unmapping and remapping a window). For each wl_surface, this state must not be committed more than once, otherwise the `already_associated` protocol error will be raised. Destroy the xwayland_surface_v1 object. Any already existing associations are unaffected by this action. ================================================ FILE: wayland/generate.go ================================================ package wayland //go:generate sh -c "go run ./generate ./protocols . $(go list) WlSurface XdgPositioner XdgSurface WlPointer WlSubsurface XdgToplevel" ================================================ FILE: wayland/mmap.c ================================================ #include #include #include #include #include void *mmap_fd(int fd, size_t size) { int prot = PROT_READ | PROT_WRITE; int flags = MAP_SHARED; void *addr = mmap(NULL, size, prot, flags, fd, 0); if (addr == MAP_FAILED) { perror("mmap"); return MAP_FAILED; } return addr; } bool unmap(void* addr, size_t size) { if (addr != MAP_FAILED) { if (munmap(addr, size) == -1) { perror("munmap in unmap"); return false; } } return true; } void* remap(int fd, void* addr, size_t size, size_t new_size) { if (new_size == size) { return addr; } if (addr == MAP_FAILED) { return MAP_FAILED; } bool unmap_success = unmap(addr, size); if (!unmap_success) { return MAP_FAILED; } addr = mmap_fd(fd, new_size); if (addr == MAP_FAILED) { perror("mmap in remap"); return MAP_FAILED; } size = new_size; return addr; } void* map_failed(void) { return MAP_FAILED; } ================================================ FILE: wayland/mmap.h ================================================ #include #include void *mmap_fd(int fd, size_t size); bool unmap(void* addr, size_t size); void* remap(int fd, void* addr, size_t size, size_t new_size); void* map_failed(void); ================================================ FILE: wayland/pointerslices/Readme.md ================================================ This implements parts of the slices package of the stdlib but for slices that contain pointers, less bugs. ================================================ FILE: wayland/pointerslices/lib.go ================================================ package pointerslices import "slices" func Contains[T comparable](slice []*T, item T) bool { for _, s := range slice { if s == nil { continue } if *s == item { return true } } return false } func DeleteFunc[T any](slice []*T, f func(T) bool) []*T { for i, s := range slice { if s == nil { continue } if f(*s) { return slices.Delete(slice, i, i+1) } } return slice } func Index[T comparable](slice []*T, item T) int { for i, s := range slice { if s == nil { continue } if *s == item { return i } } return -1 } // Compares for value equality, not pointer equality // But will return the index of nil if item is nil and there is a nil in the slice func IndexOfItemOrNil[T comparable](slice []*T, item *T) int { for i, s := range slice { if s == nil && item == nil { return i } if s != nil && item != nil && *s == *item { return i } } return -1 } func Delete[T any](slice []*T, start, end int) []*T { return slices.Delete(slice, start, end) } func Insert[T any](slice []*T, index int, values ...*T) []*T { return slices.Insert(slice, index, values...) } ================================================ FILE: wayland/protocols/GlobalObjects.go ================================================ package protocols type GlobalID AnyObjectID type Version uint32 const ( GlobalID_WlDisplay GlobalID = 1 GlobalID_WlCompositor GlobalID = 0xff00000 GlobalID_WlSubcompositor GlobalID = 0xff00001 GlobalID_WlOutput GlobalID = 0xff00002 GlobalID_WlSeat GlobalID = 0xff00003 GlobalID_WlShm GlobalID = 0xff00004 GlobalID_XdgWmBase GlobalID = 0xff00005 GlobalID_WlDataDeviceManager GlobalID = 0xff00006 GlobalID_WlKeyboard GlobalID = 0xff00007 GlobalID_WlPointer GlobalID = 0xff00008 GlobalID_ZwpXwaylandKeyboardGrabManagerV1 GlobalID = 0xff00009 GlobalID_XwaylandShellV1 GlobalID = 0xff00011 GlobalID_WlDataDevice GlobalID = 0xff00012 GlobalID_WlTouch GlobalID = 0xff00013 GlobalID_ZxdgDecorationManagerV1 GlobalID = 0xff00014 ) type AdvertisedGlobalObjectName struct { Name string Id GlobalID Version uint32 } var AdvertisedGlobalObjectNames = []AdvertisedGlobalObjectName{ {"wl_compositor", GlobalID_WlCompositor, 6}, /** * Turning off the wl_subcompositor will turn off * decorations. Any other side effects??? Looks like * GameScope has it turned off, so maybe we could do that * too. * * some programs will crash if wl_subcompositor is not * advertised. */ {"wl_subcompositor", GlobalID_WlSubcompositor, 1}, {"wl_output", GlobalID_WlOutput, 5}, {"wl_seat", GlobalID_WlSeat, 10}, {"wl_shm", GlobalID_WlShm, 2}, {"xdg_wm_base", GlobalID_XdgWmBase, 6}, {"wl_data_device_manager", GlobalID_WlDataDeviceManager, 3}, {"zxdg_decoration_manager_v1", GlobalID_ZxdgDecorationManagerV1, 1}, /** * @TODO only advertise these to Xwayland clients */ {"zwp_xwayland_keyboard_grab_manager_v1", GlobalID_ZwpXwaylandKeyboardGrabManagerV1, 1}, {"xwayland_shell_v1", GlobalID_XwaylandShellV1, 1}, } func GetGlobalWlDisplayBinds(cs ClientState) map[ObjectID[WlDisplay]]Version { v := cs.GetGlobalBinds(GlobalID(GlobalID_WlDisplay)) if v == nil { return nil } m := v.(map[ObjectID[WlDisplay]]Version) return m } func GetGlobalWlCompositorBinds(cs ClientState) map[ObjectID[WlCompositor]]Version { v := cs.GetGlobalBinds(GlobalID(GlobalID_WlCompositor)) if v == nil { return nil } m := v.(map[ObjectID[WlCompositor]]Version) return m } func GetGlobalWlSubcompositorBinds(cs ClientState) map[ObjectID[WlSubcompositor]]Version { v := cs.GetGlobalBinds(GlobalID(GlobalID_WlSubcompositor)) if v == nil { return nil } m := v.(map[ObjectID[WlSubcompositor]]Version) return m } func GetGlobalWlOutputBinds(cs ClientState) map[ObjectID[WlOutput]]Version { v := cs.GetGlobalBinds(GlobalID(GlobalID_WlOutput)) if v == nil { return nil } m := v.(map[ObjectID[WlOutput]]Version) return m } func GetGlobalWlSeatBinds(cs ClientState) map[ObjectID[WlSeat]]Version { v := cs.GetGlobalBinds(GlobalID(GlobalID_WlSeat)) if v == nil { return nil } m := v.(map[ObjectID[WlSeat]]Version) return m } func GetGlobalWlShmBinds(cs ClientState) map[ObjectID[WlShm]]Version { v := cs.GetGlobalBinds(GlobalID(GlobalID_WlShm)) if v == nil { return nil } m := v.(map[ObjectID[WlShm]]Version) return m } func GetGlobalXdgWmBaseBinds(cs ClientState) map[ObjectID[XdgWmBase]]Version { v := cs.GetGlobalBinds(GlobalID(GlobalID_XdgWmBase)) if v == nil { return nil } m := v.(map[ObjectID[XdgWmBase]]Version) return m } func GetGlobalWlDataDeviceManagerBinds(cs ClientState) map[ObjectID[WlDataDeviceManager]]Version { v := cs.GetGlobalBinds(GlobalID(GlobalID_WlDataDeviceManager)) if v == nil { return nil } m := v.(map[ObjectID[WlDataDeviceManager]]Version) return m } func GetGlobalWlKeyboardBinds(cs ClientState) map[ObjectID[WlKeyboard]]Version { v := cs.GetGlobalBinds(GlobalID(GlobalID_WlKeyboard)) if v == nil { return nil } m := v.(map[ObjectID[WlKeyboard]]Version) return m } func GetGlobalWlPointerBinds(cs ClientState) map[ObjectID[WlPointer]]Version { v := cs.GetGlobalBinds(GlobalID(GlobalID_WlPointer)) if v == nil { return nil } m := v.(map[ObjectID[WlPointer]]Version) return m } func GetGlobalZwpXwaylandKeyboardGrabManagerV1Binds(cs ClientState) map[ObjectID[ZwpXwaylandKeyboardGrabManagerV1]]Version { v := cs.GetGlobalBinds(GlobalID(GlobalID_ZwpXwaylandKeyboardGrabManagerV1)) if v == nil { return nil } m := v.(map[ObjectID[ZwpXwaylandKeyboardGrabManagerV1]]Version) return m } func GetGlobalXwaylandShellV1Binds(cs ClientState) map[ObjectID[XwaylandShellV1]]Version { v := cs.GetGlobalBinds(GlobalID(GlobalID_XwaylandShellV1)) if v == nil { return nil } m := v.(map[ObjectID[XwaylandShellV1]]Version) return m } func GetGlobalWlDataDeviceBinds(cs ClientState) map[ObjectID[WlDataDevice]]Version { v := cs.GetGlobalBinds(GlobalID(GlobalID_WlDataDevice)) if v == nil { return nil } m := v.(map[ObjectID[WlDataDevice]]Version) return m } func GetGlobalWlTouchBinds(cs ClientState) map[ObjectID[WlTouch]]Version { v := cs.GetGlobalBinds(GlobalID(GlobalID_WlTouch)) if v == nil { return nil } m := v.(map[ObjectID[WlTouch]]Version) return m } func GetGlobalZxdgDecorationManagerV1Binds(cs ClientState) map[ObjectID[ZxdgDecorationManagerV1]]Version { v := cs.GetGlobalBinds(GlobalID(GlobalID_ZxdgDecorationManagerV1)) if v == nil { return nil } m := v.(map[ObjectID[ZxdgDecorationManagerV1]]Version) return m } ================================================ FILE: wayland/protocols/structs.go ================================================ package protocols type ObjectID[T any] uint32 type AnyObjectID = ObjectID[any] type OnBindable interface { OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type HasBindable interface { GetBindable() OnBindable } type WaylandObject[T OnBindable] interface { GetDelegate() T OnRequest(s FileDescriptorClaimClientState, message Message) GetBindable() OnBindable } type OnRequestable interface { OnRequest(s FileDescriptorClaimClientState, message Message) } // Don't use these functions directly; use the ones in wayland/types.go type ClientState interface { RemoveObject(AnyObjectID) // RemoveGlobalBind(GlobalID, AnyObjectID) AddObject(AnyObjectID, any) SetCompositorVersion(uint32) GetCompositorVersion() uint32 GetObject(AnyObjectID) any RegisterRoleToSurface(AnyObjectID, ObjectID[WlSurface]) UnregisterRoleToSurface(AnyObjectID) Send(OutgoingEvent) SendError(AnyObjectID, uint32, string) DrawableSurfaces() map[ObjectID[WlSurface]]bool TopLevelSurfaces() map[ObjectID[XdgToplevel]]bool AddFrameDrawRequest(ObjectID[WlCallback]) GetSurfaceIDFromRole(AnyObjectID) *ObjectID[WlSurface] GetSurfaceFromRole(AnyObjectID) any FindDescendantSurface(ObjectID[WlSurface], ObjectID[WlSurface]) bool GetGlobalBinds(GlobalID) any // AddGlobalBind(GlobalID, AnyObjectID, Version) AddGlobalWlShmBind(ObjectID[WlShm], Version) AddGlobalWlSeatBind(ObjectID[WlSeat], Version) AddGlobalWlOutputBind(ObjectID[WlOutput], Version) AddGlobalWlKeyboardBind(ObjectID[WlKeyboard], Version) AddGlobalWlPointerBind(ObjectID[WlPointer], Version) AddGlobalWlTouchBind(ObjectID[WlTouch], Version) AddGlobalWlDataDeviceBind(ObjectID[WlDataDevice], Version) AddGlobalZwpXwaylandKeyboardGrabManagerV1Bind(ObjectID[ZwpXwaylandKeyboardGrabManagerV1], Version) RemoveGlobalWlShmBind(ObjectID[WlShm]) RemoveGlobalWlSeatBind(ObjectID[WlSeat]) RemoveGlobalWlOutputBind(ObjectID[WlOutput]) RemoveGlobalWlKeyboardBind(ObjectID[WlKeyboard]) RemoveGlobalWlPointerBind(ObjectID[WlPointer]) RemoveGlobalWlTouchBind(ObjectID[WlTouch]) RemoveGlobalWlDataDeviceBind(ObjectID[WlDataDevice]) RemoveGlobalZwpXwaylandKeyboardGrabManagerV1Bind(ObjectID[ZwpXwaylandKeyboardGrabManagerV1]) } type OutgoingEvent struct { ObjectID AnyObjectID Opcode uint16 Data []byte FileDescriptor *FileDescriptor } type FileDescriptorClaimClientState interface { ClientState ClaimFileDescriptor() *FileDescriptor } type FileDescriptor int type Sender interface { Send(OutgoingEvent) } type DecodeStateType int type Message struct { ObjectID AnyObjectID Opcode uint16 Size uint16 Data []byte } type DecodeState struct { Phase DecodeStateType I uint // bit offset within current field (0,8,16,24) ObjectID AnyObjectID Opcode uint16 Size uint16 Data []byte } type Fixed = float64 ================================================ FILE: wayland/protocols/wayland.xml.go ================================================ // Code generated by `cmd/protocols`; DO NOT EDIT. package protocols import "fmt" type WlDisplay_delegate interface { WlDisplay_sync(s ClientState, object_id ObjectID[WlDisplay], callback ObjectID[WlCallback]) WlDisplay_get_registry(s ClientState, object_id ObjectID[WlDisplay], registry ObjectID[WlRegistry]) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type WlDisplay struct { Delegate WlDisplay_delegate } func (p *WlDisplay) GetDelegate() WlDisplay_delegate { return p.Delegate } func (p *WlDisplay) GetBindable() OnBindable { return p.Delegate } func WlDisplay_error(s Sender, eventObjectID ObjectID[WlDisplay], object_id AnyObjectID, code uint32, message string) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(object_id)) putUint32(uint32(code)) { b := []byte(message) total := len(b) + 1 // include null terminator putUint32(uint32(total)) data = append(data, b...) data = append(data, 0) if pad := (4 - (total % 4)) % 4; pad != 0 { data = append(data, make([]byte, pad)...) } } obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 0, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlDisplay_delete_id(s Sender, eventObjectID ObjectID[WlDisplay], id uint32) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(id)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 1, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func (p *WlDisplay) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { callbackVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 callback := ObjectID[WlCallback](callbackVal) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlDisplay@", message.ObjectID, ".sync(") fmt.Println("callback: ", callback, ")") } d.WlDisplay_sync(s, ObjectID[WlDisplay](message.ObjectID), callback) break } case 1: { registryVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 registry := ObjectID[WlRegistry](registryVal) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlDisplay@", message.ObjectID, ".get_registry(") fmt.Println("registry: ", registry, ")") } d.WlDisplay_get_registry(s, ObjectID[WlDisplay](message.ObjectID), registry) break } default: fmt.Println("Unknown opcode on WlDisplay", message.Opcode) } } type WlDisplayError_enum uint32 const ( WlDisplayError_enum_invalid_object WlDisplayError_enum = 0 WlDisplayError_enum_invalid_method WlDisplayError_enum = 1 WlDisplayError_enum_no_memory WlDisplayError_enum = 2 WlDisplayError_enum_implementation WlDisplayError_enum = 3 ) type WlRegistry_delegate interface { WlRegistry_bind(s ClientState, object_id ObjectID[WlRegistry], name uint32, idInterface string, idVersion uint32, idID AnyObjectID) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type WlRegistry struct { Delegate WlRegistry_delegate } func (p *WlRegistry) GetDelegate() WlRegistry_delegate { return p.Delegate } func (p *WlRegistry) GetBindable() OnBindable { return p.Delegate } func WlRegistry_global(s Sender, eventObjectID ObjectID[WlRegistry], name uint32, interface_ string, version uint32) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(name)) { b := []byte(interface_) total := len(b) + 1 // include null terminator putUint32(uint32(total)) data = append(data, b...) data = append(data, 0) if pad := (4 - (total % 4)) % 4; pad != 0 { data = append(data, make([]byte, pad)...) } } putUint32(uint32(version)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 0, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlRegistry_global_remove(s Sender, eventObjectID ObjectID[WlRegistry], name uint32) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(name)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 1, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func (p *WlRegistry) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { name := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 idInterfaceLen := int(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 idInterface := string(message.Data[_data_in_offset__ : _data_in_offset__+idInterfaceLen-1]) // NUL-terminated // 4-byte alignment if idInterfaceLen%4 != 0 { _data_in_offset__ += idInterfaceLen + (4 - (idInterfaceLen % 4)) } else { _data_in_offset__ += idInterfaceLen } idVersion := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 idID := AnyObjectID(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlRegistry@", message.ObjectID, ".bind(") fmt.Println("name: ", name, ", ", "idInterface: ", idInterface, ", ", "idVersion: ", idVersion, ", ", "idID: ", idID, ")") } d.WlRegistry_bind(s, ObjectID[WlRegistry](message.ObjectID), name, idInterface, idVersion, idID) break } default: fmt.Println("Unknown opcode on WlRegistry", message.Opcode) } } type WlCallback_delegate interface { OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type WlCallback struct { Delegate WlCallback_delegate } func (p *WlCallback) GetDelegate() WlCallback_delegate { return p.Delegate } func (p *WlCallback) GetBindable() OnBindable { return p.Delegate } func WlCallback_done(s Sender, eventObjectID ObjectID[WlCallback], callback_data uint32) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(callback_data)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 0, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func (p *WlCallback) OnRequest(s FileDescriptorClaimClientState, message Message) { switch message.Opcode { default: fmt.Println("Unknown opcode on WlCallback", message.Opcode) } } type WlCompositor_delegate interface { WlCompositor_create_surface(s ClientState, object_id ObjectID[WlCompositor], id ObjectID[WlSurface]) WlCompositor_create_region(s ClientState, object_id ObjectID[WlCompositor], id ObjectID[WlRegion]) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type WlCompositor struct { Delegate WlCompositor_delegate } func (p *WlCompositor) GetDelegate() WlCompositor_delegate { return p.Delegate } func (p *WlCompositor) GetBindable() OnBindable { return p.Delegate } func (p *WlCompositor) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { idVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 id := ObjectID[WlSurface](idVal) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlCompositor@", message.ObjectID, ".create_surface(") fmt.Println("id: ", id, ")") } d.WlCompositor_create_surface(s, ObjectID[WlCompositor](message.ObjectID), id) break } case 1: { idVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 id := ObjectID[WlRegion](idVal) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlCompositor@", message.ObjectID, ".create_region(") fmt.Println("id: ", id, ")") } d.WlCompositor_create_region(s, ObjectID[WlCompositor](message.ObjectID), id) break } default: fmt.Println("Unknown opcode on WlCompositor", message.Opcode) } } type WlShmPool_delegate interface { WlShmPool_create_buffer(s ClientState, object_id ObjectID[WlShmPool], id ObjectID[WlBuffer], offset int32, width int32, height int32, stride int32, format WlShmFormat_enum) WlShmPool_destroy(s ClientState, object_id ObjectID[WlShmPool]) bool WlShmPool_resize(s ClientState, object_id ObjectID[WlShmPool], size int32) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type WlShmPool struct { Delegate WlShmPool_delegate } func (p *WlShmPool) GetDelegate() WlShmPool_delegate { return p.Delegate } func (p *WlShmPool) GetBindable() OnBindable { return p.Delegate } func (p *WlShmPool) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { idVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 id := ObjectID[WlBuffer](idVal) _data_in_offset__ += 4 offset := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 width := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 height := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 stride := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 format := WlShmFormat_enum(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlShmPool@", message.ObjectID, ".create_buffer(") fmt.Println("id: ", id, ", ", "offset: ", offset, ", ", "width: ", width, ", ", "height: ", height, ", ", "stride: ", stride, ", ", "format: ", format, ")") } d.WlShmPool_create_buffer(s, ObjectID[WlShmPool](message.ObjectID), id, offset, width, height, stride, format) break } case 1: { if DebugRequests { fmt.Print("WlShmPool@", message.ObjectID, ".destroy(") fmt.Println(")") } autoRemove := d.WlShmPool_destroy(s, ObjectID[WlShmPool](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) } break } case 2: { size := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlShmPool@", message.ObjectID, ".resize(") fmt.Println("size: ", size, ")") } d.WlShmPool_resize(s, ObjectID[WlShmPool](message.ObjectID), size) break } default: fmt.Println("Unknown opcode on WlShmPool", message.Opcode) } } type WlShm_delegate interface { WlShm_create_pool(s ClientState, object_id ObjectID[WlShm], id ObjectID[WlShmPool], fd *FileDescriptor, size int32) WlShm_release(s ClientState, object_id ObjectID[WlShm]) bool OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type WlShm struct { Delegate WlShm_delegate } func (p *WlShm) GetDelegate() WlShm_delegate { return p.Delegate } func (p *WlShm) GetBindable() OnBindable { return p.Delegate } func WlShm_format(s Sender, eventObjectID ObjectID[WlShm], format WlShmFormat_enum) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(format)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 0, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func (p *WlShm) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { idVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 id := ObjectID[WlShmPool](idVal) _data_in_offset__ += 4 fd := s.ClaimFileDescriptor() size := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlShm@", message.ObjectID, ".create_pool(") fmt.Println("id: ", id, ", ", "fd: ", fd, ", ", "size: ", size, ")") } d.WlShm_create_pool(s, ObjectID[WlShm](message.ObjectID), id, fd, size) break } case 1: { if DebugRequests { fmt.Print("WlShm@", message.ObjectID, ".release(") fmt.Println(")") } autoRemove := d.WlShm_release(s, ObjectID[WlShm](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) s.RemoveGlobalWlShmBind(ObjectID[WlShm](message.ObjectID)) } break } default: fmt.Println("Unknown opcode on WlShm", message.Opcode) } } type WlShmError_enum uint32 const ( WlShmError_enum_invalid_format WlShmError_enum = 0 WlShmError_enum_invalid_stride WlShmError_enum = 1 WlShmError_enum_invalid_fd WlShmError_enum = 2 ) type WlShmFormat_enum uint32 const ( WlShmFormat_enum_argb8888 WlShmFormat_enum = 0 WlShmFormat_enum_xrgb8888 WlShmFormat_enum = 1 WlShmFormat_enum_c8 WlShmFormat_enum = 0x20203843 WlShmFormat_enum_rgb332 WlShmFormat_enum = 0x38424752 WlShmFormat_enum_bgr233 WlShmFormat_enum = 0x38524742 WlShmFormat_enum_xrgb4444 WlShmFormat_enum = 0x32315258 WlShmFormat_enum_xbgr4444 WlShmFormat_enum = 0x32314258 WlShmFormat_enum_rgbx4444 WlShmFormat_enum = 0x32315852 WlShmFormat_enum_bgrx4444 WlShmFormat_enum = 0x32315842 WlShmFormat_enum_argb4444 WlShmFormat_enum = 0x32315241 WlShmFormat_enum_abgr4444 WlShmFormat_enum = 0x32314241 WlShmFormat_enum_rgba4444 WlShmFormat_enum = 0x32314152 WlShmFormat_enum_bgra4444 WlShmFormat_enum = 0x32314142 WlShmFormat_enum_xrgb1555 WlShmFormat_enum = 0x35315258 WlShmFormat_enum_xbgr1555 WlShmFormat_enum = 0x35314258 WlShmFormat_enum_rgbx5551 WlShmFormat_enum = 0x35315852 WlShmFormat_enum_bgrx5551 WlShmFormat_enum = 0x35315842 WlShmFormat_enum_argb1555 WlShmFormat_enum = 0x35315241 WlShmFormat_enum_abgr1555 WlShmFormat_enum = 0x35314241 WlShmFormat_enum_rgba5551 WlShmFormat_enum = 0x35314152 WlShmFormat_enum_bgra5551 WlShmFormat_enum = 0x35314142 WlShmFormat_enum_rgb565 WlShmFormat_enum = 0x36314752 WlShmFormat_enum_bgr565 WlShmFormat_enum = 0x36314742 WlShmFormat_enum_rgb888 WlShmFormat_enum = 0x34324752 WlShmFormat_enum_bgr888 WlShmFormat_enum = 0x34324742 WlShmFormat_enum_xbgr8888 WlShmFormat_enum = 0x34324258 WlShmFormat_enum_rgbx8888 WlShmFormat_enum = 0x34325852 WlShmFormat_enum_bgrx8888 WlShmFormat_enum = 0x34325842 WlShmFormat_enum_abgr8888 WlShmFormat_enum = 0x34324241 WlShmFormat_enum_rgba8888 WlShmFormat_enum = 0x34324152 WlShmFormat_enum_bgra8888 WlShmFormat_enum = 0x34324142 WlShmFormat_enum_xrgb2101010 WlShmFormat_enum = 0x30335258 WlShmFormat_enum_xbgr2101010 WlShmFormat_enum = 0x30334258 WlShmFormat_enum_rgbx1010102 WlShmFormat_enum = 0x30335852 WlShmFormat_enum_bgrx1010102 WlShmFormat_enum = 0x30335842 WlShmFormat_enum_argb2101010 WlShmFormat_enum = 0x30335241 WlShmFormat_enum_abgr2101010 WlShmFormat_enum = 0x30334241 WlShmFormat_enum_rgba1010102 WlShmFormat_enum = 0x30334152 WlShmFormat_enum_bgra1010102 WlShmFormat_enum = 0x30334142 WlShmFormat_enum_yuyv WlShmFormat_enum = 0x56595559 WlShmFormat_enum_yvyu WlShmFormat_enum = 0x55595659 WlShmFormat_enum_uyvy WlShmFormat_enum = 0x59565955 WlShmFormat_enum_vyuy WlShmFormat_enum = 0x59555956 WlShmFormat_enum_ayuv WlShmFormat_enum = 0x56555941 WlShmFormat_enum_nv12 WlShmFormat_enum = 0x3231564e WlShmFormat_enum_nv21 WlShmFormat_enum = 0x3132564e WlShmFormat_enum_nv16 WlShmFormat_enum = 0x3631564e WlShmFormat_enum_nv61 WlShmFormat_enum = 0x3136564e WlShmFormat_enum_yuv410 WlShmFormat_enum = 0x39565559 WlShmFormat_enum_yvu410 WlShmFormat_enum = 0x39555659 WlShmFormat_enum_yuv411 WlShmFormat_enum = 0x31315559 WlShmFormat_enum_yvu411 WlShmFormat_enum = 0x31315659 WlShmFormat_enum_yuv420 WlShmFormat_enum = 0x32315559 WlShmFormat_enum_yvu420 WlShmFormat_enum = 0x32315659 WlShmFormat_enum_yuv422 WlShmFormat_enum = 0x36315559 WlShmFormat_enum_yvu422 WlShmFormat_enum = 0x36315659 WlShmFormat_enum_yuv444 WlShmFormat_enum = 0x34325559 WlShmFormat_enum_yvu444 WlShmFormat_enum = 0x34325659 WlShmFormat_enum_r8 WlShmFormat_enum = 0x20203852 WlShmFormat_enum_r16 WlShmFormat_enum = 0x20363152 WlShmFormat_enum_rg88 WlShmFormat_enum = 0x38384752 WlShmFormat_enum_gr88 WlShmFormat_enum = 0x38385247 WlShmFormat_enum_rg1616 WlShmFormat_enum = 0x32334752 WlShmFormat_enum_gr1616 WlShmFormat_enum = 0x32335247 WlShmFormat_enum_xrgb16161616f WlShmFormat_enum = 0x48345258 WlShmFormat_enum_xbgr16161616f WlShmFormat_enum = 0x48344258 WlShmFormat_enum_argb16161616f WlShmFormat_enum = 0x48345241 WlShmFormat_enum_abgr16161616f WlShmFormat_enum = 0x48344241 WlShmFormat_enum_xyuv8888 WlShmFormat_enum = 0x56555958 WlShmFormat_enum_vuy888 WlShmFormat_enum = 0x34325556 WlShmFormat_enum_vuy101010 WlShmFormat_enum = 0x30335556 WlShmFormat_enum_y210 WlShmFormat_enum = 0x30313259 WlShmFormat_enum_y212 WlShmFormat_enum = 0x32313259 WlShmFormat_enum_y216 WlShmFormat_enum = 0x36313259 WlShmFormat_enum_y410 WlShmFormat_enum = 0x30313459 WlShmFormat_enum_y412 WlShmFormat_enum = 0x32313459 WlShmFormat_enum_y416 WlShmFormat_enum = 0x36313459 WlShmFormat_enum_xvyu2101010 WlShmFormat_enum = 0x30335658 WlShmFormat_enum_xvyu12_16161616 WlShmFormat_enum = 0x36335658 WlShmFormat_enum_xvyu16161616 WlShmFormat_enum = 0x38345658 WlShmFormat_enum_y0l0 WlShmFormat_enum = 0x304c3059 WlShmFormat_enum_x0l0 WlShmFormat_enum = 0x304c3058 WlShmFormat_enum_y0l2 WlShmFormat_enum = 0x324c3059 WlShmFormat_enum_x0l2 WlShmFormat_enum = 0x324c3058 WlShmFormat_enum_yuv420_8bit WlShmFormat_enum = 0x38305559 WlShmFormat_enum_yuv420_10bit WlShmFormat_enum = 0x30315559 WlShmFormat_enum_xrgb8888_a8 WlShmFormat_enum = 0x38415258 WlShmFormat_enum_xbgr8888_a8 WlShmFormat_enum = 0x38414258 WlShmFormat_enum_rgbx8888_a8 WlShmFormat_enum = 0x38415852 WlShmFormat_enum_bgrx8888_a8 WlShmFormat_enum = 0x38415842 WlShmFormat_enum_rgb888_a8 WlShmFormat_enum = 0x38413852 WlShmFormat_enum_bgr888_a8 WlShmFormat_enum = 0x38413842 WlShmFormat_enum_rgb565_a8 WlShmFormat_enum = 0x38413552 WlShmFormat_enum_bgr565_a8 WlShmFormat_enum = 0x38413542 WlShmFormat_enum_nv24 WlShmFormat_enum = 0x3432564e WlShmFormat_enum_nv42 WlShmFormat_enum = 0x3234564e WlShmFormat_enum_p210 WlShmFormat_enum = 0x30313250 WlShmFormat_enum_p010 WlShmFormat_enum = 0x30313050 WlShmFormat_enum_p012 WlShmFormat_enum = 0x32313050 WlShmFormat_enum_p016 WlShmFormat_enum = 0x36313050 WlShmFormat_enum_axbxgxrx106106106106 WlShmFormat_enum = 0x30314241 WlShmFormat_enum_nv15 WlShmFormat_enum = 0x3531564e WlShmFormat_enum_q410 WlShmFormat_enum = 0x30313451 WlShmFormat_enum_q401 WlShmFormat_enum = 0x31303451 WlShmFormat_enum_xrgb16161616 WlShmFormat_enum = 0x38345258 WlShmFormat_enum_xbgr16161616 WlShmFormat_enum = 0x38344258 WlShmFormat_enum_argb16161616 WlShmFormat_enum = 0x38345241 WlShmFormat_enum_abgr16161616 WlShmFormat_enum = 0x38344241 WlShmFormat_enum_c1 WlShmFormat_enum = 0x20203143 WlShmFormat_enum_c2 WlShmFormat_enum = 0x20203243 WlShmFormat_enum_c4 WlShmFormat_enum = 0x20203443 WlShmFormat_enum_d1 WlShmFormat_enum = 0x20203144 WlShmFormat_enum_d2 WlShmFormat_enum = 0x20203244 WlShmFormat_enum_d4 WlShmFormat_enum = 0x20203444 WlShmFormat_enum_d8 WlShmFormat_enum = 0x20203844 WlShmFormat_enum_r1 WlShmFormat_enum = 0x20203152 WlShmFormat_enum_r2 WlShmFormat_enum = 0x20203252 WlShmFormat_enum_r4 WlShmFormat_enum = 0x20203452 WlShmFormat_enum_r10 WlShmFormat_enum = 0x20303152 WlShmFormat_enum_r12 WlShmFormat_enum = 0x20323152 WlShmFormat_enum_avuy8888 WlShmFormat_enum = 0x59555641 WlShmFormat_enum_xvuy8888 WlShmFormat_enum = 0x59555658 WlShmFormat_enum_p030 WlShmFormat_enum = 0x30333050 ) type WlBuffer_delegate interface { WlBuffer_destroy(s ClientState, object_id ObjectID[WlBuffer]) bool OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type WlBuffer struct { Delegate WlBuffer_delegate } func (p *WlBuffer) GetDelegate() WlBuffer_delegate { return p.Delegate } func (p *WlBuffer) GetBindable() OnBindable { return p.Delegate } func WlBuffer_release(s Sender, eventObjectID ObjectID[WlBuffer]) { data := make([]byte, 0) var fileDescriptor *FileDescriptor obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 0, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func (p *WlBuffer) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { if DebugRequests { fmt.Print("WlBuffer@", message.ObjectID, ".destroy(") fmt.Println(")") } autoRemove := d.WlBuffer_destroy(s, ObjectID[WlBuffer](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) } break } default: fmt.Println("Unknown opcode on WlBuffer", message.Opcode) } } type WlDataOffer_delegate interface { WlDataOffer_accept(s ClientState, object_id ObjectID[WlDataOffer], serial uint32, mime_type string) WlDataOffer_receive(s ClientState, object_id ObjectID[WlDataOffer], mime_type string, fd *FileDescriptor) WlDataOffer_destroy(s ClientState, object_id ObjectID[WlDataOffer]) bool WlDataOffer_finish(s ClientState, object_id ObjectID[WlDataOffer]) WlDataOffer_set_actions(s ClientState, object_id ObjectID[WlDataOffer], dnd_actions WlDataDeviceManagerDndAction_enum, preferred_action WlDataDeviceManagerDndAction_enum) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type WlDataOffer struct { Delegate WlDataOffer_delegate } func (p *WlDataOffer) GetDelegate() WlDataOffer_delegate { return p.Delegate } func (p *WlDataOffer) GetBindable() OnBindable { return p.Delegate } func WlDataOffer_offer(s Sender, eventObjectID ObjectID[WlDataOffer], mime_type string) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor { b := []byte(mime_type) total := len(b) + 1 // include null terminator putUint32(uint32(total)) data = append(data, b...) data = append(data, 0) if pad := (4 - (total % 4)) % 4; pad != 0 { data = append(data, make([]byte, pad)...) } } obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 0, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlDataOffer_source_actions(s Sender, boundVersion uint32, eventObjectID ObjectID[WlDataOffer], source_actions WlDataDeviceManagerDndAction_enum) { if boundVersion < 3 { // Event not available in this version; skip return } data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(source_actions)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 1, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlDataOffer_action(s Sender, boundVersion uint32, eventObjectID ObjectID[WlDataOffer], dnd_action WlDataDeviceManagerDndAction_enum) { if boundVersion < 3 { // Event not available in this version; skip return } data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(dnd_action)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 2, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func (p *WlDataOffer) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { serial := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 mime_typeLen := int(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 mime_type := string(message.Data[_data_in_offset__ : _data_in_offset__+mime_typeLen-1]) // NUL-terminated // 4-byte alignment if mime_typeLen%4 != 0 { _data_in_offset__ += mime_typeLen + (4 - (mime_typeLen % 4)) } else { _data_in_offset__ += mime_typeLen } if DebugRequests { fmt.Print("WlDataOffer@", message.ObjectID, ".accept(") fmt.Println("serial: ", serial, ", ", "mime_type: ", mime_type, ")") } d.WlDataOffer_accept(s, ObjectID[WlDataOffer](message.ObjectID), serial, mime_type) break } case 1: { mime_typeLen := int(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 mime_type := string(message.Data[_data_in_offset__ : _data_in_offset__+mime_typeLen-1]) // NUL-terminated // 4-byte alignment if mime_typeLen%4 != 0 { _data_in_offset__ += mime_typeLen + (4 - (mime_typeLen % 4)) } else { _data_in_offset__ += mime_typeLen } fd := s.ClaimFileDescriptor() if DebugRequests { fmt.Print("WlDataOffer@", message.ObjectID, ".receive(") fmt.Println("mime_type: ", mime_type, ", ", "fd: ", fd, ")") } d.WlDataOffer_receive(s, ObjectID[WlDataOffer](message.ObjectID), mime_type, fd) break } case 2: { if DebugRequests { fmt.Print("WlDataOffer@", message.ObjectID, ".destroy(") fmt.Println(")") } autoRemove := d.WlDataOffer_destroy(s, ObjectID[WlDataOffer](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) } break } case 3: { if DebugRequests { fmt.Print("WlDataOffer@", message.ObjectID, ".finish(") fmt.Println(")") } d.WlDataOffer_finish(s, ObjectID[WlDataOffer](message.ObjectID)) break } case 4: { dnd_actions := WlDataDeviceManagerDndAction_enum(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 preferred_action := WlDataDeviceManagerDndAction_enum(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlDataOffer@", message.ObjectID, ".set_actions(") fmt.Println("dnd_actions: ", dnd_actions, ", ", "preferred_action: ", preferred_action, ")") } d.WlDataOffer_set_actions(s, ObjectID[WlDataOffer](message.ObjectID), dnd_actions, preferred_action) break } default: fmt.Println("Unknown opcode on WlDataOffer", message.Opcode) } } type WlDataOfferError_enum uint32 const ( WlDataOfferError_enum_invalid_finish WlDataOfferError_enum = 0 WlDataOfferError_enum_invalid_action_mask WlDataOfferError_enum = 1 WlDataOfferError_enum_invalid_action WlDataOfferError_enum = 2 WlDataOfferError_enum_invalid_offer WlDataOfferError_enum = 3 ) type WlDataSource_delegate interface { WlDataSource_offer(s ClientState, object_id ObjectID[WlDataSource], mime_type string) WlDataSource_destroy(s ClientState, object_id ObjectID[WlDataSource]) bool WlDataSource_set_actions(s ClientState, object_id ObjectID[WlDataSource], dnd_actions WlDataDeviceManagerDndAction_enum) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type WlDataSource struct { Delegate WlDataSource_delegate } func (p *WlDataSource) GetDelegate() WlDataSource_delegate { return p.Delegate } func (p *WlDataSource) GetBindable() OnBindable { return p.Delegate } func WlDataSource_target(s Sender, eventObjectID ObjectID[WlDataSource], mime_type string) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor { b := []byte(mime_type) total := len(b) + 1 // include null terminator putUint32(uint32(total)) data = append(data, b...) data = append(data, 0) if pad := (4 - (total % 4)) % 4; pad != 0 { data = append(data, make([]byte, pad)...) } } obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 0, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlDataSource_send(s Sender, eventObjectID ObjectID[WlDataSource], mime_type string, fd FileDescriptor) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor { b := []byte(mime_type) total := len(b) + 1 // include null terminator putUint32(uint32(total)) data = append(data, b...) data = append(data, 0) if pad := (4 - (total % 4)) % 4; pad != 0 { data = append(data, make([]byte, pad)...) } } fileDescriptor = &fd obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 1, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlDataSource_cancelled(s Sender, eventObjectID ObjectID[WlDataSource]) { data := make([]byte, 0) var fileDescriptor *FileDescriptor obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 2, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlDataSource_dnd_drop_performed(s Sender, boundVersion uint32, eventObjectID ObjectID[WlDataSource]) { if boundVersion < 3 { // Event not available in this version; skip return } data := make([]byte, 0) var fileDescriptor *FileDescriptor obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 3, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlDataSource_dnd_finished(s Sender, boundVersion uint32, eventObjectID ObjectID[WlDataSource]) { if boundVersion < 3 { // Event not available in this version; skip return } data := make([]byte, 0) var fileDescriptor *FileDescriptor obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 4, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlDataSource_action(s Sender, boundVersion uint32, eventObjectID ObjectID[WlDataSource], dnd_action WlDataDeviceManagerDndAction_enum) { if boundVersion < 3 { // Event not available in this version; skip return } data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(dnd_action)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 5, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func (p *WlDataSource) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { mime_typeLen := int(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 mime_type := string(message.Data[_data_in_offset__ : _data_in_offset__+mime_typeLen-1]) // NUL-terminated // 4-byte alignment if mime_typeLen%4 != 0 { _data_in_offset__ += mime_typeLen + (4 - (mime_typeLen % 4)) } else { _data_in_offset__ += mime_typeLen } if DebugRequests { fmt.Print("WlDataSource@", message.ObjectID, ".offer(") fmt.Println("mime_type: ", mime_type, ")") } d.WlDataSource_offer(s, ObjectID[WlDataSource](message.ObjectID), mime_type) break } case 1: { if DebugRequests { fmt.Print("WlDataSource@", message.ObjectID, ".destroy(") fmt.Println(")") } autoRemove := d.WlDataSource_destroy(s, ObjectID[WlDataSource](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) } break } case 2: { dnd_actions := WlDataDeviceManagerDndAction_enum(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlDataSource@", message.ObjectID, ".set_actions(") fmt.Println("dnd_actions: ", dnd_actions, ")") } d.WlDataSource_set_actions(s, ObjectID[WlDataSource](message.ObjectID), dnd_actions) break } default: fmt.Println("Unknown opcode on WlDataSource", message.Opcode) } } type WlDataSourceError_enum uint32 const ( WlDataSourceError_enum_invalid_action_mask WlDataSourceError_enum = 0 WlDataSourceError_enum_invalid_source WlDataSourceError_enum = 1 ) type WlDataDevice_delegate interface { WlDataDevice_start_drag(s ClientState, object_id ObjectID[WlDataDevice], source *ObjectID[WlDataSource], origin ObjectID[WlSurface], icon *ObjectID[WlSurface], serial uint32) WlDataDevice_set_selection(s ClientState, object_id ObjectID[WlDataDevice], source *ObjectID[WlDataSource], serial uint32) WlDataDevice_release(s ClientState, object_id ObjectID[WlDataDevice]) bool OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type WlDataDevice struct { Delegate WlDataDevice_delegate } func (p *WlDataDevice) GetDelegate() WlDataDevice_delegate { return p.Delegate } func (p *WlDataDevice) GetBindable() OnBindable { return p.Delegate } func WlDataDevice_data_offer(s Sender, eventObjectID ObjectID[WlDataDevice], id ObjectID[WlDataOffer]) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(id)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 0, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlDataDevice_enter(s Sender, eventObjectID ObjectID[WlDataDevice], serial uint32, surface ObjectID[WlSurface], x float32, y float32, id *ObjectID[WlDataOffer]) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } putInt32 := func(v int32) { putUint32(uint32(v)) } var fileDescriptor *FileDescriptor putUint32(uint32(serial)) putUint32(uint32(surface)) // fixed: 24.8 putInt32(int32(x * 256.0)) // fixed: 24.8 putInt32(int32(y * 256.0)) var __tmp_id uint32 if id != nil { __tmp_id = uint32(*id) } putUint32(__tmp_id) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 1, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlDataDevice_leave(s Sender, eventObjectID ObjectID[WlDataDevice]) { data := make([]byte, 0) var fileDescriptor *FileDescriptor obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 2, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlDataDevice_motion(s Sender, eventObjectID ObjectID[WlDataDevice], time uint32, x float32, y float32) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } putInt32 := func(v int32) { putUint32(uint32(v)) } var fileDescriptor *FileDescriptor putUint32(uint32(time)) // fixed: 24.8 putInt32(int32(x * 256.0)) // fixed: 24.8 putInt32(int32(y * 256.0)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 3, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlDataDevice_drop(s Sender, eventObjectID ObjectID[WlDataDevice]) { data := make([]byte, 0) var fileDescriptor *FileDescriptor obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 4, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlDataDevice_selection(s Sender, eventObjectID ObjectID[WlDataDevice], id *ObjectID[WlDataOffer]) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor var __tmp_id uint32 if id != nil { __tmp_id = uint32(*id) } putUint32(__tmp_id) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 5, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func (p *WlDataDevice) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { sourceTmp := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 var source *ObjectID[WlDataSource] if sourceTmp != 0 { tmp := ObjectID[WlDataSource](sourceTmp) source = &tmp } origin := ObjectID[WlSurface](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 iconTmp := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 var icon *ObjectID[WlSurface] if iconTmp != 0 { tmp := ObjectID[WlSurface](iconTmp) icon = &tmp } serial := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlDataDevice@", message.ObjectID, ".start_drag(") fmt.Println("source: ", source, ", ", "origin: ", origin, ", ", "icon: ", icon, ", ", "serial: ", serial, ")") } d.WlDataDevice_start_drag(s, ObjectID[WlDataDevice](message.ObjectID), source, origin, icon, serial) break } case 1: { sourceTmp := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 var source *ObjectID[WlDataSource] if sourceTmp != 0 { tmp := ObjectID[WlDataSource](sourceTmp) source = &tmp } serial := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlDataDevice@", message.ObjectID, ".set_selection(") fmt.Println("source: ", source, ", ", "serial: ", serial, ")") } d.WlDataDevice_set_selection(s, ObjectID[WlDataDevice](message.ObjectID), source, serial) break } case 2: { if DebugRequests { fmt.Print("WlDataDevice@", message.ObjectID, ".release(") fmt.Println(")") } autoRemove := d.WlDataDevice_release(s, ObjectID[WlDataDevice](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) s.RemoveGlobalWlDataDeviceBind(ObjectID[WlDataDevice](message.ObjectID)) } break } default: fmt.Println("Unknown opcode on WlDataDevice", message.Opcode) } } type WlDataDeviceError_enum uint32 const ( WlDataDeviceError_enum_role WlDataDeviceError_enum = 0 WlDataDeviceError_enum_used_source WlDataDeviceError_enum = 1 ) type WlDataDeviceManager_delegate interface { WlDataDeviceManager_create_data_source(s ClientState, object_id ObjectID[WlDataDeviceManager], id ObjectID[WlDataSource]) WlDataDeviceManager_get_data_device(s ClientState, object_id ObjectID[WlDataDeviceManager], id ObjectID[WlDataDevice], seat ObjectID[WlSeat]) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type WlDataDeviceManager struct { Delegate WlDataDeviceManager_delegate } func (p *WlDataDeviceManager) GetDelegate() WlDataDeviceManager_delegate { return p.Delegate } func (p *WlDataDeviceManager) GetBindable() OnBindable { return p.Delegate } func (p *WlDataDeviceManager) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { idVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 id := ObjectID[WlDataSource](idVal) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlDataDeviceManager@", message.ObjectID, ".create_data_source(") fmt.Println("id: ", id, ")") } d.WlDataDeviceManager_create_data_source(s, ObjectID[WlDataDeviceManager](message.ObjectID), id) break } case 1: { idVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 id := ObjectID[WlDataDevice](idVal) _data_in_offset__ += 4 seat := ObjectID[WlSeat](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlDataDeviceManager@", message.ObjectID, ".get_data_device(") fmt.Println("id: ", id, ", ", "seat: ", seat, ")") } d.WlDataDeviceManager_get_data_device(s, ObjectID[WlDataDeviceManager](message.ObjectID), id, seat) break } default: fmt.Println("Unknown opcode on WlDataDeviceManager", message.Opcode) } } type WlDataDeviceManagerDndAction_enum uint32 const ( WlDataDeviceManagerDndAction_enum_none WlDataDeviceManagerDndAction_enum = 0 WlDataDeviceManagerDndAction_enum_copy WlDataDeviceManagerDndAction_enum = 1 WlDataDeviceManagerDndAction_enum_move WlDataDeviceManagerDndAction_enum = 2 WlDataDeviceManagerDndAction_enum_ask WlDataDeviceManagerDndAction_enum = 4 ) type WlShell_delegate interface { WlShell_get_shell_surface(s ClientState, object_id ObjectID[WlShell], id ObjectID[WlShellSurface], surface ObjectID[WlSurface]) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type WlShell struct { Delegate WlShell_delegate } func (p *WlShell) GetDelegate() WlShell_delegate { return p.Delegate } func (p *WlShell) GetBindable() OnBindable { return p.Delegate } func (p *WlShell) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { idVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 id := ObjectID[WlShellSurface](idVal) _data_in_offset__ += 4 surface := ObjectID[WlSurface](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlShell@", message.ObjectID, ".get_shell_surface(") fmt.Println("id: ", id, ", ", "surface: ", surface, ")") } d.WlShell_get_shell_surface(s, ObjectID[WlShell](message.ObjectID), id, surface) break } default: fmt.Println("Unknown opcode on WlShell", message.Opcode) } } type WlShellError_enum uint32 const ( WlShellError_enum_role WlShellError_enum = 0 ) type WlShellSurface_delegate interface { WlShellSurface_pong(s ClientState, object_id ObjectID[WlShellSurface], serial uint32) WlShellSurface_move(s ClientState, object_id ObjectID[WlShellSurface], seat ObjectID[WlSeat], serial uint32) WlShellSurface_resize(s ClientState, object_id ObjectID[WlShellSurface], seat ObjectID[WlSeat], serial uint32, edges WlShellSurfaceResize_enum) WlShellSurface_set_toplevel(s ClientState, object_id ObjectID[WlShellSurface]) WlShellSurface_set_transient(s ClientState, object_id ObjectID[WlShellSurface], parent ObjectID[WlSurface], x int32, y int32, flags WlShellSurfaceTransient_enum) WlShellSurface_set_fullscreen(s ClientState, object_id ObjectID[WlShellSurface], method WlShellSurfaceFullscreenMethod_enum, framerate uint32, output *ObjectID[WlOutput]) WlShellSurface_set_popup(s ClientState, object_id ObjectID[WlShellSurface], seat ObjectID[WlSeat], serial uint32, parent ObjectID[WlSurface], x int32, y int32, flags WlShellSurfaceTransient_enum) WlShellSurface_set_maximized(s ClientState, object_id ObjectID[WlShellSurface], output *ObjectID[WlOutput]) WlShellSurface_set_title(s ClientState, object_id ObjectID[WlShellSurface], title string) WlShellSurface_set_class(s ClientState, object_id ObjectID[WlShellSurface], class_ string) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type WlShellSurface struct { Delegate WlShellSurface_delegate } func (p *WlShellSurface) GetDelegate() WlShellSurface_delegate { return p.Delegate } func (p *WlShellSurface) GetBindable() OnBindable { return p.Delegate } func WlShellSurface_ping(s Sender, eventObjectID ObjectID[WlShellSurface], serial uint32) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(serial)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 0, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlShellSurface_configure(s Sender, eventObjectID ObjectID[WlShellSurface], edges WlShellSurfaceResize_enum, width int32, height int32) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } putInt32 := func(v int32) { putUint32(uint32(v)) } var fileDescriptor *FileDescriptor putUint32(uint32(edges)) putInt32(int32(width)) putInt32(int32(height)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 1, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlShellSurface_popup_done(s Sender, eventObjectID ObjectID[WlShellSurface]) { data := make([]byte, 0) var fileDescriptor *FileDescriptor obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 2, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func (p *WlShellSurface) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { serial := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlShellSurface@", message.ObjectID, ".pong(") fmt.Println("serial: ", serial, ")") } d.WlShellSurface_pong(s, ObjectID[WlShellSurface](message.ObjectID), serial) break } case 1: { seat := ObjectID[WlSeat](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 serial := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlShellSurface@", message.ObjectID, ".move(") fmt.Println("seat: ", seat, ", ", "serial: ", serial, ")") } d.WlShellSurface_move(s, ObjectID[WlShellSurface](message.ObjectID), seat, serial) break } case 2: { seat := ObjectID[WlSeat](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 serial := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 edges := WlShellSurfaceResize_enum(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlShellSurface@", message.ObjectID, ".resize(") fmt.Println("seat: ", seat, ", ", "serial: ", serial, ", ", "edges: ", edges, ")") } d.WlShellSurface_resize(s, ObjectID[WlShellSurface](message.ObjectID), seat, serial, edges) break } case 3: { if DebugRequests { fmt.Print("WlShellSurface@", message.ObjectID, ".set_toplevel(") fmt.Println(")") } d.WlShellSurface_set_toplevel(s, ObjectID[WlShellSurface](message.ObjectID)) break } case 4: { parent := ObjectID[WlSurface](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 x := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 y := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 flags := WlShellSurfaceTransient_enum(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlShellSurface@", message.ObjectID, ".set_transient(") fmt.Println("parent: ", parent, ", ", "x: ", x, ", ", "y: ", y, ", ", "flags: ", flags, ")") } d.WlShellSurface_set_transient(s, ObjectID[WlShellSurface](message.ObjectID), parent, x, y, flags) break } case 5: { method := WlShellSurfaceFullscreenMethod_enum(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 framerate := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 outputTmp := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 var output *ObjectID[WlOutput] if outputTmp != 0 { tmp := ObjectID[WlOutput](outputTmp) output = &tmp } if DebugRequests { fmt.Print("WlShellSurface@", message.ObjectID, ".set_fullscreen(") fmt.Println("method: ", method, ", ", "framerate: ", framerate, ", ", "output: ", output, ")") } d.WlShellSurface_set_fullscreen(s, ObjectID[WlShellSurface](message.ObjectID), method, framerate, output) break } case 6: { seat := ObjectID[WlSeat](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 serial := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 parent := ObjectID[WlSurface](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 x := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 y := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 flags := WlShellSurfaceTransient_enum(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlShellSurface@", message.ObjectID, ".set_popup(") fmt.Println("seat: ", seat, ", ", "serial: ", serial, ", ", "parent: ", parent, ", ", "x: ", x, ", ", "y: ", y, ", ", "flags: ", flags, ")") } d.WlShellSurface_set_popup(s, ObjectID[WlShellSurface](message.ObjectID), seat, serial, parent, x, y, flags) break } case 7: { outputTmp := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 var output *ObjectID[WlOutput] if outputTmp != 0 { tmp := ObjectID[WlOutput](outputTmp) output = &tmp } if DebugRequests { fmt.Print("WlShellSurface@", message.ObjectID, ".set_maximized(") fmt.Println("output: ", output, ")") } d.WlShellSurface_set_maximized(s, ObjectID[WlShellSurface](message.ObjectID), output) break } case 8: { titleLen := int(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 title := string(message.Data[_data_in_offset__ : _data_in_offset__+titleLen-1]) // NUL-terminated // 4-byte alignment if titleLen%4 != 0 { _data_in_offset__ += titleLen + (4 - (titleLen % 4)) } else { _data_in_offset__ += titleLen } if DebugRequests { fmt.Print("WlShellSurface@", message.ObjectID, ".set_title(") fmt.Println("title: ", title, ")") } d.WlShellSurface_set_title(s, ObjectID[WlShellSurface](message.ObjectID), title) break } case 9: { class_Len := int(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 class_ := string(message.Data[_data_in_offset__ : _data_in_offset__+class_Len-1]) // NUL-terminated // 4-byte alignment if class_Len%4 != 0 { _data_in_offset__ += class_Len + (4 - (class_Len % 4)) } else { _data_in_offset__ += class_Len } if DebugRequests { fmt.Print("WlShellSurface@", message.ObjectID, ".set_class(") fmt.Println("class_: ", class_, ")") } d.WlShellSurface_set_class(s, ObjectID[WlShellSurface](message.ObjectID), class_) break } default: fmt.Println("Unknown opcode on WlShellSurface", message.Opcode) } } type WlShellSurfaceResize_enum uint32 const ( WlShellSurfaceResize_enum_none WlShellSurfaceResize_enum = 0 WlShellSurfaceResize_enum_top WlShellSurfaceResize_enum = 1 WlShellSurfaceResize_enum_bottom WlShellSurfaceResize_enum = 2 WlShellSurfaceResize_enum_left WlShellSurfaceResize_enum = 4 WlShellSurfaceResize_enum_top_left WlShellSurfaceResize_enum = 5 WlShellSurfaceResize_enum_bottom_left WlShellSurfaceResize_enum = 6 WlShellSurfaceResize_enum_right WlShellSurfaceResize_enum = 8 WlShellSurfaceResize_enum_top_right WlShellSurfaceResize_enum = 9 WlShellSurfaceResize_enum_bottom_right WlShellSurfaceResize_enum = 10 ) type WlShellSurfaceTransient_enum uint32 const ( WlShellSurfaceTransient_enum_inactive WlShellSurfaceTransient_enum = 0x1 ) type WlShellSurfaceFullscreenMethod_enum uint32 const ( WlShellSurfaceFullscreenMethod_enum_default_ WlShellSurfaceFullscreenMethod_enum = 0 WlShellSurfaceFullscreenMethod_enum_scale WlShellSurfaceFullscreenMethod_enum = 1 WlShellSurfaceFullscreenMethod_enum_driver WlShellSurfaceFullscreenMethod_enum = 2 WlShellSurfaceFullscreenMethod_enum_fill WlShellSurfaceFullscreenMethod_enum = 3 ) type WlSurface_delegate interface { WlSurface_destroy(s ClientState, object_id ObjectID[WlSurface]) bool WlSurface_attach(s ClientState, object_id ObjectID[WlSurface], buffer *ObjectID[WlBuffer], x int32, y int32) WlSurface_damage(s ClientState, object_id ObjectID[WlSurface], x int32, y int32, width int32, height int32) WlSurface_frame(s ClientState, object_id ObjectID[WlSurface], callback ObjectID[WlCallback]) WlSurface_set_opaque_region(s ClientState, object_id ObjectID[WlSurface], region *ObjectID[WlRegion]) WlSurface_set_input_region(s ClientState, object_id ObjectID[WlSurface], region *ObjectID[WlRegion]) WlSurface_commit(s ClientState, object_id ObjectID[WlSurface]) WlSurface_set_buffer_transform(s ClientState, object_id ObjectID[WlSurface], transform int32) WlSurface_set_buffer_scale(s ClientState, object_id ObjectID[WlSurface], scale int32) WlSurface_damage_buffer(s ClientState, object_id ObjectID[WlSurface], x int32, y int32, width int32, height int32) WlSurface_offset(s ClientState, object_id ObjectID[WlSurface], x int32, y int32) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type WlSurface struct { Delegate WlSurface_delegate } func (p *WlSurface) GetDelegate() WlSurface_delegate { return p.Delegate } func (p *WlSurface) GetBindable() OnBindable { return p.Delegate } func WlSurface_enter(s Sender, eventObjectID ObjectID[WlSurface], output ObjectID[WlOutput]) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(output)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 0, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlSurface_leave(s Sender, eventObjectID ObjectID[WlSurface], output ObjectID[WlOutput]) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(output)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 1, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlSurface_preferred_buffer_scale(s Sender, boundVersion uint32, eventObjectID ObjectID[WlSurface], factor int32) { if boundVersion < 6 { // Event not available in this version; skip return } data := make([]byte, 0) putInt32 := func(v int32) { uv := uint32(v); data = append(data, byte(uv), byte(uv>>8), byte(uv>>16), byte(uv>>24)) } var fileDescriptor *FileDescriptor putInt32(int32(factor)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 2, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlSurface_preferred_buffer_transform(s Sender, boundVersion uint32, eventObjectID ObjectID[WlSurface], transform WlOutputTransform_enum) { if boundVersion < 6 { // Event not available in this version; skip return } data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(transform)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 3, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func (p *WlSurface) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { if DebugRequests { fmt.Print("WlSurface@", message.ObjectID, ".destroy(") fmt.Println(")") } autoRemove := d.WlSurface_destroy(s, ObjectID[WlSurface](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) } break } case 1: { bufferTmp := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 var buffer *ObjectID[WlBuffer] if bufferTmp != 0 { tmp := ObjectID[WlBuffer](bufferTmp) buffer = &tmp } x := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 y := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlSurface@", message.ObjectID, ".attach(") fmt.Println("buffer: ", buffer, ", ", "x: ", x, ", ", "y: ", y, ")") } d.WlSurface_attach(s, ObjectID[WlSurface](message.ObjectID), buffer, x, y) break } case 2: { x := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 y := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 width := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 height := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlSurface@", message.ObjectID, ".damage(") fmt.Println("x: ", x, ", ", "y: ", y, ", ", "width: ", width, ", ", "height: ", height, ")") } d.WlSurface_damage(s, ObjectID[WlSurface](message.ObjectID), x, y, width, height) break } case 3: { callbackVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 callback := ObjectID[WlCallback](callbackVal) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlSurface@", message.ObjectID, ".frame(") fmt.Println("callback: ", callback, ")") } d.WlSurface_frame(s, ObjectID[WlSurface](message.ObjectID), callback) break } case 4: { regionTmp := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 var region *ObjectID[WlRegion] if regionTmp != 0 { tmp := ObjectID[WlRegion](regionTmp) region = &tmp } if DebugRequests { fmt.Print("WlSurface@", message.ObjectID, ".set_opaque_region(") fmt.Println("region: ", region, ")") } d.WlSurface_set_opaque_region(s, ObjectID[WlSurface](message.ObjectID), region) break } case 5: { regionTmp := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 var region *ObjectID[WlRegion] if regionTmp != 0 { tmp := ObjectID[WlRegion](regionTmp) region = &tmp } if DebugRequests { fmt.Print("WlSurface@", message.ObjectID, ".set_input_region(") fmt.Println("region: ", region, ")") } d.WlSurface_set_input_region(s, ObjectID[WlSurface](message.ObjectID), region) break } case 6: { if DebugRequests { fmt.Print("WlSurface@", message.ObjectID, ".commit(") fmt.Println(")") } d.WlSurface_commit(s, ObjectID[WlSurface](message.ObjectID)) break } case 7: { transform := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlSurface@", message.ObjectID, ".set_buffer_transform(") fmt.Println("transform: ", transform, ")") } d.WlSurface_set_buffer_transform(s, ObjectID[WlSurface](message.ObjectID), transform) break } case 8: { scale := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlSurface@", message.ObjectID, ".set_buffer_scale(") fmt.Println("scale: ", scale, ")") } d.WlSurface_set_buffer_scale(s, ObjectID[WlSurface](message.ObjectID), scale) break } case 9: { x := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 y := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 width := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 height := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlSurface@", message.ObjectID, ".damage_buffer(") fmt.Println("x: ", x, ", ", "y: ", y, ", ", "width: ", width, ", ", "height: ", height, ")") } d.WlSurface_damage_buffer(s, ObjectID[WlSurface](message.ObjectID), x, y, width, height) break } case 10: { x := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 y := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlSurface@", message.ObjectID, ".offset(") fmt.Println("x: ", x, ", ", "y: ", y, ")") } d.WlSurface_offset(s, ObjectID[WlSurface](message.ObjectID), x, y) break } default: fmt.Println("Unknown opcode on WlSurface", message.Opcode) } } type WlSurfaceError_enum uint32 const ( WlSurfaceError_enum_invalid_scale WlSurfaceError_enum = 0 WlSurfaceError_enum_invalid_transform WlSurfaceError_enum = 1 WlSurfaceError_enum_invalid_size WlSurfaceError_enum = 2 WlSurfaceError_enum_invalid_offset WlSurfaceError_enum = 3 WlSurfaceError_enum_defunct_role_object WlSurfaceError_enum = 4 ) type WlSeat_delegate interface { WlSeat_get_pointer(s ClientState, object_id ObjectID[WlSeat], id ObjectID[WlPointer]) WlSeat_get_keyboard(s ClientState, object_id ObjectID[WlSeat], id ObjectID[WlKeyboard]) WlSeat_get_touch(s ClientState, object_id ObjectID[WlSeat], id ObjectID[WlTouch]) WlSeat_release(s ClientState, object_id ObjectID[WlSeat]) bool OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type WlSeat struct { Delegate WlSeat_delegate } func (p *WlSeat) GetDelegate() WlSeat_delegate { return p.Delegate } func (p *WlSeat) GetBindable() OnBindable { return p.Delegate } func WlSeat_capabilities(s Sender, eventObjectID ObjectID[WlSeat], capabilities WlSeatCapability_enum) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(capabilities)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 0, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlSeat_name(s Sender, boundVersion uint32, eventObjectID ObjectID[WlSeat], name string) { if boundVersion < 2 { // Event not available in this version; skip return } data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor { b := []byte(name) total := len(b) + 1 // include null terminator putUint32(uint32(total)) data = append(data, b...) data = append(data, 0) if pad := (4 - (total % 4)) % 4; pad != 0 { data = append(data, make([]byte, pad)...) } } obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 1, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func (p *WlSeat) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { idVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 id := ObjectID[WlPointer](idVal) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlSeat@", message.ObjectID, ".get_pointer(") fmt.Println("id: ", id, ")") } d.WlSeat_get_pointer(s, ObjectID[WlSeat](message.ObjectID), id) break } case 1: { idVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 id := ObjectID[WlKeyboard](idVal) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlSeat@", message.ObjectID, ".get_keyboard(") fmt.Println("id: ", id, ")") } d.WlSeat_get_keyboard(s, ObjectID[WlSeat](message.ObjectID), id) break } case 2: { idVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 id := ObjectID[WlTouch](idVal) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlSeat@", message.ObjectID, ".get_touch(") fmt.Println("id: ", id, ")") } d.WlSeat_get_touch(s, ObjectID[WlSeat](message.ObjectID), id) break } case 3: { if DebugRequests { fmt.Print("WlSeat@", message.ObjectID, ".release(") fmt.Println(")") } autoRemove := d.WlSeat_release(s, ObjectID[WlSeat](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) s.RemoveGlobalWlSeatBind(ObjectID[WlSeat](message.ObjectID)) } break } default: fmt.Println("Unknown opcode on WlSeat", message.Opcode) } } type WlSeatCapability_enum uint32 const ( WlSeatCapability_enum_pointer WlSeatCapability_enum = 1 WlSeatCapability_enum_keyboard WlSeatCapability_enum = 2 WlSeatCapability_enum_touch WlSeatCapability_enum = 4 ) type WlSeatError_enum uint32 const ( WlSeatError_enum_missing_capability WlSeatError_enum = 0 ) type WlPointer_delegate interface { WlPointer_set_cursor(s ClientState, object_id ObjectID[WlPointer], serial uint32, surface *ObjectID[WlSurface], hotspot_x int32, hotspot_y int32) WlPointer_release(s ClientState, object_id ObjectID[WlPointer]) bool OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) AfterGetPointer(s ClientState, object_id ObjectID[WlPointer]) } type WlPointer struct { Delegate WlPointer_delegate } func (p *WlPointer) GetDelegate() WlPointer_delegate { return p.Delegate } func (p *WlPointer) GetBindable() OnBindable { return p.Delegate } func WlPointer_enter(s Sender, eventObjectID ObjectID[WlPointer], serial uint32, surface ObjectID[WlSurface], surface_x float32, surface_y float32) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } putInt32 := func(v int32) { putUint32(uint32(v)) } var fileDescriptor *FileDescriptor putUint32(uint32(serial)) putUint32(uint32(surface)) // fixed: 24.8 putInt32(int32(surface_x * 256.0)) // fixed: 24.8 putInt32(int32(surface_y * 256.0)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 0, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlPointer_leave(s Sender, eventObjectID ObjectID[WlPointer], serial uint32, surface ObjectID[WlSurface]) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(serial)) putUint32(uint32(surface)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 1, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlPointer_motion(s Sender, eventObjectID ObjectID[WlPointer], time uint32, surface_x float32, surface_y float32) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } putInt32 := func(v int32) { putUint32(uint32(v)) } var fileDescriptor *FileDescriptor putUint32(uint32(time)) // fixed: 24.8 putInt32(int32(surface_x * 256.0)) // fixed: 24.8 putInt32(int32(surface_y * 256.0)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 2, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlPointer_button(s Sender, eventObjectID ObjectID[WlPointer], serial uint32, time uint32, button uint32, state WlPointerButtonState_enum) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(serial)) putUint32(uint32(time)) putUint32(uint32(button)) putUint32(uint32(state)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 3, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlPointer_axis(s Sender, eventObjectID ObjectID[WlPointer], time uint32, axis WlPointerAxis_enum, value float32) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } putInt32 := func(v int32) { putUint32(uint32(v)) } var fileDescriptor *FileDescriptor putUint32(uint32(time)) putUint32(uint32(axis)) // fixed: 24.8 putInt32(int32(value * 256.0)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 4, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlPointer_frame(s Sender, boundVersion uint32, eventObjectID ObjectID[WlPointer]) { if boundVersion < 5 { // Event not available in this version; skip return } data := make([]byte, 0) var fileDescriptor *FileDescriptor obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 5, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlPointer_axis_source(s Sender, boundVersion uint32, eventObjectID ObjectID[WlPointer], axis_source WlPointerAxisSource_enum) { if boundVersion < 5 { // Event not available in this version; skip return } data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(axis_source)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 6, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlPointer_axis_stop(s Sender, boundVersion uint32, eventObjectID ObjectID[WlPointer], time uint32, axis WlPointerAxis_enum) { if boundVersion < 5 { // Event not available in this version; skip return } data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(time)) putUint32(uint32(axis)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 7, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlPointer_axis_discrete(s Sender, boundVersion uint32, eventObjectID ObjectID[WlPointer], axis WlPointerAxis_enum, discrete int32) { if boundVersion < 5 { // Event not available in this version; skip return } data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } putInt32 := func(v int32) { putUint32(uint32(v)) } var fileDescriptor *FileDescriptor putUint32(uint32(axis)) putInt32(int32(discrete)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 8, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlPointer_axis_value120(s Sender, boundVersion uint32, eventObjectID ObjectID[WlPointer], axis WlPointerAxis_enum, value120 int32) { if boundVersion < 8 { // Event not available in this version; skip return } data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } putInt32 := func(v int32) { putUint32(uint32(v)) } var fileDescriptor *FileDescriptor putUint32(uint32(axis)) putInt32(int32(value120)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 9, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlPointer_axis_relative_direction(s Sender, boundVersion uint32, eventObjectID ObjectID[WlPointer], axis WlPointerAxis_enum, direction WlPointerAxisRelativeDirection_enum) { if boundVersion < 9 { // Event not available in this version; skip return } data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(axis)) putUint32(uint32(direction)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 10, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func (p *WlPointer) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { serial := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 surfaceTmp := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 var surface *ObjectID[WlSurface] if surfaceTmp != 0 { tmp := ObjectID[WlSurface](surfaceTmp) surface = &tmp } hotspot_x := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 hotspot_y := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlPointer@", message.ObjectID, ".set_cursor(") fmt.Println("serial: ", serial, ", ", "surface: ", surface, ", ", "hotspot_x: ", hotspot_x, ", ", "hotspot_y: ", hotspot_y, ")") } d.WlPointer_set_cursor(s, ObjectID[WlPointer](message.ObjectID), serial, surface, hotspot_x, hotspot_y) break } case 1: { if DebugRequests { fmt.Print("WlPointer@", message.ObjectID, ".release(") fmt.Println(")") } autoRemove := d.WlPointer_release(s, ObjectID[WlPointer](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) s.RemoveGlobalWlPointerBind(ObjectID[WlPointer](message.ObjectID)) } break } default: fmt.Println("Unknown opcode on WlPointer", message.Opcode) } } type WlPointerError_enum uint32 const ( WlPointerError_enum_role WlPointerError_enum = 0 ) type WlPointerButtonState_enum uint32 const ( WlPointerButtonState_enum_released WlPointerButtonState_enum = 0 WlPointerButtonState_enum_pressed WlPointerButtonState_enum = 1 ) type WlPointerAxis_enum uint32 const ( WlPointerAxis_enum_vertical_scroll WlPointerAxis_enum = 0 WlPointerAxis_enum_horizontal_scroll WlPointerAxis_enum = 1 ) type WlPointerAxisSource_enum uint32 const ( WlPointerAxisSource_enum_wheel WlPointerAxisSource_enum = 0 WlPointerAxisSource_enum_finger WlPointerAxisSource_enum = 1 WlPointerAxisSource_enum_continuous WlPointerAxisSource_enum = 2 WlPointerAxisSource_enum_wheel_tilt WlPointerAxisSource_enum = 3 ) type WlPointerAxisRelativeDirection_enum uint32 const ( WlPointerAxisRelativeDirection_enum_identical WlPointerAxisRelativeDirection_enum = 0 WlPointerAxisRelativeDirection_enum_inverted WlPointerAxisRelativeDirection_enum = 1 ) type WlKeyboard_delegate interface { WlKeyboard_release(s ClientState, object_id ObjectID[WlKeyboard]) bool OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) AfterGetKeyboard(s ClientState, object_id ObjectID[WlKeyboard]) } type WlKeyboard struct { Delegate WlKeyboard_delegate } func (p *WlKeyboard) GetDelegate() WlKeyboard_delegate { return p.Delegate } func (p *WlKeyboard) GetBindable() OnBindable { return p.Delegate } func WlKeyboard_keymap(s Sender, eventObjectID ObjectID[WlKeyboard], format WlKeyboardKeymapFormat_enum, fd FileDescriptor, size uint32) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(format)) fileDescriptor = &fd putUint32(uint32(size)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 0, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlKeyboard_enter(s Sender, eventObjectID ObjectID[WlKeyboard], serial uint32, surface ObjectID[WlSurface], keys []byte) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(serial)) putUint32(uint32(surface)) { n := len(keys) putUint32(uint32(n)) data = append(data, keys...) if pad := (4 - (n % 4)) % 4; pad != 0 { data = append(data, make([]byte, pad)...) } } obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 1, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlKeyboard_leave(s Sender, eventObjectID ObjectID[WlKeyboard], serial uint32, surface ObjectID[WlSurface]) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(serial)) putUint32(uint32(surface)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 2, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlKeyboard_key(s Sender, eventObjectID ObjectID[WlKeyboard], serial uint32, time uint32, key uint32, state WlKeyboardKeyState_enum) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(serial)) putUint32(uint32(time)) putUint32(uint32(key)) putUint32(uint32(state)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 3, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlKeyboard_modifiers(s Sender, eventObjectID ObjectID[WlKeyboard], serial uint32, mods_depressed uint32, mods_latched uint32, mods_locked uint32, group uint32) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(serial)) putUint32(uint32(mods_depressed)) putUint32(uint32(mods_latched)) putUint32(uint32(mods_locked)) putUint32(uint32(group)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 4, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlKeyboard_repeat_info(s Sender, boundVersion uint32, eventObjectID ObjectID[WlKeyboard], rate int32, delay int32) { if boundVersion < 4 { // Event not available in this version; skip return } data := make([]byte, 0) putInt32 := func(v int32) { uv := uint32(v); data = append(data, byte(uv), byte(uv>>8), byte(uv>>16), byte(uv>>24)) } var fileDescriptor *FileDescriptor putInt32(int32(rate)) putInt32(int32(delay)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 5, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func (p *WlKeyboard) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { if DebugRequests { fmt.Print("WlKeyboard@", message.ObjectID, ".release(") fmt.Println(")") } autoRemove := d.WlKeyboard_release(s, ObjectID[WlKeyboard](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) s.RemoveGlobalWlKeyboardBind(ObjectID[WlKeyboard](message.ObjectID)) } break } default: fmt.Println("Unknown opcode on WlKeyboard", message.Opcode) } } type WlKeyboardKeymapFormat_enum uint32 const ( WlKeyboardKeymapFormat_enum_no_keymap WlKeyboardKeymapFormat_enum = 0 WlKeyboardKeymapFormat_enum_xkb_v1 WlKeyboardKeymapFormat_enum = 1 ) type WlKeyboardKeyState_enum uint32 const ( WlKeyboardKeyState_enum_released WlKeyboardKeyState_enum = 0 WlKeyboardKeyState_enum_pressed WlKeyboardKeyState_enum = 1 ) type WlTouch_delegate interface { WlTouch_release(s ClientState, object_id ObjectID[WlTouch]) bool OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type WlTouch struct { Delegate WlTouch_delegate } func (p *WlTouch) GetDelegate() WlTouch_delegate { return p.Delegate } func (p *WlTouch) GetBindable() OnBindable { return p.Delegate } func WlTouch_down(s Sender, eventObjectID ObjectID[WlTouch], serial uint32, time uint32, surface ObjectID[WlSurface], id int32, x float32, y float32) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } putInt32 := func(v int32) { putUint32(uint32(v)) } var fileDescriptor *FileDescriptor putUint32(uint32(serial)) putUint32(uint32(time)) putUint32(uint32(surface)) putInt32(int32(id)) // fixed: 24.8 putInt32(int32(x * 256.0)) // fixed: 24.8 putInt32(int32(y * 256.0)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 0, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlTouch_up(s Sender, eventObjectID ObjectID[WlTouch], serial uint32, time uint32, id int32) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } putInt32 := func(v int32) { putUint32(uint32(v)) } var fileDescriptor *FileDescriptor putUint32(uint32(serial)) putUint32(uint32(time)) putInt32(int32(id)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 1, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlTouch_motion(s Sender, eventObjectID ObjectID[WlTouch], time uint32, id int32, x float32, y float32) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } putInt32 := func(v int32) { putUint32(uint32(v)) } var fileDescriptor *FileDescriptor putUint32(uint32(time)) putInt32(int32(id)) // fixed: 24.8 putInt32(int32(x * 256.0)) // fixed: 24.8 putInt32(int32(y * 256.0)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 2, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlTouch_frame(s Sender, eventObjectID ObjectID[WlTouch]) { data := make([]byte, 0) var fileDescriptor *FileDescriptor obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 3, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlTouch_cancel(s Sender, eventObjectID ObjectID[WlTouch]) { data := make([]byte, 0) var fileDescriptor *FileDescriptor obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 4, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlTouch_shape(s Sender, boundVersion uint32, eventObjectID ObjectID[WlTouch], id int32, major float32, minor float32) { if boundVersion < 6 { // Event not available in this version; skip return } data := make([]byte, 0) putInt32 := func(v int32) { uv := uint32(v); data = append(data, byte(uv), byte(uv>>8), byte(uv>>16), byte(uv>>24)) } var fileDescriptor *FileDescriptor putInt32(int32(id)) // fixed: 24.8 putInt32(int32(major * 256.0)) // fixed: 24.8 putInt32(int32(minor * 256.0)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 5, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlTouch_orientation(s Sender, boundVersion uint32, eventObjectID ObjectID[WlTouch], id int32, orientation float32) { if boundVersion < 6 { // Event not available in this version; skip return } data := make([]byte, 0) putInt32 := func(v int32) { uv := uint32(v); data = append(data, byte(uv), byte(uv>>8), byte(uv>>16), byte(uv>>24)) } var fileDescriptor *FileDescriptor putInt32(int32(id)) // fixed: 24.8 putInt32(int32(orientation * 256.0)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 6, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func (p *WlTouch) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { if DebugRequests { fmt.Print("WlTouch@", message.ObjectID, ".release(") fmt.Println(")") } autoRemove := d.WlTouch_release(s, ObjectID[WlTouch](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) s.RemoveGlobalWlTouchBind(ObjectID[WlTouch](message.ObjectID)) } break } default: fmt.Println("Unknown opcode on WlTouch", message.Opcode) } } type WlOutput_delegate interface { WlOutput_release(s ClientState, object_id ObjectID[WlOutput]) bool OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type WlOutput struct { Delegate WlOutput_delegate } func (p *WlOutput) GetDelegate() WlOutput_delegate { return p.Delegate } func (p *WlOutput) GetBindable() OnBindable { return p.Delegate } func WlOutput_geometry(s Sender, eventObjectID ObjectID[WlOutput], x int32, y int32, physical_width int32, physical_height int32, subpixel int32, make_ string, model string, transform int32) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } putInt32 := func(v int32) { putUint32(uint32(v)) } var fileDescriptor *FileDescriptor putInt32(int32(x)) putInt32(int32(y)) putInt32(int32(physical_width)) putInt32(int32(physical_height)) putInt32(int32(subpixel)) { b := []byte(make_) total := len(b) + 1 // include null terminator putUint32(uint32(total)) data = append(data, b...) data = append(data, 0) if pad := (4 - (total % 4)) % 4; pad != 0 { data = append(data, make([]byte, pad)...) } } { b := []byte(model) total := len(b) + 1 // include null terminator putUint32(uint32(total)) data = append(data, b...) data = append(data, 0) if pad := (4 - (total % 4)) % 4; pad != 0 { data = append(data, make([]byte, pad)...) } } putInt32(int32(transform)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 0, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlOutput_mode(s Sender, eventObjectID ObjectID[WlOutput], flags WlOutputMode_enum, width int32, height int32, refresh int32) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } putInt32 := func(v int32) { putUint32(uint32(v)) } var fileDescriptor *FileDescriptor putUint32(uint32(flags)) putInt32(int32(width)) putInt32(int32(height)) putInt32(int32(refresh)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 1, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlOutput_done(s Sender, boundVersion uint32, eventObjectID ObjectID[WlOutput]) { if boundVersion < 2 { // Event not available in this version; skip return } data := make([]byte, 0) var fileDescriptor *FileDescriptor obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 2, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlOutput_scale(s Sender, boundVersion uint32, eventObjectID ObjectID[WlOutput], factor int32) { if boundVersion < 2 { // Event not available in this version; skip return } data := make([]byte, 0) putInt32 := func(v int32) { uv := uint32(v); data = append(data, byte(uv), byte(uv>>8), byte(uv>>16), byte(uv>>24)) } var fileDescriptor *FileDescriptor putInt32(int32(factor)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 3, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlOutput_name(s Sender, boundVersion uint32, eventObjectID ObjectID[WlOutput], name string) { if boundVersion < 4 { // Event not available in this version; skip return } data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor { b := []byte(name) total := len(b) + 1 // include null terminator putUint32(uint32(total)) data = append(data, b...) data = append(data, 0) if pad := (4 - (total % 4)) % 4; pad != 0 { data = append(data, make([]byte, pad)...) } } obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 4, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func WlOutput_description(s Sender, boundVersion uint32, eventObjectID ObjectID[WlOutput], description string) { if boundVersion < 4 { // Event not available in this version; skip return } data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor { b := []byte(description) total := len(b) + 1 // include null terminator putUint32(uint32(total)) data = append(data, b...) data = append(data, 0) if pad := (4 - (total % 4)) % 4; pad != 0 { data = append(data, make([]byte, pad)...) } } obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 5, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func (p *WlOutput) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { if DebugRequests { fmt.Print("WlOutput@", message.ObjectID, ".release(") fmt.Println(")") } autoRemove := d.WlOutput_release(s, ObjectID[WlOutput](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) s.RemoveGlobalWlOutputBind(ObjectID[WlOutput](message.ObjectID)) } break } default: fmt.Println("Unknown opcode on WlOutput", message.Opcode) } } type WlOutputSubpixel_enum uint32 const ( WlOutputSubpixel_enum_unknown WlOutputSubpixel_enum = 0 WlOutputSubpixel_enum_none WlOutputSubpixel_enum = 1 WlOutputSubpixel_enum_horizontal_rgb WlOutputSubpixel_enum = 2 WlOutputSubpixel_enum_horizontal_bgr WlOutputSubpixel_enum = 3 WlOutputSubpixel_enum_vertical_rgb WlOutputSubpixel_enum = 4 WlOutputSubpixel_enum_vertical_bgr WlOutputSubpixel_enum = 5 ) type WlOutputTransform_enum uint32 const ( WlOutputTransform_enum_normal WlOutputTransform_enum = 0 WlOutputTransform_enum__90 WlOutputTransform_enum = 1 WlOutputTransform_enum__180 WlOutputTransform_enum = 2 WlOutputTransform_enum__270 WlOutputTransform_enum = 3 WlOutputTransform_enum_flipped WlOutputTransform_enum = 4 WlOutputTransform_enum_flipped_90 WlOutputTransform_enum = 5 WlOutputTransform_enum_flipped_180 WlOutputTransform_enum = 6 WlOutputTransform_enum_flipped_270 WlOutputTransform_enum = 7 ) type WlOutputMode_enum uint32 const ( WlOutputMode_enum_current WlOutputMode_enum = 0x1 WlOutputMode_enum_preferred WlOutputMode_enum = 0x2 ) type WlRegion_delegate interface { WlRegion_destroy(s ClientState, object_id ObjectID[WlRegion]) bool WlRegion_add(s ClientState, object_id ObjectID[WlRegion], x int32, y int32, width int32, height int32) WlRegion_subtract(s ClientState, object_id ObjectID[WlRegion], x int32, y int32, width int32, height int32) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type WlRegion struct { Delegate WlRegion_delegate } func (p *WlRegion) GetDelegate() WlRegion_delegate { return p.Delegate } func (p *WlRegion) GetBindable() OnBindable { return p.Delegate } func (p *WlRegion) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { if DebugRequests { fmt.Print("WlRegion@", message.ObjectID, ".destroy(") fmt.Println(")") } autoRemove := d.WlRegion_destroy(s, ObjectID[WlRegion](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) } break } case 1: { x := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 y := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 width := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 height := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlRegion@", message.ObjectID, ".add(") fmt.Println("x: ", x, ", ", "y: ", y, ", ", "width: ", width, ", ", "height: ", height, ")") } d.WlRegion_add(s, ObjectID[WlRegion](message.ObjectID), x, y, width, height) break } case 2: { x := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 y := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 width := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 height := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlRegion@", message.ObjectID, ".subtract(") fmt.Println("x: ", x, ", ", "y: ", y, ", ", "width: ", width, ", ", "height: ", height, ")") } d.WlRegion_subtract(s, ObjectID[WlRegion](message.ObjectID), x, y, width, height) break } default: fmt.Println("Unknown opcode on WlRegion", message.Opcode) } } type WlSubcompositor_delegate interface { WlSubcompositor_destroy(s ClientState, object_id ObjectID[WlSubcompositor]) bool WlSubcompositor_get_subsurface(s ClientState, object_id ObjectID[WlSubcompositor], id ObjectID[WlSubsurface], surface ObjectID[WlSurface], parent ObjectID[WlSurface]) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type WlSubcompositor struct { Delegate WlSubcompositor_delegate } func (p *WlSubcompositor) GetDelegate() WlSubcompositor_delegate { return p.Delegate } func (p *WlSubcompositor) GetBindable() OnBindable { return p.Delegate } func (p *WlSubcompositor) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { if DebugRequests { fmt.Print("WlSubcompositor@", message.ObjectID, ".destroy(") fmt.Println(")") } autoRemove := d.WlSubcompositor_destroy(s, ObjectID[WlSubcompositor](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) } break } case 1: { idVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 id := ObjectID[WlSubsurface](idVal) _data_in_offset__ += 4 surface := ObjectID[WlSurface](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 parent := ObjectID[WlSurface](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlSubcompositor@", message.ObjectID, ".get_subsurface(") fmt.Println("id: ", id, ", ", "surface: ", surface, ", ", "parent: ", parent, ")") } d.WlSubcompositor_get_subsurface(s, ObjectID[WlSubcompositor](message.ObjectID), id, surface, parent) break } default: fmt.Println("Unknown opcode on WlSubcompositor", message.Opcode) } } type WlSubcompositorError_enum uint32 const ( WlSubcompositorError_enum_bad_surface WlSubcompositorError_enum = 0 WlSubcompositorError_enum_bad_parent WlSubcompositorError_enum = 1 ) type WlSubsurface_delegate interface { WlSubsurface_destroy(s ClientState, object_id ObjectID[WlSubsurface]) bool WlSubsurface_set_position(s ClientState, object_id ObjectID[WlSubsurface], x int32, y int32) WlSubsurface_place_above(s ClientState, object_id ObjectID[WlSubsurface], sibling ObjectID[WlSurface]) WlSubsurface_place_below(s ClientState, object_id ObjectID[WlSubsurface], sibling ObjectID[WlSurface]) WlSubsurface_set_sync(s ClientState, object_id ObjectID[WlSubsurface]) WlSubsurface_set_desync(s ClientState, object_id ObjectID[WlSubsurface]) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type WlSubsurface struct { Delegate WlSubsurface_delegate } func (p *WlSubsurface) GetDelegate() WlSubsurface_delegate { return p.Delegate } func (p *WlSubsurface) GetBindable() OnBindable { return p.Delegate } func (p *WlSubsurface) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { if DebugRequests { fmt.Print("WlSubsurface@", message.ObjectID, ".destroy(") fmt.Println(")") } autoRemove := d.WlSubsurface_destroy(s, ObjectID[WlSubsurface](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) } break } case 1: { x := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 y := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlSubsurface@", message.ObjectID, ".set_position(") fmt.Println("x: ", x, ", ", "y: ", y, ")") } d.WlSubsurface_set_position(s, ObjectID[WlSubsurface](message.ObjectID), x, y) break } case 2: { sibling := ObjectID[WlSurface](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlSubsurface@", message.ObjectID, ".place_above(") fmt.Println("sibling: ", sibling, ")") } d.WlSubsurface_place_above(s, ObjectID[WlSubsurface](message.ObjectID), sibling) break } case 3: { sibling := ObjectID[WlSurface](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("WlSubsurface@", message.ObjectID, ".place_below(") fmt.Println("sibling: ", sibling, ")") } d.WlSubsurface_place_below(s, ObjectID[WlSubsurface](message.ObjectID), sibling) break } case 4: { if DebugRequests { fmt.Print("WlSubsurface@", message.ObjectID, ".set_sync(") fmt.Println(")") } d.WlSubsurface_set_sync(s, ObjectID[WlSubsurface](message.ObjectID)) break } case 5: { if DebugRequests { fmt.Print("WlSubsurface@", message.ObjectID, ".set_desync(") fmt.Println(")") } d.WlSubsurface_set_desync(s, ObjectID[WlSubsurface](message.ObjectID)) break } default: fmt.Println("Unknown opcode on WlSubsurface", message.Opcode) } } type WlSubsurfaceError_enum uint32 const ( WlSubsurfaceError_enum_bad_surface WlSubsurfaceError_enum = 0 ) ================================================ FILE: wayland/protocols/wayland_debug.go ================================================ //go:build debug // +build debug package protocols const DebugRequests = true ================================================ FILE: wayland/protocols/wayland_nodebug.go ================================================ //go:build !debug // +build !debug package protocols const DebugRequests = false ================================================ FILE: wayland/protocols/xdg-decoration-unstable-v1.xml.go ================================================ // Code generated by `cmd/protocols`; DO NOT EDIT. package protocols import "fmt" type ZxdgDecorationManagerV1_delegate interface { ZxdgDecorationManagerV1_destroy(s ClientState, object_id ObjectID[ZxdgDecorationManagerV1]) bool ZxdgDecorationManagerV1_get_toplevel_decoration(s ClientState, object_id ObjectID[ZxdgDecorationManagerV1], id ObjectID[ZxdgToplevelDecorationV1], toplevel ObjectID[XdgToplevel]) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type ZxdgDecorationManagerV1 struct { Delegate ZxdgDecorationManagerV1_delegate } func (p *ZxdgDecorationManagerV1) GetDelegate() ZxdgDecorationManagerV1_delegate { return p.Delegate } func (p *ZxdgDecorationManagerV1) GetBindable() OnBindable { return p.Delegate } func (p *ZxdgDecorationManagerV1) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { if DebugRequests { fmt.Print("ZxdgDecorationManagerV1@", message.ObjectID, ".destroy(") fmt.Println(")") } autoRemove := d.ZxdgDecorationManagerV1_destroy(s, ObjectID[ZxdgDecorationManagerV1](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) } break } case 1: { idVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 id := ObjectID[ZxdgToplevelDecorationV1](idVal) _data_in_offset__ += 4 toplevel := ObjectID[XdgToplevel](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("ZxdgDecorationManagerV1@", message.ObjectID, ".get_toplevel_decoration(") fmt.Println("id: ", id, ", ", "toplevel: ", toplevel, ")") } d.ZxdgDecorationManagerV1_get_toplevel_decoration(s, ObjectID[ZxdgDecorationManagerV1](message.ObjectID), id, toplevel) break } default: fmt.Println("Unknown opcode on ZxdgDecorationManagerV1", message.Opcode) } } type ZxdgToplevelDecorationV1_delegate interface { ZxdgToplevelDecorationV1_destroy(s ClientState, object_id ObjectID[ZxdgToplevelDecorationV1]) bool ZxdgToplevelDecorationV1_set_mode(s ClientState, object_id ObjectID[ZxdgToplevelDecorationV1], mode ZxdgToplevelDecorationV1Mode_enum) ZxdgToplevelDecorationV1_unset_mode(s ClientState, object_id ObjectID[ZxdgToplevelDecorationV1]) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type ZxdgToplevelDecorationV1 struct { Delegate ZxdgToplevelDecorationV1_delegate } func (p *ZxdgToplevelDecorationV1) GetDelegate() ZxdgToplevelDecorationV1_delegate { return p.Delegate } func (p *ZxdgToplevelDecorationV1) GetBindable() OnBindable { return p.Delegate } func ZxdgToplevelDecorationV1_configure(s Sender, eventObjectID ObjectID[ZxdgToplevelDecorationV1], mode ZxdgToplevelDecorationV1Mode_enum) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(mode)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 0, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func (p *ZxdgToplevelDecorationV1) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { if DebugRequests { fmt.Print("ZxdgToplevelDecorationV1@", message.ObjectID, ".destroy(") fmt.Println(")") } autoRemove := d.ZxdgToplevelDecorationV1_destroy(s, ObjectID[ZxdgToplevelDecorationV1](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) } break } case 1: { mode := ZxdgToplevelDecorationV1Mode_enum(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("ZxdgToplevelDecorationV1@", message.ObjectID, ".set_mode(") fmt.Println("mode: ", mode, ")") } d.ZxdgToplevelDecorationV1_set_mode(s, ObjectID[ZxdgToplevelDecorationV1](message.ObjectID), mode) break } case 2: { if DebugRequests { fmt.Print("ZxdgToplevelDecorationV1@", message.ObjectID, ".unset_mode(") fmt.Println(")") } d.ZxdgToplevelDecorationV1_unset_mode(s, ObjectID[ZxdgToplevelDecorationV1](message.ObjectID)) break } default: fmt.Println("Unknown opcode on ZxdgToplevelDecorationV1", message.Opcode) } } type ZxdgToplevelDecorationV1Error_enum uint32 const ( ZxdgToplevelDecorationV1Error_enum_unconfigured_buffer ZxdgToplevelDecorationV1Error_enum = 0 ZxdgToplevelDecorationV1Error_enum_already_constructed ZxdgToplevelDecorationV1Error_enum = 1 ZxdgToplevelDecorationV1Error_enum_orphaned ZxdgToplevelDecorationV1Error_enum = 2 ZxdgToplevelDecorationV1Error_enum_invalid_mode ZxdgToplevelDecorationV1Error_enum = 3 ) type ZxdgToplevelDecorationV1Mode_enum uint32 const ( ZxdgToplevelDecorationV1Mode_enum_client_side ZxdgToplevelDecorationV1Mode_enum = 1 ZxdgToplevelDecorationV1Mode_enum_server_side ZxdgToplevelDecorationV1Mode_enum = 2 ) ================================================ FILE: wayland/protocols/xdg-shell.xml.go ================================================ // Code generated by `cmd/protocols`; DO NOT EDIT. package protocols import "fmt" type XdgWmBase_delegate interface { XdgWmBase_destroy(s ClientState, object_id ObjectID[XdgWmBase]) bool XdgWmBase_create_positioner(s ClientState, object_id ObjectID[XdgWmBase], id ObjectID[XdgPositioner]) XdgWmBase_get_xdg_surface(s ClientState, object_id ObjectID[XdgWmBase], id ObjectID[XdgSurface], surface ObjectID[WlSurface]) XdgWmBase_pong(s ClientState, object_id ObjectID[XdgWmBase], serial uint32) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type XdgWmBase struct { Delegate XdgWmBase_delegate } func (p *XdgWmBase) GetDelegate() XdgWmBase_delegate { return p.Delegate } func (p *XdgWmBase) GetBindable() OnBindable { return p.Delegate } func XdgWmBase_ping(s Sender, eventObjectID ObjectID[XdgWmBase], serial uint32) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(serial)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 0, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func (p *XdgWmBase) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { if DebugRequests { fmt.Print("XdgWmBase@", message.ObjectID, ".destroy(") fmt.Println(")") } autoRemove := d.XdgWmBase_destroy(s, ObjectID[XdgWmBase](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) } break } case 1: { idVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 id := ObjectID[XdgPositioner](idVal) _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgWmBase@", message.ObjectID, ".create_positioner(") fmt.Println("id: ", id, ")") } d.XdgWmBase_create_positioner(s, ObjectID[XdgWmBase](message.ObjectID), id) break } case 2: { idVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 id := ObjectID[XdgSurface](idVal) _data_in_offset__ += 4 surface := ObjectID[WlSurface](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgWmBase@", message.ObjectID, ".get_xdg_surface(") fmt.Println("id: ", id, ", ", "surface: ", surface, ")") } d.XdgWmBase_get_xdg_surface(s, ObjectID[XdgWmBase](message.ObjectID), id, surface) break } case 3: { serial := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgWmBase@", message.ObjectID, ".pong(") fmt.Println("serial: ", serial, ")") } d.XdgWmBase_pong(s, ObjectID[XdgWmBase](message.ObjectID), serial) break } default: fmt.Println("Unknown opcode on XdgWmBase", message.Opcode) } } type XdgWmBaseError_enum uint32 const ( XdgWmBaseError_enum_role XdgWmBaseError_enum = 0 XdgWmBaseError_enum_defunct_surfaces XdgWmBaseError_enum = 1 XdgWmBaseError_enum_not_the_topmost_popup XdgWmBaseError_enum = 2 XdgWmBaseError_enum_invalid_popup_parent XdgWmBaseError_enum = 3 XdgWmBaseError_enum_invalid_surface_state XdgWmBaseError_enum = 4 XdgWmBaseError_enum_invalid_positioner XdgWmBaseError_enum = 5 XdgWmBaseError_enum_unresponsive XdgWmBaseError_enum = 6 ) type XdgPositioner_delegate interface { XdgPositioner_destroy(s ClientState, object_id ObjectID[XdgPositioner]) bool XdgPositioner_set_size(s ClientState, object_id ObjectID[XdgPositioner], width int32, height int32) XdgPositioner_set_anchor_rect(s ClientState, object_id ObjectID[XdgPositioner], x int32, y int32, width int32, height int32) XdgPositioner_set_anchor(s ClientState, object_id ObjectID[XdgPositioner], anchor XdgPositionerAnchor_enum) XdgPositioner_set_gravity(s ClientState, object_id ObjectID[XdgPositioner], gravity XdgPositionerGravity_enum) XdgPositioner_set_constraint_adjustment(s ClientState, object_id ObjectID[XdgPositioner], constraint_adjustment XdgPositionerConstraintAdjustment_enum) XdgPositioner_set_offset(s ClientState, object_id ObjectID[XdgPositioner], x int32, y int32) XdgPositioner_set_reactive(s ClientState, object_id ObjectID[XdgPositioner]) XdgPositioner_set_parent_size(s ClientState, object_id ObjectID[XdgPositioner], parent_width int32, parent_height int32) XdgPositioner_set_parent_configure(s ClientState, object_id ObjectID[XdgPositioner], serial uint32) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type XdgPositioner struct { Delegate XdgPositioner_delegate } func (p *XdgPositioner) GetDelegate() XdgPositioner_delegate { return p.Delegate } func (p *XdgPositioner) GetBindable() OnBindable { return p.Delegate } func (p *XdgPositioner) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { if DebugRequests { fmt.Print("XdgPositioner@", message.ObjectID, ".destroy(") fmt.Println(")") } autoRemove := d.XdgPositioner_destroy(s, ObjectID[XdgPositioner](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) } break } case 1: { width := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 height := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgPositioner@", message.ObjectID, ".set_size(") fmt.Println("width: ", width, ", ", "height: ", height, ")") } d.XdgPositioner_set_size(s, ObjectID[XdgPositioner](message.ObjectID), width, height) break } case 2: { x := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 y := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 width := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 height := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgPositioner@", message.ObjectID, ".set_anchor_rect(") fmt.Println("x: ", x, ", ", "y: ", y, ", ", "width: ", width, ", ", "height: ", height, ")") } d.XdgPositioner_set_anchor_rect(s, ObjectID[XdgPositioner](message.ObjectID), x, y, width, height) break } case 3: { anchor := XdgPositionerAnchor_enum(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgPositioner@", message.ObjectID, ".set_anchor(") fmt.Println("anchor: ", anchor, ")") } d.XdgPositioner_set_anchor(s, ObjectID[XdgPositioner](message.ObjectID), anchor) break } case 4: { gravity := XdgPositionerGravity_enum(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgPositioner@", message.ObjectID, ".set_gravity(") fmt.Println("gravity: ", gravity, ")") } d.XdgPositioner_set_gravity(s, ObjectID[XdgPositioner](message.ObjectID), gravity) break } case 5: { constraint_adjustment := XdgPositionerConstraintAdjustment_enum(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgPositioner@", message.ObjectID, ".set_constraint_adjustment(") fmt.Println("constraint_adjustment: ", constraint_adjustment, ")") } d.XdgPositioner_set_constraint_adjustment(s, ObjectID[XdgPositioner](message.ObjectID), constraint_adjustment) break } case 6: { x := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 y := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgPositioner@", message.ObjectID, ".set_offset(") fmt.Println("x: ", x, ", ", "y: ", y, ")") } d.XdgPositioner_set_offset(s, ObjectID[XdgPositioner](message.ObjectID), x, y) break } case 7: { if DebugRequests { fmt.Print("XdgPositioner@", message.ObjectID, ".set_reactive(") fmt.Println(")") } d.XdgPositioner_set_reactive(s, ObjectID[XdgPositioner](message.ObjectID)) break } case 8: { parent_width := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 parent_height := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgPositioner@", message.ObjectID, ".set_parent_size(") fmt.Println("parent_width: ", parent_width, ", ", "parent_height: ", parent_height, ")") } d.XdgPositioner_set_parent_size(s, ObjectID[XdgPositioner](message.ObjectID), parent_width, parent_height) break } case 9: { serial := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgPositioner@", message.ObjectID, ".set_parent_configure(") fmt.Println("serial: ", serial, ")") } d.XdgPositioner_set_parent_configure(s, ObjectID[XdgPositioner](message.ObjectID), serial) break } default: fmt.Println("Unknown opcode on XdgPositioner", message.Opcode) } } type XdgPositionerError_enum uint32 const ( XdgPositionerError_enum_invalid_input XdgPositionerError_enum = 0 ) type XdgPositionerAnchor_enum uint32 const ( XdgPositionerAnchor_enum_none XdgPositionerAnchor_enum = 0 XdgPositionerAnchor_enum_top XdgPositionerAnchor_enum = 1 XdgPositionerAnchor_enum_bottom XdgPositionerAnchor_enum = 2 XdgPositionerAnchor_enum_left XdgPositionerAnchor_enum = 3 XdgPositionerAnchor_enum_right XdgPositionerAnchor_enum = 4 XdgPositionerAnchor_enum_top_left XdgPositionerAnchor_enum = 5 XdgPositionerAnchor_enum_bottom_left XdgPositionerAnchor_enum = 6 XdgPositionerAnchor_enum_top_right XdgPositionerAnchor_enum = 7 XdgPositionerAnchor_enum_bottom_right XdgPositionerAnchor_enum = 8 ) type XdgPositionerGravity_enum uint32 const ( XdgPositionerGravity_enum_none XdgPositionerGravity_enum = 0 XdgPositionerGravity_enum_top XdgPositionerGravity_enum = 1 XdgPositionerGravity_enum_bottom XdgPositionerGravity_enum = 2 XdgPositionerGravity_enum_left XdgPositionerGravity_enum = 3 XdgPositionerGravity_enum_right XdgPositionerGravity_enum = 4 XdgPositionerGravity_enum_top_left XdgPositionerGravity_enum = 5 XdgPositionerGravity_enum_bottom_left XdgPositionerGravity_enum = 6 XdgPositionerGravity_enum_top_right XdgPositionerGravity_enum = 7 XdgPositionerGravity_enum_bottom_right XdgPositionerGravity_enum = 8 ) type XdgPositionerConstraintAdjustment_enum uint32 const ( XdgPositionerConstraintAdjustment_enum_none XdgPositionerConstraintAdjustment_enum = 0 XdgPositionerConstraintAdjustment_enum_slide_x XdgPositionerConstraintAdjustment_enum = 1 XdgPositionerConstraintAdjustment_enum_slide_y XdgPositionerConstraintAdjustment_enum = 2 XdgPositionerConstraintAdjustment_enum_flip_x XdgPositionerConstraintAdjustment_enum = 4 XdgPositionerConstraintAdjustment_enum_flip_y XdgPositionerConstraintAdjustment_enum = 8 XdgPositionerConstraintAdjustment_enum_resize_x XdgPositionerConstraintAdjustment_enum = 16 XdgPositionerConstraintAdjustment_enum_resize_y XdgPositionerConstraintAdjustment_enum = 32 ) type XdgSurface_delegate interface { XdgSurface_destroy(s ClientState, object_id ObjectID[XdgSurface]) bool XdgSurface_get_toplevel(s ClientState, object_id ObjectID[XdgSurface], id ObjectID[XdgToplevel]) XdgSurface_get_popup(s ClientState, object_id ObjectID[XdgSurface], id ObjectID[XdgPopup], parent *ObjectID[XdgSurface], positioner ObjectID[XdgPositioner]) XdgSurface_set_window_geometry(s ClientState, object_id ObjectID[XdgSurface], x int32, y int32, width int32, height int32) XdgSurface_ack_configure(s ClientState, object_id ObjectID[XdgSurface], serial uint32) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type XdgSurface struct { Delegate XdgSurface_delegate } func (p *XdgSurface) GetDelegate() XdgSurface_delegate { return p.Delegate } func (p *XdgSurface) GetBindable() OnBindable { return p.Delegate } func XdgSurface_configure(s Sender, eventObjectID ObjectID[XdgSurface], serial uint32) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(serial)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 0, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func (p *XdgSurface) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { if DebugRequests { fmt.Print("XdgSurface@", message.ObjectID, ".destroy(") fmt.Println(")") } autoRemove := d.XdgSurface_destroy(s, ObjectID[XdgSurface](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) } break } case 1: { idVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 id := ObjectID[XdgToplevel](idVal) _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgSurface@", message.ObjectID, ".get_toplevel(") fmt.Println("id: ", id, ")") } d.XdgSurface_get_toplevel(s, ObjectID[XdgSurface](message.ObjectID), id) break } case 2: { idVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 id := ObjectID[XdgPopup](idVal) _data_in_offset__ += 4 parentTmp := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 var parent *ObjectID[XdgSurface] if parentTmp != 0 { tmp := ObjectID[XdgSurface](parentTmp) parent = &tmp } positioner := ObjectID[XdgPositioner](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgSurface@", message.ObjectID, ".get_popup(") fmt.Println("id: ", id, ", ", "parent: ", parent, ", ", "positioner: ", positioner, ")") } d.XdgSurface_get_popup(s, ObjectID[XdgSurface](message.ObjectID), id, parent, positioner) break } case 3: { x := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 y := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 width := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 height := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgSurface@", message.ObjectID, ".set_window_geometry(") fmt.Println("x: ", x, ", ", "y: ", y, ", ", "width: ", width, ", ", "height: ", height, ")") } d.XdgSurface_set_window_geometry(s, ObjectID[XdgSurface](message.ObjectID), x, y, width, height) break } case 4: { serial := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgSurface@", message.ObjectID, ".ack_configure(") fmt.Println("serial: ", serial, ")") } d.XdgSurface_ack_configure(s, ObjectID[XdgSurface](message.ObjectID), serial) break } default: fmt.Println("Unknown opcode on XdgSurface", message.Opcode) } } type XdgSurfaceError_enum uint32 const ( XdgSurfaceError_enum_not_constructed XdgSurfaceError_enum = 1 XdgSurfaceError_enum_already_constructed XdgSurfaceError_enum = 2 XdgSurfaceError_enum_unconfigured_buffer XdgSurfaceError_enum = 3 XdgSurfaceError_enum_invalid_serial XdgSurfaceError_enum = 4 XdgSurfaceError_enum_invalid_size XdgSurfaceError_enum = 5 XdgSurfaceError_enum_defunct_role_object XdgSurfaceError_enum = 6 ) type XdgToplevel_delegate interface { XdgToplevel_destroy(s ClientState, object_id ObjectID[XdgToplevel]) bool XdgToplevel_set_parent(s ClientState, object_id ObjectID[XdgToplevel], parent *ObjectID[XdgToplevel]) XdgToplevel_set_title(s ClientState, object_id ObjectID[XdgToplevel], title string) XdgToplevel_set_app_id(s ClientState, object_id ObjectID[XdgToplevel], app_id string) XdgToplevel_show_window_menu(s ClientState, object_id ObjectID[XdgToplevel], seat ObjectID[WlSeat], serial uint32, x int32, y int32) XdgToplevel_move(s ClientState, object_id ObjectID[XdgToplevel], seat ObjectID[WlSeat], serial uint32) XdgToplevel_resize(s ClientState, object_id ObjectID[XdgToplevel], seat ObjectID[WlSeat], serial uint32, edges XdgToplevelResizeEdge_enum) XdgToplevel_set_max_size(s ClientState, object_id ObjectID[XdgToplevel], width int32, height int32) XdgToplevel_set_min_size(s ClientState, object_id ObjectID[XdgToplevel], width int32, height int32) XdgToplevel_set_maximized(s ClientState, object_id ObjectID[XdgToplevel]) XdgToplevel_unset_maximized(s ClientState, object_id ObjectID[XdgToplevel]) XdgToplevel_set_fullscreen(s ClientState, object_id ObjectID[XdgToplevel], output *ObjectID[WlOutput]) XdgToplevel_unset_fullscreen(s ClientState, object_id ObjectID[XdgToplevel]) XdgToplevel_set_minimized(s ClientState, object_id ObjectID[XdgToplevel]) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type XdgToplevel struct { Delegate XdgToplevel_delegate } func (p *XdgToplevel) GetDelegate() XdgToplevel_delegate { return p.Delegate } func (p *XdgToplevel) GetBindable() OnBindable { return p.Delegate } func XdgToplevel_configure(s Sender, eventObjectID ObjectID[XdgToplevel], width int32, height int32, states []byte) { data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } putInt32 := func(v int32) { putUint32(uint32(v)) } var fileDescriptor *FileDescriptor putInt32(int32(width)) putInt32(int32(height)) { n := len(states) putUint32(uint32(n)) data = append(data, states...) if pad := (4 - (n % 4)) % 4; pad != 0 { data = append(data, make([]byte, pad)...) } } obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 0, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func XdgToplevel_close(s Sender, eventObjectID ObjectID[XdgToplevel]) { data := make([]byte, 0) var fileDescriptor *FileDescriptor obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 1, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func XdgToplevel_configure_bounds(s Sender, boundVersion uint32, eventObjectID ObjectID[XdgToplevel], width int32, height int32) { if boundVersion < 4 { // Event not available in this version; skip return } data := make([]byte, 0) putInt32 := func(v int32) { uv := uint32(v); data = append(data, byte(uv), byte(uv>>8), byte(uv>>16), byte(uv>>24)) } var fileDescriptor *FileDescriptor putInt32(int32(width)) putInt32(int32(height)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 2, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func XdgToplevel_wm_capabilities(s Sender, boundVersion uint32, eventObjectID ObjectID[XdgToplevel], capabilities []byte) { if boundVersion < 5 { // Event not available in this version; skip return } data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor { n := len(capabilities) putUint32(uint32(n)) data = append(data, capabilities...) if pad := (4 - (n % 4)) % 4; pad != 0 { data = append(data, make([]byte, pad)...) } } obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 3, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func (p *XdgToplevel) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { if DebugRequests { fmt.Print("XdgToplevel@", message.ObjectID, ".destroy(") fmt.Println(")") } autoRemove := d.XdgToplevel_destroy(s, ObjectID[XdgToplevel](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) } break } case 1: { parentTmp := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 var parent *ObjectID[XdgToplevel] if parentTmp != 0 { tmp := ObjectID[XdgToplevel](parentTmp) parent = &tmp } if DebugRequests { fmt.Print("XdgToplevel@", message.ObjectID, ".set_parent(") fmt.Println("parent: ", parent, ")") } d.XdgToplevel_set_parent(s, ObjectID[XdgToplevel](message.ObjectID), parent) break } case 2: { titleLen := int(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 title := string(message.Data[_data_in_offset__ : _data_in_offset__+titleLen-1]) // NUL-terminated // 4-byte alignment if titleLen%4 != 0 { _data_in_offset__ += titleLen + (4 - (titleLen % 4)) } else { _data_in_offset__ += titleLen } if DebugRequests { fmt.Print("XdgToplevel@", message.ObjectID, ".set_title(") fmt.Println("title: ", title, ")") } d.XdgToplevel_set_title(s, ObjectID[XdgToplevel](message.ObjectID), title) break } case 3: { app_idLen := int(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 app_id := string(message.Data[_data_in_offset__ : _data_in_offset__+app_idLen-1]) // NUL-terminated // 4-byte alignment if app_idLen%4 != 0 { _data_in_offset__ += app_idLen + (4 - (app_idLen % 4)) } else { _data_in_offset__ += app_idLen } if DebugRequests { fmt.Print("XdgToplevel@", message.ObjectID, ".set_app_id(") fmt.Println("app_id: ", app_id, ")") } d.XdgToplevel_set_app_id(s, ObjectID[XdgToplevel](message.ObjectID), app_id) break } case 4: { seat := ObjectID[WlSeat](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 serial := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 x := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 y := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgToplevel@", message.ObjectID, ".show_window_menu(") fmt.Println("seat: ", seat, ", ", "serial: ", serial, ", ", "x: ", x, ", ", "y: ", y, ")") } d.XdgToplevel_show_window_menu(s, ObjectID[XdgToplevel](message.ObjectID), seat, serial, x, y) break } case 5: { seat := ObjectID[WlSeat](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 serial := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgToplevel@", message.ObjectID, ".move(") fmt.Println("seat: ", seat, ", ", "serial: ", serial, ")") } d.XdgToplevel_move(s, ObjectID[XdgToplevel](message.ObjectID), seat, serial) break } case 6: { seat := ObjectID[WlSeat](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 serial := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 edges := XdgToplevelResizeEdge_enum(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgToplevel@", message.ObjectID, ".resize(") fmt.Println("seat: ", seat, ", ", "serial: ", serial, ", ", "edges: ", edges, ")") } d.XdgToplevel_resize(s, ObjectID[XdgToplevel](message.ObjectID), seat, serial, edges) break } case 7: { width := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 height := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgToplevel@", message.ObjectID, ".set_max_size(") fmt.Println("width: ", width, ", ", "height: ", height, ")") } d.XdgToplevel_set_max_size(s, ObjectID[XdgToplevel](message.ObjectID), width, height) break } case 8: { width := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 height := int32(uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgToplevel@", message.ObjectID, ".set_min_size(") fmt.Println("width: ", width, ", ", "height: ", height, ")") } d.XdgToplevel_set_min_size(s, ObjectID[XdgToplevel](message.ObjectID), width, height) break } case 9: { if DebugRequests { fmt.Print("XdgToplevel@", message.ObjectID, ".set_maximized(") fmt.Println(")") } d.XdgToplevel_set_maximized(s, ObjectID[XdgToplevel](message.ObjectID)) break } case 10: { if DebugRequests { fmt.Print("XdgToplevel@", message.ObjectID, ".unset_maximized(") fmt.Println(")") } d.XdgToplevel_unset_maximized(s, ObjectID[XdgToplevel](message.ObjectID)) break } case 11: { outputTmp := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 var output *ObjectID[WlOutput] if outputTmp != 0 { tmp := ObjectID[WlOutput](outputTmp) output = &tmp } if DebugRequests { fmt.Print("XdgToplevel@", message.ObjectID, ".set_fullscreen(") fmt.Println("output: ", output, ")") } d.XdgToplevel_set_fullscreen(s, ObjectID[XdgToplevel](message.ObjectID), output) break } case 12: { if DebugRequests { fmt.Print("XdgToplevel@", message.ObjectID, ".unset_fullscreen(") fmt.Println(")") } d.XdgToplevel_unset_fullscreen(s, ObjectID[XdgToplevel](message.ObjectID)) break } case 13: { if DebugRequests { fmt.Print("XdgToplevel@", message.ObjectID, ".set_minimized(") fmt.Println(")") } d.XdgToplevel_set_minimized(s, ObjectID[XdgToplevel](message.ObjectID)) break } default: fmt.Println("Unknown opcode on XdgToplevel", message.Opcode) } } type XdgToplevelError_enum uint32 const ( XdgToplevelError_enum_invalid_resize_edge XdgToplevelError_enum = 0 XdgToplevelError_enum_invalid_parent XdgToplevelError_enum = 1 XdgToplevelError_enum_invalid_size XdgToplevelError_enum = 2 ) type XdgToplevelResizeEdge_enum uint32 const ( XdgToplevelResizeEdge_enum_none XdgToplevelResizeEdge_enum = 0 XdgToplevelResizeEdge_enum_top XdgToplevelResizeEdge_enum = 1 XdgToplevelResizeEdge_enum_bottom XdgToplevelResizeEdge_enum = 2 XdgToplevelResizeEdge_enum_left XdgToplevelResizeEdge_enum = 4 XdgToplevelResizeEdge_enum_top_left XdgToplevelResizeEdge_enum = 5 XdgToplevelResizeEdge_enum_bottom_left XdgToplevelResizeEdge_enum = 6 XdgToplevelResizeEdge_enum_right XdgToplevelResizeEdge_enum = 8 XdgToplevelResizeEdge_enum_top_right XdgToplevelResizeEdge_enum = 9 XdgToplevelResizeEdge_enum_bottom_right XdgToplevelResizeEdge_enum = 10 ) type XdgToplevelState_enum uint32 const ( XdgToplevelState_enum_maximized XdgToplevelState_enum = 1 XdgToplevelState_enum_fullscreen XdgToplevelState_enum = 2 XdgToplevelState_enum_resizing XdgToplevelState_enum = 3 XdgToplevelState_enum_activated XdgToplevelState_enum = 4 XdgToplevelState_enum_tiled_left XdgToplevelState_enum = 5 XdgToplevelState_enum_tiled_right XdgToplevelState_enum = 6 XdgToplevelState_enum_tiled_top XdgToplevelState_enum = 7 XdgToplevelState_enum_tiled_bottom XdgToplevelState_enum = 8 XdgToplevelState_enum_suspended XdgToplevelState_enum = 9 ) type XdgToplevelWmCapabilities_enum uint32 const ( XdgToplevelWmCapabilities_enum_window_menu XdgToplevelWmCapabilities_enum = 1 XdgToplevelWmCapabilities_enum_maximize XdgToplevelWmCapabilities_enum = 2 XdgToplevelWmCapabilities_enum_fullscreen XdgToplevelWmCapabilities_enum = 3 XdgToplevelWmCapabilities_enum_minimize XdgToplevelWmCapabilities_enum = 4 ) type XdgPopup_delegate interface { XdgPopup_destroy(s ClientState, object_id ObjectID[XdgPopup]) bool XdgPopup_grab(s ClientState, object_id ObjectID[XdgPopup], seat ObjectID[WlSeat], serial uint32) XdgPopup_reposition(s ClientState, object_id ObjectID[XdgPopup], positioner ObjectID[XdgPositioner], token uint32) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type XdgPopup struct { Delegate XdgPopup_delegate } func (p *XdgPopup) GetDelegate() XdgPopup_delegate { return p.Delegate } func (p *XdgPopup) GetBindable() OnBindable { return p.Delegate } func XdgPopup_configure(s Sender, eventObjectID ObjectID[XdgPopup], x int32, y int32, width int32, height int32) { data := make([]byte, 0) putInt32 := func(v int32) { uv := uint32(v); data = append(data, byte(uv), byte(uv>>8), byte(uv>>16), byte(uv>>24)) } var fileDescriptor *FileDescriptor putInt32(int32(x)) putInt32(int32(y)) putInt32(int32(width)) putInt32(int32(height)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 0, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func XdgPopup_popup_done(s Sender, eventObjectID ObjectID[XdgPopup]) { data := make([]byte, 0) var fileDescriptor *FileDescriptor obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 1, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func XdgPopup_repositioned(s Sender, boundVersion uint32, eventObjectID ObjectID[XdgPopup], token uint32) { if boundVersion < 3 { // Event not available in this version; skip return } data := make([]byte, 0) putUint32 := func(v uint32) { data = append(data, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) } var fileDescriptor *FileDescriptor putUint32(uint32(token)) obj := OutgoingEvent{ ObjectID: AnyObjectID(eventObjectID), Opcode: 2, Data: data, FileDescriptor: fileDescriptor, } s.Send(obj) } func (p *XdgPopup) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { if DebugRequests { fmt.Print("XdgPopup@", message.ObjectID, ".destroy(") fmt.Println(")") } autoRemove := d.XdgPopup_destroy(s, ObjectID[XdgPopup](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) } break } case 1: { seat := ObjectID[WlSeat](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 serial := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgPopup@", message.ObjectID, ".grab(") fmt.Println("seat: ", seat, ", ", "serial: ", serial, ")") } d.XdgPopup_grab(s, ObjectID[XdgPopup](message.ObjectID), seat, serial) break } case 2: { positioner := ObjectID[XdgPositioner](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 token := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 if DebugRequests { fmt.Print("XdgPopup@", message.ObjectID, ".reposition(") fmt.Println("positioner: ", positioner, ", ", "token: ", token, ")") } d.XdgPopup_reposition(s, ObjectID[XdgPopup](message.ObjectID), positioner, token) break } default: fmt.Println("Unknown opcode on XdgPopup", message.Opcode) } } type XdgPopupError_enum uint32 const ( XdgPopupError_enum_invalid_grab XdgPopupError_enum = 0 ) ================================================ FILE: wayland/protocols/xwayland-keyboard-grab-unstable-v1.xml.go ================================================ // Code generated by `cmd/protocols`; DO NOT EDIT. package protocols import "fmt" type ZwpXwaylandKeyboardGrabManagerV1_delegate interface { ZwpXwaylandKeyboardGrabManagerV1_destroy(s ClientState, object_id ObjectID[ZwpXwaylandKeyboardGrabManagerV1]) bool ZwpXwaylandKeyboardGrabManagerV1_grab_keyboard(s ClientState, object_id ObjectID[ZwpXwaylandKeyboardGrabManagerV1], id ObjectID[ZwpXwaylandKeyboardGrabV1], surface ObjectID[WlSurface], seat ObjectID[WlSeat]) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type ZwpXwaylandKeyboardGrabManagerV1 struct { Delegate ZwpXwaylandKeyboardGrabManagerV1_delegate } func (p *ZwpXwaylandKeyboardGrabManagerV1) GetDelegate() ZwpXwaylandKeyboardGrabManagerV1_delegate { return p.Delegate } func (p *ZwpXwaylandKeyboardGrabManagerV1) GetBindable() OnBindable { return p.Delegate } func (p *ZwpXwaylandKeyboardGrabManagerV1) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { if DebugRequests { fmt.Print("ZwpXwaylandKeyboardGrabManagerV1@", message.ObjectID, ".destroy(") fmt.Println(")") } autoRemove := d.ZwpXwaylandKeyboardGrabManagerV1_destroy(s, ObjectID[ZwpXwaylandKeyboardGrabManagerV1](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) } break } case 1: { idVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 id := ObjectID[ZwpXwaylandKeyboardGrabV1](idVal) _data_in_offset__ += 4 surface := ObjectID[WlSurface](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 seat := ObjectID[WlSeat](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("ZwpXwaylandKeyboardGrabManagerV1@", message.ObjectID, ".grab_keyboard(") fmt.Println("id: ", id, ", ", "surface: ", surface, ", ", "seat: ", seat, ")") } d.ZwpXwaylandKeyboardGrabManagerV1_grab_keyboard(s, ObjectID[ZwpXwaylandKeyboardGrabManagerV1](message.ObjectID), id, surface, seat) break } default: fmt.Println("Unknown opcode on ZwpXwaylandKeyboardGrabManagerV1", message.Opcode) } } type ZwpXwaylandKeyboardGrabV1_delegate interface { ZwpXwaylandKeyboardGrabV1_destroy(s ClientState, object_id ObjectID[ZwpXwaylandKeyboardGrabV1]) bool OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type ZwpXwaylandKeyboardGrabV1 struct { Delegate ZwpXwaylandKeyboardGrabV1_delegate } func (p *ZwpXwaylandKeyboardGrabV1) GetDelegate() ZwpXwaylandKeyboardGrabV1_delegate { return p.Delegate } func (p *ZwpXwaylandKeyboardGrabV1) GetBindable() OnBindable { return p.Delegate } func (p *ZwpXwaylandKeyboardGrabV1) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { if DebugRequests { fmt.Print("ZwpXwaylandKeyboardGrabV1@", message.ObjectID, ".destroy(") fmt.Println(")") } autoRemove := d.ZwpXwaylandKeyboardGrabV1_destroy(s, ObjectID[ZwpXwaylandKeyboardGrabV1](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) } break } default: fmt.Println("Unknown opcode on ZwpXwaylandKeyboardGrabV1", message.Opcode) } } ================================================ FILE: wayland/protocols/xwayland-shell-v1.xml.go ================================================ // Code generated by `cmd/protocols`; DO NOT EDIT. package protocols import "fmt" type XwaylandShellV1_delegate interface { XwaylandShellV1_destroy(s ClientState, object_id ObjectID[XwaylandShellV1]) bool XwaylandShellV1_get_xwayland_surface(s ClientState, object_id ObjectID[XwaylandShellV1], id ObjectID[XwaylandSurfaceV1], surface ObjectID[WlSurface]) OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type XwaylandShellV1 struct { Delegate XwaylandShellV1_delegate } func (p *XwaylandShellV1) GetDelegate() XwaylandShellV1_delegate { return p.Delegate } func (p *XwaylandShellV1) GetBindable() OnBindable { return p.Delegate } func (p *XwaylandShellV1) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { if DebugRequests { fmt.Print("XwaylandShellV1@", message.ObjectID, ".destroy(") fmt.Println(")") } autoRemove := d.XwaylandShellV1_destroy(s, ObjectID[XwaylandShellV1](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) } break } case 1: { idVal := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 id := ObjectID[XwaylandSurfaceV1](idVal) _data_in_offset__ += 4 surface := ObjectID[WlSurface](uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24) _data_in_offset__ += 4 if DebugRequests { fmt.Print("XwaylandShellV1@", message.ObjectID, ".get_xwayland_surface(") fmt.Println("id: ", id, ", ", "surface: ", surface, ")") } d.XwaylandShellV1_get_xwayland_surface(s, ObjectID[XwaylandShellV1](message.ObjectID), id, surface) break } default: fmt.Println("Unknown opcode on XwaylandShellV1", message.Opcode) } } type XwaylandShellV1Error_enum uint32 const ( XwaylandShellV1Error_enum_role XwaylandShellV1Error_enum = 0 ) type XwaylandSurfaceV1_delegate interface { XwaylandSurfaceV1_set_serial(s ClientState, object_id ObjectID[XwaylandSurfaceV1], serial_lo uint32, serial_hi uint32) XwaylandSurfaceV1_destroy(s ClientState, object_id ObjectID[XwaylandSurfaceV1]) bool OnBind(s ClientState, name AnyObjectID, interface_ string, new_id AnyObjectID, version_number uint32) } type XwaylandSurfaceV1 struct { Delegate XwaylandSurfaceV1_delegate } func (p *XwaylandSurfaceV1) GetDelegate() XwaylandSurfaceV1_delegate { return p.Delegate } func (p *XwaylandSurfaceV1) GetBindable() OnBindable { return p.Delegate } func (p *XwaylandSurfaceV1) OnRequest(s FileDescriptorClaimClientState, message Message) { _data_in_offset__ := 0 _ = _data_in_offset__ d := p.Delegate switch message.Opcode { case 0: { serial_lo := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 serial_hi := uint32(message.Data[_data_in_offset__+0]) | uint32(message.Data[_data_in_offset__+1])<<8 | uint32(message.Data[_data_in_offset__+2])<<16 | uint32(message.Data[_data_in_offset__+3])<<24 _data_in_offset__ += 4 if DebugRequests { fmt.Print("XwaylandSurfaceV1@", message.ObjectID, ".set_serial(") fmt.Println("serial_lo: ", serial_lo, ", ", "serial_hi: ", serial_hi, ")") } d.XwaylandSurfaceV1_set_serial(s, ObjectID[XwaylandSurfaceV1](message.ObjectID), serial_lo, serial_hi) break } case 1: { if DebugRequests { fmt.Print("XwaylandSurfaceV1@", message.ObjectID, ".destroy(") fmt.Println(")") } autoRemove := d.XwaylandSurfaceV1_destroy(s, ObjectID[XwaylandSurfaceV1](message.ObjectID)) if autoRemove { s.RemoveObject(message.ObjectID) } break } default: fmt.Println("Unknown opcode on XwaylandSurfaceV1", message.Opcode) } } type XwaylandSurfaceV1Error_enum uint32 const ( XwaylandSurfaceV1Error_enum_already_associated XwaylandSurfaceV1Error_enum = 0 XwaylandSurfaceV1Error_enum_invalid_serial XwaylandSurfaceV1Error_enum = 1 ) ================================================ FILE: wayland/resources/server-1.xkb ================================================ xkb_keymap { xkb_keycodes "evdev+aliases(qwerty)" { minimum = 8; maximum = 255; = 9; = 10; = 11; = 12; = 13; = 14; = 15; = 16; = 17; = 18; = 19; = 20; = 21; = 22; = 23; = 24; = 25; = 26; = 27; = 28; = 29; = 30; = 31; = 32; = 33; = 34; = 35; = 36; = 37; = 38; = 39; = 40; = 41; = 42; = 43; = 44; = 45; = 46; = 47; = 48; = 49; = 50; = 51; = 52; = 53; = 54; = 55; = 56; = 57; = 58; = 59; = 60; = 61; = 62; = 63; = 64; = 65; = 66; = 67; = 68; = 69; = 70; = 71; = 72; = 73; = 74; = 75; = 76; = 77; = 78; = 79; = 80; = 81; = 82; = 83; = 84; = 85; = 86; = 87; = 88; = 89; = 90; = 91; = 92; = 94; = 95; = 96; = 97; = 98; = 99; = 100; = 101; = 102; = 103; = 104; = 105; = 106; = 107; = 108; = 109; = 110; = 111; = 112; = 113; = 114; = 115; = 116; = 117; = 118; = 119; = 120; = 121; = 122; = 123; = 124; = 125; = 126; = 127; = 128; = 129; = 130; = 131; = 132; = 133; = 134; = 135; = 136; = 137; = 138; = 139; = 140; = 141; = 142; = 143; = 144; = 145; = 146; = 147; = 148; = 149; = 150; = 151; = 152; = 153; = 154; = 155; = 156; = 157; = 158; = 159; = 160; = 161; = 162; = 163; = 164; = 165; = 166; = 167; = 168; = 169; = 170; = 171; = 172; = 173; = 174; = 175; = 176; = 177; = 178; = 179; = 180; = 181; = 182; = 183; = 184; = 185; = 186; = 187; = 188; = 189; = 190; = 191; = 192; = 193; = 194; = 195; = 196; = 197; = 198; = 199; = 200; = 201; = 202; = 203; = 204; = 205; = 206; = 207; = 208; = 209; = 210; = 211; = 212; = 213; = 214; = 215; = 216; = 217; = 218; = 219; = 220; = 221; = 222; = 223; = 224; = 225; = 226; = 227; = 228; = 229; = 230;