├── .github └── workflows │ ├── backup-to-gitlab.yml │ ├── call-auto-tag.yml │ ├── call-build-distribution.yml │ ├── call-chatOps.yml │ ├── call-clacheck.yml │ ├── call-commitlint.yml │ └── call-license-check.yml ├── .gitlab-ci.yml ├── .obs └── workflows.yml ├── .packit.yaml ├── .reuse └── dep5 ├── CHANGELOG.md ├── LICENSE ├── LICENSES ├── CC-BY-4.0.txt ├── CC0-1.0.txt └── GPL-3.0-or-later.txt ├── Makefile ├── README.md ├── README.zh_CN.md ├── archlinux └── PKGBUILD ├── atom.go ├── auth.go ├── client_message_data.go ├── conn.go ├── conn_connect.go ├── conn_in.go ├── conn_out.go ├── const.go ├── debian ├── changelog ├── compat ├── control ├── copyright ├── gbp.conf ├── rules ├── source │ └── format └── watch ├── error.go ├── event.go ├── ext ├── bigrequests │ ├── auto.go │ ├── bigreq.go │ └── bigreq_req_auto.go ├── composite │ ├── auto.go │ ├── composite.go │ └── composite_req_auto.go ├── damage │ ├── auto.go │ ├── damage.go │ └── damage_req_auto.go ├── dpms │ ├── auto.go │ ├── dpms.go │ └── dpms_req_auto.go ├── ge │ ├── auto.go │ ├── ge.go │ └── ge_req_auto.go ├── input │ ├── auto.go │ ├── input.go │ ├── input1.go │ ├── input1_req_auto.go │ ├── input_event.go │ └── input_req_auto.go ├── randr │ ├── auto.go │ ├── randr.go │ ├── randr_event.go │ └── randr_req_auto.go ├── record │ ├── auto.go │ ├── record.go │ └── record_req_auto.go ├── render │ ├── auto.go │ ├── render.go │ └── render_req_auto.go ├── screensaver │ ├── auto.go │ ├── screensaver.go │ └── screensaver_req_auto.go ├── shm │ ├── auto.go │ ├── shm.go │ └── shm_req_auto.go ├── test │ ├── auto.go │ ├── test.go │ └── test_req_auto.go ├── xfixes │ ├── auto.go │ ├── xfixes.go │ └── xfixes_req_auto.go └── xkb │ ├── auto.go │ ├── xkb.go │ ├── xkb_event.go │ └── xkb_req_auto.go ├── extension.go ├── gen.sh ├── go.mod ├── go.sum ├── help.go ├── in.go ├── reader.go ├── reader_test.go ├── resource_id.go ├── rpm └── golang-github-linuxdeepin-go-x11-client.spec ├── tools ├── common.py ├── enum.py ├── gen │ └── main.go └── go_client.py ├── util ├── atom │ └── atom.go ├── cursor │ ├── cursor.go │ ├── cursor_test.go │ ├── read.go │ ├── testdata │ │ ├── left_ptr │ │ └── watch │ └── theme.go ├── keybind │ └── keybind.go ├── keysyms │ ├── auto.go │ └── keysyms.go ├── mousebind │ └── mousebind.go ├── tool │ └── gen-keysymdef │ │ ├── gen.sh │ │ └── main.go └── wm │ ├── ewmh │ ├── a.py │ ├── auto.go │ └── manual.go │ └── icccm │ ├── icccm.go │ └── text_property.go ├── writer.go ├── xproto.go ├── xproto_auto.go ├── xproto_auto_req.go ├── xproto_event.go └── xproto_test.go /.github/workflows/backup-to-gitlab.yml: -------------------------------------------------------------------------------- 1 | name: backup to gitlab 2 | on: [push] 3 | 4 | concurrency: 5 | group: ${{ github.workflow }} 6 | cancel-in-progress: true 7 | 8 | jobs: 9 | backup-to-gitlabwh: 10 | uses: linuxdeepin/.github/.github/workflows/backup-to-gitlabwh.yml@master 11 | secrets: inherit 12 | 13 | backup-to-gitee: 14 | uses: linuxdeepin/.github/.github/workflows/backup-to-gitee.yml@master 15 | secrets: inherit 16 | -------------------------------------------------------------------------------- /.github/workflows/call-auto-tag.yml: -------------------------------------------------------------------------------- 1 | name: auto tag 2 | 3 | on: 4 | pull_request_target: 5 | types: [opened, synchronize, closed] 6 | paths: 7 | - "debian/changelog" 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-pull/${{ github.event.number }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | auto_tag: 15 | uses: linuxdeepin/.github/.github/workflows/auto-tag.yml@master 16 | secrets: inherit 17 | -------------------------------------------------------------------------------- /.github/workflows/call-build-distribution.yml: -------------------------------------------------------------------------------- 1 | name: Call build-distribution 2 | on: 3 | push: 4 | paths-ignore: 5 | - ".github/workflows/**" 6 | pull_request_target: 7 | paths-ignore: 8 | - ".github/workflows/**" 9 | 10 | jobs: 11 | check_job: 12 | uses: linuxdeepin/.github/.github/workflows/build-distribution.yml@master 13 | secrets: inherit 14 | -------------------------------------------------------------------------------- /.github/workflows/call-chatOps.yml: -------------------------------------------------------------------------------- 1 | name: chatOps 2 | on: 3 | issue_comment: 4 | types: [created] 5 | 6 | jobs: 7 | chatopt: 8 | uses: linuxdeepin/.github/.github/workflows/chatOps.yml@master 9 | secrets: inherit 10 | -------------------------------------------------------------------------------- /.github/workflows/call-clacheck.yml: -------------------------------------------------------------------------------- 1 | name: Call CLA check 2 | on: 3 | issue_comment: 4 | types: [created] 5 | pull_request_target: 6 | types: [opened, closed, synchronize] 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-pull/${{ github.event.number }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | clacheck: 14 | uses: linuxdeepin/.github/.github/workflows/cla-check.yml@master 15 | secrets: inherit 16 | -------------------------------------------------------------------------------- /.github/workflows/call-commitlint.yml: -------------------------------------------------------------------------------- 1 | name: Call commitlint 2 | on: 3 | pull_request_target: 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}-pull/${{ github.event.number }} 7 | cancel-in-progress: true 8 | 9 | jobs: 10 | check_job: 11 | uses: linuxdeepin/.github/.github/workflows/commitlint.yml@master 12 | -------------------------------------------------------------------------------- /.github/workflows/call-license-check.yml: -------------------------------------------------------------------------------- 1 | name: Call License and README Check 2 | on: 3 | pull_request_target: 4 | types: [opened, synchronize, reopened] 5 | 6 | permissions: 7 | pull-requests: write 8 | contents: read 9 | 10 | concurrency: 11 | group: ${{ github.workflow }}-pull/${{ github.event.number }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | license-check: 16 | uses: linuxdeepin/.github/.github/workflows/license-check.yml@master 17 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | include: 2 | - remote: 'https://gitlab.deepin.io/dev-tools/letmeci/raw/master/gitlab-ci/dde.yml' 3 | -------------------------------------------------------------------------------- /.obs/workflows.yml: -------------------------------------------------------------------------------- 1 | test_build: 2 | steps: 3 | - link_package: 4 | source_project: deepin:Develop:dde 5 | source_package: %{SCM_REPOSITORY_NAME} 6 | target_project: deepin:CI 7 | 8 | - configure_repositories: 9 | project: deepin:CI 10 | repositories: 11 | - name: deepin_develop 12 | paths: 13 | - target_project: deepin:CI 14 | target_repository: deepin_develop 15 | architectures: 16 | - x86_64 17 | - aarch64 18 | 19 | - name: debian 20 | paths: 21 | - target_project: deepin:CI 22 | target_repository: debian_sid 23 | architectures: 24 | - x86_64 25 | 26 | - name: archlinux 27 | paths: 28 | - target_project: deepin:CI 29 | target_repository: archlinux 30 | architectures: 31 | - x86_64 32 | 33 | filters: 34 | event: pull_request 35 | 36 | tag_build: 37 | steps: 38 | - trigger_services: 39 | project: deepin:Unstable:dde 40 | package: %{SCM_REPOSITORY_NAME} 41 | filters: 42 | event: tag_push 43 | 44 | commit_build: 45 | steps: 46 | - trigger_services: 47 | project: deepin:Develop:dde 48 | package: %{SCM_REPOSITORY_NAME} 49 | filters: 50 | event: push 51 | -------------------------------------------------------------------------------- /.packit.yaml: -------------------------------------------------------------------------------- 1 | # See the documentation for more information: 2 | # https://packit.dev/docs/configuration/ 3 | 4 | specfile_path: rpm/golang-github-linuxdeepin-go-x11-client.spec 5 | 6 | # add or remove files that should be synced 7 | synced_files: 8 | - rpm/golang-github-linuxdeepin-go-x11-client.spec 9 | - .packit.yaml 10 | 11 | upstream_package_name: go-x11-client 12 | # downstream (Fedora) RPM package name 13 | downstream_package_name: golang-github-linuxdeepin-go-x11-client 14 | 15 | actions: 16 | fix-spec-file: | 17 | bash -c "sed -i -r \"0,/Version:/ s/Version:(\s*)\S*/Version:\1${PACKIT_PROJECT_VERSION}/\" rpm/golang-github-linuxdeepin-go-x11-client.spec" 18 | -------------------------------------------------------------------------------- /.reuse/dep5: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: go-x11-client 3 | Upstream-Contact: UnionTech Software Technology Co., Ltd. <> 4 | Source: https://github.com/linuxdeepin/go-x11-client 5 | 6 | # gitignore clang-format gitreview .tx 7 | Files: .gitignore .clang-format .gitreview .mailmap .tx/config 8 | Copyright: None 9 | License: CC0-1.0 10 | 11 | # README 12 | Files: *.md README README.zh_CN.md 13 | Copyright: UnionTech Software Technology Co., Ltd. 14 | License: CC-BY-4.0 15 | 16 | # Project file 17 | Files: *Makefile* 18 | Copyright: None 19 | License: CC0-1.0 20 | 21 | # ci 22 | Files: .github/* .gitlab-ci.yml .obs/workflows.yml 23 | Copyright: None 24 | License: CC0-1.0 25 | 26 | # sh 27 | Files: gen.sh util/tool/gen-keysymdef/gen.sh 28 | Copyright: None 29 | License: GPL-3.0-or-later 30 | 31 | # debian rpm archlinux 32 | Files: debian/* rpm/* archlinux/* 33 | Copyright: None 34 | License: CC0-1.0 35 | 36 | # README 37 | Files: *.md src/gi/README README.zh_CN.md 38 | Copyright: UnionTech Software Technology Co., Ltd. 39 | License: CC-BY-4.0 40 | 41 | # docs documentation 42 | Files: docs/* documentation/* 43 | Copyright: UnionTech Software Technology Co., Ltd. 44 | License: GPL-3.0-or-later 45 | 46 | # org xml json yaml html yml css in ui 47 | Files: *.org *.xml *.json *.yaml *.html *.yml *.css *.devhelp2 *.in *.ui 48 | Copyright: UnionTech Software Technology Co., Ltd. 49 | License: GPL-3.0-or-later 50 | 51 | # png svg jpg gif 52 | Files: *.png *.svg *.jpg *.gif 53 | Copyright: UnionTech Software Technology Co., Ltd. 54 | License: GPL-3.0-or-later 55 | 56 | # test file 57 | Files: *testdata/* 58 | Copyright: UnionTech Software Technology Co., Ltd. 59 | License: GPL-3.0-or-later 60 | 61 | # gomod files 62 | Files: go.mod go.sum 63 | Copyright: None 64 | License: CC0-1.0 65 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | [0.4.1] 2019-04-03 2 | * fix: build failed 3 | 4 | [0.4.0] 2019-03-27 5 | * feat: add util xcursor 6 | 7 | [0.3.0] 2019-02-26 8 | * chore: use WriteBool and ReadBool 9 | * feat: xkb add more functions 10 | * chore: exts use new reader 11 | * chore: xproto event use new reader 12 | * feat: implement new Reader 13 | * feat: add ext xkb 14 | * feat: delete other error types, leaving only the Error type 15 | * chore: continue to replace uint64 with SeqNum 16 | * feat: use special seqNum to indicate error 17 | * fix: requestCheck do not unlock c.ioMu before return 18 | * chore: replace uint64 with SeqNum 19 | * feat: reduce memory usage for encoding requests 20 | 21 | # [0.2.0] - 2018-11-23 22 | * fix: readSetup 23 | 24 | # [0.1.0] - 2018-10-25 25 | * fix(wm/ewmh): get icon failed 26 | * feat: add WriteSelectionNotifyEvent 27 | * chore: add makefile for `sw_64` 28 | 29 | # [0.0.4] - 2018-07-19 30 | * fix: requestCheck method 31 | * feat: add ext shm 32 | * feat: add ext render 33 | * feat: support ge generic event 34 | * feat: add ext input 35 | * fix: readMapNotifyEvent no set Window field 36 | * fix: conn read blocked when event chan full 37 | * feat(ext/randr): add more events 38 | * fix(ext/randr): name typo 39 | * feat: add ext xfixes 40 | * fead: handle conn read write error 41 | * feat: Conn add method IDUsedCount 42 | * fix: wrong call NewError 43 | * feat: add resource id allocator 44 | * feat: conn add atom cache 45 | * fix: ewmh _NET_SUPPORTING_WM_CHECK is not root property 46 | * feat: add ext randr 47 | * feat: add ext dpms and screensaver 48 | * chore: call log.Print if env DEBUG_X11_CLIENT = 1 49 | * chore(deb): set env DH_GOLANG_EXCLUDES 50 | * feat: handwriting encode decode part 51 | * fix: atom WM_CHANGE_STATE not found 52 | 53 | # [0.0.3] - 2018-03-07 54 | * remove usr/bin 55 | * expand event chan buffer size 56 | * fix: Adapt lintian 57 | 58 | -------------------------------------------------------------------------------- /LICENSES/CC0-1.0.txt: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PREFIX = /usr 2 | GOSITE_DIR = ${PREFIX}/share/gocode 3 | GOPKG_PERFIX = github.com/linuxdeepin/go-x11-client 4 | SRC_DIR=${DESTDIR}${GOSITE_DIR}/src/${GOPKG_PERFIX} 5 | 6 | all: build 7 | 8 | build: 9 | echo ignore build 10 | 11 | print_gopath: 12 | GOPATH="${CURDIR}/${GOPATH_DIR}:${GOPATH}" 13 | 14 | install: 15 | mkdir -p ${SRC_DIR} 16 | cp *.go ${SRC_DIR} 17 | cp -r ext ${SRC_DIR} 18 | cp -r util ${SRC_DIR} 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-x11-client 2 | 3 | **Description**: 4 | go-x11-client it is a X11 protocol go language binding. 5 | 6 | ## Dependencies 7 | You can also check the "Depends" provided in the debian/control file. 8 | 9 | ### Build dependencies 10 | You can also check the "Build-Depends" provided in the debian/control file. 11 | 12 | ## Installation 13 | 14 | ### Deepin 15 | 16 | Install prerequisites 17 | ``` 18 | $ sudo apt-get build-dep go-x11-client 19 | ``` 20 | 21 | Build 22 | ``` 23 | $ GOPATH=/usr/share/gocode make 24 | ``` 25 | 26 | Install 27 | If you have isolated testing build environment (say a docker container), you can install it directly. 28 | 29 | ``` 30 | $ sudo make install 31 | ``` 32 | 33 | generate package files and install go-x11-client with it. 34 | ``` 35 | $ debuild -uc -us ... 36 | $ sudo dpkg -i ../golang-github-linuxdeepin-go-x11-client.deb 37 | ``` 38 | 39 | ## Usage 40 | go get github.com/linuxdeepin/go-x11-client 41 | 42 | ## Getting help 43 | 44 | Any usage issues can ask for help via 45 | 46 | * [Gitter](https://gitter.im/orgs/linuxdeepin/rooms) 47 | * [IRC channel](https://webchat.freenode.net/?channels=deepin) 48 | * [Forum](https://bbs.deepin.org) 49 | * [WiKi](https://wiki.deepin.org/) 50 | 51 | ## Getting involved 52 | 53 | We encourage you to report issues and contribute changes. 54 | 55 | * [Contribution guide for developers](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers-en). (English) 56 | * [开发者代码贡献指南](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers) (中文) 57 | 58 | ## License 59 | 60 | go-x11-client is licensed under [GPL-3.0-or-later](LICENSE). 61 | 62 | 63 | -------------------------------------------------------------------------------- /README.zh_CN.md: -------------------------------------------------------------------------------- 1 | # go-x11-client 2 | 3 | **Description**: 4 | go-x11-client是一个用go语言实现与X11协议进行绑定的项目。 5 | 6 | ## 依赖 7 | 请查看“debian/control”文件中提供的“Depends”。 8 | 9 | ### 编译依赖 10 | 请查看“debian/control”文件中提供的“Build-Depends”。 11 | 12 | ## 安装 13 | 14 | ### Deepin 15 | 16 | go-x11-client需要预安装以下包 17 | ``` 18 | $ sudo apt-get build-dep go-x11-client 19 | ``` 20 | 21 | 构建 22 | ``` 23 | $ GOPATH=/usr/share/gocode make 24 | ``` 25 | 26 | 安装 27 | 如果你有独立的测试构建环境(比如一个 docker 容器),你可以直接安装它。 28 | 29 | ``` 30 | $ sudo make install 31 | ``` 32 | 33 | 生成包文件并安装 go-x11-client 34 | ``` 35 | $ debuild -uc -us ... 36 | $ sudo dpkg -i ../golang-github-linuxdeepin-go-x11-client.deb 37 | ``` 38 | 39 | ## 用法 40 | go get github.com/linuxdeepin/go-x11-client 41 | 42 | ## 获得帮助 43 | 44 | 如果您遇到任何其他问题,您可能还会发现这些渠道很有用: 45 | 46 | * [Gitter](https://gitter.im/orgs/linuxdeepin/rooms) 47 | * [IRC channel](https://webchat.freenode.net/?channels=deepin) 48 | * [Forum](https://bbs.deepin.org) 49 | * [WiKi](https://wiki.deepin.org/) 50 | 51 | ## 贡献指南 52 | 53 | 我们鼓励您报告问题并做出更改 54 | 55 | * [Contribution guide for developers](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers-en). (English) 56 | * [开发者代码贡献指南](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers) (中文) 57 | 58 | ## License 59 | 60 | go-x11-client项目在 [GPL-3.0-or-later](LICENSE)下发布。 61 | 62 | 63 | -------------------------------------------------------------------------------- /archlinux/PKGBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: justforlxz 2 | pkgname=golang-github-linuxdeepin-go-x11-client-git 3 | pkgver=0.6.8.r2.g9476531 4 | pkgrel=1 5 | sourcename=go-x11-client 6 | pkgsourcename="golang-github-linuxdeepin-go-x11-client" 7 | sourcetars=("$pkgsourcename"_"$pkgver".tar.xz vendor.tar.gz) 8 | sourcedir="$sourcename" 9 | pkgdesc='X11 protocol go language binding' 10 | arch=('any') 11 | url="https://github.com/linuxdeepin/go-x11-client" 12 | license=('GPL') 13 | conflicts=('golang-github-linuxdeepin-go-x11-client') 14 | provides=('golang-github-linuxdeepin-go-x11-client') 15 | groups=('deepin-git') 16 | makedepends=('git' 'go' 'xorg-server-xvfb') 17 | checkdepends=('xorg-server-xvfb' 'git') 18 | source=("${sourcetars[@]}") 19 | sha512sums=('SKIP' 'SKIP') 20 | 21 | prepare() { 22 | cd $sourcedir 23 | rm -rf tools 24 | } 25 | 26 | check() { 27 | export GOPATH="$srcdir/build:/usr/share/gocode" 28 | #export GO111MODULE=off 29 | mkdir -p "$srcdir"/build/src/github.com/linuxdeepin 30 | mv "$srcdir"/vendor "$srcdir"/"$sourcedir"/vendor 31 | cp -a "$srcdir/$sourcedir" "$srcdir"/build/src/github.com/linuxdeepin/go-x11-client 32 | cd "$srcdir"/build/src/github.com/linuxdeepin/go-x11-client 33 | xvfb-run go test -v $(go list ./...) 34 | } 35 | 36 | package() { 37 | mkdir -p "$pkgdir"/usr/share/gocode/src/github.com/linuxdeepin 38 | cp -a "$srcdir/$sourcedir" "$pkgdir"/usr/share/gocode/src/github.com/linuxdeepin/go-x11-client 39 | rm -r "$pkgdir"/usr/share/gocode/src/github.com/linuxdeepin/go-x11-client/debian 40 | } 41 | -------------------------------------------------------------------------------- /atom.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package x 6 | 7 | import ( 8 | "sync" 9 | ) 10 | 11 | type AtomCache struct { 12 | atoms map[string]Atom 13 | atomNames map[Atom]string 14 | mu sync.RWMutex 15 | } 16 | 17 | func (ac *AtomCache) getVal(name string) (val Atom, ok bool) { 18 | ac.mu.RLock() 19 | val, ok = ac.atoms[name] 20 | ac.mu.RUnlock() 21 | return 22 | } 23 | 24 | func (ac *AtomCache) getName(val Atom) (name string, ok bool) { 25 | ac.mu.RLock() 26 | name, ok = ac.atomNames[val] 27 | ac.mu.RUnlock() 28 | return 29 | } 30 | 31 | func (ac *AtomCache) store(name string, val Atom) { 32 | ac.mu.Lock() 33 | ac.atoms[name] = val 34 | ac.atomNames[val] = name 35 | ac.mu.Unlock() 36 | } 37 | 38 | func NewAtomCache() *AtomCache { 39 | ac := &AtomCache{ 40 | atoms: make(map[string]Atom), 41 | atomNames: make(map[Atom]string), 42 | } 43 | return ac 44 | } 45 | 46 | var defaultAtomCache *AtomCache 47 | var defaultAtomCacheMu sync.Mutex 48 | 49 | func (c *Conn) getAtomCache() *AtomCache { 50 | c.atomCacheMu.Lock() 51 | if c.atomCache == nil { 52 | // try default atom cache 53 | defaultAtomCacheMu.Lock() 54 | if defaultAtomCache == nil { 55 | defaultAtomCache = NewAtomCache() 56 | } 57 | c.atomCache = defaultAtomCache 58 | defaultAtomCacheMu.Unlock() 59 | } 60 | v := c.atomCache 61 | c.atomCacheMu.Unlock() 62 | return v 63 | } 64 | 65 | func (c *Conn) SetAtomCache(ac *AtomCache) { 66 | c.atomCacheMu.Lock() 67 | c.atomCache = ac 68 | c.atomCacheMu.Unlock() 69 | } 70 | 71 | func (c *Conn) GetAtomCache() (ac *AtomCache) { 72 | c.atomCacheMu.Lock() 73 | ac = c.atomCache 74 | c.atomCacheMu.Unlock() 75 | return 76 | } 77 | 78 | func (c *Conn) GetAtom(name string) (Atom, error) { 79 | return c.getAtom(false, name) 80 | } 81 | 82 | func (c *Conn) GetAtomExisting(name string) (Atom, error) { 83 | return c.getAtom(true, name) 84 | } 85 | 86 | func (c *Conn) getAtom(onlyIfExists bool, name string) (Atom, error) { 87 | ac := c.getAtomCache() 88 | val, ok := ac.getVal(name) 89 | if ok { 90 | return val, nil 91 | } 92 | 93 | reply, err := InternAtom(c, onlyIfExists, name).Reply(c) 94 | if err != nil { 95 | return AtomNone, err 96 | } 97 | ac.store(name, reply.Atom) 98 | return reply.Atom, nil 99 | } 100 | 101 | func (c *Conn) GetAtomName(atom Atom) (string, error) { 102 | ac := c.getAtomCache() 103 | name, ok := ac.getName(atom) 104 | if ok { 105 | return name, nil 106 | } 107 | 108 | reply, err := GetAtomName(c, atom).Reply(c) 109 | if err != nil { 110 | return "", err 111 | } 112 | ac.store(reply.Name, atom) 113 | return reply.Name, nil 114 | } 115 | -------------------------------------------------------------------------------- /auth.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package x 6 | 7 | /* 8 | auth.go contains functions to facilitate the parsing of .Xauthority files. 9 | 10 | It is largely unmodified from the original XGB package that I forked. 11 | */ 12 | 13 | import ( 14 | "encoding/binary" 15 | "errors" 16 | "io" 17 | "os" 18 | ) 19 | 20 | // readAuthority reads the X authority file for the DISPLAY. 21 | // If hostname == "" or hostname == "localhost", 22 | // then use the system's hostname (as returned by os.Hostname) instead. 23 | func readAuthority(hostname, display string) ( 24 | name string, data []byte, err error) { 25 | 26 | // b is a scratch buffer to use and should be at least 256 bytes long 27 | // (i.e. it should be able to hold a hostname). 28 | b := make([]byte, 256) 29 | 30 | // As per /usr/include/X11/Xauth.h. 31 | const familyLocal = 256 32 | const familyWild = 65535 33 | 34 | if len(hostname) == 0 || hostname == "localhost" { 35 | hostname, err = os.Hostname() 36 | if err != nil { 37 | return "", nil, err 38 | } 39 | } 40 | 41 | fname := os.Getenv("XAUTHORITY") 42 | if len(fname) == 0 { 43 | home := os.Getenv("HOME") 44 | if len(home) == 0 { 45 | err = errors.New("Xauthority not found: $XAUTHORITY, $HOME not set") 46 | return "", nil, err 47 | } 48 | fname = home + "/.Xauthority" 49 | } 50 | 51 | r, err := os.Open(fname) 52 | if err != nil { 53 | return "", nil, err 54 | } 55 | defer r.Close() 56 | 57 | for { 58 | var family uint16 59 | if err := binary.Read(r, binary.BigEndian, &family); err != nil { 60 | return "", nil, err 61 | } 62 | 63 | addr, err := getString(r, b) 64 | if err != nil { 65 | return "", nil, err 66 | } 67 | 68 | disp, err := getString(r, b) 69 | if err != nil { 70 | return "", nil, err 71 | } 72 | 73 | name0, err := getString(r, b) 74 | if err != nil { 75 | return "", nil, err 76 | } 77 | 78 | data0, err := getBytes(r, b) 79 | if err != nil { 80 | return "", nil, err 81 | } 82 | 83 | addrmatch := (family == familyWild) || 84 | (family == familyLocal && addr == hostname) 85 | dispmatch := (disp == "") || (disp == display) 86 | 87 | if addrmatch && dispmatch { 88 | return name0, data0, nil 89 | } 90 | } 91 | } 92 | 93 | func getBytes(r io.Reader, b []byte) ([]byte, error) { 94 | var n uint16 95 | if err := binary.Read(r, binary.BigEndian, &n); err != nil { 96 | return nil, err 97 | } else if n > uint16(len(b)) { 98 | return nil, errors.New("bytes too long for buffer") 99 | } 100 | 101 | if _, err := io.ReadFull(r, b[0:n]); err != nil { 102 | return nil, err 103 | } 104 | return b[0:n], nil 105 | } 106 | 107 | func getString(r io.Reader, b []byte) (string, error) { 108 | b, err := getBytes(r, b) 109 | if err != nil { 110 | return "", err 111 | } 112 | return string(b), nil 113 | } 114 | -------------------------------------------------------------------------------- /client_message_data.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package x 6 | 7 | type ClientMessageData struct { 8 | data []byte 9 | } 10 | 11 | func ClientMessageDataRead(r *Reader, v *ClientMessageData) int { 12 | v.data = r.MustReadBytes(20) 13 | return 20 14 | } 15 | 16 | func writeClientMessageData(w *Writer, v *ClientMessageData) int { 17 | w.WriteNBytes(20, v.data) 18 | return 20 19 | } 20 | 21 | func (v *ClientMessageData) GetData8() []byte { 22 | return v.data 23 | } 24 | 25 | func (v *ClientMessageData) GetData16() []uint16 { 26 | ret := make([]uint16, 10) 27 | idx := 0 28 | for i := 0; i < 20; i += 2 { 29 | ret[idx] = Get16(v.data[i : i+2]) 30 | idx++ 31 | } 32 | return ret 33 | } 34 | 35 | func (v *ClientMessageData) GetData32() []uint32 { 36 | ret := make([]uint32, 5) 37 | idx := 0 38 | for i := 0; i < 20; i += 4 { 39 | ret[idx] = Get32(v.data[i : i+4]) 40 | idx++ 41 | } 42 | return ret 43 | } 44 | 45 | func (v *ClientMessageData) SetData8(p *[20]byte) { 46 | v.data = p[:] 47 | } 48 | 49 | func (v *ClientMessageData) SetData16(p *[10]uint16) { 50 | w := NewWriter() 51 | for i := 0; i < 10; i++ { 52 | w.Write2b(p[i]) 53 | } 54 | v.data = w.Bytes() 55 | } 56 | 57 | func (v *ClientMessageData) SetData32(p *[5]uint32) { 58 | w := NewWriter() 59 | for i := 0; i < 5; i++ { 60 | w.Write4b(p[i]) 61 | } 62 | v.data = w.Bytes() 63 | } 64 | -------------------------------------------------------------------------------- /conn.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package x 6 | 7 | import ( 8 | "bufio" 9 | "errors" 10 | "fmt" 11 | "log" 12 | "net" 13 | "os" 14 | "sync" 15 | "sync/atomic" 16 | ) 17 | 18 | var Logger *log.Logger 19 | var debugEnabled bool 20 | 21 | func init() { 22 | if os.Getenv("DEBUG_X11_CLIENT") == "1" { 23 | debugEnabled = true 24 | Logger = log.New(os.Stderr, "[x] ", log.Lshortfile) 25 | } 26 | } 27 | 28 | func logPrintln(v ...interface{}) { 29 | if debugEnabled { 30 | _ = Logger.Output(2, fmt.Sprintln(v...)) 31 | } 32 | } 33 | func logPrintf(format string, v ...interface{}) { 34 | if debugEnabled { 35 | _ = Logger.Output(2, fmt.Sprintf(format, v...)) 36 | } 37 | } 38 | 39 | type Conn struct { 40 | conn net.Conn 41 | closed int32 42 | bufReader *bufio.Reader 43 | 44 | host string 45 | display string 46 | DisplayNumber int 47 | ScreenNumber int 48 | setup *Setup 49 | 50 | ioMu sync.Mutex 51 | in in 52 | out out 53 | 54 | ext ext 55 | ridAllocator resourceIdAllocator 56 | atomCache *AtomCache 57 | atomCacheMu sync.Mutex 58 | errorCb func(err *Error) 59 | } 60 | 61 | func (c *Conn) GetSetup() *Setup { 62 | return c.setup 63 | } 64 | 65 | func (c *Conn) GetDefaultScreen() *Screen { 66 | return &c.setup.Roots[c.ScreenNumber] 67 | } 68 | 69 | func (c *Conn) isClosed() bool { 70 | return 1 == atomic.LoadInt32(&c.closed) 71 | } 72 | 73 | func (c *Conn) markClosed() { 74 | atomic.StoreInt32(&c.closed, 1) 75 | } 76 | 77 | func (c *Conn) Close() { 78 | if c.isClosed() { 79 | return 80 | } 81 | c.markClosed() 82 | c.conn.Close() 83 | 84 | c.in.eventsCond.Signal() 85 | go func() { 86 | c.ioMu.Lock() 87 | c.in.wakeUpAllReaders() 88 | c.ioMu.Unlock() 89 | }() 90 | } 91 | 92 | var errConnClosed = errors.New("conn closed") 93 | 94 | func (c *Conn) AddEventChan(eventChan chan<- GenericEvent) { 95 | if c.isClosed() || eventChan == nil { 96 | return 97 | } 98 | c.in.addEventChan(eventChan) 99 | } 100 | 101 | func (c *Conn) RemoveEventChan(eventChan chan<- GenericEvent) { 102 | if eventChan == nil { 103 | return 104 | } 105 | c.in.removeEventChan(eventChan) 106 | } 107 | 108 | func (c *Conn) SetErrorCallback(fn func(err *Error)) { 109 | c.errorCb = fn 110 | } 111 | 112 | func (c *Conn) MakeAndAddEventChan(bufSize int) chan GenericEvent { 113 | ch := make(chan GenericEvent, bufSize) 114 | c.AddEventChan(ch) 115 | 116 | return ch 117 | } 118 | -------------------------------------------------------------------------------- /conn_connect.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package x 6 | 7 | import ( 8 | "bufio" 9 | "errors" 10 | "fmt" 11 | "io" 12 | "net" 13 | "os" 14 | "strconv" 15 | "strings" 16 | ) 17 | 18 | func NewConn() (*Conn, error) { 19 | return NewConnDisplay("") 20 | } 21 | 22 | func NewConnDisplay(display string) (*Conn, error) { 23 | c := new(Conn) 24 | err := c.connectDisplay(display) 25 | if err != nil { 26 | return nil, err 27 | } 28 | 29 | c.bufReader = bufio.NewReader(c.conn) 30 | c.in.init(&c.ioMu) 31 | c.out.bw = bufio.NewWriter(c.conn) 32 | c.ridAllocator.init(c.setup.ResourceIdBase, c.setup.ResourceIdMask) 33 | go c.readLoop() 34 | go c.eventSendLoop() 35 | return c, nil 36 | } 37 | 38 | func (c *Conn) connectDisplay(display string) error { 39 | err := c.dial(display) 40 | if err != nil { 41 | return err 42 | } 43 | 44 | return c.postConnect() 45 | } 46 | 47 | // dial initializes the actual net connection with X. 48 | func (c *Conn) dial(display string) error { 49 | if len(display) == 0 { 50 | display = os.Getenv("DISPLAY") 51 | } 52 | 53 | display0 := display 54 | if len(display) == 0 { 55 | return errors.New("empty display string") 56 | } 57 | 58 | colonIdx := strings.LastIndex(display, ":") 59 | if colonIdx < 0 { 60 | return errors.New("bad display string: " + display0) 61 | } 62 | 63 | var protocol, socket string 64 | 65 | if display[0] == '/' { 66 | socket = display[0:colonIdx] 67 | } else { 68 | slashIdx := strings.LastIndex(display, "/") 69 | if slashIdx >= 0 { 70 | protocol = display[0:slashIdx] 71 | c.host = display[slashIdx+1 : colonIdx] 72 | } else { 73 | c.host = display[0:colonIdx] 74 | } 75 | } 76 | 77 | display = display[colonIdx+1:] 78 | if len(display) == 0 { 79 | return errors.New("bad display string: " + display0) 80 | } 81 | 82 | var scr string 83 | dotIdx := strings.LastIndex(display, ".") 84 | if dotIdx < 0 { 85 | c.display = display[0:] 86 | } else { 87 | c.display = display[0:dotIdx] 88 | scr = display[dotIdx+1:] 89 | } 90 | 91 | var err error 92 | c.DisplayNumber, err = strconv.Atoi(c.display) 93 | if err != nil || c.DisplayNumber < 0 { 94 | return errors.New("bad display string: " + display0) 95 | } 96 | 97 | if scr != "" { 98 | c.ScreenNumber, err = strconv.Atoi(scr) 99 | if err != nil { 100 | return errors.New("bad display string: " + display0) 101 | } 102 | } 103 | logPrintf("socket: %q, protocol: %q\n", socket, protocol) 104 | 105 | // Connect to server 106 | if len(socket) != 0 { 107 | c.conn, err = net.Dial("unix", socket+":"+c.display) 108 | } else if len(c.host) != 0 { 109 | if protocol == "" { 110 | protocol = "tcp" 111 | } 112 | logPrintln("dial tcp") 113 | c.conn, err = net.Dial(protocol, 114 | c.host+":"+strconv.Itoa(6000+c.DisplayNumber)) 115 | } else { 116 | logPrintln("dial unix") 117 | c.conn, err = net.Dial("unix", "/tmp/.X11-unix/X"+c.display) 118 | } 119 | 120 | if err != nil { 121 | return errors.New("cannot connect to " + display0 + ": " + err.Error()) 122 | } 123 | return nil 124 | } 125 | 126 | // do the postConnect action after Conn get it's underly net.Conn 127 | func (c *Conn) postConnect() error { 128 | // Get authentication data 129 | authName, authData, err := readAuthority(c.host, c.display) 130 | noAuth := false 131 | if err != nil { 132 | logPrintf("Could not get authority info: %v", err) 133 | logPrintln("Trying connection without authority info...") 134 | authName = "" 135 | authData = []byte{} 136 | noAuth = true 137 | } 138 | 139 | // Assume that the authentication protocol is "MIT-MAGIC-COOKIE-1". 140 | if !noAuth && (authName != "MIT-MAGIC-COOKIE-1" || len(authData) != 16) { 141 | return errors.New("unsupported auth protocol " + authName) 142 | } 143 | 144 | bufLen := 12 + len(authName) + Pad(len(authName)) + len(authData) + Pad(len(authData)) 145 | buf := make([]byte, bufLen) 146 | buf[0] = 0x6c 147 | buf[1] = 0 148 | Put16(buf[2:], 11) 149 | Put16(buf[4:], 0) 150 | Put16(buf[6:], uint16(len(authName))) 151 | Put16(buf[8:], uint16(len(authData))) 152 | Put16(buf[10:], 0) 153 | copy(buf[12:], []byte(authName)) 154 | copy(buf[12+len(authName)+Pad(len(authName)):], authData) 155 | if _, err = c.conn.Write(buf); err != nil { 156 | return err 157 | } 158 | 159 | head := make([]byte, 8) 160 | if _, err = io.ReadFull(c.conn, head[0:8]); err != nil { 161 | return err 162 | } 163 | respType := head[0] 164 | major := Get16(head[2:]) 165 | minor := Get16(head[4:]) 166 | dataLen := Get16(head[6:]) 167 | 168 | if major != 11 || minor != 0 { 169 | return fmt.Errorf("x protocol version mismatch: %d.%d", major, minor) 170 | } 171 | 172 | buf = make([]byte, 8+dataLen*4) 173 | copy(buf, head) 174 | if _, err = io.ReadFull(c.conn, buf[8:]); err != nil { 175 | return err 176 | } 177 | 178 | if respType == ResponseTypeError { 179 | reasonLen := head[1] 180 | reason := buf[8 : 8+reasonLen] 181 | return fmt.Errorf("x protocol authentication refused: %s", 182 | string(reason)) 183 | } 184 | 185 | var setup Setup 186 | r := NewReaderFromData(buf) 187 | err = readSetup(r, &setup) 188 | if err != nil { 189 | return err 190 | } 191 | c.setup = &setup 192 | 193 | /* Make sure requested screen number is in bounds for this server */ 194 | if c.ScreenNumber >= len(setup.Roots) { 195 | return errors.New("invalid screen") 196 | } 197 | 198 | return nil 199 | } 200 | -------------------------------------------------------------------------------- /conn_out.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package x 6 | 7 | import ( 8 | "bufio" 9 | "errors" 10 | "io" 11 | "math" 12 | ) 13 | 14 | func (c *Conn) Flush() (err error) { 15 | c.ioMu.Lock() 16 | err = c.out.flushTo(c.out.request) 17 | c.ioMu.Unlock() 18 | if err != nil { 19 | c.Close() 20 | } 21 | return 22 | } 23 | 24 | func (c *Conn) sendSync() { 25 | header := RequestHeader{ 26 | Opcode: GetInputFocusOpcode, 27 | Length: 4, 28 | } 29 | logPrintln("sendSync") 30 | c.sendRequest(false, 0, RequestDiscardReply, 31 | header.toBytes(), nil) 32 | } 33 | 34 | func (c *Conn) SendSync() { 35 | c.ioMu.Lock() 36 | c.sendSync() 37 | c.ioMu.Unlock() 38 | } 39 | 40 | // sequence number 41 | type SeqNum uint64 42 | 43 | const ( 44 | seqNumConnClosed SeqNum = 0 45 | seqNumExtNotPresent SeqNum = math.MaxUint64 - iota 46 | seqNumQueryExtErr 47 | ) 48 | 49 | var errExtNotPresent = errors.New("extension not present") 50 | var errQueryExtErr = errors.New("query extension error") 51 | 52 | func (n SeqNum) err() error { 53 | switch n { 54 | case seqNumConnClosed: 55 | return errConnClosed 56 | case seqNumExtNotPresent: 57 | return errExtNotPresent 58 | case seqNumQueryExtErr: 59 | return errQueryExtErr 60 | default: 61 | return nil 62 | } 63 | } 64 | 65 | type out struct { 66 | request SeqNum 67 | requestWritten SeqNum 68 | bw *bufio.Writer 69 | } 70 | 71 | func (o *out) flushTo(request SeqNum) error { 72 | if !(request <= o.request) { 73 | panic("assert request < o.request failed") 74 | } 75 | 76 | if o.requestWritten >= request { 77 | return nil 78 | } 79 | 80 | logPrintln("flushTo", request) 81 | err := o.bw.Flush() 82 | if err != nil { 83 | return err 84 | } 85 | o.requestWritten = o.request 86 | return nil 87 | } 88 | 89 | func (c *Conn) writeRequest(header []byte, body RequestBody) error { 90 | _, err := c.out.bw.Write(header) 91 | if err != nil { 92 | return err 93 | } 94 | var emptyBuf [3]byte 95 | for _, data := range body { 96 | _, err = c.out.bw.Write(data) 97 | if err != nil { 98 | return err 99 | } 100 | 101 | pad := Pad(len(data)) 102 | if pad > 0 { 103 | _, err = c.out.bw.Write(emptyBuf[:pad]) 104 | if err != nil { 105 | return err 106 | } 107 | } 108 | } 109 | return nil 110 | } 111 | 112 | func (c *Conn) sendRequest(noReply bool, workaround uint, flags uint, header []byte, body RequestBody) { 113 | if c.isClosed() { 114 | return 115 | } 116 | c.out.request++ 117 | if !noReply { 118 | // has reply 119 | c.in.requestExpected = c.out.request 120 | } 121 | logPrintln("sendRequest seq:", c.out.request) 122 | 123 | if workaround != 0 || flags != 0 { 124 | c.in.expectReply(c.out.request, workaround, flags) 125 | } 126 | 127 | err := c.writeRequest(header, body) 128 | if err != nil { 129 | logPrintln("write error:", err) 130 | c.Close() 131 | return 132 | } 133 | 134 | if c.out.bw.Buffered() == 0 { 135 | // write all the data of request to c.conn 136 | c.out.requestWritten = c.out.request 137 | } 138 | } 139 | 140 | type ProtocolRequest struct { 141 | Ext *Extension 142 | NoReply bool 143 | Header RequestHeader 144 | Body RequestBody 145 | } 146 | 147 | // return sequence id 148 | func (c *Conn) SendRequest(flags uint, req *ProtocolRequest) SeqNum { 149 | if c.isClosed() { 150 | return seqNumConnClosed 151 | } 152 | 153 | // process data auto field 154 | // set the major opcode, and the minor opcode for extensions 155 | if req.Ext != nil { 156 | extension := c.GetExtensionData(req.Ext) 157 | if extension == nil { 158 | return seqNumQueryExtErr 159 | } 160 | if !extension.Present { 161 | return seqNumExtNotPresent 162 | } 163 | 164 | req.Header.Opcode = extension.MajorOpcode 165 | } 166 | 167 | var requestLen uint64 168 | requestLen = 4 169 | for _, data := range req.Body { 170 | requestLen += uint64(len(data)) 171 | requestLen += uint64(Pad(len(data))) 172 | } 173 | req.Header.Length = requestLen 174 | 175 | header := req.Header.toBytes() 176 | 177 | c.ioMu.Lock() 178 | c.sendRequest(req.NoReply, 0, flags, header, req.Body) 179 | request := c.out.request 180 | c.ioMu.Unlock() 181 | return request 182 | } 183 | 184 | type RequestHeader struct { 185 | Opcode uint8 // major opcode 186 | Data uint8 // data or minor opcode 187 | Length uint64 // unit is byte 188 | } 189 | 190 | func (rh RequestHeader) toBytes() []byte { 191 | b := make([]byte, 4) 192 | b[0] = rh.Opcode 193 | b[1] = rh.Data 194 | 195 | if rh.Length&3 != 0 { 196 | panic("length is not a multiple of 4") 197 | } 198 | 199 | length := uint16(rh.Length) 200 | length >>= 2 201 | b[2] = byte(length) 202 | b[3] = byte(length >> 8) 203 | return b 204 | } 205 | 206 | type FixedSizeBuf struct { 207 | data []byte 208 | offset int 209 | } 210 | 211 | func (b *FixedSizeBuf) Write1b(v uint8) *FixedSizeBuf { 212 | b.data[b.offset] = v 213 | b.offset++ 214 | return b 215 | } 216 | 217 | // byte order: least significant byte first 218 | 219 | func (b *FixedSizeBuf) Write2b(v uint16) *FixedSizeBuf { 220 | b.data[b.offset] = byte(v) 221 | b.data[b.offset+1] = byte(v >> 8) 222 | b.offset += 2 223 | return b 224 | } 225 | 226 | func (b *FixedSizeBuf) Write4b(v uint32) *FixedSizeBuf { 227 | b.data[b.offset] = byte(v) 228 | b.data[b.offset+1] = byte(v >> 8) 229 | b.data[b.offset+2] = byte(v >> 16) 230 | b.data[b.offset+3] = byte(v >> 24) 231 | b.offset += 4 232 | return b 233 | } 234 | 235 | func (b *FixedSizeBuf) Write8b(v uint64) *FixedSizeBuf { 236 | b.data[b.offset] = byte(v) 237 | b.data[b.offset+1] = byte(v >> 8) 238 | b.data[b.offset+2] = byte(v >> 16) 239 | b.data[b.offset+3] = byte(v >> 24) 240 | b.data[b.offset+4] = byte(v >> 32) 241 | b.data[b.offset+5] = byte(v >> 40) 242 | b.data[b.offset+6] = byte(v >> 48) 243 | b.data[b.offset+7] = byte(v >> 56) 244 | b.offset += 8 245 | return b 246 | } 247 | 248 | func (b *FixedSizeBuf) WritePad(n int) *FixedSizeBuf { 249 | b.offset += n 250 | return b 251 | } 252 | 253 | func (b *FixedSizeBuf) WriteString(s string) *FixedSizeBuf { 254 | n := copy(b.data[b.offset:], s) 255 | b.offset += n 256 | if n != len(s) { 257 | panic(io.ErrShortWrite) 258 | } 259 | return b 260 | } 261 | 262 | func (b *FixedSizeBuf) WriteBytes(p []byte) *FixedSizeBuf { 263 | n := copy(b.data[b.offset:], p) 264 | b.offset += n 265 | if n != len(p) { 266 | panic(io.ErrShortWrite) 267 | } 268 | return b 269 | } 270 | 271 | func (b *FixedSizeBuf) WriteBool(v bool) *FixedSizeBuf { 272 | return b.Write1b(BoolToUint8(v)) 273 | } 274 | 275 | func (b *FixedSizeBuf) End() { 276 | if len(b.data) != b.offset { 277 | panic("not end") 278 | } 279 | } 280 | 281 | func (b *FixedSizeBuf) Bytes() []byte { 282 | return b.data 283 | } 284 | 285 | func NewFixedSizeBuf(size int) *FixedSizeBuf { 286 | return &FixedSizeBuf{ 287 | data: make([]byte, size), 288 | } 289 | } 290 | 291 | type RequestBody [][]byte 292 | 293 | func (rb *RequestBody) AddBlock(n int) *FixedSizeBuf { 294 | b := NewFixedSizeBuf(n * 4) 295 | *rb = append(*rb, b.data) 296 | return b 297 | } 298 | 299 | func (rb *RequestBody) AddBytes(data []byte) { 300 | *rb = append(*rb, data) 301 | } 302 | -------------------------------------------------------------------------------- /const.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package x 6 | 7 | const ( 8 | // None is the universal null resource or null atom parameter value for many core X requests 9 | None = 0 10 | 11 | // CurrentTime can be used in most requests that take an Timestamp 12 | CurrentTime = 0 13 | 14 | // NoSymbol fills in unused entries in Keysym tables 15 | NoSymbol = 0 16 | 17 | // CopyFromParent can be used for many CreateWindow parameters */ 18 | CopyFromParent = 0 19 | 20 | True = 1 21 | False = 0 22 | ) 23 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | golang-github-linuxdeepin-go-x11-client (1.0.2) unstable; urgency=medium 2 | 3 | * Add GrabCheckedV2 4 | 5 | -- quezhiyong Fri, 12 Apr 2024 13:17:30 +0800 6 | 7 | golang-github-linuxdeepin-go-x11-client (1.0.1) unstable; urgency=medium 8 | 9 | * modify changelog for V23 beta 10 | 11 | -- linxin Wed, 29 Mar 2023 11:46:38 +0800 12 | 13 | golang-github-linuxdeepin-go-x11-client (1.0.0.0) unstable; urgency=medium 14 | 15 | * release 1.0.0.0 16 | 17 | -- Tue, 14 June 2022 17:11:13 +0800 18 | 19 | golang-github-linuxdeepin-go-x11-client (0.0.3) unstable; urgency=medium 20 | 21 | * adapt license and copyright 22 | 23 | -- dengbo Wed, 14 Sep 2022 16:27:01 +0000 24 | 25 | golang-github-linuxdeepin-go-x11-client (0.0.2-1) unstable; urgency=medium 26 | 27 | * update 28 | 29 | -- Deepin Packages Builder Fri, 15 Dec 2017 17:12:00 +0800 30 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 10 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: golang-github-linuxdeepin-go-x11-client 2 | Section: devel 3 | Priority: extra 4 | Maintainer: Deepin Packages Builder 5 | Build-Depends: debhelper (>= 10), 6 | dh-golang, 7 | golang-any, 8 | golang-gopkg-check.v1-dev, 9 | golang-golang-x-text-dev (>=0.0~git20161013), 10 | golang-github-stretchr-testify-dev (>=1.1.4) 11 | Standards-Version: 4.0.0 12 | Homepage: https://github.com/linuxdeepin/go-x11-client 13 | XS-Go-Import-Path: github.com/linuxdeepin/go-x11-client 14 | Testsuite: autopkgtest-pkg-go 15 | 16 | Package: golang-github-linuxdeepin-go-x11-client-dev 17 | Architecture: all 18 | Depends: ${shlibs:Depends}, 19 | ${misc:Depends}, 20 | golang-github-gavv-monotime-dev, 21 | golang-gopkg-check.v1-dev 22 | Description: deepin go x11 client 23 | mirrored from https://cr.deepin.io/#/admin/projects/go-x11-client 24 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: go-x11-client 3 | 4 | Files: * 5 | Copyright: 2017 Deepin Technology Co., Ltd. 6 | License: GPL-3+ 7 | This package is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 3 of the License, or 10 | (at your option) any later version. 11 | . 12 | This package is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | . 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see 19 | . 20 | On Debian systems, the complete text of the GNU General 21 | Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". 22 | -------------------------------------------------------------------------------- /debian/gbp.conf: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | pristine-tar = True 3 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | export GOCACHE := /tmp/gocache 4 | export DH_GOLANG_EXCLUDES := tools/gen util/tool/gen-keysymdef 5 | 6 | ifeq ($(DEB_BUILD_ARCH),sw_64) 7 | %: 8 | dh $@ 9 | else 10 | %: 11 | dh $@ --buildsystem=golang --with=golang 12 | endif 13 | 14 | 15 | override_dh_auto_clean: 16 | dh_auto_clean -- 17 | rm -fr obj-x86_64-linux-gnu 18 | 19 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /debian/watch: -------------------------------------------------------------------------------- 1 | version=3 2 | opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/golang-github-linuxdeepin-go-x11-client-\$1\.tar\.gz/,\ 3 | uversionmangle=s/(\d)[_\.\-\+]?(RC|rc|pre|dev|beta|alpha)[.]?(\d*)$/\$1~\$2\$3/ \ 4 | https://github.com/linuxdeepin/go-x11-client/tags .*/v?(\d\S*)\.tar\.gz 5 | -------------------------------------------------------------------------------- /error.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package x 6 | 7 | import "fmt" 8 | 9 | type Error struct { 10 | conn *Conn 11 | Code uint8 // ErrorCode 12 | Sequence uint16 // Sequence number 13 | ResourceID uint32 // Resource ID for requests with side effects only 14 | MinorCode uint16 // Minor opcode of the failed request 15 | MajorCode uint8 // Major opcode of the failed request 16 | } 17 | 18 | func (err *Error) Error() string { 19 | var errDesc string 20 | var errName string 21 | if 1 <= err.Code && err.Code <= 127 { 22 | // core error code in range [1,127] 23 | errName = errorCodeNameMap[err.Code] 24 | } else { 25 | // is ext error 26 | errName = err.conn.ext.getExtErrName(err.Code) 27 | } 28 | if errName != "" { 29 | errDesc = " (" + errName + ")" 30 | } 31 | 32 | var majorCodeDesc, minorCodeDesc string 33 | 34 | if 1 <= err.MajorCode && err.MajorCode <= 127 { 35 | // is core request 36 | reqName := requestOpcodeNameMap[uint(err.MajorCode)] 37 | if reqName != "" { 38 | majorCodeDesc = " (" + reqName + ")" 39 | } 40 | } else { 41 | // is ext request 42 | ext := err.conn.ext.getExtByMajorOpcode(err.MajorCode) 43 | if ext != nil { 44 | reqName := ext.reqOpcodeNameMap[uint(err.MinorCode)] 45 | if reqName != "" { 46 | minorCodeDesc = " (" + reqName + ")" 47 | } 48 | majorCodeDesc = " (" + ext.name + ")" 49 | } 50 | } 51 | 52 | return fmt.Sprintf("x.Error: %d%s, sequence: %d, resource id: %d,"+ 53 | " major code: %d%s, minor code: %d%s", 54 | err.Code, errDesc, err.Sequence, err.ResourceID, 55 | err.MajorCode, majorCodeDesc, 56 | err.MinorCode, minorCodeDesc) 57 | } 58 | 59 | func newError(data []byte) *Error { 60 | var v Error 61 | 62 | responseType := data[0] 63 | if responseType != ResponseTypeError { 64 | panic("not error") 65 | } 66 | b := 1 67 | 68 | v.Code = data[b] 69 | b += 1 70 | 71 | v.Sequence = Get16(data[b:]) 72 | b += 2 73 | 74 | v.ResourceID = Get32(data[b:]) 75 | b += 4 76 | 77 | v.MinorCode = Get16(data[b:]) 78 | b += 2 79 | 80 | v.MajorCode = data[b] 81 | 82 | return &v 83 | } 84 | 85 | func (c *Conn) NewError(data []byte) *Error { 86 | err := newError(data) 87 | err.conn = c 88 | return err 89 | } 90 | -------------------------------------------------------------------------------- /event.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package x 6 | 7 | import ( 8 | "fmt" 9 | ) 10 | 11 | type GenericEvent []byte 12 | 13 | func (ge GenericEvent) GetEventCode() uint8 { 14 | return ge[0] &^ 0x80 15 | } 16 | 17 | func (ge GenericEvent) Real() bool { 18 | return ge[0]&0x80 == 0 19 | } 20 | 21 | func (ge GenericEvent) String() string { 22 | return fmt.Sprintf("GenericEvent{ EventCode: %d, Real: %v }", ge.GetEventCode(), ge.Real()) 23 | } 24 | -------------------------------------------------------------------------------- /ext/bigrequests/auto.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package bigrequests 6 | 7 | import x "github.com/linuxdeepin/go-x11-client" 8 | 9 | // _ns.ext_name: BigRequests 10 | const MajorVersion = 0 11 | const MinorVersion = 0 12 | 13 | var _ext *x.Extension 14 | 15 | func Ext() *x.Extension { 16 | return _ext 17 | } 18 | 19 | const EnableOpcode = 0 20 | 21 | type EnableCookie x.SeqNum 22 | 23 | var requestOpcodeNameMap = map[uint]string{ 24 | EnableOpcode: "Enable", 25 | } 26 | 27 | func init() { 28 | _ext = x.NewExtension("BIG-REQUESTS", 0, nil, requestOpcodeNameMap) 29 | } 30 | -------------------------------------------------------------------------------- /ext/bigrequests/bigreq.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package bigrequests 6 | 7 | import "github.com/linuxdeepin/go-x11-client" 8 | 9 | // #WREQ 10 | func encodeEnable() (b x.RequestBody) { 11 | return 12 | } 13 | 14 | type EnableReply struct { 15 | MaximumRequestLength uint32 16 | } 17 | 18 | func readEnableReply(r *x.Reader, v *EnableReply) error { 19 | if !r.RemainAtLeast4b(3) { 20 | return x.ErrDataLenShort 21 | } 22 | 23 | r.ReadPad(8) 24 | 25 | v.MaximumRequestLength = r.Read4b() // 3 26 | 27 | return nil 28 | } 29 | -------------------------------------------------------------------------------- /ext/bigrequests/bigreq_req_auto.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package bigrequests 6 | 7 | import x "github.com/linuxdeepin/go-x11-client" 8 | 9 | func Enable(conn *x.Conn) EnableCookie { 10 | body := encodeEnable() 11 | req := &x.ProtocolRequest{ 12 | Ext: _ext, 13 | Header: x.RequestHeader{ 14 | Data: EnableOpcode, 15 | }, 16 | Body: body, 17 | } 18 | seq := conn.SendRequest(x.RequestChecked, req) 19 | return EnableCookie(seq) 20 | } 21 | 22 | func (cookie EnableCookie) Reply(conn *x.Conn) (*EnableReply, error) { 23 | replyBuf, err := conn.WaitForReply(x.SeqNum(cookie)) 24 | if err != nil { 25 | return nil, err 26 | } 27 | r := x.NewReaderFromData(replyBuf) 28 | var reply EnableReply 29 | err = readEnableReply(r, &reply) 30 | if err != nil { 31 | return nil, err 32 | } 33 | return &reply, nil 34 | } 35 | -------------------------------------------------------------------------------- /ext/composite/auto.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package composite 6 | 7 | import x "github.com/linuxdeepin/go-x11-client" 8 | 9 | // _ns.ext_name: Composite 10 | const MajorVersion = 0 11 | const MinorVersion = 4 12 | 13 | var _ext *x.Extension 14 | 15 | func Ext() *x.Extension { 16 | return _ext 17 | } 18 | 19 | // enum Redirect 20 | const ( 21 | RedirectAutomatic = 0 22 | RedirectManual = 1 23 | ) 24 | 25 | const QueryVersionOpcode = 0 26 | 27 | type QueryVersionCookie x.SeqNum 28 | 29 | const RedirectWindowOpcode = 1 30 | const RedirectSubwindowsOpcode = 2 31 | const UnredirectWindowOpcode = 3 32 | const UnredirectSubwindowsOpcode = 4 33 | const CreateRegionFromBorderClipOpcode = 5 34 | const NameWindowPixmapOpcode = 6 35 | const GetOverlayWindowOpcode = 7 36 | 37 | type GetOverlayWindowCookie x.SeqNum 38 | 39 | const ReleaseOverlayWindowOpcode = 8 40 | 41 | var requestOpcodeNameMap = map[uint]string{ 42 | QueryVersionOpcode: "QueryVersion", 43 | RedirectWindowOpcode: "RedirectWindow", 44 | RedirectSubwindowsOpcode: "RedirectSubwindows", 45 | UnredirectWindowOpcode: "UnredirectWindow", 46 | UnredirectSubwindowsOpcode: "UnredirectSubwindows", 47 | CreateRegionFromBorderClipOpcode: "CreateRegionFromBorderClip", 48 | NameWindowPixmapOpcode: "NameWindowPixmap", 49 | GetOverlayWindowOpcode: "GetOverlayWindow", 50 | ReleaseOverlayWindowOpcode: "ReleaseOverlayWindow", 51 | } 52 | 53 | func init() { 54 | _ext = x.NewExtension("Composite", 0, nil, requestOpcodeNameMap) 55 | } 56 | -------------------------------------------------------------------------------- /ext/composite/composite.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package composite 6 | 7 | import "github.com/linuxdeepin/go-x11-client" 8 | 9 | // #WREQ 10 | func encodeQueryVersion(majorVersion, minorVersion uint32) (b x.RequestBody) { 11 | b.AddBlock(2). 12 | Write4b(majorVersion). 13 | Write4b(minorVersion). 14 | End() 15 | return 16 | } 17 | 18 | type QueryVersionReply struct { 19 | MajorVersion uint32 20 | MinorVersion uint32 21 | } 22 | 23 | func readQueryVersionReply(r *x.Reader, v *QueryVersionReply) error { 24 | if !r.RemainAtLeast4b(4) { 25 | return x.ErrDataLenShort 26 | } 27 | 28 | r.ReadPad(8) 29 | 30 | v.MajorVersion = r.Read4b() 31 | 32 | v.MinorVersion = r.Read4b() // 4 33 | 34 | return nil 35 | } 36 | 37 | // #WREQ 38 | func encodeRedirectWindow(window x.Window, update uint8) (b x.RequestBody) { 39 | b.AddBlock(2). 40 | Write4b(uint32(window)). 41 | Write1b(update). 42 | WritePad(3). 43 | End() 44 | return 45 | } 46 | 47 | // #WREQ 48 | func encodeRedirectSubwindows(window x.Window, update uint8) (b x.RequestBody) { 49 | b.AddBlock(2). 50 | Write4b(uint32(window)). 51 | Write1b(update). 52 | WritePad(3). 53 | End() 54 | return 55 | } 56 | 57 | // #WREQ 58 | func encodeUnredirectWindow(window x.Window) (b x.RequestBody) { 59 | b.AddBlock(1). 60 | Write4b(uint32(window)). 61 | End() 62 | return 63 | } 64 | 65 | // #WREQ 66 | func encodeUnredirectSubwindows(window x.Window) (b x.RequestBody) { 67 | b.AddBlock(1). 68 | Write4b(uint32(window)). 69 | End() 70 | return 71 | } 72 | 73 | // #WREQ 74 | func encodeNameWindowPixmap(window x.Window, pixmap x.Pixmap) (b x.RequestBody) { 75 | b.AddBlock(2). 76 | Write4b(uint32(window)). 77 | Write4b(uint32(pixmap)). 78 | End() 79 | return 80 | } 81 | -------------------------------------------------------------------------------- /ext/composite/composite_req_auto.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package composite 6 | 7 | import x "github.com/linuxdeepin/go-x11-client" 8 | 9 | func QueryVersion(conn *x.Conn, majorVersion, minorVersion uint32) QueryVersionCookie { 10 | body := encodeQueryVersion(majorVersion, minorVersion) 11 | req := &x.ProtocolRequest{ 12 | Ext: _ext, 13 | Header: x.RequestHeader{ 14 | Data: QueryVersionOpcode, 15 | }, 16 | Body: body, 17 | } 18 | seq := conn.SendRequest(x.RequestChecked, req) 19 | return QueryVersionCookie(seq) 20 | } 21 | 22 | func (cookie QueryVersionCookie) Reply(conn *x.Conn) (*QueryVersionReply, error) { 23 | replyBuf, err := conn.WaitForReply(x.SeqNum(cookie)) 24 | if err != nil { 25 | return nil, err 26 | } 27 | r := x.NewReaderFromData(replyBuf) 28 | var reply QueryVersionReply 29 | err = readQueryVersionReply(r, &reply) 30 | if err != nil { 31 | return nil, err 32 | } 33 | return &reply, nil 34 | } 35 | 36 | func RedirectWindow(conn *x.Conn, window x.Window, update uint8) { 37 | body := encodeRedirectWindow(window, update) 38 | req := &x.ProtocolRequest{ 39 | Ext: _ext, 40 | NoReply: true, 41 | Header: x.RequestHeader{ 42 | Data: RedirectWindowOpcode, 43 | }, 44 | Body: body, 45 | } 46 | conn.SendRequest(0, req) 47 | } 48 | 49 | func RedirectWindowChecked(conn *x.Conn, window x.Window, update uint8) x.VoidCookie { 50 | body := encodeRedirectWindow(window, update) 51 | req := &x.ProtocolRequest{ 52 | Ext: _ext, 53 | NoReply: true, 54 | Header: x.RequestHeader{ 55 | Data: RedirectWindowOpcode, 56 | }, 57 | Body: body, 58 | } 59 | seq := conn.SendRequest(x.RequestChecked, req) 60 | return x.VoidCookie(seq) 61 | } 62 | 63 | func RedirectSubwindows(conn *x.Conn, window x.Window, update uint8) { 64 | body := encodeRedirectSubwindows(window, update) 65 | req := &x.ProtocolRequest{ 66 | Ext: _ext, 67 | NoReply: true, 68 | Header: x.RequestHeader{ 69 | Data: RedirectSubwindowsOpcode, 70 | }, 71 | Body: body, 72 | } 73 | conn.SendRequest(0, req) 74 | } 75 | 76 | func RedirectSubwindowsChecked(conn *x.Conn, window x.Window, update uint8) x.VoidCookie { 77 | body := encodeRedirectSubwindows(window, update) 78 | req := &x.ProtocolRequest{ 79 | Ext: _ext, 80 | NoReply: true, 81 | Header: x.RequestHeader{ 82 | Data: RedirectSubwindowsOpcode, 83 | }, 84 | Body: body, 85 | } 86 | seq := conn.SendRequest(x.RequestChecked, req) 87 | return x.VoidCookie(seq) 88 | } 89 | 90 | func UnredirectWindow(conn *x.Conn, window x.Window) { 91 | body := encodeUnredirectWindow(window) 92 | req := &x.ProtocolRequest{ 93 | Ext: _ext, 94 | NoReply: true, 95 | Header: x.RequestHeader{ 96 | Data: UnredirectWindowOpcode, 97 | }, 98 | Body: body, 99 | } 100 | conn.SendRequest(0, req) 101 | } 102 | 103 | func UnredirectWindowChecked(conn *x.Conn, window x.Window) x.VoidCookie { 104 | body := encodeUnredirectWindow(window) 105 | req := &x.ProtocolRequest{ 106 | Ext: _ext, 107 | NoReply: true, 108 | Header: x.RequestHeader{ 109 | Data: UnredirectWindowOpcode, 110 | }, 111 | Body: body, 112 | } 113 | seq := conn.SendRequest(x.RequestChecked, req) 114 | return x.VoidCookie(seq) 115 | } 116 | 117 | func UnredirectSubwindows(conn *x.Conn, window x.Window) { 118 | body := encodeUnredirectSubwindows(window) 119 | req := &x.ProtocolRequest{ 120 | Ext: _ext, 121 | NoReply: true, 122 | Header: x.RequestHeader{ 123 | Data: UnredirectSubwindowsOpcode, 124 | }, 125 | Body: body, 126 | } 127 | conn.SendRequest(0, req) 128 | } 129 | 130 | func UnredirectSubwindowsChecked(conn *x.Conn, window x.Window) x.VoidCookie { 131 | body := encodeUnredirectSubwindows(window) 132 | req := &x.ProtocolRequest{ 133 | Ext: _ext, 134 | NoReply: true, 135 | Header: x.RequestHeader{ 136 | Data: UnredirectSubwindowsOpcode, 137 | }, 138 | Body: body, 139 | } 140 | seq := conn.SendRequest(x.RequestChecked, req) 141 | return x.VoidCookie(seq) 142 | } 143 | 144 | func NameWindowPixmap(conn *x.Conn, window x.Window, pixmap x.Pixmap) { 145 | body := encodeNameWindowPixmap(window, pixmap) 146 | req := &x.ProtocolRequest{ 147 | Ext: _ext, 148 | NoReply: true, 149 | Header: x.RequestHeader{ 150 | Data: NameWindowPixmapOpcode, 151 | }, 152 | Body: body, 153 | } 154 | conn.SendRequest(0, req) 155 | } 156 | 157 | func NameWindowPixmapChecked(conn *x.Conn, window x.Window, pixmap x.Pixmap) x.VoidCookie { 158 | body := encodeNameWindowPixmap(window, pixmap) 159 | req := &x.ProtocolRequest{ 160 | Ext: _ext, 161 | NoReply: true, 162 | Header: x.RequestHeader{ 163 | Data: NameWindowPixmapOpcode, 164 | }, 165 | Body: body, 166 | } 167 | seq := conn.SendRequest(x.RequestChecked, req) 168 | return x.VoidCookie(seq) 169 | } 170 | -------------------------------------------------------------------------------- /ext/damage/auto.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package damage 6 | 7 | import x "github.com/linuxdeepin/go-x11-client" 8 | 9 | // _ns.ext_name: Damage 10 | const MajorVersion = 1 11 | const MinorVersion = 1 12 | 13 | var _ext *x.Extension 14 | 15 | func Ext() *x.Extension { 16 | return _ext 17 | } 18 | 19 | // simple ('xcb', 'Damage', 'DAMAGE') 20 | type Damage uint32 21 | 22 | // enum ReportLevel 23 | const ( 24 | ReportLevelRawRectangles = 0 25 | ReportLevelDeltaRectangles = 1 26 | ReportLevelBoundingBox = 2 27 | ReportLevelNonEmpty = 3 28 | ) 29 | 30 | const BadDamageErrorCode = 0 31 | const QueryVersionOpcode = 0 32 | 33 | type QueryVersionCookie x.SeqNum 34 | 35 | const CreateOpcode = 1 36 | const DestroyOpcode = 2 37 | const SubtractOpcode = 3 38 | const AddOpcode = 4 39 | const NotifyEventCode = 0 40 | 41 | func NewNotifyEvent(data []byte) (*NotifyEvent, error) { 42 | var ev NotifyEvent 43 | r := x.NewReaderFromData(data) 44 | err := readNotifyEvent(r, &ev) 45 | if err != nil { 46 | return nil, err 47 | } 48 | return &ev, nil 49 | } 50 | 51 | var errorCodeNameMap = map[uint8]string{ 52 | BadDamageErrorCode: "BadDamage", 53 | } 54 | var requestOpcodeNameMap = map[uint]string{ 55 | QueryVersionOpcode: "QueryVersion", 56 | CreateOpcode: "Create", 57 | DestroyOpcode: "Destroy", 58 | SubtractOpcode: "Subtract", 59 | AddOpcode: "Add", 60 | } 61 | 62 | func init() { 63 | _ext = x.NewExtension("DAMAGE", 0, errorCodeNameMap, requestOpcodeNameMap) 64 | } 65 | -------------------------------------------------------------------------------- /ext/damage/damage.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package damage 6 | 7 | import ( 8 | x "github.com/linuxdeepin/go-x11-client" 9 | ) 10 | 11 | type NotifyEvent struct { 12 | Level uint8 13 | Sequence uint16 14 | Drawable x.Drawable 15 | Damage Damage 16 | Timestamp x.Timestamp 17 | Area x.Rectangle 18 | Geometry x.Rectangle 19 | } 20 | 21 | func readNotifyEvent(r *x.Reader, v *NotifyEvent) error { 22 | if !r.RemainAtLeast4b(8) { 23 | return x.ErrDataLenShort 24 | } 25 | v.Level, v.Sequence = r.ReadEventHeader() 26 | 27 | v.Drawable = x.Drawable(r.Read4b()) 28 | 29 | v.Damage = Damage(r.Read4b()) 30 | 31 | v.Timestamp = x.Timestamp(r.Read4b()) // 4 32 | 33 | v.Area = x.ReadRectangle(r) // 6 34 | 35 | v.Geometry = x.ReadRectangle(r) // 8 36 | 37 | return nil 38 | } 39 | 40 | // #WREQ 41 | func encodeQueryVersion(majorVersion, minorVersion uint32) (b x.RequestBody) { 42 | b.AddBlock(2). 43 | Write4b(majorVersion). 44 | Write4b(minorVersion). 45 | End() 46 | return 47 | } 48 | 49 | type QueryVersionReply struct { 50 | MajorVersion uint32 51 | MinorVersion uint32 52 | } 53 | 54 | func readQueryVersionReply(r *x.Reader, v *QueryVersionReply) error { 55 | if !r.RemainAtLeast4b(4) { 56 | return x.ErrDataLenShort 57 | } 58 | r.ReadPad(8) 59 | 60 | v.MajorVersion = r.Read4b() 61 | 62 | v.MinorVersion = r.Read4b() // 4 63 | 64 | return nil 65 | } 66 | 67 | // #WREQ 68 | func encodeCreate(damage Damage, drawable x.Drawable, level uint8) (b x.RequestBody) { 69 | b.AddBlock(3). 70 | Write4b(uint32(damage)). 71 | Write4b(uint32(drawable)). 72 | Write1b(level). 73 | WritePad(3). 74 | End() 75 | return 76 | } 77 | 78 | // #WREQ 79 | func encodeDestroy(damage Damage) (b x.RequestBody) { 80 | b.AddBlock(1). 81 | Write4b(uint32(damage)). 82 | End() 83 | return 84 | } 85 | 86 | // #WREQ 87 | //func Subtract() { 88 | // 89 | //} 90 | -------------------------------------------------------------------------------- /ext/damage/damage_req_auto.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package damage 6 | 7 | import x "github.com/linuxdeepin/go-x11-client" 8 | 9 | func QueryVersion(conn *x.Conn, majorVersion, minorVersion uint32) QueryVersionCookie { 10 | body := encodeQueryVersion(majorVersion, minorVersion) 11 | req := &x.ProtocolRequest{ 12 | Ext: _ext, 13 | Header: x.RequestHeader{ 14 | Data: QueryVersionOpcode, 15 | }, 16 | Body: body, 17 | } 18 | seq := conn.SendRequest(x.RequestChecked, req) 19 | return QueryVersionCookie(seq) 20 | } 21 | 22 | func (cookie QueryVersionCookie) Reply(conn *x.Conn) (*QueryVersionReply, error) { 23 | replyBuf, err := conn.WaitForReply(x.SeqNum(cookie)) 24 | if err != nil { 25 | return nil, err 26 | } 27 | r := x.NewReaderFromData(replyBuf) 28 | var reply QueryVersionReply 29 | err = readQueryVersionReply(r, &reply) 30 | if err != nil { 31 | return nil, err 32 | } 33 | return &reply, nil 34 | } 35 | 36 | func Create(conn *x.Conn, damage Damage, drawable x.Drawable, level uint8) { 37 | body := encodeCreate(damage, drawable, level) 38 | req := &x.ProtocolRequest{ 39 | Ext: _ext, 40 | NoReply: true, 41 | Header: x.RequestHeader{ 42 | Data: CreateOpcode, 43 | }, 44 | Body: body, 45 | } 46 | conn.SendRequest(0, req) 47 | } 48 | 49 | func CreateChecked(conn *x.Conn, damage Damage, drawable x.Drawable, level uint8) x.VoidCookie { 50 | body := encodeCreate(damage, drawable, level) 51 | req := &x.ProtocolRequest{ 52 | Ext: _ext, 53 | NoReply: true, 54 | Header: x.RequestHeader{ 55 | Data: CreateOpcode, 56 | }, 57 | Body: body, 58 | } 59 | seq := conn.SendRequest(x.RequestChecked, req) 60 | return x.VoidCookie(seq) 61 | } 62 | 63 | func Destroy(conn *x.Conn, damage Damage) { 64 | body := encodeDestroy(damage) 65 | req := &x.ProtocolRequest{ 66 | Ext: _ext, 67 | NoReply: true, 68 | Header: x.RequestHeader{ 69 | Data: DestroyOpcode, 70 | }, 71 | Body: body, 72 | } 73 | conn.SendRequest(0, req) 74 | } 75 | 76 | func DestroyChecked(conn *x.Conn, damage Damage) x.VoidCookie { 77 | body := encodeDestroy(damage) 78 | req := &x.ProtocolRequest{ 79 | Ext: _ext, 80 | NoReply: true, 81 | Header: x.RequestHeader{ 82 | Data: DestroyOpcode, 83 | }, 84 | Body: body, 85 | } 86 | seq := conn.SendRequest(x.RequestChecked, req) 87 | return x.VoidCookie(seq) 88 | } 89 | -------------------------------------------------------------------------------- /ext/dpms/auto.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package dpms 6 | 7 | import x "github.com/linuxdeepin/go-x11-client" 8 | 9 | // _ns.ext_name: DPMS 10 | const MajorVersion = 0 11 | const MinorVersion = 0 12 | 13 | var _ext *x.Extension 14 | 15 | func Ext() *x.Extension { 16 | return _ext 17 | } 18 | 19 | const GetVersionOpcode = 0 20 | 21 | type GetVersionCookie x.SeqNum 22 | 23 | const CapableOpcode = 1 24 | 25 | type CapableCookie x.SeqNum 26 | 27 | const GetTimeoutsOpcode = 2 28 | 29 | type GetTimeoutsCookie x.SeqNum 30 | 31 | const SetTimeoutsOpcode = 3 32 | const EnableOpcode = 4 33 | const DisableOpcode = 5 34 | 35 | // enum DPMSMode 36 | const ( 37 | DPMSModeOn = 0 38 | DPMSModeStandby = 1 39 | DPMSModeSuspend = 2 40 | DPMSModeOff = 3 41 | ) 42 | 43 | const ForceLevelOpcode = 6 44 | const InfoOpcode = 7 45 | 46 | type InfoCookie x.SeqNum 47 | 48 | var requestOpcodeNameMap = map[uint]string{ 49 | GetVersionOpcode: "GetVersion", 50 | CapableOpcode: "Capable", 51 | GetTimeoutsOpcode: "GetTimeouts", 52 | SetTimeoutsOpcode: "SetTimeouts", 53 | EnableOpcode: "Enable", 54 | DisableOpcode: "Disable", 55 | ForceLevelOpcode: "ForceLevel", 56 | InfoOpcode: "Info", 57 | } 58 | 59 | func init() { 60 | _ext = x.NewExtension("DPMS", 0, nil, requestOpcodeNameMap) 61 | } 62 | -------------------------------------------------------------------------------- /ext/dpms/dpms.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package dpms 6 | 7 | import "github.com/linuxdeepin/go-x11-client" 8 | 9 | // #WREQ 10 | func encodeGetVersion(clientMajorVersion, clientMinorVersion uint16) (b x.RequestBody) { 11 | b.AddBlock(1). 12 | Write2b(clientMajorVersion). 13 | Write2b(clientMinorVersion). 14 | End() 15 | return 16 | } 17 | 18 | type GetVersionReply struct { 19 | ServerMajorVersion uint16 20 | ServerMinorVersion uint16 21 | } 22 | 23 | func readGetVersionReply(r *x.Reader, v *GetVersionReply) error { 24 | if !r.RemainAtLeast4b(3) { 25 | return x.ErrDataLenShort 26 | } 27 | r.ReadPad(8) 28 | 29 | v.ServerMajorVersion = r.Read2b() 30 | v.ServerMinorVersion = r.Read2b() // 3 31 | 32 | return nil 33 | } 34 | 35 | // #WREQ 36 | func encodeCapable() (b x.RequestBody) { 37 | return 38 | } 39 | 40 | type CapableReply struct { 41 | Capable bool 42 | } 43 | 44 | func readCapableReply(r *x.Reader, v *CapableReply) error { 45 | if !r.RemainAtLeast4b(3) { 46 | return x.ErrDataLenShort 47 | } 48 | 49 | r.ReadPad(8) 50 | 51 | v.Capable = r.ReadBool() // 3 52 | 53 | return nil 54 | } 55 | 56 | // #WREQ 57 | func encodeGetTimeouts() (b x.RequestBody) { 58 | return 59 | } 60 | 61 | type GetTimeoutsReply struct { 62 | StandbyTimeout uint16 63 | SuspendTimeout uint16 64 | OffTimeout uint16 65 | } 66 | 67 | func readGetTimeoutsReply(r *x.Reader, v *GetTimeoutsReply) error { 68 | if !r.RemainAtLeast4b(4) { 69 | return x.ErrDataLenShort 70 | } 71 | r.ReadPad(8) 72 | 73 | v.StandbyTimeout = r.Read2b() 74 | v.SuspendTimeout = r.Read2b() 75 | 76 | v.OffTimeout = r.Read2b() // 4 77 | 78 | return nil 79 | } 80 | 81 | // #WREQ 82 | func encodeSetTimeouts(standbyTimeout, suspendTimeout, offTimeout uint16) (b x.RequestBody) { 83 | b.AddBlock(2). 84 | Write2b(standbyTimeout). 85 | Write2b(suspendTimeout). 86 | Write2b(offTimeout). 87 | WritePad(2). 88 | End() 89 | return 90 | } 91 | 92 | // #WREQ 93 | func encodeEnable() (b x.RequestBody) { 94 | return 95 | } 96 | 97 | // #WREQ 98 | func encodeDisable() (b x.RequestBody) { 99 | return 100 | } 101 | 102 | // #WREQ 103 | func encodeForceLevel(powerLevel uint16) (b x.RequestBody) { 104 | b.AddBlock(1). 105 | Write2b(powerLevel). 106 | WritePad(2). 107 | End() 108 | return 109 | } 110 | 111 | // #WREQ 112 | func encodeInfo() (b x.RequestBody) { 113 | return 114 | } 115 | 116 | type InfoReply struct { 117 | PowerLevel uint16 118 | State bool 119 | } 120 | 121 | func readInfoReply(r *x.Reader, v *InfoReply) error { 122 | if !r.RemainAtLeast4b(3) { 123 | return x.ErrDataLenShort 124 | } 125 | r.ReadPad(8) 126 | 127 | v.PowerLevel = r.Read2b() 128 | v.State = r.ReadBool() // 3 129 | 130 | return nil 131 | } 132 | -------------------------------------------------------------------------------- /ext/dpms/dpms_req_auto.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package dpms 6 | 7 | import x "github.com/linuxdeepin/go-x11-client" 8 | 9 | func GetVersion(conn *x.Conn, clientMajorVersion, clientMinorVersion uint16) GetVersionCookie { 10 | body := encodeGetVersion(clientMajorVersion, clientMinorVersion) 11 | req := &x.ProtocolRequest{ 12 | Ext: _ext, 13 | Header: x.RequestHeader{ 14 | Data: GetVersionOpcode, 15 | }, 16 | Body: body, 17 | } 18 | seq := conn.SendRequest(x.RequestChecked, req) 19 | return GetVersionCookie(seq) 20 | } 21 | 22 | func (cookie GetVersionCookie) Reply(conn *x.Conn) (*GetVersionReply, error) { 23 | replyBuf, err := conn.WaitForReply(x.SeqNum(cookie)) 24 | if err != nil { 25 | return nil, err 26 | } 27 | r := x.NewReaderFromData(replyBuf) 28 | var reply GetVersionReply 29 | err = readGetVersionReply(r, &reply) 30 | if err != nil { 31 | return nil, err 32 | } 33 | return &reply, nil 34 | } 35 | 36 | func Capable(conn *x.Conn) CapableCookie { 37 | body := encodeCapable() 38 | req := &x.ProtocolRequest{ 39 | Ext: _ext, 40 | Header: x.RequestHeader{ 41 | Data: CapableOpcode, 42 | }, 43 | Body: body, 44 | } 45 | seq := conn.SendRequest(x.RequestChecked, req) 46 | return CapableCookie(seq) 47 | } 48 | 49 | func (cookie CapableCookie) Reply(conn *x.Conn) (*CapableReply, error) { 50 | replyBuf, err := conn.WaitForReply(x.SeqNum(cookie)) 51 | if err != nil { 52 | return nil, err 53 | } 54 | r := x.NewReaderFromData(replyBuf) 55 | var reply CapableReply 56 | err = readCapableReply(r, &reply) 57 | if err != nil { 58 | return nil, err 59 | } 60 | return &reply, nil 61 | } 62 | 63 | func GetTimeouts(conn *x.Conn) GetTimeoutsCookie { 64 | body := encodeGetTimeouts() 65 | req := &x.ProtocolRequest{ 66 | Ext: _ext, 67 | Header: x.RequestHeader{ 68 | Data: GetTimeoutsOpcode, 69 | }, 70 | Body: body, 71 | } 72 | seq := conn.SendRequest(x.RequestChecked, req) 73 | return GetTimeoutsCookie(seq) 74 | } 75 | 76 | func (cookie GetTimeoutsCookie) Reply(conn *x.Conn) (*GetTimeoutsReply, error) { 77 | replyBuf, err := conn.WaitForReply(x.SeqNum(cookie)) 78 | if err != nil { 79 | return nil, err 80 | } 81 | r := x.NewReaderFromData(replyBuf) 82 | var reply GetTimeoutsReply 83 | err = readGetTimeoutsReply(r, &reply) 84 | if err != nil { 85 | return nil, err 86 | } 87 | return &reply, nil 88 | } 89 | 90 | func SetTimeouts(conn *x.Conn, standbyTimeout, suspendTimeout, offTimeout uint16) { 91 | body := encodeSetTimeouts(standbyTimeout, suspendTimeout, offTimeout) 92 | req := &x.ProtocolRequest{ 93 | Ext: _ext, 94 | NoReply: true, 95 | Header: x.RequestHeader{ 96 | Data: SetTimeoutsOpcode, 97 | }, 98 | Body: body, 99 | } 100 | conn.SendRequest(0, req) 101 | } 102 | 103 | func SetTimeoutsChecked(conn *x.Conn, standbyTimeout, suspendTimeout, offTimeout uint16) x.VoidCookie { 104 | body := encodeSetTimeouts(standbyTimeout, suspendTimeout, offTimeout) 105 | req := &x.ProtocolRequest{ 106 | Ext: _ext, 107 | NoReply: true, 108 | Header: x.RequestHeader{ 109 | Data: SetTimeoutsOpcode, 110 | }, 111 | Body: body, 112 | } 113 | seq := conn.SendRequest(x.RequestChecked, req) 114 | return x.VoidCookie(seq) 115 | } 116 | 117 | func Enable(conn *x.Conn) { 118 | body := encodeEnable() 119 | req := &x.ProtocolRequest{ 120 | Ext: _ext, 121 | NoReply: true, 122 | Header: x.RequestHeader{ 123 | Data: EnableOpcode, 124 | }, 125 | Body: body, 126 | } 127 | conn.SendRequest(0, req) 128 | } 129 | 130 | func EnableChecked(conn *x.Conn) x.VoidCookie { 131 | body := encodeEnable() 132 | req := &x.ProtocolRequest{ 133 | Ext: _ext, 134 | NoReply: true, 135 | Header: x.RequestHeader{ 136 | Data: EnableOpcode, 137 | }, 138 | Body: body, 139 | } 140 | seq := conn.SendRequest(x.RequestChecked, req) 141 | return x.VoidCookie(seq) 142 | } 143 | 144 | func Disable(conn *x.Conn) { 145 | body := encodeDisable() 146 | req := &x.ProtocolRequest{ 147 | Ext: _ext, 148 | NoReply: true, 149 | Header: x.RequestHeader{ 150 | Data: DisableOpcode, 151 | }, 152 | Body: body, 153 | } 154 | conn.SendRequest(0, req) 155 | } 156 | 157 | func DisableChecked(conn *x.Conn) x.VoidCookie { 158 | body := encodeDisable() 159 | req := &x.ProtocolRequest{ 160 | Ext: _ext, 161 | NoReply: true, 162 | Header: x.RequestHeader{ 163 | Data: DisableOpcode, 164 | }, 165 | Body: body, 166 | } 167 | seq := conn.SendRequest(x.RequestChecked, req) 168 | return x.VoidCookie(seq) 169 | } 170 | 171 | func ForceLevel(conn *x.Conn, powerLevel uint16) { 172 | body := encodeForceLevel(powerLevel) 173 | req := &x.ProtocolRequest{ 174 | Ext: _ext, 175 | NoReply: true, 176 | Header: x.RequestHeader{ 177 | Data: ForceLevelOpcode, 178 | }, 179 | Body: body, 180 | } 181 | conn.SendRequest(0, req) 182 | } 183 | 184 | func ForceLevelChecked(conn *x.Conn, powerLevel uint16) x.VoidCookie { 185 | body := encodeForceLevel(powerLevel) 186 | req := &x.ProtocolRequest{ 187 | Ext: _ext, 188 | NoReply: true, 189 | Header: x.RequestHeader{ 190 | Data: ForceLevelOpcode, 191 | }, 192 | Body: body, 193 | } 194 | seq := conn.SendRequest(x.RequestChecked, req) 195 | return x.VoidCookie(seq) 196 | } 197 | 198 | func Info(conn *x.Conn) InfoCookie { 199 | body := encodeInfo() 200 | req := &x.ProtocolRequest{ 201 | Ext: _ext, 202 | Header: x.RequestHeader{ 203 | Data: InfoOpcode, 204 | }, 205 | Body: body, 206 | } 207 | seq := conn.SendRequest(x.RequestChecked, req) 208 | return InfoCookie(seq) 209 | } 210 | 211 | func (cookie InfoCookie) Reply(conn *x.Conn) (*InfoReply, error) { 212 | replyBuf, err := conn.WaitForReply(x.SeqNum(cookie)) 213 | if err != nil { 214 | return nil, err 215 | } 216 | r := x.NewReaderFromData(replyBuf) 217 | var reply InfoReply 218 | err = readInfoReply(r, &reply) 219 | if err != nil { 220 | return nil, err 221 | } 222 | return &reply, nil 223 | } 224 | -------------------------------------------------------------------------------- /ext/ge/auto.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package ge 6 | 7 | import x "github.com/linuxdeepin/go-x11-client" 8 | 9 | // _ns.ext_name: GenericEvent 10 | const MajorVersion = 1 11 | const MinorVersion = 0 12 | 13 | var _ext *x.Extension 14 | 15 | func Ext() *x.Extension { 16 | return _ext 17 | } 18 | 19 | const QueryVersionOpcode = 0 20 | 21 | type QueryVersionCookie x.SeqNum 22 | 23 | var requestOpcodeNameMap = map[uint]string{ 24 | QueryVersionOpcode: "QueryVersion", 25 | } 26 | 27 | func init() { 28 | _ext = x.NewExtension("Generic Event Extension", 0, nil, requestOpcodeNameMap) 29 | } 30 | -------------------------------------------------------------------------------- /ext/ge/ge.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package ge 6 | 7 | import "github.com/linuxdeepin/go-x11-client" 8 | 9 | // #WREQ 10 | func encodeQueryVersion(majorVersion, minorVersion uint16) (b x.RequestBody) { 11 | b.AddBlock(1). 12 | Write2b(majorVersion). 13 | Write2b(minorVersion). 14 | End() 15 | return 16 | } 17 | 18 | type QueryVersionReply struct { 19 | MajorVersion uint16 20 | MinorVersion uint16 21 | } 22 | 23 | func readQueryVersionReply(r *x.Reader, v *QueryVersionReply) error { 24 | if !r.RemainAtLeast4b(3) { 25 | return x.ErrDataLenShort 26 | } 27 | 28 | r.ReadPad(8) 29 | 30 | v.MajorVersion = r.Read2b() 31 | v.MinorVersion = r.Read2b() // 3 32 | 33 | return nil 34 | } 35 | -------------------------------------------------------------------------------- /ext/ge/ge_req_auto.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package ge 6 | 7 | import x "github.com/linuxdeepin/go-x11-client" 8 | 9 | func QueryVersion(conn *x.Conn, majorVersion, minorVersion uint16) QueryVersionCookie { 10 | body := encodeQueryVersion(majorVersion, minorVersion) 11 | req := &x.ProtocolRequest{ 12 | Ext: _ext, 13 | Header: x.RequestHeader{ 14 | Data: QueryVersionOpcode, 15 | }, 16 | Body: body, 17 | } 18 | seq := conn.SendRequest(x.RequestChecked, req) 19 | return QueryVersionCookie(seq) 20 | } 21 | 22 | func (cookie QueryVersionCookie) Reply(conn *x.Conn) (*QueryVersionReply, error) { 23 | replyBuf, err := conn.WaitForReply(x.SeqNum(cookie)) 24 | if err != nil { 25 | return nil, err 26 | } 27 | r := x.NewReaderFromData(replyBuf) 28 | var reply QueryVersionReply 29 | err = readQueryVersionReply(r, &reply) 30 | if err != nil { 31 | return nil, err 32 | } 33 | return &reply, nil 34 | } 35 | -------------------------------------------------------------------------------- /ext/input/input1.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package input 6 | 7 | import ( 8 | "github.com/linuxdeepin/go-x11-client" 9 | ) 10 | 11 | // #WREQ 12 | func encodeOpenDevice(deviceId uint8) (b x.RequestBody) { 13 | b.AddBlock(1). 14 | Write1b(deviceId). 15 | WritePad(3). 16 | End() 17 | return 18 | } 19 | 20 | type OpenDeviceReply struct { 21 | XIReplyType uint8 22 | ClassInfos []ClassInfo 23 | } 24 | 25 | func readOpenDeviceReply(r *x.Reader, v *OpenDeviceReply) error { 26 | if !r.RemainAtLeast4b(8) { 27 | return x.ErrDataLenShort 28 | } 29 | 30 | v.XIReplyType, _ = r.ReadReplyHeader() 31 | 32 | classInfosLen := int(r.Read1b()) 33 | 34 | r.ReadPad(23) // 8 35 | 36 | if classInfosLen > 0 { 37 | if !r.RemainAtLeast(2 * classInfosLen) { 38 | return x.ErrDataLenShort 39 | } 40 | v.ClassInfos = make([]ClassInfo, classInfosLen) 41 | for i := 0; i < classInfosLen; i++ { 42 | v.ClassInfos[i] = readClassInfo(r) 43 | } 44 | } 45 | 46 | return nil 47 | } 48 | 49 | func FindTypeAndClass(deviceId uint8, classInfos []ClassInfo, 50 | classId uint8, eventCode uint8) (Type uint8, class EventClass) { 51 | for _, classInfo := range classInfos { 52 | if classInfo.ClassId == classId { 53 | Type = classInfo.EventTypeBase + eventCode 54 | class = EventClass(uint32(deviceId)<<8 | uint32(Type)) 55 | } 56 | } 57 | return 58 | } 59 | 60 | // size: 2b 61 | type ClassInfo struct { 62 | ClassId uint8 63 | EventTypeBase uint8 64 | } 65 | 66 | func readClassInfo(r *x.Reader) ClassInfo { 67 | var v ClassInfo 68 | v.ClassId = r.Read1b() 69 | v.EventTypeBase = r.Read1b() 70 | return v 71 | } 72 | 73 | // #WREQ 74 | func encodeCloseDevice(deviceId uint8) (b x.RequestBody) { 75 | b.AddBlock(1). 76 | Write1b(deviceId). 77 | WritePad(3). 78 | End() 79 | return 80 | } 81 | 82 | // #WREQ 83 | func encodeSelectExtensionEvent(window x.Window, classes []EventClass) (b x.RequestBody) { 84 | b0 := b.AddBlock(2 + len(classes)). 85 | Write4b(uint32(window)). 86 | Write2b(uint16(len(classes))). 87 | WritePad(2) 88 | 89 | for _, class := range classes { 90 | b0.Write4b(uint32(class)) 91 | } 92 | b0.End() 93 | return 94 | } 95 | -------------------------------------------------------------------------------- /ext/input/input1_req_auto.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package input 6 | 7 | import x "github.com/linuxdeepin/go-x11-client" 8 | 9 | func OpenDevice(conn *x.Conn, deviceId uint8) OpenDeviceCookie { 10 | body := encodeOpenDevice(deviceId) 11 | req := &x.ProtocolRequest{ 12 | Ext: _ext, 13 | Header: x.RequestHeader{ 14 | Data: OpenDeviceOpcode, 15 | }, 16 | Body: body, 17 | } 18 | seq := conn.SendRequest(x.RequestChecked, req) 19 | return OpenDeviceCookie(seq) 20 | } 21 | 22 | func (cookie OpenDeviceCookie) Reply(conn *x.Conn) (*OpenDeviceReply, error) { 23 | replyBuf, err := conn.WaitForReply(x.SeqNum(cookie)) 24 | if err != nil { 25 | return nil, err 26 | } 27 | r := x.NewReaderFromData(replyBuf) 28 | var reply OpenDeviceReply 29 | err = readOpenDeviceReply(r, &reply) 30 | if err != nil { 31 | return nil, err 32 | } 33 | return &reply, nil 34 | } 35 | 36 | func CloseDevice(conn *x.Conn, deviceId uint8) { 37 | body := encodeCloseDevice(deviceId) 38 | req := &x.ProtocolRequest{ 39 | Ext: _ext, 40 | NoReply: true, 41 | Header: x.RequestHeader{ 42 | Data: CloseDeviceOpcode, 43 | }, 44 | Body: body, 45 | } 46 | conn.SendRequest(0, req) 47 | } 48 | 49 | func CloseDeviceChecked(conn *x.Conn, deviceId uint8) x.VoidCookie { 50 | body := encodeCloseDevice(deviceId) 51 | req := &x.ProtocolRequest{ 52 | Ext: _ext, 53 | NoReply: true, 54 | Header: x.RequestHeader{ 55 | Data: CloseDeviceOpcode, 56 | }, 57 | Body: body, 58 | } 59 | seq := conn.SendRequest(x.RequestChecked, req) 60 | return x.VoidCookie(seq) 61 | } 62 | 63 | func SelectExtensionEvent(conn *x.Conn, window x.Window, classes []EventClass) { 64 | body := encodeSelectExtensionEvent(window, classes) 65 | req := &x.ProtocolRequest{ 66 | Ext: _ext, 67 | NoReply: true, 68 | Header: x.RequestHeader{ 69 | Data: SelectExtensionEventOpcode, 70 | }, 71 | Body: body, 72 | } 73 | conn.SendRequest(0, req) 74 | } 75 | 76 | func SelectExtensionEventChecked(conn *x.Conn, window x.Window, classes []EventClass) x.VoidCookie { 77 | body := encodeSelectExtensionEvent(window, classes) 78 | req := &x.ProtocolRequest{ 79 | Ext: _ext, 80 | NoReply: true, 81 | Header: x.RequestHeader{ 82 | Data: SelectExtensionEventOpcode, 83 | }, 84 | Body: body, 85 | } 86 | seq := conn.SendRequest(x.RequestChecked, req) 87 | return x.VoidCookie(seq) 88 | } 89 | -------------------------------------------------------------------------------- /ext/randr/randr_event.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package randr 6 | 7 | import "github.com/linuxdeepin/go-x11-client" 8 | 9 | type ScreenChangeNotifyEvent struct { 10 | Rotation uint8 11 | Sequence uint16 12 | Timestamp x.Timestamp 13 | ConfigTimestamp x.Timestamp 14 | Root x.Window 15 | RequestWindow x.Window 16 | SizeID uint16 17 | SubpixelOrder uint16 18 | Width uint16 19 | Height uint16 20 | MmWidth uint16 21 | MmHeight uint16 22 | } 23 | 24 | func readScreenChangeNotifyEvent(r *x.Reader, v *ScreenChangeNotifyEvent) error { 25 | if !r.RemainAtLeast4b(8) { 26 | return x.ErrDataLenShort 27 | } 28 | v.Rotation, v.Sequence = r.ReadEventHeader() 29 | 30 | v.Timestamp = x.Timestamp(r.Read4b()) 31 | 32 | v.ConfigTimestamp = x.Timestamp(r.Read4b()) 33 | 34 | v.Root = x.Window(r.Read4b()) 35 | 36 | v.RequestWindow = x.Window(r.Read4b()) // 5 37 | 38 | v.SizeID = r.Read2b() 39 | v.SubpixelOrder = r.Read2b() 40 | 41 | v.Width = r.Read2b() 42 | v.Height = r.Read2b() 43 | 44 | v.MmWidth = r.Read2b() 45 | v.MmHeight = r.Read2b() // 8 46 | 47 | return nil 48 | } 49 | 50 | type NotifyEvent struct { 51 | SubCode uint8 52 | Sequence uint16 53 | Data []byte 54 | } 55 | 56 | func readNotifyEvent(r *x.Reader, v *NotifyEvent) error { 57 | if !r.RemainAtLeast4b(8) { 58 | return x.ErrDataLenShort 59 | } 60 | v.SubCode, v.Sequence = r.ReadEventHeader() 61 | 62 | v.Data = r.MustReadBytes(28) // 8 63 | 64 | return nil 65 | } 66 | 67 | func (e *NotifyEvent) NewCrtcChangeNotifyEvent() (*CrtcChangeNotifyEvent, error) { 68 | var ev CrtcChangeNotifyEvent 69 | r := x.NewReaderFromData(e.Data) 70 | err := readCrtcChangeNotifyEvent(r, &ev) 71 | if err != nil { 72 | return nil, err 73 | } 74 | return &ev, nil 75 | } 76 | 77 | func (e *NotifyEvent) NewOutputChangeNotifyEvent() (*OutputChangeNotifyEvent, error) { 78 | var ev OutputChangeNotifyEvent 79 | r := x.NewReaderFromData(e.Data) 80 | err := readOutputChangeNotifyEvent(r, &ev) 81 | if err != nil { 82 | return nil, err 83 | } 84 | return &ev, nil 85 | } 86 | 87 | func (e *NotifyEvent) NewOutputPropertyNotifyEvent() (*OutputPropertyNotifyEvent, 88 | error) { 89 | var ev OutputPropertyNotifyEvent 90 | r := x.NewReaderFromData(e.Data) 91 | err := readOutputPropertyNotifyEvent(r, &ev) 92 | if err != nil { 93 | return nil, err 94 | } 95 | return &ev, nil 96 | } 97 | 98 | func (e *NotifyEvent) NewResourceChangeNotifyEvent() (*ResourceChangeNotifyEvent, 99 | error) { 100 | var ev ResourceChangeNotifyEvent 101 | r := x.NewReaderFromData(e.Data) 102 | err := readResourceChangeNotifyEvent(r, &ev) 103 | if err != nil { 104 | return nil, err 105 | } 106 | return &ev, nil 107 | } 108 | 109 | type CrtcChangeNotifyEvent struct { 110 | Timestamp x.Timestamp 111 | Window x.Window 112 | Crtc Crtc 113 | Mode Mode 114 | Rotation uint16 115 | X, Y int16 116 | Width, Height uint16 117 | } 118 | 119 | func readCrtcChangeNotifyEvent(r *x.Reader, v *CrtcChangeNotifyEvent) error { 120 | if !r.RemainAtLeast4b(7) { 121 | return x.ErrDataLenShort 122 | } 123 | v.Timestamp = x.Timestamp(r.Read4b()) 124 | 125 | v.Window = x.Window(r.Read4b()) 126 | 127 | v.Crtc = Crtc(r.Read4b()) 128 | 129 | v.Mode = Mode(r.Read4b()) 130 | 131 | v.Rotation = r.Read2b() 132 | r.ReadPad(2) // 5 133 | 134 | v.X = int16(r.Read2b()) 135 | v.Y = int16(r.Read2b()) 136 | 137 | v.Width = r.Read2b() 138 | v.Height = r.Read2b() // 7 139 | 140 | return nil 141 | } 142 | 143 | type OutputChangeNotifyEvent struct { 144 | Timestamp x.Timestamp 145 | ConfigTimestamp x.Timestamp 146 | Window x.Window 147 | Output Output 148 | Crtc Crtc 149 | Mode Mode 150 | Rotation uint16 151 | Connection uint8 152 | SubPixelOrder uint8 153 | } 154 | 155 | func readOutputChangeNotifyEvent(r *x.Reader, v *OutputChangeNotifyEvent) error { 156 | if !r.RemainAtLeast4b(7) { 157 | return x.ErrDataLenShort 158 | } 159 | v.Timestamp = x.Timestamp(r.Read4b()) 160 | 161 | v.ConfigTimestamp = x.Timestamp(r.Read4b()) 162 | 163 | v.Window = x.Window(r.Read4b()) 164 | 165 | v.Output = Output(r.Read4b()) 166 | 167 | v.Crtc = Crtc(r.Read4b()) // 5 168 | 169 | v.Mode = Mode(r.Read4b()) 170 | 171 | v.Rotation = r.Read2b() 172 | v.Connection = r.Read1b() 173 | v.SubPixelOrder = r.Read1b() // 7 174 | 175 | return nil 176 | } 177 | 178 | type OutputPropertyNotifyEvent struct { 179 | Window x.Window 180 | Output Output 181 | Atom x.Atom 182 | Timestamp x.Timestamp 183 | Status uint8 184 | } 185 | 186 | func readOutputPropertyNotifyEvent(r *x.Reader, v *OutputPropertyNotifyEvent) error { 187 | if !r.RemainAtLeast4b(5) { 188 | return x.ErrDataLenShort 189 | } 190 | v.Window = x.Window(r.Read4b()) 191 | 192 | v.Output = Output(r.Read4b()) 193 | 194 | v.Atom = x.Atom(r.Read4b()) 195 | 196 | v.Timestamp = x.Timestamp(r.Read4b()) 197 | 198 | v.Status = r.Read1b() // 5 199 | 200 | return nil 201 | } 202 | 203 | type ResourceChangeNotifyEvent struct { 204 | Timestamp x.Timestamp 205 | Window x.Window 206 | } 207 | 208 | func readResourceChangeNotifyEvent(r *x.Reader, v *ResourceChangeNotifyEvent) error { 209 | if !r.RemainAtLeast4b(2) { 210 | return x.ErrDataLenShort 211 | } 212 | v.Timestamp = x.Timestamp(r.Read4b()) 213 | v.Window = x.Window(r.Read4b()) 214 | return nil 215 | } 216 | -------------------------------------------------------------------------------- /ext/record/auto.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package record 6 | 7 | import x "github.com/linuxdeepin/go-x11-client" 8 | 9 | // _ns.ext_name: Record 10 | const MajorVersion = 1 11 | const MinorVersion = 13 12 | 13 | var _ext *x.Extension 14 | 15 | func Ext() *x.Extension { 16 | return _ext 17 | } 18 | 19 | // simple ('xcb', 'Record', 'CONTEXT') 20 | type Context uint32 21 | 22 | // simple ('xcb', 'Record', 'ElementHeader') 23 | type ElementHeader uint8 24 | 25 | // enum HType 26 | const ( 27 | HTypeFromServerTime = 1 28 | HTypeFromClientTime = 2 29 | HTypeFromClientSequence = 4 30 | ) 31 | 32 | // simple ('xcb', 'Record', 'ClientSpec') 33 | type ClientSpec uint32 34 | 35 | // enum CS 36 | const ( 37 | CSCurrentClients = 1 38 | CSFutureClients = 2 39 | CSAllClients = 3 40 | ) 41 | 42 | const BadContextErrorCode = 0 43 | const QueryVersionOpcode = 0 44 | 45 | type QueryVersionCookie x.SeqNum 46 | 47 | const CreateContextOpcode = 1 48 | const RegisterClientsOpcode = 2 49 | const UnregisterClientsOpcode = 3 50 | const GetContextOpcode = 4 51 | 52 | type GetContextCookie x.SeqNum 53 | 54 | const EnableContextOpcode = 5 55 | 56 | type EnableContextCookie x.SeqNum 57 | 58 | const DisableContextOpcode = 6 59 | const FreeContextOpcode = 7 60 | 61 | var errorCodeNameMap = map[uint8]string{ 62 | BadContextErrorCode: "BadContext", 63 | } 64 | var requestOpcodeNameMap = map[uint]string{ 65 | QueryVersionOpcode: "QueryVersion", 66 | CreateContextOpcode: "CreateContext", 67 | RegisterClientsOpcode: "RegisterClients", 68 | UnregisterClientsOpcode: "UnregisterClients", 69 | GetContextOpcode: "GetContext", 70 | EnableContextOpcode: "EnableContext", 71 | DisableContextOpcode: "DisableContext", 72 | FreeContextOpcode: "FreeContext", 73 | } 74 | 75 | func init() { 76 | _ext = x.NewExtension("RECORD", 0, errorCodeNameMap, requestOpcodeNameMap) 77 | } 78 | -------------------------------------------------------------------------------- /ext/record/record.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package record 6 | 7 | import ( 8 | "github.com/linuxdeepin/go-x11-client" 9 | ) 10 | 11 | // size: 2b 12 | type Range8 struct { 13 | First uint8 14 | Last uint8 15 | } 16 | 17 | func writeRange8(b *x.FixedSizeBuf, v Range8) { 18 | b.Write1b(v.First) 19 | b.Write1b(v.Last) 20 | } 21 | 22 | func readRange8(r *x.Reader) Range8 { 23 | var v Range8 24 | v.First = r.Read1b() 25 | v.Last = r.Read1b() 26 | return v 27 | } 28 | 29 | // size: 4b 30 | type Range16 struct { 31 | First uint16 32 | Last uint16 33 | } 34 | 35 | func readRange16(r *x.Reader) Range16 { 36 | var v Range16 37 | v.First = r.Read2b() 38 | v.Last = r.Read2b() 39 | return v 40 | } 41 | 42 | func writeRange16(b *x.FixedSizeBuf, v Range16) { 43 | b.Write2b(v.First) 44 | b.Write2b(v.Last) 45 | } 46 | 47 | // size: 6b 48 | type ExtRange struct { 49 | Major Range8 50 | Minor Range16 51 | } 52 | 53 | func readExtRange(r *x.Reader) (v ExtRange) { 54 | v.Major = readRange8(r) 55 | v.Minor = readRange16(r) 56 | return 57 | } 58 | 59 | func writeExtRange(b *x.FixedSizeBuf, v ExtRange) { 60 | writeRange8(b, v.Major) 61 | writeRange16(b, v.Minor) 62 | } 63 | 64 | // size: 6 * 4b 65 | type Range struct { 66 | CoreRequests Range8 67 | CoreReplies Range8 68 | ExtRequests ExtRange 69 | ExtReplies ExtRange 70 | DeliveredEvents Range8 71 | DeviceEvents Range8 72 | Errors Range8 73 | ClientStarted bool 74 | ClientDied bool 75 | } 76 | 77 | func writeRange(b *x.FixedSizeBuf, v *Range) { 78 | writeRange8(b, v.CoreRequests) 79 | writeRange8(b, v.CoreReplies) 80 | writeExtRange(b, v.ExtRequests) 81 | writeExtRange(b, v.ExtReplies) 82 | writeRange8(b, v.DeliveredEvents) 83 | writeRange8(b, v.DeviceEvents) 84 | writeRange8(b, v.Errors) 85 | 86 | b.WriteBool(v.ClientStarted). 87 | WriteBool(v.ClientDied) 88 | } 89 | 90 | func readRange(r *x.Reader, v *Range) { 91 | v.CoreRequests = readRange8(r) 92 | v.CoreReplies = readRange8(r) 93 | 94 | v.ExtRequests = readExtRange(r) 95 | 96 | v.ExtRequests = readExtRange(r) 97 | 98 | v.DeliveredEvents = readRange8(r) 99 | v.DeviceEvents = readRange8(r) 100 | 101 | v.Errors = readRange8(r) 102 | v.ClientStarted = r.ReadBool() 103 | v.ClientDied = r.ReadBool() 104 | } 105 | 106 | type ClientInfo struct { 107 | ClientResource ClientSpec 108 | InterceptedProtocol []Range 109 | } 110 | 111 | func readClientInfo(r *x.Reader, v *ClientInfo) error { 112 | if !r.RemainAtLeast4b(2) { 113 | return x.ErrDataLenShort 114 | } 115 | v.ClientResource = ClientSpec(r.Read4b()) 116 | 117 | interceptedProtocolLen := int(r.Read4b()) // 2 118 | 119 | if interceptedProtocolLen > 0 { 120 | if !r.RemainAtLeast4b(6 * interceptedProtocolLen) { 121 | return x.ErrDataLenShort 122 | } 123 | v.InterceptedProtocol = make([]Range, interceptedProtocolLen) 124 | for i := 0; i < interceptedProtocolLen; i++ { 125 | readRange(r, &v.InterceptedProtocol[i]) 126 | } 127 | } 128 | 129 | return nil 130 | } 131 | 132 | // #WREQ 133 | func encodeQueryVersion(majorVersion, minorVersion uint16) (b x.RequestBody) { 134 | b.AddBlock(1). 135 | Write2b(majorVersion). 136 | Write2b(minorVersion). 137 | End() 138 | return 139 | } 140 | 141 | type QueryVersionReply struct { 142 | MajorVersion uint16 143 | MinorVersion uint16 144 | } 145 | 146 | func readQueryVersionReply(r *x.Reader, v *QueryVersionReply) error { 147 | if !r.RemainAtLeast4b(3) { 148 | return x.ErrDataLenShort 149 | } 150 | r.ReadPad(8) 151 | 152 | v.MajorVersion = r.Read2b() 153 | v.MinorVersion = r.Read2b() // 3 154 | 155 | return nil 156 | } 157 | 158 | // #WREQ 159 | func encodeCreateContext(context Context, elementHeader ElementHeader, 160 | clientSpecs []ClientSpec, ranges []Range) (b x.RequestBody) { 161 | 162 | clientSpecsLen := len(clientSpecs) 163 | rangesLen := len(ranges) 164 | b0 := b.AddBlock(4 + clientSpecsLen + rangesLen*6). 165 | Write4b(uint32(context)). 166 | Write1b(uint8(elementHeader)). 167 | WritePad(3). 168 | Write4b(uint32(clientSpecsLen)). 169 | Write4b(uint32(rangesLen)) 170 | 171 | for _, clientSpec := range clientSpecs { 172 | b0.Write4b(uint32(clientSpec)) 173 | } 174 | 175 | for i := 0; i < rangesLen; i++ { 176 | writeRange(b0, &ranges[i]) 177 | } 178 | b0.End() 179 | return 180 | } 181 | 182 | // #WREQ 183 | func encodeRegisterClients(context Context, elementHeader ElementHeader, 184 | clientSpecs []ClientSpec, ranges []Range) (b x.RequestBody) { 185 | 186 | clientSpecsLen := len(clientSpecs) 187 | rangesLen := len(ranges) 188 | 189 | b0 := b.AddBlock(4 + clientSpecsLen + rangesLen*6). 190 | Write4b(uint32(context)). 191 | Write1b(uint8(elementHeader)). 192 | WritePad(3). 193 | Write4b(uint32(clientSpecsLen)). 194 | Write4b(uint32(rangesLen)) 195 | 196 | for _, clientSpec := range clientSpecs { 197 | b0.Write4b(uint32(clientSpec)) 198 | } 199 | 200 | for i := 0; i < rangesLen; i++ { 201 | writeRange(b0, &ranges[i]) 202 | } 203 | b0.End() 204 | return 205 | } 206 | 207 | // #WREQ 208 | func encodeUnregisterClients(context Context, clientSpecs []ClientSpec) (b x.RequestBody) { 209 | clientSpecsLen := len(clientSpecs) 210 | b0 := b.AddBlock(2 + clientSpecsLen). 211 | Write4b(uint32(context)). 212 | Write4b(uint32(clientSpecsLen)) 213 | 214 | for _, clientSpec := range clientSpecs { 215 | b0.Write4b(uint32(clientSpec)) 216 | } 217 | b0.End() 218 | return 219 | } 220 | 221 | // #WREQ 222 | func encodeGetContext(context Context) (b x.RequestBody) { 223 | b.AddBlock(1). 224 | Write4b(uint32(context)). 225 | End() 226 | return 227 | } 228 | 229 | type GetContextReply struct { 230 | Enabled bool 231 | ElementHeader ElementHeader 232 | InterceptedClients []ClientInfo 233 | } 234 | 235 | func readGetContextReply(r *x.Reader, v *GetContextReply) error { 236 | if !r.RemainAtLeast4b(4) { 237 | return x.ErrDataLenShort 238 | } 239 | enabled, _ := r.ReadReplyHeader() 240 | v.Enabled = x.Uint8ToBool(enabled) 241 | 242 | v.ElementHeader = ElementHeader(r.Read1b()) 243 | r.ReadPad(3) 244 | 245 | interceptedClientsLen := int(r.Read4b()) // 4 246 | 247 | if interceptedClientsLen > 0 { 248 | v.InterceptedClients = make([]ClientInfo, interceptedClientsLen) 249 | for i := 0; i < interceptedClientsLen; i++ { 250 | err := readClientInfo(r, &v.InterceptedClients[i]) 251 | if err != nil { 252 | return err 253 | } 254 | } 255 | } 256 | return nil 257 | } 258 | 259 | // #WREQ 260 | func encodeEnableContext(context Context) (b x.RequestBody) { 261 | b.AddBlock(1). 262 | Write4b(uint32(context)). 263 | End() 264 | return 265 | } 266 | 267 | type EnableContextReply struct { 268 | Category uint8 269 | ElementHeader ElementHeader 270 | ClientSwapped bool 271 | XidBase uint32 272 | ServerTime x.Timestamp 273 | RecSequenceNum uint32 274 | Data []uint8 275 | } 276 | 277 | func readEnableContextReply(r *x.Reader, v *EnableContextReply) error { 278 | if !r.RemainAtLeast4b(8) { 279 | return x.ErrDataLenShort 280 | } 281 | var replyLen uint32 282 | v.Category, replyLen = r.ReadReplyHeader() // 2 283 | 284 | v.ElementHeader = ElementHeader(r.Read1b()) 285 | v.ClientSwapped = r.ReadBool() 286 | r.ReadPad(2) // 3 287 | 288 | v.XidBase = r.Read4b() 289 | 290 | v.ServerTime = x.Timestamp(r.Read4b()) 291 | 292 | v.RecSequenceNum = r.Read4b() // 6 293 | 294 | // unused 295 | r.ReadPad(8) // 8 296 | 297 | dataLen := 4 * int(replyLen) 298 | var err error 299 | v.Data, err = r.ReadBytes(dataLen) 300 | return err 301 | } 302 | 303 | // #WREQ 304 | func encodeDisableContext(context Context) (b x.RequestBody) { 305 | b.AddBlock(1). 306 | Write4b(uint32(context)). 307 | End() 308 | return 309 | } 310 | 311 | // #WREQ 312 | func encodeFreeContext(context Context) (b x.RequestBody) { 313 | b.AddBlock(1). 314 | Write4b(uint32(context)). 315 | End() 316 | return 317 | } 318 | -------------------------------------------------------------------------------- /ext/record/record_req_auto.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package record 6 | 7 | import x "github.com/linuxdeepin/go-x11-client" 8 | 9 | func QueryVersion(conn *x.Conn, majorVersion, minorVersion uint16) QueryVersionCookie { 10 | body := encodeQueryVersion(majorVersion, minorVersion) 11 | req := &x.ProtocolRequest{ 12 | Ext: _ext, 13 | Header: x.RequestHeader{ 14 | Data: QueryVersionOpcode, 15 | }, 16 | Body: body, 17 | } 18 | seq := conn.SendRequest(x.RequestChecked, req) 19 | return QueryVersionCookie(seq) 20 | } 21 | 22 | func (cookie QueryVersionCookie) Reply(conn *x.Conn) (*QueryVersionReply, error) { 23 | replyBuf, err := conn.WaitForReply(x.SeqNum(cookie)) 24 | if err != nil { 25 | return nil, err 26 | } 27 | r := x.NewReaderFromData(replyBuf) 28 | var reply QueryVersionReply 29 | err = readQueryVersionReply(r, &reply) 30 | if err != nil { 31 | return nil, err 32 | } 33 | return &reply, nil 34 | } 35 | 36 | func CreateContext(conn *x.Conn, context Context, elementHeader ElementHeader, clientSpecs []ClientSpec, ranges []Range) { 37 | body := encodeCreateContext(context, elementHeader, clientSpecs, ranges) 38 | req := &x.ProtocolRequest{ 39 | Ext: _ext, 40 | NoReply: true, 41 | Header: x.RequestHeader{ 42 | Data: CreateContextOpcode, 43 | }, 44 | Body: body, 45 | } 46 | conn.SendRequest(0, req) 47 | } 48 | 49 | func CreateContextChecked(conn *x.Conn, context Context, elementHeader ElementHeader, clientSpecs []ClientSpec, ranges []Range) x.VoidCookie { 50 | body := encodeCreateContext(context, elementHeader, clientSpecs, ranges) 51 | req := &x.ProtocolRequest{ 52 | Ext: _ext, 53 | NoReply: true, 54 | Header: x.RequestHeader{ 55 | Data: CreateContextOpcode, 56 | }, 57 | Body: body, 58 | } 59 | seq := conn.SendRequest(x.RequestChecked, req) 60 | return x.VoidCookie(seq) 61 | } 62 | 63 | func RegisterClients(conn *x.Conn, context Context, elementHeader ElementHeader, clientSpecs []ClientSpec, ranges []Range) { 64 | body := encodeRegisterClients(context, elementHeader, clientSpecs, ranges) 65 | req := &x.ProtocolRequest{ 66 | Ext: _ext, 67 | NoReply: true, 68 | Header: x.RequestHeader{ 69 | Data: RegisterClientsOpcode, 70 | }, 71 | Body: body, 72 | } 73 | conn.SendRequest(0, req) 74 | } 75 | 76 | func RegisterClientsChecked(conn *x.Conn, context Context, elementHeader ElementHeader, clientSpecs []ClientSpec, ranges []Range) x.VoidCookie { 77 | body := encodeRegisterClients(context, elementHeader, clientSpecs, ranges) 78 | req := &x.ProtocolRequest{ 79 | Ext: _ext, 80 | NoReply: true, 81 | Header: x.RequestHeader{ 82 | Data: RegisterClientsOpcode, 83 | }, 84 | Body: body, 85 | } 86 | seq := conn.SendRequest(x.RequestChecked, req) 87 | return x.VoidCookie(seq) 88 | } 89 | 90 | func UnregisterClients(conn *x.Conn, context Context, clientSpecs []ClientSpec) { 91 | body := encodeUnregisterClients(context, clientSpecs) 92 | req := &x.ProtocolRequest{ 93 | Ext: _ext, 94 | NoReply: true, 95 | Header: x.RequestHeader{ 96 | Data: UnregisterClientsOpcode, 97 | }, 98 | Body: body, 99 | } 100 | conn.SendRequest(0, req) 101 | } 102 | 103 | func UnregisterClientsChecked(conn *x.Conn, context Context, clientSpecs []ClientSpec) x.VoidCookie { 104 | body := encodeUnregisterClients(context, clientSpecs) 105 | req := &x.ProtocolRequest{ 106 | Ext: _ext, 107 | NoReply: true, 108 | Header: x.RequestHeader{ 109 | Data: UnregisterClientsOpcode, 110 | }, 111 | Body: body, 112 | } 113 | seq := conn.SendRequest(x.RequestChecked, req) 114 | return x.VoidCookie(seq) 115 | } 116 | 117 | func GetContext(conn *x.Conn, context Context) GetContextCookie { 118 | body := encodeGetContext(context) 119 | req := &x.ProtocolRequest{ 120 | Ext: _ext, 121 | Header: x.RequestHeader{ 122 | Data: GetContextOpcode, 123 | }, 124 | Body: body, 125 | } 126 | seq := conn.SendRequest(x.RequestChecked, req) 127 | return GetContextCookie(seq) 128 | } 129 | 130 | func (cookie GetContextCookie) Reply(conn *x.Conn) (*GetContextReply, error) { 131 | replyBuf, err := conn.WaitForReply(x.SeqNum(cookie)) 132 | if err != nil { 133 | return nil, err 134 | } 135 | r := x.NewReaderFromData(replyBuf) 136 | var reply GetContextReply 137 | err = readGetContextReply(r, &reply) 138 | if err != nil { 139 | return nil, err 140 | } 141 | return &reply, nil 142 | } 143 | 144 | func EnableContext(conn *x.Conn, context Context) EnableContextCookie { 145 | body := encodeEnableContext(context) 146 | req := &x.ProtocolRequest{ 147 | Ext: _ext, 148 | Header: x.RequestHeader{ 149 | Data: EnableContextOpcode, 150 | }, 151 | Body: body, 152 | } 153 | seq := conn.SendRequest(x.RequestChecked, req) 154 | return EnableContextCookie(seq) 155 | } 156 | 157 | func (cookie EnableContextCookie) Reply(conn *x.Conn) (*EnableContextReply, error) { 158 | replyBuf, err := conn.WaitForReply(x.SeqNum(cookie)) 159 | if err != nil { 160 | return nil, err 161 | } 162 | r := x.NewReaderFromData(replyBuf) 163 | var reply EnableContextReply 164 | err = readEnableContextReply(r, &reply) 165 | if err != nil { 166 | return nil, err 167 | } 168 | return &reply, nil 169 | } 170 | 171 | func DisableContext(conn *x.Conn, context Context) { 172 | body := encodeDisableContext(context) 173 | req := &x.ProtocolRequest{ 174 | Ext: _ext, 175 | NoReply: true, 176 | Header: x.RequestHeader{ 177 | Data: DisableContextOpcode, 178 | }, 179 | Body: body, 180 | } 181 | conn.SendRequest(0, req) 182 | } 183 | 184 | func DisableContextChecked(conn *x.Conn, context Context) x.VoidCookie { 185 | body := encodeDisableContext(context) 186 | req := &x.ProtocolRequest{ 187 | Ext: _ext, 188 | NoReply: true, 189 | Header: x.RequestHeader{ 190 | Data: DisableContextOpcode, 191 | }, 192 | Body: body, 193 | } 194 | seq := conn.SendRequest(x.RequestChecked, req) 195 | return x.VoidCookie(seq) 196 | } 197 | 198 | func FreeContext(conn *x.Conn, context Context) { 199 | body := encodeFreeContext(context) 200 | req := &x.ProtocolRequest{ 201 | Ext: _ext, 202 | NoReply: true, 203 | Header: x.RequestHeader{ 204 | Data: FreeContextOpcode, 205 | }, 206 | Body: body, 207 | } 208 | conn.SendRequest(0, req) 209 | } 210 | 211 | func FreeContextChecked(conn *x.Conn, context Context) x.VoidCookie { 212 | body := encodeFreeContext(context) 213 | req := &x.ProtocolRequest{ 214 | Ext: _ext, 215 | NoReply: true, 216 | Header: x.RequestHeader{ 217 | Data: FreeContextOpcode, 218 | }, 219 | Body: body, 220 | } 221 | seq := conn.SendRequest(x.RequestChecked, req) 222 | return x.VoidCookie(seq) 223 | } 224 | -------------------------------------------------------------------------------- /ext/render/auto.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package render 6 | 7 | import x "github.com/linuxdeepin/go-x11-client" 8 | 9 | // _ns.ext_name: Render 10 | const MajorVersion = 0 11 | const MinorVersion = 11 12 | 13 | var _ext *x.Extension 14 | 15 | func Ext() *x.Extension { 16 | return _ext 17 | } 18 | 19 | // enum PictType 20 | const ( 21 | PictTypeIndexed = 0 22 | PictTypeDirect = 1 23 | ) 24 | 25 | // enum Picture 26 | const ( 27 | PictureNone = 0 28 | ) 29 | 30 | // enum PictOp 31 | const ( 32 | PictOpClear = 0 33 | PictOpSrc = 1 34 | PictOpDst = 2 35 | PictOpOver = 3 36 | PictOpOverReverse = 4 37 | PictOpIn = 5 38 | PictOpInReverse = 6 39 | PictOpOut = 7 40 | PictOpOutReverse = 8 41 | PictOpAtop = 9 42 | PictOpAtopReverse = 10 43 | PictOpXor = 11 44 | PictOpAdd = 12 45 | PictOpSaturate = 13 46 | PictOpDisjointClear = 16 47 | PictOpDisjointSrc = 17 48 | PictOpDisjointDst = 18 49 | PictOpDisjointOver = 19 50 | PictOpDisjointOverReverse = 20 51 | PictOpDisjointIn = 21 52 | PictOpDisjointInReverse = 22 53 | PictOpDisjointOut = 23 54 | PictOpDisjointOutReverse = 24 55 | PictOpDisjointAtop = 25 56 | PictOpDisjointAtopReverse = 26 57 | PictOpDisjointXor = 27 58 | PictOpConjointClear = 32 59 | PictOpConjointSrc = 33 60 | PictOpConjointDst = 34 61 | PictOpConjointOver = 35 62 | PictOpConjointOverReverse = 36 63 | PictOpConjointIn = 37 64 | PictOpConjointInReverse = 38 65 | PictOpConjointOut = 39 66 | PictOpConjointOutReverse = 40 67 | PictOpConjointAtop = 41 68 | PictOpConjointAtopReverse = 42 69 | PictOpConjointXor = 43 70 | PictOpMultiply = 48 71 | PictOpScreen = 49 72 | PictOpOverlay = 50 73 | PictOpDarken = 51 74 | PictOpLighten = 52 75 | PictOpColorDodge = 53 76 | PictOpColorBurn = 54 77 | PictOpHardLight = 55 78 | PictOpSoftLight = 56 79 | PictOpDifference = 57 80 | PictOpExclusion = 58 81 | PictOpHSLHue = 59 82 | PictOpHSLSaturation = 60 83 | PictOpHSLColor = 61 84 | PictOpHSLLuminosity = 62 85 | ) 86 | 87 | // enum PolyEdge 88 | const ( 89 | PolyEdgeSharp = 0 90 | PolyEdgeSmooth = 1 91 | ) 92 | 93 | // enum PolyMode 94 | const ( 95 | PolyModePrecise = 0 96 | PolyModeImprecise = 1 97 | ) 98 | 99 | // enum CP 100 | const ( 101 | CPRepeat = 1 102 | CPAlphaMap = 2 103 | CPAlphaXOrigin = 4 104 | CPAlphaYOrigin = 8 105 | CPClipXOrigin = 16 106 | CPClipYOrigin = 32 107 | CPClipMask = 64 108 | CPGraphicsExposure = 128 109 | CPSubwindowMode = 256 110 | CPPolyEdge = 512 111 | CPPolyMode = 1024 112 | CPDither = 2048 113 | CPComponentAlpha = 4096 114 | ) 115 | 116 | // enum SubPixel 117 | const ( 118 | SubPixelUnknown = 0 119 | SubPixelHorizontalRGB = 1 120 | SubPixelHorizontalBGR = 2 121 | SubPixelVerticalRGB = 3 122 | SubPixelVerticalBGR = 4 123 | SubPixelNone = 5 124 | ) 125 | 126 | // enum Repeat 127 | const ( 128 | RepeatNone = 0 129 | RepeatNormal = 1 130 | RepeatPad = 2 131 | RepeatReflect = 3 132 | ) 133 | 134 | // simple ('xcb', 'Render', 'GLYPH') 135 | type Glyph uint32 136 | 137 | // simple ('xcb', 'Render', 'GLYPHSET') 138 | type GlyphSet uint32 139 | 140 | // simple ('xcb', 'Render', 'PICTURE') 141 | type Picture uint32 142 | 143 | // simple ('xcb', 'Render', 'PICTFORMAT') 144 | type PictFormat uint32 145 | 146 | // simple ('xcb', 'Render', 'FIXED') 147 | type Fixed int32 148 | 149 | const PictFormatErrorCode = 0 150 | const PictureErrorCode = 1 151 | const PictOpErrorCode = 2 152 | const GlyphSetErrorCode = 3 153 | const GlyphErrorCode = 4 154 | const QueryVersionOpcode = 0 155 | 156 | type QueryVersionCookie x.SeqNum 157 | 158 | const QueryPictFormatsOpcode = 1 159 | 160 | type QueryPictFormatsCookie x.SeqNum 161 | 162 | const QueryPictIndexValuesOpcode = 2 163 | 164 | type QueryPictIndexValuesCookie x.SeqNum 165 | 166 | const CreatePictureOpcode = 4 167 | const ChangePictureOpcode = 5 168 | const SetPictureClipRectanglesOpcode = 6 169 | const FreePictureOpcode = 7 170 | const CompositeOpcode = 8 171 | const TrapezoidsOpcode = 10 172 | const TrianglesOpcode = 11 173 | const TriStripOpcode = 12 174 | const TriFanOpcode = 13 175 | const CreateGlyphSetOpcode = 17 176 | const ReferenceGlyphSetOpcode = 18 177 | const FreeGlyphSetOpcode = 19 178 | const AddGlyphsOpcode = 20 179 | const FreeGlyphsOpcode = 22 180 | const CompositeGlyphs8Opcode = 23 181 | const CompositeGlyphs16Opcode = 24 182 | const CompositeGlyphs32Opcode = 25 183 | const FillRectanglesOpcode = 26 184 | const CreateCursorOpcode = 27 185 | const SetPictureTransformOpcode = 28 186 | const QueryFiltersOpcode = 29 187 | 188 | type QueryFiltersCookie x.SeqNum 189 | 190 | const SetPictureFilterOpcode = 30 191 | const CreateAnimCursorOpcode = 31 192 | const AddTrapsOpcode = 32 193 | const CreateSolidFillOpcode = 33 194 | const CreateLinearGradientOpcode = 34 195 | const CreateRadialGradientOpcode = 35 196 | const CreateConicalGradientOpcode = 36 197 | 198 | var errorCodeNameMap = map[uint8]string{ 199 | PictFormatErrorCode: "BadPictFormat", 200 | PictureErrorCode: "BadPicture", 201 | PictOpErrorCode: "BadPictOp", 202 | GlyphSetErrorCode: "BadGlyphSet", 203 | GlyphErrorCode: "BadGlyph", 204 | } 205 | var requestOpcodeNameMap = map[uint]string{ 206 | QueryVersionOpcode: "QueryVersion", 207 | QueryPictFormatsOpcode: "QueryPictFormats", 208 | QueryPictIndexValuesOpcode: "QueryPictIndexValues", 209 | CreatePictureOpcode: "CreatePicture", 210 | ChangePictureOpcode: "ChangePicture", 211 | SetPictureClipRectanglesOpcode: "SetPictureClipRectangles", 212 | FreePictureOpcode: "FreePicture", 213 | CompositeOpcode: "Composite", 214 | TrapezoidsOpcode: "Trapezoids", 215 | TrianglesOpcode: "Triangles", 216 | TriStripOpcode: "TriStrip", 217 | TriFanOpcode: "TriFan", 218 | CreateGlyphSetOpcode: "CreateGlyphSet", 219 | ReferenceGlyphSetOpcode: "ReferenceGlyphSet", 220 | FreeGlyphSetOpcode: "FreeGlyphSet", 221 | AddGlyphsOpcode: "AddGlyphs", 222 | FreeGlyphsOpcode: "FreeGlyphs", 223 | CompositeGlyphs8Opcode: "CompositeGlyphs8", 224 | CompositeGlyphs16Opcode: "CompositeGlyphs16", 225 | CompositeGlyphs32Opcode: "CompositeGlyphs32", 226 | FillRectanglesOpcode: "FillRectangles", 227 | CreateCursorOpcode: "CreateCursor", 228 | SetPictureTransformOpcode: "SetPictureTransform", 229 | QueryFiltersOpcode: "QueryFilters", 230 | SetPictureFilterOpcode: "SetPictureFilter", 231 | CreateAnimCursorOpcode: "CreateAnimCursor", 232 | AddTrapsOpcode: "AddTraps", 233 | CreateSolidFillOpcode: "CreateSolidFill", 234 | CreateLinearGradientOpcode: "CreateLinearGradient", 235 | CreateRadialGradientOpcode: "CreateRadialGradient", 236 | CreateConicalGradientOpcode: "CreateConicalGradient", 237 | } 238 | 239 | func init() { 240 | _ext = x.NewExtension("RENDER", 4, errorCodeNameMap, requestOpcodeNameMap) 241 | } 242 | -------------------------------------------------------------------------------- /ext/screensaver/auto.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package screensaver 6 | 7 | import x "github.com/linuxdeepin/go-x11-client" 8 | 9 | // _ns.ext_name: ScreenSaver 10 | const MajorVersion = 1 11 | const MinorVersion = 1 12 | 13 | var _ext *x.Extension 14 | 15 | func Ext() *x.Extension { 16 | return _ext 17 | } 18 | 19 | // enum Kind 20 | const ( 21 | KindBlanked = 0 22 | KindInternal = 1 23 | KindExternal = 2 24 | ) 25 | 26 | // enum Event 27 | const ( 28 | EventNotifyMask = 1 29 | EventCycleMask = 2 30 | ) 31 | 32 | // enum State 33 | const ( 34 | StateOff = 0 35 | StateOn = 1 36 | StateCycle = 2 37 | StateDisabled = 3 38 | ) 39 | 40 | const QueryVersionOpcode = 0 41 | 42 | type QueryVersionCookie x.SeqNum 43 | 44 | const QueryInfoOpcode = 1 45 | 46 | type QueryInfoCookie x.SeqNum 47 | 48 | const SelectInputOpcode = 2 49 | const SetAttributesOpcode = 3 50 | const UnsetAttributesOpcode = 4 51 | const SuspendOpcode = 5 52 | const NotifyEventCode = 0 53 | 54 | func NewNotifyEvent(data []byte) (*NotifyEvent, error) { 55 | var ev NotifyEvent 56 | r := x.NewReaderFromData(data) 57 | err := readNotifyEvent(r, &ev) 58 | if err != nil { 59 | return nil, err 60 | } 61 | return &ev, nil 62 | } 63 | 64 | var requestOpcodeNameMap = map[uint]string{ 65 | QueryVersionOpcode: "QueryVersion", 66 | QueryInfoOpcode: "QueryInfo", 67 | SelectInputOpcode: "SelectInput", 68 | SetAttributesOpcode: "SetAttributes", 69 | UnsetAttributesOpcode: "UnsetAttributes", 70 | SuspendOpcode: "Suspend", 71 | } 72 | 73 | func init() { 74 | _ext = x.NewExtension("MIT-SCREEN-SAVER", 0, nil, requestOpcodeNameMap) 75 | } 76 | -------------------------------------------------------------------------------- /ext/screensaver/screensaver.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package screensaver 6 | 7 | import "github.com/linuxdeepin/go-x11-client" 8 | 9 | type NotifyEvent struct { 10 | State uint8 11 | Sequence uint16 12 | Time x.Timestamp 13 | Root x.Window 14 | Window x.Window 15 | Kind uint8 16 | Forced bool 17 | } 18 | 19 | func readNotifyEvent(r *x.Reader, v *NotifyEvent) error { 20 | if !r.RemainAtLeast4b(5) { 21 | return x.ErrDataLenShort 22 | } 23 | v.State, v.Sequence = r.ReadEventHeader() 24 | 25 | v.Time = x.Timestamp(r.Read4b()) 26 | 27 | v.Root = x.Window(r.Read4b()) 28 | 29 | v.Window = x.Window(r.Read4b()) 30 | 31 | v.Kind = r.Read1b() 32 | v.Forced = r.ReadBool() // 5 33 | 34 | return nil 35 | } 36 | 37 | // #WREQ 38 | func encodeQueryVersion(clientMajorVersion, clientMinorVersion uint8) (b x.RequestBody) { 39 | b.AddBlock(1). 40 | Write1b(clientMajorVersion). 41 | Write1b(clientMinorVersion). 42 | WritePad(2). 43 | End() 44 | return 45 | } 46 | 47 | type QueryVersionReply struct { 48 | ServerMajorVersion uint16 49 | ServerMinorVersion uint16 50 | } 51 | 52 | func readQueryVersionReply(r *x.Reader, v *QueryVersionReply) error { 53 | if !r.RemainAtLeast4b(3) { 54 | return x.ErrDataLenShort 55 | } 56 | r.ReadPad(8) 57 | 58 | v.ServerMajorVersion = r.Read2b() 59 | v.ServerMinorVersion = r.Read2b() // 3 60 | 61 | return nil 62 | } 63 | 64 | // #WREQ 65 | func encodeQueryInfo(drawable x.Drawable) (b x.RequestBody) { 66 | b.AddBlock(1). 67 | Write4b(uint32(drawable)). 68 | End() 69 | return 70 | } 71 | 72 | type QueryInfoReply struct { 73 | State uint8 74 | SaverWindow x.Window 75 | MsUntilServer uint32 76 | MsSinceUserInput uint32 77 | EventMask uint32 78 | Kind uint8 79 | } 80 | 81 | func readQueryInfoReply(r *x.Reader, v *QueryInfoReply) error { 82 | if !r.RemainAtLeast4b(7) { 83 | return x.ErrDataLenShort 84 | } 85 | v.State, _ = r.ReadReplyHeader() 86 | 87 | v.SaverWindow = x.Window(r.Read4b()) 88 | 89 | v.MsUntilServer = r.Read4b() 90 | 91 | v.MsSinceUserInput = r.Read4b() 92 | 93 | v.EventMask = r.Read4b() // 6 94 | 95 | v.Kind = r.Read1b() // 7 96 | 97 | return nil 98 | } 99 | 100 | // #WREQ 101 | func encodeSelectInput(drawable x.Drawable, eventMask uint32) (b x.RequestBody) { 102 | b.AddBlock(2). 103 | Write4b(uint32(drawable)). 104 | Write4b(eventMask). 105 | End() 106 | return 107 | } 108 | 109 | // #WREQ 110 | func encodeSetAttributes(drawable x.Drawable, X, y int16, width, height, 111 | boardWidth uint16, class, depth uint8, visual x.VisualID, valueMask uint32, 112 | valueList []uint32) (b x.RequestBody) { 113 | 114 | b0 := b.AddBlock(6 + len(valueList)). 115 | Write4b(uint32(drawable)). 116 | Write2b(uint16(X)). 117 | Write2b(uint16(y)). 118 | Write2b(width). 119 | Write2b(height). 120 | Write2b(boardWidth). 121 | Write1b(class). 122 | Write1b(depth). 123 | Write4b(uint32(visual)). 124 | Write4b(valueMask) 125 | 126 | for _, value := range valueList { 127 | b0.Write4b(value) 128 | } 129 | b0.End() 130 | return 131 | } 132 | 133 | // #WREQ 134 | func encodeUnsetAttributes(drawable x.Drawable) (b x.RequestBody) { 135 | b.AddBlock(1). 136 | Write4b(uint32(drawable)). 137 | End() 138 | return 139 | } 140 | 141 | // #WREQ 142 | func encodeSuspend(suspend bool) (b x.RequestBody) { 143 | b.AddBlock(1). 144 | WriteBool(suspend). 145 | WritePad(3). 146 | End() 147 | return 148 | } 149 | -------------------------------------------------------------------------------- /ext/screensaver/screensaver_req_auto.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package screensaver 6 | 7 | import x "github.com/linuxdeepin/go-x11-client" 8 | 9 | func QueryVersion(conn *x.Conn, clientMajorVersion, clientMinorVersion uint8) QueryVersionCookie { 10 | body := encodeQueryVersion(clientMajorVersion, clientMinorVersion) 11 | req := &x.ProtocolRequest{ 12 | Ext: _ext, 13 | Header: x.RequestHeader{ 14 | Data: QueryVersionOpcode, 15 | }, 16 | Body: body, 17 | } 18 | seq := conn.SendRequest(x.RequestChecked, req) 19 | return QueryVersionCookie(seq) 20 | } 21 | 22 | func (cookie QueryVersionCookie) Reply(conn *x.Conn) (*QueryVersionReply, error) { 23 | replyBuf, err := conn.WaitForReply(x.SeqNum(cookie)) 24 | if err != nil { 25 | return nil, err 26 | } 27 | r := x.NewReaderFromData(replyBuf) 28 | var reply QueryVersionReply 29 | err = readQueryVersionReply(r, &reply) 30 | if err != nil { 31 | return nil, err 32 | } 33 | return &reply, nil 34 | } 35 | 36 | func QueryInfo(conn *x.Conn, drawable x.Drawable) QueryInfoCookie { 37 | body := encodeQueryInfo(drawable) 38 | req := &x.ProtocolRequest{ 39 | Ext: _ext, 40 | Header: x.RequestHeader{ 41 | Data: QueryInfoOpcode, 42 | }, 43 | Body: body, 44 | } 45 | seq := conn.SendRequest(x.RequestChecked, req) 46 | return QueryInfoCookie(seq) 47 | } 48 | 49 | func (cookie QueryInfoCookie) Reply(conn *x.Conn) (*QueryInfoReply, error) { 50 | replyBuf, err := conn.WaitForReply(x.SeqNum(cookie)) 51 | if err != nil { 52 | return nil, err 53 | } 54 | r := x.NewReaderFromData(replyBuf) 55 | var reply QueryInfoReply 56 | err = readQueryInfoReply(r, &reply) 57 | if err != nil { 58 | return nil, err 59 | } 60 | return &reply, nil 61 | } 62 | 63 | func SelectInput(conn *x.Conn, drawable x.Drawable, eventMask uint32) { 64 | body := encodeSelectInput(drawable, eventMask) 65 | req := &x.ProtocolRequest{ 66 | Ext: _ext, 67 | NoReply: true, 68 | Header: x.RequestHeader{ 69 | Data: SelectInputOpcode, 70 | }, 71 | Body: body, 72 | } 73 | conn.SendRequest(0, req) 74 | } 75 | 76 | func SelectInputChecked(conn *x.Conn, drawable x.Drawable, eventMask uint32) x.VoidCookie { 77 | body := encodeSelectInput(drawable, eventMask) 78 | req := &x.ProtocolRequest{ 79 | Ext: _ext, 80 | NoReply: true, 81 | Header: x.RequestHeader{ 82 | Data: SelectInputOpcode, 83 | }, 84 | Body: body, 85 | } 86 | seq := conn.SendRequest(x.RequestChecked, req) 87 | return x.VoidCookie(seq) 88 | } 89 | 90 | func SetAttributes(conn *x.Conn, drawable x.Drawable, X, y int16, width, height, boardWidth uint16, class, depth uint8, visual x.VisualID, valueMask uint32, valueList []uint32) { 91 | body := encodeSetAttributes(drawable, X, y, width, height, boardWidth, class, depth, visual, valueMask, valueList) 92 | req := &x.ProtocolRequest{ 93 | Ext: _ext, 94 | NoReply: true, 95 | Header: x.RequestHeader{ 96 | Data: SetAttributesOpcode, 97 | }, 98 | Body: body, 99 | } 100 | conn.SendRequest(0, req) 101 | } 102 | 103 | func SetAttributesChecked(conn *x.Conn, drawable x.Drawable, X, y int16, width, height, boardWidth uint16, class, depth uint8, visual x.VisualID, valueMask uint32, valueList []uint32) x.VoidCookie { 104 | body := encodeSetAttributes(drawable, X, y, width, height, boardWidth, class, depth, visual, valueMask, valueList) 105 | req := &x.ProtocolRequest{ 106 | Ext: _ext, 107 | NoReply: true, 108 | Header: x.RequestHeader{ 109 | Data: SetAttributesOpcode, 110 | }, 111 | Body: body, 112 | } 113 | seq := conn.SendRequest(x.RequestChecked, req) 114 | return x.VoidCookie(seq) 115 | } 116 | 117 | func UnsetAttributes(conn *x.Conn, drawable x.Drawable) { 118 | body := encodeUnsetAttributes(drawable) 119 | req := &x.ProtocolRequest{ 120 | Ext: _ext, 121 | NoReply: true, 122 | Header: x.RequestHeader{ 123 | Data: UnsetAttributesOpcode, 124 | }, 125 | Body: body, 126 | } 127 | conn.SendRequest(0, req) 128 | } 129 | 130 | func UnsetAttributesChecked(conn *x.Conn, drawable x.Drawable) x.VoidCookie { 131 | body := encodeUnsetAttributes(drawable) 132 | req := &x.ProtocolRequest{ 133 | Ext: _ext, 134 | NoReply: true, 135 | Header: x.RequestHeader{ 136 | Data: UnsetAttributesOpcode, 137 | }, 138 | Body: body, 139 | } 140 | seq := conn.SendRequest(x.RequestChecked, req) 141 | return x.VoidCookie(seq) 142 | } 143 | 144 | func Suspend(conn *x.Conn, suspend bool) { 145 | body := encodeSuspend(suspend) 146 | req := &x.ProtocolRequest{ 147 | Ext: _ext, 148 | NoReply: true, 149 | Header: x.RequestHeader{ 150 | Data: SuspendOpcode, 151 | }, 152 | Body: body, 153 | } 154 | conn.SendRequest(0, req) 155 | } 156 | 157 | func SuspendChecked(conn *x.Conn, suspend bool) x.VoidCookie { 158 | body := encodeSuspend(suspend) 159 | req := &x.ProtocolRequest{ 160 | Ext: _ext, 161 | NoReply: true, 162 | Header: x.RequestHeader{ 163 | Data: SuspendOpcode, 164 | }, 165 | Body: body, 166 | } 167 | seq := conn.SendRequest(x.RequestChecked, req) 168 | return x.VoidCookie(seq) 169 | } 170 | -------------------------------------------------------------------------------- /ext/shm/auto.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package shm 6 | 7 | import x "github.com/linuxdeepin/go-x11-client" 8 | 9 | // _ns.ext_name: Shm 10 | const MajorVersion = 1 11 | const MinorVersion = 2 12 | 13 | var _ext *x.Extension 14 | 15 | func Ext() *x.Extension { 16 | return _ext 17 | } 18 | 19 | // simple ('xcb', 'Shm', 'SEG') 20 | type Seg uint32 21 | 22 | const CompletionEventCode = 0 23 | 24 | func NewCompletionEvent(data []byte) (*CompletionEvent, error) { 25 | var ev CompletionEvent 26 | r := x.NewReaderFromData(data) 27 | err := readCompletionEvent(r, &ev) 28 | if err != nil { 29 | return nil, err 30 | } 31 | return &ev, nil 32 | } 33 | 34 | const BadSegErrorCode = 0 35 | const QueryVersionOpcode = 0 36 | 37 | type QueryVersionCookie x.SeqNum 38 | 39 | const AttachOpcode = 1 40 | const DetachOpcode = 2 41 | const PutImageOpcode = 3 42 | const GetImageOpcode = 4 43 | 44 | type GetImageCookie x.SeqNum 45 | 46 | const CreatePixmapOpcode = 5 47 | const AttachFdOpcode = 6 48 | const CreateSegmentOpcode = 7 49 | 50 | type CreateSegmentCookie x.SeqNum 51 | 52 | var errorCodeNameMap = map[uint8]string{ 53 | BadSegErrorCode: "BadSeg", 54 | } 55 | var requestOpcodeNameMap = map[uint]string{ 56 | QueryVersionOpcode: "QueryVersion", 57 | AttachOpcode: "Attach", 58 | DetachOpcode: "Detach", 59 | PutImageOpcode: "PutImage", 60 | GetImageOpcode: "GetImage", 61 | CreatePixmapOpcode: "CreatePixmap", 62 | AttachFdOpcode: "AttachFd", 63 | CreateSegmentOpcode: "CreateSegment", 64 | } 65 | 66 | func init() { 67 | _ext = x.NewExtension("MIT-SHM", 0, errorCodeNameMap, requestOpcodeNameMap) 68 | } 69 | -------------------------------------------------------------------------------- /ext/shm/shm.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package shm 6 | 7 | import "github.com/linuxdeepin/go-x11-client" 8 | 9 | type CompletionEvent struct { 10 | Sequence uint16 11 | } 12 | 13 | func readCompletionEvent(r *x.Reader, v *CompletionEvent) error { 14 | if !r.RemainAtLeast4b(1) { 15 | return x.ErrDataLenShort 16 | } 17 | _, v.Sequence = r.ReadEventHeader() 18 | return nil 19 | } 20 | 21 | // #WREQ 22 | func encodeQueryVersion() (b x.RequestBody) { 23 | return 24 | } 25 | 26 | type QueryVersionReply struct { 27 | SharedPixmaps bool 28 | MajorVersion uint16 29 | MinorVersion uint16 30 | Uid uint16 31 | Gid uint16 32 | PixmapFormat uint8 33 | } 34 | 35 | func readQueryVersionReply(r *x.Reader, v *QueryVersionReply) error { 36 | if !r.RemainAtLeast4b(5) { 37 | return x.ErrDataLenShort 38 | } 39 | sharedPixmaps, _ := r.ReadReplyHeader() 40 | v.SharedPixmaps = x.Uint8ToBool(sharedPixmaps) 41 | 42 | v.MajorVersion = r.Read2b() 43 | v.MinorVersion = r.Read2b() 44 | 45 | v.Uid = r.Read2b() 46 | v.Gid = r.Read2b() 47 | 48 | v.PixmapFormat = r.Read1b() // 5 49 | 50 | return nil 51 | } 52 | 53 | // #WREQ 54 | func encodeAttach(shmSeg Seg, shmId uint32, readOnly bool) (b x.RequestBody) { 55 | b.AddBlock(3). 56 | Write4b(uint32(shmSeg)). 57 | Write4b(shmId). 58 | WriteBool(readOnly). 59 | WritePad(3). 60 | End() 61 | return 62 | } 63 | 64 | // #WREQ 65 | func encodeDetach(shmSeg Seg) (b x.RequestBody) { 66 | b.AddBlock(1). 67 | Write4b(uint32(shmSeg)). 68 | End() 69 | return 70 | } 71 | 72 | // #WREQ 73 | func encodePutImage(drawable x.Drawable, gc x.GContext, totalWidth, 74 | totalHeight, srcX, srcY, srcWidth, srcHeight uint16, dstX, dstY int16, 75 | depth, format uint8, sendEvent bool, shmSeg Seg, offset uint32) (b x.RequestBody) { 76 | 77 | b.AddBlock(9). 78 | Write4b(uint32(drawable)). 79 | Write4b(uint32(gc)). 80 | Write2b(totalWidth). 81 | Write2b(totalHeight). 82 | Write2b(srcX). 83 | Write2b(srcY). 84 | Write2b(srcWidth). 85 | Write2b(srcHeight). 86 | Write2b(uint16(dstX)). 87 | Write2b(uint16(dstY)). 88 | Write1b(depth). 89 | Write1b(format). 90 | WriteBool(sendEvent). 91 | WritePad(1). 92 | Write4b(uint32(shmSeg)). 93 | Write4b(offset). 94 | End() 95 | return 96 | } 97 | 98 | // #WREQ 99 | func encodeGetImage(drawable x.Drawable, X, y int16, width, height uint16, 100 | planeMask uint32, format uint8, shmSeg Seg, offset uint32) (b x.RequestBody) { 101 | b.AddBlock(7). 102 | Write4b(uint32(drawable)). 103 | Write2b(uint16(X)). 104 | Write2b(uint16(y)). 105 | Write2b(width). 106 | Write2b(height). 107 | Write4b(planeMask). 108 | Write1b(format). 109 | WritePad(3). 110 | Write4b(uint32(shmSeg)). 111 | Write4b(offset). 112 | End() 113 | return 114 | } 115 | 116 | type GetImageReply struct { 117 | Depth uint8 118 | Visual x.VisualID 119 | Size uint32 120 | } 121 | 122 | func readGetImageReply(r *x.Reader, v *GetImageReply) error { 123 | if !r.RemainAtLeast4b(4) { 124 | return x.ErrDataLenShort 125 | } 126 | v.Depth, _ = r.ReadReplyHeader() 127 | 128 | v.Visual = x.VisualID(r.Read4b()) 129 | 130 | v.Size = r.Read4b() // 4 131 | 132 | return nil 133 | } 134 | 135 | // #WREQ 136 | func encodeCreatePixmap(pid x.Pixmap, drawable x.Drawable, 137 | width, height uint16, depth uint8, shmSeg Seg, offset uint32) (b x.RequestBody) { 138 | b.AddBlock(6). 139 | Write4b(uint32(pid)). 140 | Write4b(uint32(drawable)). 141 | Write2b(width). 142 | Write2b(height). 143 | Write1b(depth). 144 | WritePad(3). 145 | Write4b(uint32(shmSeg)). 146 | Write4b(offset). 147 | End() 148 | return 149 | } 150 | -------------------------------------------------------------------------------- /ext/shm/shm_req_auto.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package shm 6 | 7 | import x "github.com/linuxdeepin/go-x11-client" 8 | 9 | func QueryVersion(conn *x.Conn) QueryVersionCookie { 10 | body := encodeQueryVersion() 11 | req := &x.ProtocolRequest{ 12 | Ext: _ext, 13 | Header: x.RequestHeader{ 14 | Data: QueryVersionOpcode, 15 | }, 16 | Body: body, 17 | } 18 | seq := conn.SendRequest(x.RequestChecked, req) 19 | return QueryVersionCookie(seq) 20 | } 21 | 22 | func (cookie QueryVersionCookie) Reply(conn *x.Conn) (*QueryVersionReply, error) { 23 | replyBuf, err := conn.WaitForReply(x.SeqNum(cookie)) 24 | if err != nil { 25 | return nil, err 26 | } 27 | r := x.NewReaderFromData(replyBuf) 28 | var reply QueryVersionReply 29 | err = readQueryVersionReply(r, &reply) 30 | if err != nil { 31 | return nil, err 32 | } 33 | return &reply, nil 34 | } 35 | 36 | func Attach(conn *x.Conn, shmSeg Seg, shmId uint32, readOnly bool) { 37 | body := encodeAttach(shmSeg, shmId, readOnly) 38 | req := &x.ProtocolRequest{ 39 | Ext: _ext, 40 | NoReply: true, 41 | Header: x.RequestHeader{ 42 | Data: AttachOpcode, 43 | }, 44 | Body: body, 45 | } 46 | conn.SendRequest(0, req) 47 | } 48 | 49 | func AttachChecked(conn *x.Conn, shmSeg Seg, shmId uint32, readOnly bool) x.VoidCookie { 50 | body := encodeAttach(shmSeg, shmId, readOnly) 51 | req := &x.ProtocolRequest{ 52 | Ext: _ext, 53 | NoReply: true, 54 | Header: x.RequestHeader{ 55 | Data: AttachOpcode, 56 | }, 57 | Body: body, 58 | } 59 | seq := conn.SendRequest(x.RequestChecked, req) 60 | return x.VoidCookie(seq) 61 | } 62 | 63 | func Detach(conn *x.Conn, shmSeg Seg) { 64 | body := encodeDetach(shmSeg) 65 | req := &x.ProtocolRequest{ 66 | Ext: _ext, 67 | NoReply: true, 68 | Header: x.RequestHeader{ 69 | Data: DetachOpcode, 70 | }, 71 | Body: body, 72 | } 73 | conn.SendRequest(0, req) 74 | } 75 | 76 | func DetachChecked(conn *x.Conn, shmSeg Seg) x.VoidCookie { 77 | body := encodeDetach(shmSeg) 78 | req := &x.ProtocolRequest{ 79 | Ext: _ext, 80 | NoReply: true, 81 | Header: x.RequestHeader{ 82 | Data: DetachOpcode, 83 | }, 84 | Body: body, 85 | } 86 | seq := conn.SendRequest(x.RequestChecked, req) 87 | return x.VoidCookie(seq) 88 | } 89 | 90 | func PutImage(conn *x.Conn, drawable x.Drawable, gc x.GContext, totalWidth, totalHeight, srcX, srcY, srcWidth, srcHeight uint16, dstX, dstY int16, depth, format uint8, sendEvent bool, shmSeg Seg, offset uint32) { 91 | body := encodePutImage(drawable, gc, totalWidth, totalHeight, srcX, srcY, srcWidth, srcHeight, dstX, dstY, depth, format, sendEvent, shmSeg, offset) 92 | req := &x.ProtocolRequest{ 93 | Ext: _ext, 94 | NoReply: true, 95 | Header: x.RequestHeader{ 96 | Data: PutImageOpcode, 97 | }, 98 | Body: body, 99 | } 100 | conn.SendRequest(0, req) 101 | } 102 | 103 | func PutImageChecked(conn *x.Conn, drawable x.Drawable, gc x.GContext, totalWidth, totalHeight, srcX, srcY, srcWidth, srcHeight uint16, dstX, dstY int16, depth, format uint8, sendEvent bool, shmSeg Seg, offset uint32) x.VoidCookie { 104 | body := encodePutImage(drawable, gc, totalWidth, totalHeight, srcX, srcY, srcWidth, srcHeight, dstX, dstY, depth, format, sendEvent, shmSeg, offset) 105 | req := &x.ProtocolRequest{ 106 | Ext: _ext, 107 | NoReply: true, 108 | Header: x.RequestHeader{ 109 | Data: PutImageOpcode, 110 | }, 111 | Body: body, 112 | } 113 | seq := conn.SendRequest(x.RequestChecked, req) 114 | return x.VoidCookie(seq) 115 | } 116 | 117 | func GetImage(conn *x.Conn, drawable x.Drawable, X, y int16, width, height uint16, planeMask uint32, format uint8, shmSeg Seg, offset uint32) GetImageCookie { 118 | body := encodeGetImage(drawable, X, y, width, height, planeMask, format, shmSeg, offset) 119 | req := &x.ProtocolRequest{ 120 | Ext: _ext, 121 | Header: x.RequestHeader{ 122 | Data: GetImageOpcode, 123 | }, 124 | Body: body, 125 | } 126 | seq := conn.SendRequest(x.RequestChecked, req) 127 | return GetImageCookie(seq) 128 | } 129 | 130 | func (cookie GetImageCookie) Reply(conn *x.Conn) (*GetImageReply, error) { 131 | replyBuf, err := conn.WaitForReply(x.SeqNum(cookie)) 132 | if err != nil { 133 | return nil, err 134 | } 135 | r := x.NewReaderFromData(replyBuf) 136 | var reply GetImageReply 137 | err = readGetImageReply(r, &reply) 138 | if err != nil { 139 | return nil, err 140 | } 141 | return &reply, nil 142 | } 143 | 144 | func CreatePixmap(conn *x.Conn, pid x.Pixmap, drawable x.Drawable, width, height uint16, depth uint8, shmSeg Seg, offset uint32) { 145 | body := encodeCreatePixmap(pid, drawable, width, height, depth, shmSeg, offset) 146 | req := &x.ProtocolRequest{ 147 | Ext: _ext, 148 | NoReply: true, 149 | Header: x.RequestHeader{ 150 | Data: CreatePixmapOpcode, 151 | }, 152 | Body: body, 153 | } 154 | conn.SendRequest(0, req) 155 | } 156 | 157 | func CreatePixmapChecked(conn *x.Conn, pid x.Pixmap, drawable x.Drawable, width, height uint16, depth uint8, shmSeg Seg, offset uint32) x.VoidCookie { 158 | body := encodeCreatePixmap(pid, drawable, width, height, depth, shmSeg, offset) 159 | req := &x.ProtocolRequest{ 160 | Ext: _ext, 161 | NoReply: true, 162 | Header: x.RequestHeader{ 163 | Data: CreatePixmapOpcode, 164 | }, 165 | Body: body, 166 | } 167 | seq := conn.SendRequest(x.RequestChecked, req) 168 | return x.VoidCookie(seq) 169 | } 170 | -------------------------------------------------------------------------------- /ext/test/auto.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package test 6 | 7 | import x "github.com/linuxdeepin/go-x11-client" 8 | 9 | // _ns.ext_name: Test 10 | const MajorVersion = 2 11 | const MinorVersion = 2 12 | 13 | var _ext *x.Extension 14 | 15 | func Ext() *x.Extension { 16 | return _ext 17 | } 18 | 19 | const GetVersionOpcode = 0 20 | 21 | type GetVersionCookie x.SeqNum 22 | 23 | // enum Cursor 24 | const ( 25 | CursorNone = 0 26 | CursorCurrent = 1 27 | ) 28 | 29 | const CompareCursorOpcode = 1 30 | 31 | type CompareCursorCookie x.SeqNum 32 | 33 | const FakeInputOpcode = 2 34 | const GrabControlOpcode = 3 35 | 36 | var requestOpcodeNameMap = map[uint]string{ 37 | GetVersionOpcode: "GetVersion", 38 | CompareCursorOpcode: "CompareCursor", 39 | FakeInputOpcode: "FakeInput", 40 | GrabControlOpcode: "GrabControl", 41 | } 42 | 43 | func init() { 44 | _ext = x.NewExtension("XTEST", 0, nil, requestOpcodeNameMap) 45 | } 46 | -------------------------------------------------------------------------------- /ext/test/test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package test 6 | 7 | import ( 8 | x "github.com/linuxdeepin/go-x11-client" 9 | ) 10 | 11 | // #WREQ 12 | func encodeGetVersion(majorVersion uint8, minorVersion uint16) (b x.RequestBody) { 13 | b.AddBlock(1). 14 | Write1b(majorVersion). 15 | WritePad(1). 16 | Write2b(minorVersion). 17 | End() 18 | return 19 | } 20 | 21 | type GetVersionReply struct { 22 | MajorVersion uint8 23 | MinorVersion uint16 24 | } 25 | 26 | func readGetVersionReply(r *x.Reader, v *GetVersionReply) error { 27 | if !r.RemainAtLeast4b(3) { 28 | return x.ErrDataLenShort 29 | } 30 | v.MajorVersion, _ = r.ReadReplyHeader() 31 | 32 | v.MinorVersion = r.Read2b() // 3 33 | 34 | return nil 35 | } 36 | 37 | // #WREQ 38 | func encodeCompareCursor(window x.Window, cursor x.Cursor) (b x.RequestBody) { 39 | b.AddBlock(2). 40 | Write4b(uint32(window)). 41 | Write4b(uint32(cursor)). 42 | End() 43 | return 44 | } 45 | 46 | type CompareCursorReply struct { 47 | Same bool 48 | } 49 | 50 | func readCompareCursorReply(r *x.Reader, v *CompareCursorReply) error { 51 | if !r.RemainAtLeast4b(2) { 52 | return x.ErrDataLenShort 53 | } 54 | 55 | same, _ := r.ReadReplyHeader() // 2 56 | v.Same = x.Uint8ToBool(same) 57 | return nil 58 | } 59 | 60 | // #WREQ 61 | func encodeFakeInput(evType uint8, detail uint8, time x.Timestamp, root x.Window, 62 | rootX, rootY int16, deviceId uint8) (b x.RequestBody) { 63 | 64 | b.AddBlock(8). 65 | Write1b(evType). 66 | Write1b(detail). 67 | WritePad(2). 68 | Write4b(uint32(time)). 69 | Write4b(uint32(root)). 70 | WritePad(8). 71 | Write2b(uint16(rootX)). 72 | Write2b(uint16(rootY)). 73 | WritePad(7). 74 | Write1b(deviceId). 75 | End() 76 | return 77 | } 78 | 79 | // #WREQ 80 | func encodeGrabControl(impervious bool) (b x.RequestBody) { 81 | b.AddBlock(1). 82 | WriteBool(impervious). 83 | WritePad(3). 84 | End() 85 | return 86 | } 87 | -------------------------------------------------------------------------------- /ext/test/test_req_auto.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package test 6 | 7 | import x "github.com/linuxdeepin/go-x11-client" 8 | 9 | func GetVersion(conn *x.Conn, majorVersion uint8, minorVersion uint16) GetVersionCookie { 10 | body := encodeGetVersion(majorVersion, minorVersion) 11 | req := &x.ProtocolRequest{ 12 | Ext: _ext, 13 | Header: x.RequestHeader{ 14 | Data: GetVersionOpcode, 15 | }, 16 | Body: body, 17 | } 18 | seq := conn.SendRequest(x.RequestChecked, req) 19 | return GetVersionCookie(seq) 20 | } 21 | 22 | func (cookie GetVersionCookie) Reply(conn *x.Conn) (*GetVersionReply, error) { 23 | replyBuf, err := conn.WaitForReply(x.SeqNum(cookie)) 24 | if err != nil { 25 | return nil, err 26 | } 27 | r := x.NewReaderFromData(replyBuf) 28 | var reply GetVersionReply 29 | err = readGetVersionReply(r, &reply) 30 | if err != nil { 31 | return nil, err 32 | } 33 | return &reply, nil 34 | } 35 | 36 | func CompareCursor(conn *x.Conn, window x.Window, cursor x.Cursor) CompareCursorCookie { 37 | body := encodeCompareCursor(window, cursor) 38 | req := &x.ProtocolRequest{ 39 | Ext: _ext, 40 | Header: x.RequestHeader{ 41 | Data: CompareCursorOpcode, 42 | }, 43 | Body: body, 44 | } 45 | seq := conn.SendRequest(x.RequestChecked, req) 46 | return CompareCursorCookie(seq) 47 | } 48 | 49 | func (cookie CompareCursorCookie) Reply(conn *x.Conn) (*CompareCursorReply, error) { 50 | replyBuf, err := conn.WaitForReply(x.SeqNum(cookie)) 51 | if err != nil { 52 | return nil, err 53 | } 54 | r := x.NewReaderFromData(replyBuf) 55 | var reply CompareCursorReply 56 | err = readCompareCursorReply(r, &reply) 57 | if err != nil { 58 | return nil, err 59 | } 60 | return &reply, nil 61 | } 62 | 63 | func FakeInput(conn *x.Conn, evType uint8, detail uint8, time x.Timestamp, root x.Window, rootX, rootY int16, deviceId uint8) { 64 | body := encodeFakeInput(evType, detail, time, root, rootX, rootY, deviceId) 65 | req := &x.ProtocolRequest{ 66 | Ext: _ext, 67 | NoReply: true, 68 | Header: x.RequestHeader{ 69 | Data: FakeInputOpcode, 70 | }, 71 | Body: body, 72 | } 73 | conn.SendRequest(0, req) 74 | } 75 | 76 | func FakeInputChecked(conn *x.Conn, evType uint8, detail uint8, time x.Timestamp, root x.Window, rootX, rootY int16, deviceId uint8) x.VoidCookie { 77 | body := encodeFakeInput(evType, detail, time, root, rootX, rootY, deviceId) 78 | req := &x.ProtocolRequest{ 79 | Ext: _ext, 80 | NoReply: true, 81 | Header: x.RequestHeader{ 82 | Data: FakeInputOpcode, 83 | }, 84 | Body: body, 85 | } 86 | seq := conn.SendRequest(x.RequestChecked, req) 87 | return x.VoidCookie(seq) 88 | } 89 | 90 | func GrabControl(conn *x.Conn, impervious bool) { 91 | body := encodeGrabControl(impervious) 92 | req := &x.ProtocolRequest{ 93 | Ext: _ext, 94 | NoReply: true, 95 | Header: x.RequestHeader{ 96 | Data: GrabControlOpcode, 97 | }, 98 | Body: body, 99 | } 100 | conn.SendRequest(0, req) 101 | } 102 | 103 | func GrabControlChecked(conn *x.Conn, impervious bool) x.VoidCookie { 104 | body := encodeGrabControl(impervious) 105 | req := &x.ProtocolRequest{ 106 | Ext: _ext, 107 | NoReply: true, 108 | Header: x.RequestHeader{ 109 | Data: GrabControlOpcode, 110 | }, 111 | Body: body, 112 | } 113 | seq := conn.SendRequest(x.RequestChecked, req) 114 | return x.VoidCookie(seq) 115 | } 116 | -------------------------------------------------------------------------------- /ext/xfixes/auto.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package xfixes 6 | 7 | import x "github.com/linuxdeepin/go-x11-client" 8 | 9 | // _ns.ext_name: XFixes 10 | const MajorVersion = 5 11 | const MinorVersion = 0 12 | 13 | var _ext *x.Extension 14 | 15 | func Ext() *x.Extension { 16 | return _ext 17 | } 18 | 19 | const QueryVersionOpcode = 0 20 | 21 | type QueryVersionCookie x.SeqNum 22 | 23 | // enum SaveSetMode 24 | const ( 25 | SaveSetModeInsert = 0 26 | SaveSetModeDelete = 1 27 | ) 28 | 29 | // enum SaveSetTarget 30 | const ( 31 | SaveSetTargetNearest = 0 32 | SaveSetTargetRoot = 1 33 | ) 34 | 35 | // enum SaveSetMapping 36 | const ( 37 | SaveSetMappingMap = 0 38 | SaveSetMappingUnmap = 1 39 | ) 40 | 41 | const ChangeSaveSetOpcode = 1 42 | 43 | // enum SelectionEvent 44 | const ( 45 | SelectionEventSetSelectionOwner = 0 46 | SelectionEventSelectionWindowDestroy = 1 47 | SelectionEventSelectionClientClose = 2 48 | ) 49 | 50 | // enum SelectionEventMask 51 | const ( 52 | SelectionEventMaskSetSelectionOwner = 1 53 | SelectionEventMaskSelectionWindowDestroy = 2 54 | SelectionEventMaskSelectionClientClose = 4 55 | ) 56 | 57 | const SelectionNotifyEventCode = 0 58 | 59 | func NewSelectionNotifyEvent(data []byte) (*SelectionNotifyEvent, error) { 60 | var ev SelectionNotifyEvent 61 | r := x.NewReaderFromData(data) 62 | err := readSelectionNotifyEvent(r, &ev) 63 | if err != nil { 64 | return nil, err 65 | } 66 | return &ev, nil 67 | } 68 | 69 | const SelectSelectionInputOpcode = 2 70 | 71 | // enum CursorNotify 72 | const ( 73 | CursorNotifyDisplayCursor = 0 74 | ) 75 | 76 | // enum CursorNotifyMask 77 | const ( 78 | CursorNotifyMaskDisplayCursor = 1 79 | ) 80 | 81 | const CursorNotifyEventCode = 1 82 | 83 | func NewCursorNotifyEvent(data []byte) (*CursorNotifyEvent, error) { 84 | var ev CursorNotifyEvent 85 | r := x.NewReaderFromData(data) 86 | err := readCursorNotifyEvent(r, &ev) 87 | if err != nil { 88 | return nil, err 89 | } 90 | return &ev, nil 91 | } 92 | 93 | const SelectCursorInputOpcode = 3 94 | const GetCursorImageOpcode = 4 95 | 96 | type GetCursorImageCookie x.SeqNum 97 | 98 | // simple ('xcb', 'XFixes', 'REGION') 99 | type Region uint32 100 | 101 | const BadRegionErrorCode = 0 102 | 103 | // enum Region 104 | const ( 105 | RegionNone = 0 106 | ) 107 | 108 | const CreateRegionOpcode = 5 109 | const CreateRegionFromBitmapOpcode = 6 110 | const CreateRegionFromWindowOpcode = 7 111 | const CreateRegionFromGCOpcode = 8 112 | const CreateRegionFromPictureOpcode = 9 113 | const DestroyRegionOpcode = 10 114 | const SetRegionOpcode = 11 115 | const CopyRegionOpcode = 12 116 | const UnionRegionOpcode = 13 117 | const IntersectRegionOpcode = 14 118 | const SubtractRegionOpcode = 15 119 | const InvertRegionOpcode = 16 120 | const TranslateRegionOpcode = 17 121 | const RegionExtentsOpcode = 18 122 | const FetchRegionOpcode = 19 123 | 124 | type FetchRegionCookie x.SeqNum 125 | 126 | const SetGCClipRegionOpcode = 20 127 | const SetWindowShapeRegionOpcode = 21 128 | const SetPictureClipRegionOpcode = 22 129 | const SetCursorNameOpcode = 23 130 | const GetCursorNameOpcode = 24 131 | 132 | type GetCursorNameCookie x.SeqNum 133 | 134 | const GetCursorImageAndNameOpcode = 25 135 | 136 | type GetCursorImageAndNameCookie x.SeqNum 137 | 138 | const ChangeCursorOpcode = 26 139 | const ChangeCursorByNameOpcode = 27 140 | const ExpandRegionOpcode = 28 141 | const HideCursorOpcode = 29 142 | const ShowCursorOpcode = 30 143 | 144 | // simple ('xcb', 'XFixes', 'BARRIER') 145 | type Barrier uint32 146 | 147 | // enum BarrierDirections 148 | const ( 149 | BarrierDirectionsPositiveX = 1 150 | BarrierDirectionsPositiveY = 2 151 | BarrierDirectionsNegativeX = 4 152 | BarrierDirectionsNegativeY = 8 153 | ) 154 | 155 | const CreatePointerBarrierOpcode = 31 156 | const DeletePointerBarrierOpcode = 32 157 | 158 | var errorCodeNameMap = map[uint8]string{ 159 | BadRegionErrorCode: "BadRegion", 160 | } 161 | var requestOpcodeNameMap = map[uint]string{ 162 | QueryVersionOpcode: "QueryVersion", 163 | ChangeSaveSetOpcode: "ChangeSaveSet", 164 | SelectSelectionInputOpcode: "SelectSelectionInput", 165 | SelectCursorInputOpcode: "SelectCursorInput", 166 | GetCursorImageOpcode: "GetCursorImage", 167 | CreateRegionOpcode: "CreateRegion", 168 | CreateRegionFromBitmapOpcode: "CreateRegionFromBitmap", 169 | CreateRegionFromWindowOpcode: "CreateRegionFromWindow", 170 | CreateRegionFromGCOpcode: "CreateRegionFromGC", 171 | CreateRegionFromPictureOpcode: "CreateRegionFromPicture", 172 | DestroyRegionOpcode: "DestroyRegion", 173 | SetRegionOpcode: "SetRegion", 174 | CopyRegionOpcode: "CopyRegion", 175 | UnionRegionOpcode: "UnionRegion", 176 | IntersectRegionOpcode: "IntersectRegion", 177 | SubtractRegionOpcode: "SubtractRegion", 178 | InvertRegionOpcode: "InvertRegion", 179 | TranslateRegionOpcode: "TranslateRegion", 180 | RegionExtentsOpcode: "RegionExtents", 181 | FetchRegionOpcode: "FetchRegion", 182 | SetGCClipRegionOpcode: "SetGCClipRegion", 183 | SetWindowShapeRegionOpcode: "SetWindowShapeRegion", 184 | SetPictureClipRegionOpcode: "SetPictureClipRegion", 185 | SetCursorNameOpcode: "SetCursorName", 186 | GetCursorNameOpcode: "GetCursorName", 187 | GetCursorImageAndNameOpcode: "GetCursorImageAndName", 188 | ChangeCursorOpcode: "ChangeCursor", 189 | ChangeCursorByNameOpcode: "ChangeCursorByName", 190 | ExpandRegionOpcode: "ExpandRegion", 191 | HideCursorOpcode: "HideCursor", 192 | ShowCursorOpcode: "ShowCursor", 193 | CreatePointerBarrierOpcode: "CreatePointerBarrier", 194 | DeletePointerBarrierOpcode: "DeletePointerBarrier", 195 | } 196 | 197 | func init() { 198 | _ext = x.NewExtension("XFIXES", 0, errorCodeNameMap, requestOpcodeNameMap) 199 | } 200 | -------------------------------------------------------------------------------- /extension.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package x 6 | 7 | import ( 8 | "sync" 9 | ) 10 | 11 | type ReadErrorFunc func(*Reader) Error 12 | 13 | type lazyReplyTag uint 14 | 15 | const ( 16 | lazyNone lazyReplyTag = iota 17 | lazyCookie 18 | lazyForced 19 | ) 20 | 21 | type Extension struct { 22 | id int 23 | name string // extension-xname 24 | maxErrCode uint8 25 | errCodeNameMap map[uint8]string 26 | reqOpcodeNameMap map[uint]string 27 | } 28 | 29 | func (ext *Extension) Name() string { 30 | return ext.name 31 | } 32 | 33 | var nextExtId = 1 34 | 35 | // only call it in init() func 36 | func NewExtension(name string, maxErrCode uint8, 37 | errCodeNameMap map[uint8]string, reqOpcodeNameMap map[uint]string) *Extension { 38 | id := nextExtId 39 | nextExtId++ 40 | return &Extension{ 41 | id: id, 42 | name: name, 43 | maxErrCode: maxErrCode, 44 | errCodeNameMap: errCodeNameMap, 45 | reqOpcodeNameMap: reqOpcodeNameMap, 46 | } 47 | } 48 | 49 | type lazyReply struct { 50 | tag lazyReplyTag 51 | reply *QueryExtensionReply 52 | cookie QueryExtensionCookie 53 | } 54 | 55 | type extAndData struct { 56 | ext *Extension 57 | reply *lazyReply 58 | } 59 | 60 | type ext struct { 61 | mu sync.RWMutex 62 | extensions []extAndData 63 | } 64 | 65 | func (e *ext) grow(n int) { 66 | if n <= len(e.extensions) { 67 | return 68 | } 69 | 70 | logPrintf("ext grow %d -> %d\n", len(e.extensions), n) 71 | bigger := make([]extAndData, n) 72 | copy(bigger, e.extensions) 73 | e.extensions = bigger 74 | } 75 | 76 | func (e *ext) getById(id int) *extAndData { 77 | if id > len(e.extensions) { 78 | e.grow(id * 2) 79 | } 80 | return &e.extensions[id-1] 81 | } 82 | 83 | func (e *ext) getExtByMajorOpcode(majorOpcode uint8) *Extension { 84 | for _, extAndData := range e.extensions { 85 | ext := extAndData.ext 86 | lzr := extAndData.reply 87 | if ext != nil && lzr != nil && lzr.reply != nil { 88 | if majorOpcode == lzr.reply.MajorOpcode { 89 | return ext 90 | } 91 | } 92 | } 93 | return nil 94 | } 95 | 96 | func (e *ext) getExtErrName(errCode uint8) string { 97 | for _, extAndData := range e.extensions { 98 | ext := extAndData.ext 99 | lzr := extAndData.reply 100 | if ext != nil && lzr != nil && lzr.reply != nil { 101 | base := lzr.reply.FirstError 102 | max := lzr.reply.FirstError + ext.maxErrCode 103 | 104 | if base <= errCode && errCode <= max { 105 | return ext.errCodeNameMap[errCode-base] 106 | } 107 | } 108 | } 109 | return "" 110 | } 111 | 112 | func (e *ext) getLazyReply(conn *Conn, ext *Extension) (lzr *lazyReply) { 113 | extAndData := e.getById(ext.id) 114 | 115 | if extAndData.ext == nil { 116 | // init extAndData 117 | extAndData.ext = ext 118 | extAndData.reply = &lazyReply{tag: lazyNone} 119 | } 120 | lzr = extAndData.reply 121 | 122 | // lazyReply tag: lazyNone -> lazyCookie 123 | if lzr.tag == lazyNone { 124 | lzr.tag = lazyCookie 125 | lzr.cookie = QueryExtension(conn, ext.name) 126 | } 127 | return 128 | } 129 | 130 | func (e *ext) getExtData(c *Conn, ext *Extension) *QueryExtensionReply { 131 | lzr := e.getLazyReply(c, ext) 132 | 133 | // lazyReply tag: lazyCookie -> lazyForced 134 | if lzr.tag == lazyCookie { 135 | lzr.tag = lazyForced 136 | lzr.reply, _ = lzr.cookie.Reply(c) 137 | } 138 | return lzr.reply 139 | } 140 | 141 | func (c *Conn) GetExtensionData(ext *Extension) *QueryExtensionReply { 142 | c.ext.mu.Lock() 143 | data := c.ext.getExtData(c, ext) 144 | c.ext.mu.Unlock() 145 | return data 146 | } 147 | 148 | func (c *Conn) PrefetchExtensionData(ext *Extension) { 149 | c.ext.mu.Lock() 150 | c.ext.getLazyReply(c, ext) 151 | c.ext.mu.Unlock() 152 | } 153 | -------------------------------------------------------------------------------- /gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -x 4 | set -e 5 | 6 | goClient='python2 tools/go_client.py' 7 | reqCodeGen=tools/gen/gen 8 | 9 | $goClient -o xproto_auto.go /usr/share/xcb/xproto.xml 10 | env GOPACKAGE=x $reqCodeGen xproto.go > xproto_auto_req.go 11 | 12 | $goClient -o ext/record/auto.go /usr/share/xcb/record.xml 13 | env GOPACKAGE=record $reqCodeGen -e ext/record/record.go > ext/record/record_req_auto.go 14 | 15 | $goClient -o ext/test/auto.go /usr/share/xcb/xtest.xml 16 | env GOPACKAGE=test $reqCodeGen -e ext/test/test.go > ext/test/test_req_auto.go 17 | 18 | $goClient -o ext/damage/auto.go /usr/share/xcb/damage.xml 19 | env GOPACKAGE=damage $reqCodeGen -e ext/damage/damage.go > ext/damage/damage_req_auto.go 20 | 21 | $goClient -o ext/composite/auto.go /usr/share/xcb/composite.xml 22 | env GOPACKAGE=composite $reqCodeGen -e ext/composite/composite.go > ext/composite/composite_req_auto.go 23 | 24 | $goClient -o ext/screensaver/auto.go /usr/share/xcb/screensaver.xml 25 | env GOPACKAGE=screensaver $reqCodeGen -e ext/screensaver/screensaver.go > ext/screensaver/screensaver_req_auto.go 26 | 27 | $goClient -o ext/dpms/auto.go /usr/share/xcb/dpms.xml 28 | env GOPACKAGE=dpms $reqCodeGen -e ext/dpms/dpms.go > ext/dpms/dpms_req_auto.go 29 | 30 | $goClient -o ext/randr/auto.go /usr/share/xcb/randr.xml 31 | env GOPACKAGE=randr $reqCodeGen -e -extra-exts render ext/randr/randr.go > ext/randr/randr_req_auto.go 32 | 33 | $goClient -o ext/xfixes/auto.go /usr/share/xcb/xfixes.xml 34 | env GOPACKAGE=xfixes $reqCodeGen -e ext/xfixes/xfixes.go > ext/xfixes/xfixes_req_auto.go 35 | 36 | $goClient -o ext/input/auto.go /usr/share/xcb/xinput.xml 37 | env GOPACKAGE=input $reqCodeGen -e ext/input/input.go > ext/input/input_req_auto.go 38 | env GOPACKAGE=input $reqCodeGen -e ext/input/input1.go > ext/input/input1_req_auto.go 39 | 40 | $goClient -p ge -o ext/ge/auto.go /usr/share/xcb/ge.xml 41 | env GOPACKAGE=ge $reqCodeGen -e ext/ge/ge.go > ext/ge/ge_req_auto.go 42 | 43 | $goClient -o ext/render/auto.go /usr/share/xcb/render.xml 44 | env GOPACKAGE=render $reqCodeGen -e ext/render/render.go > ext/render/render_req_auto.go 45 | 46 | $goClient -o ext/shm/auto.go /usr/share/xcb/shm.xml 47 | env GOPACKAGE=shm $reqCodeGen -e ext/shm/shm.go > ext/shm/shm_req_auto.go 48 | 49 | $goClient -o ext/bigrequests/auto.go /usr/share/xcb/bigreq.xml 50 | env GOPACKAGE=bigrequests $reqCodeGen -e ext/bigrequests/bigreq.go > ext/bigrequests/bigreq_req_auto.go 51 | 52 | $goClient -o ext/xkb/auto.go /usr/share/xcb/xkb.xml 53 | env GOPACKAGE=xkb $reqCodeGen -e ext/xkb/xkb.go > ext/xkb/xkb_req_auto.go 54 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module go-x11-client 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/linuxdeepin/go-lib v0.0.0-20240105075242-dddda54ea9f0 7 | github.com/linuxdeepin/go-x11-client v0.0.0-20240415051504-c8e43d028ff9 8 | github.com/stretchr/testify v1.9.0 9 | golang.org/x/text v0.14.0 10 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c 11 | ) 12 | 13 | require ( 14 | github.com/davecgh/go-spew v1.1.1 // indirect 15 | github.com/kr/pretty v0.2.1 // indirect 16 | github.com/kr/text v0.1.0 // indirect 17 | github.com/pmezard/go-difflib v1.0.0 // indirect 18 | gopkg.in/yaml.v3 v3.0.1 // indirect 19 | ) 20 | -------------------------------------------------------------------------------- /help.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package x 6 | 7 | /* 8 | help.go is meant to contain a rough hodge podge of functions that are mainly 9 | used in the auto generated code. Indeed, several functions here are simple 10 | wrappers so that the sub-packages don't need to be smart about which stdlib 11 | packages to import. 12 | 13 | Also, the 'Get..' and 'Put..' functions are used through the core xgb package 14 | too. (xgbutil uses them too.) 15 | */ 16 | 17 | import ( 18 | "fmt" 19 | //"github.com/gavv/monotime" 20 | "strings" 21 | ) 22 | 23 | //func GetServerCurrentTime() Timestamp { 24 | // now := monotime.Now() 25 | // ns := now.Nanoseconds() 26 | // return Timestamp(ns / 1e6) 27 | //} 28 | 29 | // StringsJoin is an alias to strings.Join. It allows us to avoid having to 30 | // import 'strings' in each of the generated Go files. 31 | func StringsJoin(ss []string, sep string) string { 32 | return strings.Join(ss, sep) 33 | } 34 | 35 | // Sprintf is so we don't need to import 'fmt' in the generated Go files. 36 | func Sprintf(format string, v ...interface{}) string { 37 | return fmt.Sprintf(format, v...) 38 | } 39 | 40 | // Errorf is just a wrapper for fmt.Errorf. Exists for the same reason 41 | // that 'stringsJoin' and 'sprintf' exists. 42 | func Errorf(format string, v ...interface{}) error { 43 | return fmt.Errorf(format, v...) 44 | } 45 | 46 | func Pad(e int) int { 47 | // pad(E) = (4 - (E mod 4)) mod 4 48 | return (4 - (e % 4)) % 4 49 | } 50 | 51 | // PopCount counts the number of bits set in a value list mask. 52 | func PopCount(mask0 int) int { 53 | mask := uint32(mask0) 54 | n := 0 55 | for i := uint32(0); i < 32; i++ { 56 | if mask&(1<> 8) 71 | } 72 | 73 | // Put32 takes a 32 bit integer and copies it into a byte slice. 74 | func Put32(buf []byte, v uint32) { 75 | buf[0] = byte(v) 76 | buf[1] = byte(v >> 8) 77 | buf[2] = byte(v >> 16) 78 | buf[3] = byte(v >> 24) 79 | } 80 | 81 | // Put64 takes a 64 bit integer and copies it into a byte slice. 82 | func Put64(buf []byte, v uint64) { 83 | buf[0] = byte(v) 84 | buf[1] = byte(v >> 8) 85 | buf[2] = byte(v >> 16) 86 | buf[3] = byte(v >> 24) 87 | buf[4] = byte(v >> 32) 88 | buf[5] = byte(v >> 40) 89 | buf[6] = byte(v >> 48) 90 | buf[7] = byte(v >> 56) 91 | } 92 | 93 | // Get16 constructs a 16 bit integer from the beginning of a byte slice. 94 | func Get16(buf []byte) uint16 { 95 | v := uint16(buf[0]) 96 | v |= uint16(buf[1]) << 8 97 | return v 98 | } 99 | 100 | // Get32 constructs a 32 bit integer from the beginning of a byte slice. 101 | func Get32(buf []byte) uint32 { 102 | v := uint32(buf[0]) 103 | v |= uint32(buf[1]) << 8 104 | v |= uint32(buf[2]) << 16 105 | v |= uint32(buf[3]) << 24 106 | return v 107 | } 108 | 109 | // Get64 constructs a 64 bit integer from the beginning of a byte slice. 110 | func Get64(buf []byte) uint64 { 111 | v := uint64(buf[0]) 112 | v |= uint64(buf[1]) << 8 113 | v |= uint64(buf[2]) << 16 114 | v |= uint64(buf[3]) << 24 115 | v |= uint64(buf[4]) << 32 116 | v |= uint64(buf[5]) << 40 117 | v |= uint64(buf[6]) << 48 118 | v |= uint64(buf[7]) << 56 119 | return v 120 | } 121 | 122 | func BoolToUint8(b bool) uint8 { 123 | if b { 124 | return 1 125 | } 126 | return 0 127 | } 128 | 129 | func Uint8ToBool(v uint8) bool { 130 | return v != 0 131 | } 132 | 133 | func TruncateStr(s string, n int) string { 134 | if len(s) > n { 135 | return s[:n] 136 | } 137 | return s 138 | } 139 | -------------------------------------------------------------------------------- /in.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package x 6 | 7 | import ( 8 | "container/list" 9 | "fmt" 10 | "os" 11 | "sync" 12 | ) 13 | 14 | type in struct { 15 | requestExpected SeqNum 16 | requestRead SeqNum 17 | requestCompleted SeqNum 18 | 19 | currentReply *list.List 20 | replies map[SeqNum]*list.List 21 | pendingReplies *list.List 22 | 23 | readers *list.List 24 | events *list.List 25 | eventsCond *sync.Cond 26 | 27 | eventChans []chan<- GenericEvent 28 | chansMu sync.Mutex 29 | } 30 | 31 | func (in *in) init(ioMu *sync.Mutex) { 32 | in.replies = make(map[SeqNum]*list.List) 33 | in.pendingReplies = list.New() 34 | in.readers = list.New() 35 | in.events = list.New() 36 | in.eventsCond = sync.NewCond(ioMu) 37 | } 38 | 39 | func (in *in) addEventChan(eventChan chan<- GenericEvent) { 40 | in.chansMu.Lock() 41 | 42 | for _, ch := range in.eventChans { 43 | if ch == eventChan { 44 | // exist 45 | in.chansMu.Unlock() 46 | return 47 | } 48 | } 49 | 50 | // COW 51 | newEventChans := make([]chan<- GenericEvent, len(in.eventChans)+1) 52 | copy(newEventChans, in.eventChans) 53 | newEventChans[len(newEventChans)-1] = eventChan 54 | in.eventChans = newEventChans 55 | in.chansMu.Unlock() 56 | } 57 | 58 | func (in *in) removeEventChan(eventChan chan<- GenericEvent) { 59 | in.chansMu.Lock() 60 | 61 | chans := in.eventChans 62 | var found bool 63 | for _, ch := range chans { 64 | if ch == eventChan { 65 | found = true 66 | break 67 | } 68 | } 69 | 70 | if !found { 71 | // not found 72 | in.chansMu.Unlock() 73 | return 74 | } 75 | 76 | // COW 77 | newEventChans := make([]chan<- GenericEvent, 0, len(in.eventChans)-1) 78 | for _, ch := range chans { 79 | if ch != eventChan { 80 | newEventChans = append(newEventChans, ch) 81 | } 82 | } 83 | in.eventChans = newEventChans 84 | in.chansMu.Unlock() 85 | } 86 | 87 | func (in *in) addEvent(e GenericEvent) { 88 | logPrintln("add event", e) 89 | if in.events.Len() > 0xfff { 90 | _, _ = fmt.Fprintf(os.Stderr, " too many events are not processed, len: %d\n", 91 | in.events.Len()) 92 | } 93 | in.events.PushBack(e) 94 | in.eventsCond.Signal() 95 | } 96 | 97 | func (in *in) sendEvent(e GenericEvent) { 98 | in.chansMu.Lock() 99 | eventChans := in.eventChans 100 | in.chansMu.Unlock() 101 | 102 | for _, ch := range eventChans { 103 | ch <- e 104 | } 105 | } 106 | 107 | func (in *in) closeEventChans() { 108 | in.chansMu.Lock() 109 | 110 | for _, ch := range in.eventChans { 111 | close(ch) 112 | } 113 | 114 | in.chansMu.Unlock() 115 | } 116 | 117 | type ReplyReader struct { 118 | request SeqNum 119 | cond *sync.Cond 120 | } 121 | 122 | func (in *in) insertNewReader(request SeqNum, cond *sync.Cond) *ReplyReader { 123 | r := &ReplyReader{ 124 | request: request, 125 | cond: cond, 126 | } 127 | 128 | var mark *list.Element 129 | l := in.readers 130 | for e := l.Front(); e != nil; e = e.Next() { 131 | reader := e.Value.(*ReplyReader) 132 | if reader.request >= request { 133 | mark = e 134 | break 135 | } 136 | } 137 | 138 | if mark != nil { 139 | logPrintf("insertNewReader %d before %d\n", request, mark.Value.(*ReplyReader).request) 140 | l.InsertBefore(r, mark) 141 | } else { 142 | logPrintf("insertNewReader %d at end\n", request) 143 | l.PushBack(r) 144 | } 145 | return r 146 | } 147 | 148 | func (in *in) removeReader(r *ReplyReader) { 149 | l := in.readers 150 | for e := l.Front(); e != nil; e = e.Next() { 151 | reader := e.Value.(*ReplyReader) 152 | if reader.request == r.request { 153 | logPrintln("remove reader", reader.request) 154 | l.Remove(e) 155 | break 156 | } 157 | } 158 | } 159 | 160 | func (in *in) removeFinishedReaders() { 161 | l := in.readers 162 | e := l.Front() 163 | for e != nil { 164 | reader := e.Value.(*ReplyReader) 165 | if reader.request <= in.requestCompleted { 166 | reader.cond.Signal() 167 | logPrintln("remove finished reader", reader.request) 168 | tmp := e 169 | e = e.Next() 170 | l.Remove(tmp) 171 | } else { 172 | break 173 | } 174 | } 175 | } 176 | 177 | func (in *in) wakeUpAllReaders() { 178 | l := in.readers 179 | for e := l.Front(); e != nil; e = e.Next() { 180 | reader := e.Value.(*ReplyReader) 181 | reader.cond.Signal() 182 | } 183 | } 184 | 185 | func (in *in) wakeUpNextReader() { 186 | if in.readers.Front() != nil { 187 | reader := in.readers.Front().Value.(*ReplyReader) 188 | logPrintln("wake up next reader", reader.request) 189 | reader.cond.Signal() 190 | } 191 | } 192 | 193 | type PendingReply struct { 194 | firstRequest SeqNum 195 | lastRequest SeqNum 196 | workaround uint 197 | flags uint 198 | } 199 | 200 | func (in *in) expectReply(request SeqNum, workaround uint, flags uint) { 201 | pend := &PendingReply{ 202 | firstRequest: request, 203 | lastRequest: request, 204 | workaround: workaround, 205 | flags: flags, 206 | } 207 | in.pendingReplies.PushBack(pend) 208 | } 209 | 210 | func (in *in) removeFinishedPendingReplies() { 211 | l := in.pendingReplies 212 | e := l.Front() 213 | for e != nil { 214 | pend := e.Value.(*PendingReply) 215 | if pend.lastRequest <= in.requestCompleted { 216 | // remove pend from list 217 | tmp := e 218 | e = e.Next() 219 | l.Remove(tmp) 220 | } else { 221 | break 222 | } 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /reader.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package x 6 | 7 | import ( 8 | "bytes" 9 | "errors" 10 | ) 11 | 12 | var ErrDataLenShort = errors.New("data length is short") 13 | 14 | type Reader struct { 15 | pos int 16 | data []byte 17 | } 18 | 19 | func NewReaderFromData(data []byte) *Reader { 20 | return &Reader{ 21 | data: data, 22 | } 23 | } 24 | 25 | func (r *Reader) Pos() int { 26 | return r.pos 27 | } 28 | 29 | func (r *Reader) Read1b() uint8 { 30 | v := r.data[r.pos] 31 | r.pos++ 32 | return v 33 | } 34 | 35 | func (r *Reader) Read2b() uint16 { 36 | v := uint16(r.data[r.pos]) 37 | v |= uint16(r.data[r.pos+1]) << 8 38 | r.pos += 2 39 | return v 40 | } 41 | 42 | func (r *Reader) Read4b() uint32 { 43 | v := uint32(r.data[r.pos]) 44 | v |= uint32(r.data[r.pos+1]) << 8 45 | v |= uint32(r.data[r.pos+2]) << 16 46 | v |= uint32(r.data[r.pos+3]) << 24 47 | r.pos += 4 48 | return v 49 | } 50 | 51 | func (r *Reader) MustReadBytes(n int) []byte { 52 | v := r.data[r.pos : r.pos+n] 53 | r.pos += n 54 | return v 55 | } 56 | 57 | func (r *Reader) ReadBytes(n int) ([]byte, error) { 58 | if !r.RemainAtLeast(n) { 59 | return nil, ErrDataLenShort 60 | } 61 | 62 | v := r.data[r.pos : r.pos+n] 63 | r.pos += n 64 | return v, nil 65 | } 66 | 67 | func (r *Reader) ReadBytesWithPad(n int) ([]byte, error) { 68 | total := n + Pad(n) 69 | if !r.RemainAtLeast(total) { 70 | return nil, ErrDataLenShort 71 | } 72 | 73 | v := r.data[r.pos : r.pos+n] 74 | r.pos += total 75 | return v, nil 76 | } 77 | 78 | func (r *Reader) ReadString(n int) (string, error) { 79 | v, err := r.ReadBytes(n) 80 | if err != nil { 81 | return "", err 82 | } 83 | return string(v), nil 84 | } 85 | 86 | func (r *Reader) ReadStrWithPad(n int) (string, error) { 87 | v, err := r.ReadBytesWithPad(n) 88 | if err != nil { 89 | return "", err 90 | } 91 | return string(v), nil 92 | } 93 | 94 | func (r *Reader) ReadNulTermStr() string { 95 | idx := bytes.IndexByte(r.data[r.pos:], 0) 96 | var v []byte 97 | if idx == -1 { 98 | v = r.data[r.pos:] 99 | r.pos = len(r.data) 100 | } else { 101 | v = r.data[r.pos : r.pos+idx] 102 | r.pos += idx 103 | } 104 | return string(v) 105 | } 106 | 107 | func (r *Reader) ReadBool() bool { 108 | return Uint8ToBool(r.Read1b()) 109 | } 110 | 111 | func (r *Reader) ReadPad(n int) { 112 | if r.pos+n > len(r.data) { 113 | panic("index out of range") 114 | } 115 | r.pos += n 116 | } 117 | 118 | func (r *Reader) Reset() { 119 | r.pos = 0 120 | } 121 | 122 | func (r *Reader) RemainAtLeast(n int) bool { 123 | return r.pos+n <= len(r.data) 124 | } 125 | 126 | func (r *Reader) RemainAtLeast4b(n int) bool { 127 | return r.RemainAtLeast(n << 2) 128 | } 129 | 130 | func (r *Reader) ReadReplyHeader() (data uint8, length uint32) { 131 | r.ReadPad(1) 132 | data = r.Read1b() 133 | // seq 134 | r.ReadPad(2) 135 | // length 136 | length = r.Read4b() // 2 137 | return 138 | } 139 | 140 | func (r *Reader) ReadEventHeader() (data uint8, seq uint16) { 141 | r.ReadPad(1) 142 | data = r.Read1b() 143 | // seq 144 | seq = r.Read2b() // 1 145 | return 146 | } 147 | -------------------------------------------------------------------------------- /reader_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package x 6 | 7 | import ( 8 | "testing" 9 | 10 | . "gopkg.in/check.v1" 11 | ) 12 | 13 | // Hook up gocheck into the "go test" runner. 14 | func Test(t *testing.T) { TestingT(t) } 15 | 16 | type MySuite struct { 17 | r *Reader 18 | } 19 | 20 | var _ = Suite(&MySuite{}) 21 | 22 | func (s *MySuite) SetUpTest(c *C) { 23 | buf := []byte{1, 2, 3, 4, 5, 6, 7, 8} 24 | s.r = NewReaderFromData(buf) 25 | } 26 | 27 | func (s *MySuite) TestReaderReadBytes(c *C) { 28 | v, err := s.r.ReadBytes(4) 29 | c.Assert(v, DeepEquals, []byte{1, 2, 3, 4}) 30 | c.Assert(err, IsNil) 31 | 32 | v, err = s.r.ReadBytes(3) 33 | c.Assert(v, DeepEquals, []byte{5, 6, 7}) 34 | c.Assert(err, IsNil) 35 | } 36 | 37 | func (s *MySuite) TestReaderReadBytesWithPad(c *C) { 38 | v, err := s.r.ReadBytesWithPad(3) 39 | c.Assert(v, DeepEquals, []byte{1, 2, 3}) 40 | c.Assert(s.r.Pos(), Equals, 4) 41 | c.Assert(err, IsNil) 42 | } 43 | 44 | func (s *MySuite) TestReaderRead1b(c *C) { 45 | for i := 1; i <= 8; i++ { 46 | c.Assert(s.r.Read1b(), Equals, uint8(i)) 47 | } 48 | } 49 | 50 | func (s *MySuite) TestReaderRead2b(c *C) { 51 | results := []uint16{0x0201, 0x0403, 0x0605, 0x0807} 52 | for _, result := range results { 53 | c.Assert(s.r.Read2b(), Equals, result) 54 | } 55 | } 56 | 57 | func (s *MySuite) TestReaderRead4b(c *C) { 58 | results := []uint32{0x04030201, 0x08070605} 59 | for _, result := range results { 60 | c.Assert(s.r.Read4b(), Equals, result) 61 | } 62 | } 63 | 64 | func (s *MySuite) TestReaderReadNulTermStr(c *C) { 65 | data := []byte{'h', 'e', 'l', 'l', 'o'} 66 | r := NewReaderFromData(data) 67 | str := r.ReadNulTermStr() 68 | c.Assert(str, Equals, "hello") 69 | c.Assert(r.Pos(), Equals, 5) 70 | 71 | data = []byte{'h', 'e', 'l', 'l', 'o', 0, 'w', 'o', 'r', 'l', 'd'} 72 | r = NewReaderFromData(data) 73 | str = r.ReadNulTermStr() 74 | c.Assert(str, Equals, "hello") 75 | c.Assert(r.Pos(), Equals, 5) 76 | } 77 | 78 | func (s *MySuite) TestReaderRemainAtLeast(c *C) { 79 | s.r.ReadPad(3) 80 | c.Assert(s.r.RemainAtLeast(5), Equals, true) 81 | c.Assert(s.r.RemainAtLeast(6), Equals, false) 82 | 83 | s.r.Reset() 84 | c.Assert(s.r.RemainAtLeast4b(0), Equals, true) 85 | c.Assert(s.r.RemainAtLeast4b(1), Equals, true) 86 | c.Assert(s.r.RemainAtLeast4b(2), Equals, true) 87 | c.Assert(s.r.RemainAtLeast4b(3), Equals, false) 88 | } 89 | -------------------------------------------------------------------------------- /resource_id.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package x 6 | 7 | import ( 8 | "errors" 9 | "math/big" 10 | "sync" 11 | ) 12 | 13 | func (c *Conn) AllocID() (uint32, error) { 14 | return c.ridAllocator.alloc() 15 | } 16 | 17 | func (c *Conn) FreeID(rid uint32) error { 18 | return c.ridAllocator.free(rid) 19 | } 20 | 21 | func (c *Conn) IDUsedCount() int { 22 | return c.ridAllocator.usedCount() 23 | } 24 | 25 | type resourceIdAllocator struct { 26 | mu sync.Mutex 27 | base uint32 28 | mask uint32 29 | last uint32 30 | bitmap *big.Int 31 | allAllocated bool 32 | } 33 | 34 | func (ra *resourceIdAllocator) init(base, mask uint32) { 35 | ra.base = base 36 | ra.mask = mask 37 | ra.bitmap = big.NewInt(0) 38 | } 39 | 40 | var errOutOfResourceIds = errors.New("out of resource ids") 41 | 42 | func (ra *resourceIdAllocator) alloc() (uint32, error) { 43 | ra.mu.Lock() 44 | defer ra.mu.Unlock() 45 | 46 | if ra.allAllocated { 47 | return 0, errOutOfResourceIds 48 | } 49 | 50 | i := ra.last 51 | for ra.bitmap.Bit(int(i)) == 1 { 52 | i++ 53 | if i > ra.mask { 54 | i = 0 55 | } 56 | if i == ra.last { 57 | ra.allAllocated = true 58 | return 0, errOutOfResourceIds 59 | } 60 | } 61 | ra.bitmap.SetBit(ra.bitmap, int(i), 1) 62 | ra.last = i 63 | return ra.base | i, nil 64 | } 65 | 66 | func (ra *resourceIdAllocator) free(rid uint32) error { 67 | ra.mu.Lock() 68 | defer ra.mu.Unlock() 69 | 70 | i := rid & ra.mask 71 | if rid-i != ra.base { 72 | return errors.New("resource id outside range") 73 | } 74 | 75 | if ra.bitmap.Bit(int(i)) == 0 { 76 | return errors.New("resource id not used") 77 | } 78 | ra.bitmap.SetBit(ra.bitmap, int(i), 0) 79 | ra.allAllocated = false 80 | return nil 81 | } 82 | 83 | func (ra *resourceIdAllocator) usedCount() int { 84 | ra.mu.Lock() 85 | count := 0 86 | bitLen := ra.bitmap.BitLen() 87 | for i := 0; i < bitLen; i++ { 88 | if ra.bitmap.Bit(i) == 1 { 89 | count++ 90 | } 91 | } 92 | ra.mu.Unlock() 93 | return count 94 | } 95 | -------------------------------------------------------------------------------- /rpm/golang-github-linuxdeepin-go-x11-client.spec: -------------------------------------------------------------------------------- 1 | # Run tests in check section 2 | # disable for bootstrapping 3 | %bcond_with check 4 | %global with_debug 1 5 | 6 | %if 0%{?with_debug} 7 | %global debug_package %{nil} 8 | %endif 9 | 10 | %global provider github 11 | %global provider_tld com 12 | %global project linuxdeepin 13 | %global repo go-x11-client 14 | 15 | %global provider_prefix %{provider}.%{provider_tld}/%{project}/%{repo} 16 | %global import_path %{provider_prefix} 17 | 18 | Name: golang-github-linuxdeepin-go-x11-client 19 | Version: 0.6.7 20 | Release: 1 21 | Summary: A X11 client Go bindings for Deepin Desktop Environment 22 | License: GPLv3 23 | URL: %{gourl} 24 | Source0: %{name}_%{version}.orig.tar.xz 25 | BuildRequires: compiler(go-compiler) 26 | 27 | %description 28 | %{summary}. 29 | 30 | %package devel 31 | Summary: %{summary} 32 | BuildArch: noarch 33 | BuildRequires: gocode 34 | 35 | 36 | %description devel 37 | %{summary}. 38 | 39 | 40 | %prep 41 | %forgeautosetup 42 | 43 | %install 44 | install -d -p %{buildroot}/%{gopath}/src/%{import_path}/ 45 | for file in $(find . -iname "*.go") ; do 46 | install -d -p %{buildroot}/%{gopath}/src/%{import_path}/$(dirname $file) 47 | cp -pav $file %{buildroot}/%{gopath}/src/%{import_path}/$file 48 | echo "%%{gopath}/src/%%{import_path}/$file" >> devel.file-list 49 | done 50 | 51 | %files devel -f devel.file-list 52 | %doc README 53 | %license LICENSE 54 | 55 | %changelog 56 | * Thu Mar 19 2021 uoser - 0.6.7-1 57 | - Update to 0.6.7 58 | -------------------------------------------------------------------------------- /tools/enum.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | from common import * 6 | 7 | _enum_to_str_list = [ 8 | # xproto.xml 9 | ('xcb', 'VisualClass'), 10 | ('xcb', 'EventMask'), 11 | ('xcb', 'BackingStore'), 12 | ('xcb', 'ImageOrder'), 13 | ('xcb', 'ModMask'), 14 | ('xcb', 'ButtonMask'), 15 | ('xcb', 'KeyButMask'), 16 | ('xcb', 'Motion'), 17 | ('xcb', 'NotifyDetail'), 18 | ('xcb', 'NotifyMode'), 19 | ('xcb', 'Visibility'), 20 | ('xcb', 'Place'), 21 | ('xcb', 'ColormapState'), 22 | ('xcb', 'Mapping'), 23 | ('xcb', 'WindowClass'), 24 | ('xcb', 'Gravity'), 25 | ('xcb', 'MapState'), 26 | ('xcb', 'ConfigWindow'), 27 | ('xcb', 'GrabStatus'), 28 | ('xcb', 'FontDraw'), 29 | ('xcb', 'StackMode'), 30 | ('xcb', 'Blanking'), 31 | ('xcb', 'Exposures'), 32 | ('xcb', 'MappingStatus'), 33 | 34 | # TODO 35 | 36 | # screensaver.xml 37 | ('xcb', 'ScreenSaver', 'Kind'), 38 | ('xcb', 'ScreenSaver', 'State'), 39 | ] 40 | 41 | def get_enum_prefix(name): 42 | pkg_name, name = split_pkg_and_type(name) 43 | # check result 44 | enum_prefix = ''.join(name) 45 | assert enum_prefix[0].isupper() 46 | 47 | _ns = get_namespace() 48 | if _ns.is_ext and pkg_name != '' and pkg_name != get_go_pkg_name(_ns.ext_name): 49 | # add pkg ident 50 | enum_prefix = pkg_name + '.' + enum_prefix 51 | 52 | return enum_prefix 53 | 54 | 55 | _cname_special_cases = { 56 | 'VISUALID': 'VisualID', 57 | } 58 | 59 | _item_name_special_list = [ 60 | # xproto.xml 61 | 'YX', 62 | 'XY', 63 | 'DE', 64 | 'RGB', 65 | 'LSB', 66 | 'MSB', 67 | 'WM', 68 | 69 | # render.xml 70 | 'BGR', 71 | 'HSL', 72 | ] 73 | 74 | def get_enum_item_name(name): 75 | if name in _cname_special_cases: 76 | return _cname_special_cases[name] 77 | 78 | name_parts = split_name(name) 79 | result = [] 80 | for x in name_parts: 81 | if x in _item_name_special_list: 82 | result.append(x) 83 | else: 84 | result.append(x.title()) 85 | return ''.join(result) 86 | 87 | 88 | def define_go_enum_to_string_func(prefix, self): 89 | if len(self.values) < 2: 90 | return 91 | if not self.name in _enum_to_str_list: 92 | return 93 | 94 | l('\nfunc %sEnumToStr(v int) string {', prefix) 95 | 96 | if len(self.bits) > 0: 97 | l('strv := []string{}') 98 | l('switch {') 99 | for (item_name, val) in self.values: 100 | val = int(val) 101 | if val == 0: 102 | continue 103 | l('case v & %s%s > 0:', prefix, item_name) 104 | l(' strv = append(strv, "%s")', item_name) 105 | l('}') # end switch 106 | l('return "[" + strings.Join(strv, "|") + "]"') 107 | 108 | else: 109 | items = dict() 110 | # key is val, value is list of item_name 111 | for (item_name, val) in self.values: 112 | val = int(val) 113 | if val in items: 114 | items[val].append(item_name) 115 | # items[val] = items[val].append(item_name) 116 | else: 117 | items[val] = [ item_name ] 118 | 119 | l('switch v {') 120 | for k in sorted(items.keys()): 121 | l('case %d:', k) 122 | l(' return "%s"', ' or '.join(items[k])) 123 | 124 | # case default 125 | l('default:') 126 | l('return ""') 127 | l('}') # end switch 128 | 129 | l('}') # end func 130 | -------------------------------------------------------------------------------- /tools/gen/main.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package main 6 | 7 | import ( 8 | "bytes" 9 | "flag" 10 | "fmt" 11 | "go/ast" 12 | "go/format" 13 | "go/parser" 14 | "go/printer" 15 | "go/token" 16 | "log" 17 | "os" 18 | "strings" 19 | 20 | "github.com/linuxdeepin/go-lib/strv" 21 | ) 22 | 23 | var optIsExt bool 24 | var optExtraExts string 25 | 26 | func init() { 27 | flag.BoolVar(&optIsExt, "e", false, "is ext") 28 | flag.StringVar(&optExtraExts, "extra-exts", "", "") 29 | } 30 | 31 | var xPrefix string 32 | 33 | func astNodeToStr(fileSet *token.FileSet, node interface{}) (string, error) { 34 | var buf bytes.Buffer 35 | err := printer.Fprint(&buf, fileSet, node) 36 | if err != nil { 37 | return "", err 38 | } 39 | return buf.String(), nil 40 | } 41 | 42 | type Generator struct { 43 | buf bytes.Buffer 44 | } 45 | 46 | func (g *Generator) p(format string, args ...interface{}) { 47 | _, err := fmt.Fprintf(&g.buf, format, args...) 48 | if err != nil { 49 | log.Fatal(err) 50 | } 51 | } 52 | 53 | func (g *Generator) format() []byte { 54 | src, err := format.Source(g.buf.Bytes()) 55 | if err != nil { 56 | log.Println("warning: internal error: invalid Go generated:", err) 57 | return g.buf.Bytes() 58 | } 59 | return src 60 | } 61 | 62 | type requestFunc struct { 63 | name string 64 | encodeFuncName string 65 | encodeFuncArgs string 66 | args string 67 | noReply bool 68 | } 69 | 70 | func main() { 71 | log.SetFlags(log.Lshortfile) 72 | 73 | goPackage := os.Getenv("GOPACKAGE") 74 | log.Println(goPackage) 75 | // parse file 76 | 77 | if goPackage != "x" { 78 | xPrefix = "x." 79 | } 80 | 81 | fs := token.NewFileSet() 82 | flag.Parse() 83 | name := flag.Arg(0) 84 | f, err := parser.ParseFile(fs, name, nil, parser.ParseComments) 85 | if err != nil { 86 | log.Fatal(err) 87 | } 88 | 89 | var requestFuncs []*requestFunc 90 | var hasReplyRequests strv.Strv 91 | ast.Inspect(f, func(node ast.Node) bool { 92 | funcDel, ok := node.(*ast.FuncDecl) 93 | if !ok { 94 | return true 95 | } 96 | if funcDel.Recv != nil { 97 | // is method 98 | return false 99 | } 100 | 101 | funcName := funcDel.Name.Name 102 | if strings.HasPrefix(funcName, "encode") { 103 | 104 | docText := funcDel.Doc.Text() 105 | if !strings.Contains(docText, "#WREQ") { 106 | return false 107 | } 108 | wreqOption := strings.TrimSpace(strings.TrimPrefix(docText, "#WREQ")) 109 | wreqOptions := strings.Split(wreqOption, " ") 110 | var varargs []string 111 | for _, value := range wreqOptions { 112 | if strings.HasPrefix(value, "vararg:") { 113 | varargs = append(varargs, value[len("vararg:"):]) 114 | } 115 | } 116 | 117 | params := funcDel.Type.Params.List 118 | var args []string 119 | var encodeFuncArgs []string 120 | for _, param := range params { 121 | log.Println(param.Names) 122 | 123 | var paramNames []string 124 | for _, name := range param.Names { 125 | paramNames = append(paramNames, name.Name) 126 | } 127 | typeStr, err := astNodeToStr(fs, param.Type) 128 | if err != nil { 129 | log.Fatal(err) 130 | } 131 | 132 | argNamesType := strings.Join(paramNames, ",") + " " + typeStr 133 | 134 | args = append(args, argNamesType) 135 | for _, value := range paramNames { 136 | if strv.Strv(varargs).Contains(value) { 137 | value = "options..." 138 | } 139 | encodeFuncArgs = append(encodeFuncArgs, value) 140 | } 141 | } 142 | 143 | requestFuncs = append(requestFuncs, &requestFunc{ 144 | encodeFuncName: funcName, 145 | encodeFuncArgs: strings.Join(encodeFuncArgs, ","), 146 | name: strings.TrimPrefix(funcName, "encode"), 147 | args: strings.Join(args, ","), 148 | }) 149 | } else if strings.HasPrefix(funcName, "read") && 150 | strings.HasSuffix(funcName, "Reply") { 151 | reqName := strings.TrimPrefix(funcName, "read") 152 | reqName = strings.TrimSuffix(reqName, "Reply") 153 | hasReplyRequests = append(hasReplyRequests, reqName) 154 | } 155 | 156 | return false 157 | }) 158 | 159 | log.Println(hasReplyRequests) 160 | for _, reqFunc := range requestFuncs { 161 | if !hasReplyRequests.Contains(reqFunc.name) { 162 | reqFunc.noReply = true 163 | } 164 | } 165 | //spew.Dump(requestFuncs) 166 | 167 | g := &Generator{} 168 | 169 | g.p("package %s\n", goPackage) 170 | 171 | const pkgPathBase = "github.com/linuxdeepin/go-x11-client" 172 | if goPackage != "x" { 173 | g.p("import x \"%s\"\n", pkgPathBase) 174 | } 175 | 176 | extraExts := strings.Split(optExtraExts, ",") 177 | for _, e := range extraExts { 178 | if e == "" { 179 | continue 180 | } 181 | g.p("import \"%s/ext/%s\"\n", pkgPathBase, e) 182 | } 183 | 184 | for _, reqFunc := range requestFuncs { 185 | if reqFunc.noReply { 186 | g.pRequestFunc(reqFunc, false) 187 | g.pRequestFunc(reqFunc, true) 188 | } else { 189 | g.pRequestFunc(reqFunc, true) 190 | // cookie Reply method 191 | g.p("\nfunc (cookie %sCookie) Reply(conn *%sConn) (*%sReply, error) {\n", 192 | reqFunc.name, xPrefix, reqFunc.name) 193 | g.p(`replyBuf, err := conn.WaitForReply(%sSeqNum(cookie)) 194 | if err != nil { 195 | return nil, err 196 | } 197 | r := %sNewReaderFromData(replyBuf) 198 | var reply %sReply 199 | err = read%sReply(r, &reply) 200 | if err != nil { 201 | return nil, err 202 | } 203 | return &reply, nil 204 | } 205 | `, xPrefix, xPrefix, reqFunc.name, reqFunc.name) 206 | } 207 | 208 | } 209 | 210 | _, err = os.Stdout.Write(g.format()) 211 | if err != nil { 212 | log.Fatal(err) 213 | } 214 | } 215 | 216 | func (g *Generator) pRequestFunc(reqFunc *requestFunc, check bool) { 217 | returnType := xPrefix + "VoidCookie" 218 | if !reqFunc.noReply { 219 | // has reply 220 | returnType = reqFunc.name + "Cookie" 221 | } else if !check { 222 | // no reply + no check 223 | returnType = "" 224 | } 225 | funcName := reqFunc.name 226 | sendReqFlag := "0" 227 | if check { 228 | sendReqFlag = xPrefix + "RequestChecked" 229 | } 230 | 231 | if reqFunc.noReply && check { 232 | funcName += "Checked" 233 | } 234 | 235 | g.p("\nfunc %s(conn *%sConn, %s) %s {\n", funcName, xPrefix, reqFunc.args, 236 | returnType) 237 | 238 | if optIsExt { 239 | g.p("body := %s(%s)\n", reqFunc.encodeFuncName, reqFunc.encodeFuncArgs) 240 | } else { 241 | g.p("headerData, body := %s(%s)\n", reqFunc.encodeFuncName, reqFunc.encodeFuncArgs) 242 | } 243 | g.p("req := &%sProtocolRequest{\n", xPrefix) 244 | 245 | if optIsExt { 246 | g.p("Ext: _ext,\n") 247 | } 248 | 249 | if reqFunc.noReply { 250 | g.p("NoReply: true,\n") 251 | } 252 | 253 | g.p("Header: %sRequestHeader{\n", xPrefix) 254 | 255 | if optIsExt { 256 | g.p(" Data: %sOpcode,\n", reqFunc.name) 257 | } else { 258 | g.p(" Opcode: %sOpcode,\n", reqFunc.name) 259 | g.p(" Data: headerData,\n") 260 | } 261 | 262 | g.p("},\n") 263 | g.p("Body: body,\n") 264 | g.p("}\n") 265 | 266 | if returnType == "" { 267 | g.p("conn.SendRequest(%s, req)\n", sendReqFlag) 268 | } else { 269 | g.p("seq := conn.SendRequest(%s, req)\n", sendReqFlag) 270 | g.p("return %s(seq)", returnType) 271 | } 272 | 273 | g.p("}\n") 274 | } 275 | -------------------------------------------------------------------------------- /tools/go_client.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | import sys 6 | from common import * 7 | from enum import * 8 | import argparse 9 | import subprocess 10 | 11 | error_names = [] 12 | request_names = [] 13 | max_error_code = 0 14 | x_prefix = '' 15 | 16 | parser = argparse.ArgumentParser() 17 | parser.add_argument('xml_file') 18 | parser.add_argument('-o', '--output', dest='output', default='/dev/stdout') 19 | parser.add_argument('-F', '--no-fmt', dest='no_fmt', action='store_true') 20 | parser.add_argument('-p', '--package', dest='package') 21 | parser.add_argument( 22 | '-I', '--no-import-x', dest='no_import_x', action='store_true') 23 | 24 | args = parser.parse_args() 25 | 26 | def go_open(self): 27 | set_namespace(self.namespace) 28 | _ns = get_namespace() 29 | 30 | global args 31 | if args.package is not None: 32 | pkg = args.package 33 | else: 34 | # pkg = _ns.header 35 | if _ns.is_ext: 36 | pkg = get_go_pkg_name(_ns.ext_name) 37 | else: 38 | pkg = 'x' 39 | 40 | set_level(0) 41 | l('package %s', pkg) 42 | 43 | if pkg != 'x': 44 | l('import x "github.com/linuxdeepin/go-x11-client"') 45 | global x_prefix 46 | x_prefix = 'x.' 47 | 48 | if _ns.is_ext: 49 | l('// _ns.ext_name: %s', _ns.ext_name) 50 | l('const MajorVersion = %d', int(_ns.major_version)) 51 | l('const MinorVersion = %d', int(_ns.minor_version)) 52 | 53 | l('var _ext *%sExtension', x_prefix) 54 | l('func Ext() *x.Extension {') 55 | l(' return _ext') 56 | l('}') 57 | 58 | def go_close(self): 59 | # handle errors 60 | _ns = get_namespace() 61 | global error_names 62 | global request_names 63 | global x_prefix 64 | 65 | if len(error_names) > 0: 66 | l("var errorCodeNameMap = map[uint8]string{") 67 | for name in error_names: 68 | error_code = get_type_name(name) + "ErrorCode" 69 | error_name = get_type_name(name) 70 | if not error_name.startswith("Bad"): 71 | error_name = "Bad" + error_name 72 | if error_name == "BadDeviceBusy": 73 | error_name = "DeviceBusy" 74 | l("%s : \"%s\",", error_code, error_name) 75 | l("}") # end error code name map 76 | 77 | if len(request_names) > 0: 78 | l("var requestOpcodeNameMap = map[uint]string{") 79 | for name in request_names: 80 | l("%sOpcode : \"%s\",", name, name) 81 | l("}") # end request opcode name map 82 | 83 | if _ns.is_ext: 84 | l("func init() {") 85 | errMap = "nil" 86 | if len(error_names) > 0: 87 | errMap = "errorCodeNameMap" 88 | reqMap = "nil" 89 | if len(request_names) > 0: 90 | reqMap = "requestOpcodeNameMap" 91 | 92 | l('_ext = %sNewExtension("%s", %d, %s, %s)', x_prefix, _ns.ext_xname, max_error_code, errMap, reqMap) 93 | l("}") # end func init 94 | 95 | # write source file 96 | global args 97 | gofile = open(args.output, 'w') 98 | if args.no_fmt: 99 | output_lines(gofile) 100 | else: 101 | pipe = subprocess.Popen( 102 | 'gofmt', bufsize=4096, stdin=subprocess.PIPE, stdout=gofile) 103 | output_lines(pipe.stdin) 104 | pipe.wait() 105 | if pipe.returncode != 0: 106 | # write no formated code and raise exception. 107 | output_lines(gofile) 108 | raise Exception("gofmt exit with error code %d" % pipe.returncode) 109 | 110 | def go_simple(self, name): 111 | if self.name != name: 112 | type_name = get_type_name(name) 113 | source_type_name = get_type_name(self.name) 114 | set_level(0) 115 | l("// simple %s", name) 116 | l("type %s %s", type_name, source_type_name) 117 | 118 | def go_enum(self, name): 119 | prefix = get_enum_prefix(name) 120 | set_level(0) 121 | l("// enum %s", prefix) 122 | l('const (') 123 | for (item_name, val) in self.values: 124 | item_name = get_enum_item_name(item_name) 125 | l("%s%s = %s", prefix, item_name, val) 126 | # newline 127 | l(')\n') 128 | 129 | 130 | def go_struct(self, name): 131 | pass 132 | 133 | def go_union(self, name): 134 | pass 135 | 136 | def go_request(self, name): 137 | global request_names 138 | name_base = get_request_name(name) 139 | opcode_name = name_base + "Opcode" 140 | l("const %s = %s", opcode_name, self.opcode) 141 | request_names.append(name_base) 142 | 143 | if self.reply: 144 | l("type %s %sSeqNum", name_base + "Cookie", x_prefix) 145 | 146 | def go_event(self, name): 147 | type_name = get_type_name(name) + "Event" 148 | code_name = type_name + "Code" 149 | code = self.opcodes[name] 150 | l('const %s = %d', code_name, int(code)) 151 | define_go_event_new_func(type_name) 152 | 153 | 154 | def define_go_event_new_func(go_type): 155 | global x_prefix 156 | l('\nfunc New%s(data []byte) (*%s, error) {', go_type, go_type) 157 | l('var ev %s', go_type) 158 | l('r := %sNewReaderFromData(data)', x_prefix) 159 | l('err := read%s(r, &ev)', go_type) 160 | l('if err != nil {') 161 | l(' return nil, err') 162 | l('}') 163 | l('return &ev, nil') 164 | l('}') 165 | 166 | def go_error(self, name): 167 | global max_error_code 168 | global error_names 169 | type_name = get_type_name(name) + 'Error' 170 | code_name = type_name + "Code" 171 | code = int(self.opcodes[name]) 172 | l('const %s = %d', code_name, code) 173 | error_names.append(name) 174 | if code > max_error_code: 175 | max_error_code = code 176 | 177 | def go_eventstruct(self, name): 178 | pass 179 | 180 | output = { 181 | 'open': go_open, 182 | 'close': go_close, 183 | 'simple': go_simple, 184 | 'enum': go_enum, 185 | 'struct': go_struct, 186 | 'union': go_union, 187 | 'request': go_request, 188 | 'event': go_event, 189 | 'error': go_error, 190 | 'eventstruct': go_eventstruct, 191 | } 192 | # Import the module class 193 | from xcbgen.state import Module 194 | from xcbgen.xtypes import * 195 | 196 | # Parse the xml header 197 | module = Module(args.xml_file, output) 198 | 199 | # Build type-registry and resolve type dependencies 200 | module.register() 201 | module.resolve() 202 | 203 | # Output the code 204 | module.generate() 205 | -------------------------------------------------------------------------------- /util/atom/atom.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package atom 6 | 7 | import ( 8 | x "github.com/linuxdeepin/go-x11-client" 9 | ) 10 | 11 | func GetVal(conn *x.Conn, name string) (x.Atom, error) { 12 | reply, err := x.InternAtom(conn, false, name).Reply(conn) 13 | if err != nil { 14 | return 0, err 15 | } 16 | return reply.Atom, nil 17 | } 18 | 19 | func GetExistingVal(conn *x.Conn, name string) (x.Atom, error) { 20 | reply, err := x.InternAtom(conn, true, name).Reply(conn) 21 | if err != nil { 22 | return 0, err 23 | } 24 | return reply.Atom, nil 25 | } 26 | 27 | func GetName(conn *x.Conn, val x.Atom) (string, error) { 28 | reply, err := x.GetAtomName(conn, val).Reply(conn) 29 | if err != nil { 30 | return "", err 31 | } 32 | return reply.Name, nil 33 | } 34 | -------------------------------------------------------------------------------- /util/cursor/cursor.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package cursor 6 | 7 | import ( 8 | "errors" 9 | "image" 10 | "image/color" 11 | "image/color/palette" 12 | "image/draw" 13 | "image/gif" 14 | "os" 15 | 16 | "github.com/linuxdeepin/go-x11-client" 17 | "github.com/linuxdeepin/go-x11-client/ext/render" 18 | "github.com/linuxdeepin/go-x11-client/ext/xfixes" 19 | ) 20 | 21 | type Image struct { 22 | Size uint32 // nominal size for matching 23 | Width uint32 // actual width 24 | Height uint32 // actual height 25 | XHot uint32 // hot spot x 26 | YHot uint32 // hot spot y 27 | Delay uint32 // delay between animation frames in milliseconds 28 | Pixels []byte 29 | img *image.RGBA 30 | } 31 | 32 | func (img *Image) Img() *image.RGBA { 33 | if img.img != nil { 34 | return img.img 35 | } 36 | 37 | // parse img.pixels 38 | pixels := img.Pixels 39 | rgbaImg := image.NewRGBA(image.Rect(0, 0, int(img.Width), int(img.Height))) 40 | pixIdx := 0 41 | for y := 0; y < int(img.Height); y++ { 42 | for X := 0; X < int(img.Width); X++ { 43 | blue := uint8(pixels[pixIdx]) 44 | green := uint8(pixels[pixIdx+1]) 45 | red := uint8(pixels[pixIdx+2]) 46 | alpha := uint8(pixels[pixIdx+3]) 47 | rgbaImg.SetRGBA(X, y, color.RGBA{R: red, G: green, B: blue, A: alpha}) 48 | pixIdx += 4 49 | } 50 | } 51 | img.img = rgbaImg 52 | return rgbaImg 53 | } 54 | 55 | var errImageNotFound = errors.New("image not found") 56 | 57 | func LoadImageFromFile(filename string, size int) (*Image, error) { 58 | f, err := os.Open(filename) 59 | if err != nil { 60 | return nil, err 61 | } 62 | return loadImageFromFile(f, size) 63 | } 64 | 65 | func loadImageFromFile(f *os.File, size int) (*Image, error) { 66 | d, err := newDecoder(f) 67 | if err != nil { 68 | return nil, err 69 | } 70 | defer d.close() 71 | 72 | bestSize, _ := d.findBestSize(size) 73 | if bestSize == 0 { 74 | return nil, errImageNotFound 75 | } 76 | 77 | for _, toc := range d.tocs { 78 | if toc.Type == typeImage && int(toc.Subtype) == bestSize { 79 | img, err := d.readImage(toc) 80 | if err != nil { 81 | return nil, err 82 | } 83 | 84 | return img, nil 85 | } 86 | } 87 | 88 | return nil, errImageNotFound 89 | } 90 | 91 | func dist(a, b int) int { 92 | if a > b { 93 | return a - b 94 | } 95 | return b - a 96 | } 97 | 98 | func (d *decoder) findBestSize(size int) (bestSize, nSizes int) { 99 | for _, toc := range d.tocs { 100 | if toc.Type != typeImage { 101 | continue 102 | } 103 | thisSize := int(toc.Subtype) 104 | if bestSize == 0 || dist(thisSize, size) < dist(bestSize, size) { 105 | bestSize = thisSize 106 | nSizes = 1 107 | } else if thisSize == bestSize { 108 | nSizes++ 109 | } 110 | } 111 | return 112 | } 113 | 114 | type Images []*Image 115 | 116 | func LoadImagesFromFile(filename string, size int) (Images, error) { 117 | f, err := os.Open(filename) 118 | if err != nil { 119 | return nil, err 120 | } 121 | return loadImagesFromFile(f, size) 122 | } 123 | 124 | func loadImagesFromFile(f *os.File, size int) (Images, error) { 125 | d, err := newDecoder(f) 126 | if err != nil { 127 | return nil, err 128 | } 129 | defer d.close() 130 | 131 | bestSize, nSizes := d.findBestSize(size) 132 | if bestSize == 0 { 133 | return nil, errImageNotFound 134 | } 135 | 136 | images := make(Images, nSizes) 137 | var idx int 138 | for _, toc := range d.tocs { 139 | if toc.Type == typeImage && int(toc.Subtype) == bestSize { 140 | img, err := d.readImage(toc) 141 | if err != nil { 142 | return nil, err 143 | } 144 | 145 | images[idx] = img 146 | idx++ 147 | } 148 | } 149 | return images, nil 150 | } 151 | 152 | func (images Images) ToGIF() *gif.GIF { 153 | p := append(palette.WebSafe, color.Transparent) 154 | result := &gif.GIF{} 155 | for _, img0 := range images { 156 | img := img0.Img() 157 | bounds := img.Bounds() 158 | pImg := image.NewPaletted(bounds, p) 159 | draw.Draw(pImg, bounds, img, image.Point{}, draw.Src) 160 | result.Image = append(result.Image, pImg) 161 | result.Delay = append(result.Delay, int(img0.Delay)/10) 162 | result.Disposal = append(result.Disposal, gif.DisposalBackground) 163 | } 164 | return result 165 | } 166 | 167 | func (img *Image) LoadCursor(conn *x.Conn, name string) (x.Cursor, error) { 168 | rootWin := conn.GetDefaultScreen().Root 169 | depth := uint8(32) 170 | xid, err := conn.AllocID() 171 | if err != nil { 172 | return 0, err 173 | } 174 | pixmapId := x.Pixmap(xid) 175 | x.CreatePixmap(conn, depth, pixmapId, x.Drawable(rootWin), uint16(img.Width), uint16(img.Height)) 176 | 177 | xid, err = conn.AllocID() 178 | if err != nil { 179 | return 0, err 180 | } 181 | cid := x.GContext(xid) 182 | x.CreateGC(conn, cid, x.Drawable(pixmapId), 0, nil) 183 | 184 | pictFormats, err := render.QueryPictFormats(conn).Reply(conn) 185 | if err != nil { 186 | return 0, err 187 | } 188 | 189 | var formatARGB32 render.PictFormat 190 | for _, f := range pictFormats.Formats { 191 | if f.Depth == 32 && 192 | f.Type == render.PictTypeDirect && 193 | f.Direct.BlueMask == 255 && 194 | f.Direct.GreenMask == 255 && 195 | f.Direct.RedMask == 255 && 196 | f.Direct.AlphaMask == 255 && 197 | 198 | f.Direct.AlphaShift == 24 && 199 | f.Direct.RedShift == 16 && 200 | f.Direct.GreenShift == 8 && 201 | f.Direct.BlueShift == 0 { 202 | 203 | formatARGB32 = f.Id 204 | break 205 | } 206 | } 207 | if formatARGB32 == 0 { 208 | return 0, errors.New("not found pic format ARGB32") 209 | } 210 | x.PutImage(conn, x.ImageFormatZPixmap, x.Drawable(pixmapId), cid, uint16(img.Width), uint16(img.Height), 0, 0, 0, depth, img.Pixels) 211 | 212 | x.FreeGC(conn, cid) 213 | err = conn.FreeID(uint32(cid)) 214 | if err != nil { 215 | return 0, err 216 | } 217 | 218 | xid, err = conn.AllocID() 219 | if err != nil { 220 | return 0, err 221 | } 222 | pictId := render.Picture(xid) 223 | render.CreatePicture(conn, pictId, x.Drawable(pixmapId), formatARGB32, 0, nil) 224 | 225 | x.FreePixmap(conn, pixmapId) 226 | err = conn.FreeID(uint32(pixmapId)) 227 | if err != nil { 228 | return 0, err 229 | } 230 | 231 | xid, err = conn.AllocID() 232 | if err != nil { 233 | return 0, err 234 | } 235 | cursorId := x.Cursor(xid) 236 | render.CreateCursor(conn, cursorId, pictId, uint16(img.XHot), uint16(img.YHot)) 237 | 238 | render.FreePicture(conn, pictId) 239 | err = conn.FreeID(uint32(pictId)) 240 | if err != nil { 241 | return 0, err 242 | } 243 | 244 | if name != "" { 245 | xfixes.SetCursorName(conn, cursorId, name) 246 | } 247 | 248 | return cursorId, nil 249 | } 250 | 251 | func (images Images) LoadCursor(conn *x.Conn, name string) (x.Cursor, error) { 252 | if len(images) == 0 { 253 | return 0, errImageNotFound 254 | } else if len(images) == 1 { 255 | return images[0].LoadCursor(conn, name) 256 | } 257 | 258 | cursors := make([]x.Cursor, 0, len(images)) 259 | defer func() { 260 | for _, cid := range cursors { 261 | x.FreeCursor(conn, cid) 262 | _ = conn.FreeID(uint32(cid)) 263 | } 264 | }() 265 | 266 | for _, img := range images { 267 | curId, err := img.LoadCursor(conn, "") 268 | if err != nil { 269 | return 0, err 270 | } 271 | cursors = append(cursors, curId) 272 | } 273 | 274 | xid, err := conn.AllocID() 275 | if err != nil { 276 | return 0, err 277 | } 278 | animCursorId := x.Cursor(xid) 279 | animCursorEltSlice := make([]render.AnimCursorElt, len(cursors)) 280 | for idx, cursorId := range cursors { 281 | animCursorEltSlice[idx] = render.AnimCursorElt{ 282 | Cursor: cursorId, 283 | Delay: images[idx].Delay, // unit is milliseconds 284 | } 285 | } 286 | render.CreateAnimCursor(conn, animCursorId, animCursorEltSlice) 287 | 288 | if name != "" { 289 | xfixes.SetCursorName(conn, animCursorId, name) 290 | } 291 | 292 | return animCursorId, nil 293 | } 294 | -------------------------------------------------------------------------------- /util/cursor/cursor_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package cursor 6 | 7 | import ( 8 | "image/gif" 9 | "io/ioutil" 10 | "os" 11 | "testing" 12 | 13 | "github.com/stretchr/testify/assert" 14 | ) 15 | 16 | func TestLoadImage(t *testing.T) { 17 | _, err := os.Stat("/usr/share/icons/deepin/cursors/left_ptr") 18 | if err == nil { 19 | _, err = LoadImage("deepin", "left_ptr", 24) 20 | assert.Nil(t, err) 21 | } else { 22 | t.Skip(err) 23 | } 24 | } 25 | 26 | func TestLoadImages(t *testing.T) { 27 | _, err := os.Stat("/usr/share/icons/deepin/cursors/watch") 28 | if err == nil { 29 | _, err = LoadImages("deepin", "watch", 24) 30 | assert.Nil(t, err) 31 | } else { 32 | t.Skip(err) 33 | } 34 | } 35 | 36 | func TestLoadImageFromFile(t *testing.T) { 37 | img, err := LoadImageFromFile("testdata/left_ptr", 24) 38 | if os.IsNotExist(err) { 39 | t.Skip(err) 40 | } 41 | 42 | assert.Nil(t, err) 43 | _ = img.Img() 44 | assert.EqualValues(t, 24, img.Size) 45 | assert.EqualValues(t, 24, img.Width) 46 | assert.EqualValues(t, 24, img.Height) 47 | assert.EqualValues(t, 7, img.XHot) 48 | assert.EqualValues(t, 4, img.YHot) 49 | assert.EqualValues(t, 50, img.Delay) 50 | } 51 | 52 | func TestLoadImagesFromFile(t *testing.T) { 53 | images, err := LoadImagesFromFile("testdata/watch", 24) 54 | if os.IsNotExist(err) { 55 | t.Skip(err) 56 | } 57 | assert.Nil(t, err) 58 | assert.Len(t, images, 16) 59 | 60 | for _, img := range images { 61 | _ = img.Img() 62 | assert.EqualValues(t, 24, img.Size) 63 | assert.EqualValues(t, 24, img.Width) 64 | assert.EqualValues(t, 24, img.Height) 65 | assert.EqualValues(t, 60, img.Delay) 66 | } 67 | } 68 | 69 | func BenchmarkLoadImageFromFile(b *testing.B) { 70 | for i := 0; i < b.N; i++ { 71 | img, err := LoadImageFromFile("testdata/left_ptr", 24) 72 | if err != nil { 73 | b.Fatal(err) 74 | } 75 | _ = img.Img() 76 | } 77 | } 78 | 79 | func BenchmarkLoadImagesFromFile(b *testing.B) { 80 | for i := 0; i < b.N; i++ { 81 | imgs, err := LoadImagesFromFile("testdata/watch", 24) 82 | if err != nil { 83 | b.Fatal(err) 84 | } 85 | for _, img := range imgs { 86 | _ = img.Img() 87 | } 88 | } 89 | } 90 | 91 | func TestImages_ToGIF(t *testing.T) { 92 | images, err := LoadImagesFromFile("testdata/watch", 24) 93 | if os.IsNotExist(err) { 94 | t.Skip(err) 95 | } 96 | assert.Nil(t, err) 97 | outGif := images.ToGIF() 98 | err = gif.EncodeAll(ioutil.Discard, outGif) 99 | assert.Nil(t, err) 100 | } 101 | -------------------------------------------------------------------------------- /util/cursor/read.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package cursor 6 | 7 | import ( 8 | "bufio" 9 | "encoding/binary" 10 | "errors" 11 | "io" 12 | "os" 13 | ) 14 | 15 | const ( 16 | typeImage = 0xfffd0002 17 | ) 18 | 19 | type decoder struct { 20 | f *os.File 21 | br *bufio.Reader 22 | version uint32 23 | tocs []tocEntry 24 | tmp [36]byte 25 | } 26 | 27 | func newDecoder(f *os.File) (*decoder, error) { 28 | var d decoder 29 | d.f = f 30 | d.br = bufio.NewReader(f) 31 | err := d.readHeader() 32 | if err != nil { 33 | return nil, err 34 | } 35 | 36 | return &d, nil 37 | } 38 | 39 | func (d *decoder) close() error { 40 | return d.f.Close() 41 | } 42 | 43 | // table of contents entry 44 | type tocEntry struct { 45 | Type uint32 // entry type 46 | Subtype uint32 // 47 | Position uint32 // absolute byte position of table in file 48 | } 49 | 50 | func readFull(r io.Reader, b []byte) error { 51 | _, err := io.ReadFull(r, b) 52 | if err == io.EOF { 53 | err = io.ErrUnexpectedEOF 54 | } 55 | return err 56 | } 57 | 58 | func (d *decoder) readHeader() error { 59 | err := readFull(d.br, d.tmp[:16]) 60 | if err != nil { 61 | return err 62 | } 63 | 64 | magic := string(d.tmp[:4]) 65 | if magic != "Xcur" { 66 | return errors.New("magic not match") 67 | } 68 | 69 | d.version = binary.LittleEndian.Uint32(d.tmp[8:12]) 70 | nToc := binary.LittleEndian.Uint32(d.tmp[12:16]) 71 | d.tocs = make([]tocEntry, nToc) 72 | for i := range d.tocs { 73 | d.tocs[i], err = d.readTocEntry() 74 | if err != nil { 75 | return err 76 | } 77 | } 78 | 79 | return nil 80 | } 81 | 82 | func (d *decoder) readTocEntry() (tocEntry, error) { 83 | err := readFull(d.br, d.tmp[:12]) 84 | if err != nil { 85 | return tocEntry{}, err 86 | } 87 | 88 | var e tocEntry 89 | e.Type = binary.LittleEndian.Uint32(d.tmp[:4]) 90 | e.Subtype = binary.LittleEndian.Uint32(d.tmp[4:8]) 91 | e.Position = binary.LittleEndian.Uint32(d.tmp[8:12]) 92 | return e, nil 93 | } 94 | 95 | func (d *decoder) setPos(pos uint32) error { 96 | _, err := d.f.Seek(int64(pos), io.SeekStart) 97 | if err != nil { 98 | return err 99 | } 100 | d.br.Reset(d.f) 101 | return nil 102 | } 103 | 104 | func (d *decoder) readImage(toc tocEntry) (*Image, error) { 105 | err := d.setPos(toc.Position) 106 | if err != nil { 107 | return nil, err 108 | } 109 | 110 | err = readFull(d.br, d.tmp[:36]) 111 | if err != nil { 112 | return nil, err 113 | } 114 | 115 | // chuck header 116 | headerLen := binary.LittleEndian.Uint32(d.tmp[:4]) 117 | if headerLen != 36 { 118 | return nil, errors.New("image type chunk head len is not 36") 119 | } 120 | 121 | type0 := binary.LittleEndian.Uint32(d.tmp[4:8]) 122 | if type0 != typeImage { 123 | return nil, errors.New("chunk type not match") 124 | } 125 | 126 | subtype := binary.LittleEndian.Uint32(d.tmp[8:12]) 127 | 128 | version := binary.LittleEndian.Uint32(d.tmp[12:16]) 129 | if version != 1 { 130 | return nil, errors.New("version not supported") 131 | } 132 | 133 | var img Image 134 | img.Size = subtype 135 | img.Width = binary.LittleEndian.Uint32(d.tmp[16:20]) 136 | img.Height = binary.LittleEndian.Uint32(d.tmp[20:24]) 137 | img.XHot = binary.LittleEndian.Uint32(d.tmp[24:28]) 138 | if img.XHot > img.Width { 139 | img.XHot = img.Width 140 | } 141 | 142 | img.YHot = binary.LittleEndian.Uint32(d.tmp[28:32]) 143 | if img.YHot > img.Height { 144 | img.YHot = img.Height 145 | } 146 | 147 | img.Delay = binary.LittleEndian.Uint32(d.tmp[32:36]) 148 | 149 | // read pixels 150 | img.Pixels = make([]byte, 4*int(img.Width)*int(img.Height)) 151 | err = readFull(d.br, img.Pixels) 152 | if err != nil { 153 | return nil, err 154 | } 155 | 156 | return &img, nil 157 | } 158 | -------------------------------------------------------------------------------- /util/cursor/testdata/left_ptr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxdeepin/go-x11-client/b7fac99b07ef6bff277187df2d0e4293a065a07d/util/cursor/testdata/left_ptr -------------------------------------------------------------------------------- /util/cursor/testdata/watch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxdeepin/go-x11-client/b7fac99b07ef6bff277187df2d0e4293a065a07d/util/cursor/testdata/watch -------------------------------------------------------------------------------- /util/cursor/theme.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package cursor 6 | 7 | import ( 8 | "bufio" 9 | "bytes" 10 | "errors" 11 | "os" 12 | "os/user" 13 | "path/filepath" 14 | "strings" 15 | ) 16 | 17 | func LoadImage(theme, name string, size int) (*Image, error) { 18 | f := scanTheme(theme, name, 0) 19 | if f == nil { 20 | f = scanTheme("default", name, 0) 21 | } 22 | if f == nil { 23 | return nil, errors.New("not found image file") 24 | } 25 | 26 | return loadImageFromFile(f, size) 27 | } 28 | 29 | func LoadImages(theme, name string, size int) (Images, error) { 30 | f := scanTheme(theme, name, 0) 31 | if f == nil { 32 | f = scanTheme("default", name, 0) 33 | } 34 | if f == nil { 35 | return nil, errors.New("not found image file") 36 | } 37 | 38 | return loadImagesFromFile(f, size) 39 | } 40 | 41 | func getLibraryPaths() []string { 42 | xcursorPath, ok := os.LookupEnv("XCURSOR_PATH") 43 | if ok { 44 | return strings.Split(xcursorPath, ":") 45 | } 46 | 47 | var paths []string 48 | home := getHome() 49 | // add ~/.icons 50 | if home != "" { 51 | paths = append(paths, filepath.Join(home, ".icons")) 52 | } 53 | paths = append(paths, "/usr/share/icons", "/usr/share/pixmaps") 54 | return paths 55 | } 56 | 57 | func getHome() string { 58 | home, ok := os.LookupEnv("HOME") 59 | if ok { 60 | return home 61 | } 62 | 63 | u, err := user.Current() 64 | if err != nil { 65 | return "" 66 | } 67 | return u.HomeDir 68 | } 69 | 70 | func scanTheme(theme, name string, depth int) *os.File { 71 | if depth > 50 { 72 | return nil 73 | } 74 | libPaths := getLibraryPaths() 75 | var inherits []string 76 | loop: 77 | for _, libPath := range libPaths { 78 | imgFile := filepath.Join(libPath, theme, "cursors", name) 79 | f, err := os.Open(imgFile) 80 | if err == nil { 81 | return f 82 | } 83 | 84 | for _, base := range []string{"cursor.theme", "index.theme"} { 85 | themeFile := filepath.Join(libPath, theme, base) 86 | inherits, _ = getThemeInherits(themeFile) 87 | if len(inherits) > 0 { 88 | break loop 89 | } 90 | } 91 | } 92 | 93 | for _, i := range inherits { 94 | if i == theme { 95 | continue 96 | } 97 | f := scanTheme(i, name, depth+1) 98 | if f != nil { 99 | return f 100 | } 101 | } 102 | 103 | // not found 104 | return nil 105 | } 106 | 107 | func getThemeInherits(themeFile string) ([]string, error) { 108 | f, err := os.Open(themeFile) 109 | if err != nil { 110 | return nil, err 111 | } 112 | 113 | scanner := bufio.NewScanner(f) 114 | for scanner.Scan() { 115 | fields := bytes.SplitN(scanner.Bytes(), []byte("="), 2) 116 | if len(fields) != 2 { 117 | continue 118 | } 119 | 120 | if "Inherits" == string(bytes.TrimSpace(fields[0])) { 121 | result := strings.Split(string(bytes.TrimSpace(fields[1])), ":") 122 | return result, nil 123 | } 124 | } 125 | if scanner.Err() != nil { 126 | return nil, scanner.Err() 127 | } 128 | 129 | return nil, nil 130 | } 131 | -------------------------------------------------------------------------------- /util/keybind/keybind.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package keybind 6 | 7 | import ( 8 | x "github.com/linuxdeepin/go-x11-client" 9 | "github.com/linuxdeepin/go-x11-client/util/keysyms" 10 | ) 11 | 12 | var grabMods []uint16 13 | 14 | func init() { 15 | grabMods = make([]uint16, len(keysyms.LockMods)+1) 16 | copy(grabMods, keysyms.LockMods) 17 | } 18 | 19 | func Grab(conn *x.Conn, win x.Window, mods uint16, key x.Keycode) { 20 | for _, m := range grabMods { 21 | x.GrabKey(conn, true, win, mods|m, 22 | key, x.GrabModeAsync, x.GrabModeAsync) 23 | } 24 | } 25 | 26 | func Ungrab(conn *x.Conn, win x.Window, mods uint16, key x.Keycode) { 27 | for _, m := range grabMods { 28 | _ = x.UngrabKeyChecked(conn, key, win, mods|m).Check(conn) 29 | } 30 | } 31 | 32 | func GrabChecked(conn *x.Conn, win x.Window, mods uint16, key x.Keycode) error { 33 | return GrabCheckedV2(conn, win, mods, key, x.GrabModeAsync, x.GrabModeAsync) 34 | } 35 | 36 | func GrabCheckedV2(conn *x.Conn, win x.Window, mods uint16, key x.Keycode, pointerMode uint8, keyboardMode uint8) error { 37 | for _, m := range grabMods { 38 | err := x.GrabKeyChecked(conn, true, win, mods|m, 39 | key, pointerMode, keyboardMode).Check(conn) 40 | if err != nil { 41 | return err 42 | } 43 | } 44 | return nil 45 | } 46 | 47 | // GrabKeyboard grabs the entire keyboard. 48 | func GrabKeyboard(conn *x.Conn, win x.Window) error { 49 | reply, err := x.GrabKeyboard(conn, true, win, x.CurrentTime, 50 | x.GrabModeAsync, x.GrabModeAsync).Reply(conn) 51 | if err != nil { 52 | return err 53 | } 54 | 55 | if reply.Status == x.GrabStatusSuccess { 56 | // successful 57 | return nil 58 | } 59 | return GrabKeyboardError{reply.Status} 60 | } 61 | 62 | type GrabKeyboardError struct { 63 | Status byte 64 | } 65 | 66 | func (err GrabKeyboardError) Error() string { 67 | const errMsgPrefix = "GrabKeyboard Failed status: " 68 | 69 | switch err.Status { 70 | case x.GrabStatusAlreadyGrabbed: 71 | return errMsgPrefix + "AlreadyGrabbed" 72 | case x.GrabStatusInvalidTime: 73 | return errMsgPrefix + "InvalidTime" 74 | case x.GrabStatusNotViewable: 75 | return errMsgPrefix + "NotViewable" 76 | case x.GrabStatusFrozen: 77 | return errMsgPrefix + "Frozen" 78 | default: 79 | return errMsgPrefix + "Unknown" 80 | } 81 | } 82 | 83 | // UngrabKeyboard undoes GrabKeyboard. 84 | func UngrabKeyboard(conn *x.Conn) error { 85 | return x.UngrabKeyboardChecked(conn, x.CurrentTime).Check(conn) 86 | } 87 | -------------------------------------------------------------------------------- /util/mousebind/mousebind.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package mousebind 6 | 7 | import ( 8 | x "github.com/linuxdeepin/go-x11-client" 9 | ) 10 | 11 | func GrabPointer(conn *x.Conn, win x.Window, eventMask uint16, confineTo x.Window, cursor x.Cursor) error { 12 | reply, err := x.GrabPointer(conn, true, win, eventMask, 13 | x.GrabModeAsync, x.GrabModeAsync, 14 | confineTo, cursor, x.CurrentTime).Reply(conn) 15 | if err != nil { 16 | return err 17 | } 18 | if reply.Status == x.GrabStatusSuccess { 19 | return nil 20 | } 21 | return GrabPointerError{reply.Status} 22 | } 23 | 24 | type GrabPointerError struct { 25 | Status byte 26 | } 27 | 28 | func (err GrabPointerError) Error() string { 29 | const errMsgPrefix = "GrabPointer Failed status: " 30 | 31 | switch err.Status { 32 | case x.GrabStatusAlreadyGrabbed: 33 | return errMsgPrefix + "AlreadyGrabbed" 34 | case x.GrabStatusInvalidTime: 35 | return errMsgPrefix + "InvalidTime" 36 | case x.GrabStatusNotViewable: 37 | return errMsgPrefix + "NotViewable" 38 | case x.GrabStatusFrozen: 39 | return errMsgPrefix + "Frozen" 40 | default: 41 | return errMsgPrefix + "Unknown" 42 | } 43 | } 44 | 45 | func UngrabPointer(conn *x.Conn) error { 46 | return x.UngrabPointerChecked(conn, x.CurrentTime).Check(conn) 47 | } 48 | -------------------------------------------------------------------------------- /util/tool/gen-keysymdef/gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | gopath=`go env GOPATH` 3 | ./gen-keysymdef 2>log |gofmt > $gopath/src/github.com/linuxdeepin/go-x11-client/util/keysyms/auto.go 4 | go build -v github.com/linuxdeepin/go-x11-client/util/keysyms 5 | -------------------------------------------------------------------------------- /util/wm/icccm/text_property.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package icccm 6 | 7 | import ( 8 | "errors" 9 | 10 | x "github.com/linuxdeepin/go-x11-client" 11 | "golang.org/x/text/encoding/charmap" 12 | ) 13 | 14 | func convertLatin1ToUTF8(p []byte) (string, error) { 15 | dec := charmap.ISO8859_1.NewDecoder() 16 | result, err := dec.Bytes(p) 17 | if err != nil { 18 | return "", err 19 | } 20 | return string(result), nil 21 | } 22 | 23 | type GetTextCookie x.GetPropertyCookie 24 | 25 | type TextProperty struct { 26 | Value []byte 27 | Encoding x.Atom 28 | Format uint8 29 | } 30 | 31 | func (tp *TextProperty) GetStr() (string, error) { 32 | if tp.Format != 8 || tp.Encoding != x.AtomString { 33 | return "", errors.New("unsupported encoding") 34 | } 35 | return convertLatin1ToUTF8(tp.Value) 36 | } 37 | 38 | func getTextProperty(c *x.Conn, window x.Window, property x.Atom) GetTextCookie { 39 | cookie := x.GetProperty(c, false, window, property, x.AtomAny, 0, getPropertyMaxLength) 40 | return GetTextCookie(cookie) 41 | } 42 | 43 | func (cookie GetTextCookie) Reply(c *x.Conn) (TextProperty, error) { 44 | reply, err := x.GetPropertyCookie(cookie).Reply(c) 45 | if err != nil { 46 | return TextProperty{}, err 47 | } 48 | return getTextPropertyFromReply(reply) 49 | } 50 | 51 | func getTextPropertyFromReply(reply *x.GetPropertyReply) (TextProperty, error) { 52 | if reply.Type == x.None { 53 | return TextProperty{}, errors.New("not found property") 54 | } 55 | 56 | return TextProperty{ 57 | Value: reply.Value, 58 | Encoding: reply.Type, 59 | Format: reply.Format, 60 | }, nil 61 | } 62 | -------------------------------------------------------------------------------- /writer.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | package x 6 | 7 | import ( 8 | "bytes" 9 | ) 10 | 11 | type Writer struct { 12 | buf bytes.Buffer 13 | } 14 | 15 | func NewWriter() *Writer { 16 | return &Writer{} 17 | } 18 | 19 | func (w *Writer) Reset() { 20 | w.buf.Reset() 21 | } 22 | 23 | func (w *Writer) WritePad(n int) { 24 | for i := 0; i < n; i++ { 25 | w.buf.WriteByte(0) 26 | } 27 | } 28 | 29 | func (w *Writer) Write1b(v uint8) { 30 | w.buf.WriteByte(v) 31 | } 32 | 33 | func (w *Writer) Write2b(v uint16) { 34 | w.buf.WriteByte(byte(v)) 35 | w.buf.WriteByte(byte(v >> 8)) 36 | } 37 | 38 | func (w *Writer) Write4b(v uint32) { 39 | w.buf.WriteByte(byte(v)) 40 | w.buf.WriteByte(byte(v >> 8)) 41 | w.buf.WriteByte(byte(v >> 16)) 42 | w.buf.WriteByte(byte(v >> 24)) 43 | } 44 | 45 | func (w *Writer) Write8b(v uint64) { 46 | w.buf.WriteByte(byte(v)) 47 | w.buf.WriteByte(byte(v >> 8)) 48 | w.buf.WriteByte(byte(v >> 16)) 49 | w.buf.WriteByte(byte(v >> 24)) 50 | w.buf.WriteByte(byte(v >> 32)) 51 | w.buf.WriteByte(byte(v >> 40)) 52 | w.buf.WriteByte(byte(v >> 48)) 53 | w.buf.WriteByte(byte(v >> 56)) 54 | } 55 | 56 | func (w *Writer) WriteBytes(p []byte) { 57 | w.buf.Write(p) 58 | } 59 | 60 | func (w *Writer) WriteNBytes(n int, p []byte) { 61 | if len(p) < n { 62 | w.buf.Write(p) 63 | w.WritePad(n - len(p)) 64 | } else { 65 | w.buf.Write(p[:n]) 66 | } 67 | } 68 | 69 | func (w *Writer) WriteString(s string) { 70 | w.buf.WriteString(s) 71 | } 72 | 73 | func (w *Writer) Bytes() []byte { 74 | return w.buf.Bytes() 75 | } 76 | --------------------------------------------------------------------------------