Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
Please login to access the resource
home:RN:kdotool
kdotool
kdotool-0.2.2-pre.obscpio
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File kdotool-0.2.2-pre.obscpio of Package kdotool
07070100000000000041ED00000000000000000000000265D6E51E00000000000000000000000000000000000000000000001A00000000kdotool-0.2.2-pre/.github07070100000001000041ED00000000000000000000000265D6E51E00000000000000000000000000000000000000000000002400000000kdotool-0.2.2-pre/.github/workflows07070100000002000081A400000000000000000000000165D6E51E000001C8000000000000000000000000000000000000002D00000000kdotool-0.2.2-pre/.github/workflows/rust.ymlname: Rust on: push: branches: [ "master" ] pull_request: branches: [ "master" ] env: CARGO_TERM_COLOR: always jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install system dependencies run: | sudo apt-get update \ && sudo apt-get install -y libdbus-1-dev - name: Build run: cargo build --verbose # - name: Run tests # run: cargo test --verbose 07070100000003000081A400000000000000000000000165D6E51E00000010000000000000000000000000000000000000001D00000000kdotool-0.2.2-pre/.gitignoretarget/ release/07070100000004000081A400000000000000000000000165D6E51E00000363000000000000000000000000000000000000001F00000000kdotool-0.2.2-pre/CHANGELOG.md# Change log ## v0.2.1 (2023-11-23) Reduced binary size. ## v0.2.0 (2023-11-23) ### Added Global options: - `--version` New global commands: - `savewindowstack` - `loadwindowstack` - `set_desktop` - `get_desktop` - `set_num_desktops` (KDE 5 only) - `get_num_desktops` New window actions: - `set_desktop_for_window` - `get_desktop_for_window` - `windowstate` - Supported properties: - above - below - skip_taskbar - skip_pager - fullscreen - shaded - demands_attention - MISSING: - modal - sticky - hidden - maximized_vert - maximized_horz New command options: - `search` - `--desktop` - `--screen` (KDE 5 only) - `windowmove` and `windowsize` - size in percentage ### Internal Changes - Script output is now sent via dbus, instead of parsing KWin logs. ## v0.1.0 (2023-11-17) Initial release 07070100000005000081A400000000000000000000000165D6E51E000050F8000000000000000000000000000000000000001D00000000kdotool-0.2.2-pre/Cargo.lock# This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "aho-corasick" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] [[package]] name = "android-tzdata" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" [[package]] name = "android_system_properties" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ "libc", ] [[package]] name = "anyhow" version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] [[package]] name = "bumpalo" version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "cc" version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "libc", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", "windows-targets", ] [[package]] name = "core-foundation-sys" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] [[package]] name = "crypto-common" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "typenum", ] [[package]] name = "dbus" version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b" dependencies = [ "libc", "libdbus-sys", "winapi", ] [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", ] [[package]] name = "env_logger" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" dependencies = [ "humantime", "is-terminal", "log", "regex", "termcolor", ] [[package]] name = "errno" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" dependencies = [ "libc", "windows-sys", ] [[package]] name = "fastrand" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "generic-array" version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", ] [[package]] name = "handlebars" version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faa67bab9ff362228eb3d00bd024a4965d8231bbb7921167f0cfa66c6626b225" dependencies = [ "log", "pest", "pest_derive", "serde", "serde_json", "thiserror", ] [[package]] name = "hermit-abi" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "iana-time-zone" version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", "windows-core", ] [[package]] name = "iana-time-zone-haiku" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ "cc", ] [[package]] name = "is-terminal" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", "rustix", "windows-sys", ] [[package]] name = "itoa" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" dependencies = [ "wasm-bindgen", ] [[package]] name = "kdotool" version = "0.2.1" dependencies = [ "anyhow", "chrono", "dbus", "env_logger", "handlebars", "lexopt", "log", "phf", "serde", "serde_json", "tempfile", ] [[package]] name = "lexopt" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baff4b617f7df3d896f97fe922b64817f6cd9a756bb81d40f8883f2f66dcb401" [[package]] name = "libc" version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "libdbus-sys" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72" dependencies = [ "pkg-config", ] [[package]] name = "linux-raw-sys" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" [[package]] name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "num-traits" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] [[package]] name = "once_cell" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "pest" version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" dependencies = [ "memchr", "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" dependencies = [ "pest", "pest_generator", ] [[package]] name = "pest_generator" version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", "syn", ] [[package]] name = "pest_meta" version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" dependencies = [ "once_cell", "pest", "sha2", ] [[package]] name = "phf" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ "phf_macros", "phf_shared", ] [[package]] name = "phf_generator" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" dependencies = [ "phf_shared", "rand", ] [[package]] name = "phf_macros" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" dependencies = [ "phf_generator", "phf_shared", "proc-macro2", "quote", "syn", ] [[package]] name = "phf_shared" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" dependencies = [ "siphasher", ] [[package]] name = "pkg-config" version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "proc-macro2" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "rand_core", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" [[package]] name = "redox_syscall" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "regex" version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rustix" version = "0.38.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" dependencies = [ "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", "windows-sys", ] [[package]] name = "ryu" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "serde" version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "sha2" version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", "digest", ] [[package]] name = "siphasher" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "syn" version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "tempfile" version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand", "redox_syscall", "rustix", "windows-sys", ] [[package]] name = "termcolor" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" dependencies = [ "winapi-util", ] [[package]] name = "thiserror" version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasm-bindgen" version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ "windows-targets", ] [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 07070100000006000081A400000000000000000000000165D6E51E00000302000000000000000000000000000000000000001D00000000kdotool-0.2.2-pre/Cargo.toml[package] name = "kdotool" version = "0.2.1" description = "A xdotool-like tool to manipulate windows on KDE Wayland" authors = ["Jin Liu <m.liu.jin@gmail.com>"] repository = "https://github.com/jinliu/kdotool" license = "Apache-2.0" keywords = ["xdotool", "wayland", "kde"] categories = ["command-line-utilities"] edition = "2021" [profile.release] strip = true # Automatically strip symbols from the binary. opt-level = "z" # Optimize for size. lto = true codegen-units = 1 [dependencies] anyhow = "1.0.75" chrono = "0.4.31" dbus = "0.9.7" env_logger = "0.10.1" handlebars = "4.5.0" lexopt = "0.3.0" log = "0.4.20" phf = { version = "0.11.2", features = ["macros"] } serde = { version = "1.0.193", features = ["derive"] } serde_json = "1.0.108" tempfile = "3.8.1" 07070100000007000081A400000000000000000000000165D6E51E00002C5D000000000000000000000000000000000000001A00000000kdotool-0.2.2-pre/LICENSE Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 07070100000008000081A400000000000000000000000165D6E51E00001098000000000000000000000000000000000000001C00000000kdotool-0.2.2-pre/README.md# kdotool - a `xdotool` clone for KDE Wayland ## Introduction Wayland, for security concerns, removed most of the X11 APIs that [xdotool](https://github.com/jordansissel/xdotool) uses to simulate user input and control windows. [ydotool](https://github.com/ReimuNotMoe/ydotool) solves the input part by talking directly to the kernel input device. However, for the window control part, you have to use each Wayland compositor's own APIs. This program uses KWin's scripting API to control windows. In each invocation, it generates a KWin script on-the-fly, loads it into KWin, runs it, and then deletes it, using KWin's DBus interface. This program should work with both KDE 5 and the upcoming KDE 6. It should work with both Wayland and X11 sessions. (But you can use the original `xdotool` in X11, anyway. So this is mainly for Wayland.) Not all `xdotool` commands are supported. Some are not available through the KWin API. Some might be not even possible in Wayland. See below for details. Please note that the `window id` this program uses is KWin's internal window id, which looks like a UUID (`{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}`). It's not a X11 window id. ## Global Options - `--help` Show help. - `--version` Show version. Options not in xdotool: - `--dry-run` Just print the generated KWin script. Don't run it. - `--debug` Print debug messages. - `--shortcut _shortcut_` Specify a shortcut to run the generated KWin script. The shortcut must be in the format of `modifier+key`, e.g. `Alt+Shift+X`. The shortcut will be registered in KWin. The script is not run immediately. You must press the shortcut to run it. - `--name _name_` Specify a name for the shortcut, So you can remove it later with `--remove`. This option is only valid with `--shortcut`. - --`remove _name_` Remove a previously registered shortcut. ## New Commands Not In xdotool The following can be used in chained commands: - `savewindowstack _name_` Save the current window stack to a variable - `loadwindowstack _name_` Load a previously saved window stack ## Supported xdotool Commands ### Window Queries These commands generate a window stack that following _window action_ commands can refer to. - `search` - MISSING: - `--maxdepth` - `--onlyvisible` - `--sync` - NOTE: - `--screen` (KDE 5 only) - `getactivewindow` ### Window Actions These commands either take a window-id argument, or use the window stack. - `getwindowname` - `getwindowclassname` - `getwindowpid` - `getwindowgeometry` - MISSING: `--shell` - NOTE: shows screen number only in KDE 5 - `windowsize` - MISSING: - `--usehints` - `--sync` - `windowmove` - MISSING: - `--sync` - `windowminimize` - MISSING: `--sync` - `windowraise` (KDE 6 only) - Use `windowactivate` instead? - `windowactivate` - MISSING: `--sync` - windowclose - `set_desktop_for_window` - `get_desktop_for_window` - `windowstate` - Supported properties: - above - below - skip_taskbar - skip_pager - fullscreen - shaded - demands_attention - MISSING: - modal - sticky - hidden - maximized_vert - maximized_horz ### Global Actions These actions aren't targeting a specific window, but the whole desktop. - `set_desktop` - MISSING: --relative - `get_desktop` - `set_num_desktops` (KDE 5 only) - `get_num_desktops` ## Won't support You can use `ydotool`, `dotool`, `wtype`, etc. for these: - Keyboard commands - Mouse commands KWin doesn't have such functionality: - `set_desktop_viewport` - `get_desktop_viewport` X11-specific: - `windowreparent` - `windowmap` - `windowunmap` ## Unclear if we can support - behave window action command - `exec` - `sleep` - scripts KWin has such functionality, but not exposed to the js API: - `selectwindow` - `windowlower` - `windowquit` - `windowkill` - `getwindowfocus`: use `getactivewindow` instead? - `windowfocus`: use `windowactivate` instead? - `set_window` ## Troubleshooting If anything fails to work, you can re-run the command with `--debug` option. It will print the generated KWin script, and the output of the script from KWin. If you think it's a bug, please create an issue in [GitHub](https://github.com/jinliu/kdotool/issues). 07070100000009000041ED00000000000000000000000265D6E51E00000000000000000000000000000000000000000000001600000000kdotool-0.2.2-pre/src0707010000000A000081A400000000000000000000000165D6E51E000014EF000000000000000000000000000000000000001E00000000kdotool-0.2.2-pre/src/help.rspub fn print_version() { println!("kdotool v{}", env!("CARGO_PKG_VERSION")); } pub fn help() { print_version(); print!( r#" kdotool is a xdotool-like window control utility for KDE 5 and 6. USAGE: kdotool [OPTIONS] COMMAND [ARGS] [COMMAND [ARGS]]... Options: -h, --help Show this help -v, --version Show program version -d, --debug Enable debug output -n, --dry-run Don't actually run the script. Just print it to stdout. --shortcut SHORTCUT [--name NAME] Register a shortcut to run the script. Optionally set a name for the shortcut, so you can remove it later. --remove NAME Remove a previously registered shortcut. Window Query Commands: search [OPTIONS] PATTERN Search for windows with titles, names, or classes matching a regular expression pattern. The default options are --name --class --classname --role (unless you specify one or more of --name, --class, --classname, or --role). OPTIONS: --class Match against the window class. --classname Match against the window classname. --role Match against the window role. --name Match against the window name. This is the same string that is displayed in the window titlebar. --pid PID Match windows that belong to a specific process id. This may not work for some X applications that do not set this metadata on its windows. --screen NUMBER (KDE 5 only) Select windows only on a specific screen. Default is to search all screens. --desktop NUMBER Only match windows on a certain desktop. The default is to search all desktops. --limit NUMBER Stop searching after finding NUMBER matching windows. The default is no search limit (which is equivalent to '--limit 0') --all Require that all conditions be met. --any Match windows that match any condition (logically, 'or'). This is on by default. getactivewindow Select the currently active window. Window Action Commands: General Syntax: COMMAND [OPTIONS] [WINDOW] [ARGS...] WINDOW can be specified as: %N - the Nth window in the stack (result from the previous Window Query Command) %@ - all windows in the stack {{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}} - the window with the given ID If not specified, it defaults to %1. I.e. the first result from the previous window query. getwindowname [WINDOW] Output the name of a window. This is the same string that is displayed in the window titlebar. getwindowclassname [WINDOW] Output the class name of a window. getwindowgeometry [WINDOW] Output the geometry (location and position) of a window. The values include: x, y, width, height, and (KDE 5 only) screen number. getwindowpid [WINDOW] Output the PID owning a window. This requires effort from the application owning a window and may not work for all windows. windowactivate [WINDOW] Activate a window. If the window is on another desktop, we will switch to that desktop. windowraise [WINDOW] (KDE 6 only) Raise a window to the top of the window stack. windowminimize [WINDOW] Minimize a window. windowclose [WINDOW] Close a window. windowsize [WINDOW] WIDTH HEIGHT Resize a window. Percentages are valid for WIDTH and HEIGHT. They are relative to the geometry of the screen the window is on. If the given WIDTH is literally 'x', then the window's current width will be unchanged. The same applies for 'y' for HEIGHT. windowmove [--relative] [WINDOW] X Y Move a window. Percentages are valid for X and Y. They are relative to relative to the geometry of the screen the window is on. If the given x coordinate is literally 'x', then the window's current x position will be unchanged. The same applies for 'y'. --relative Make movement relative to the current window position. windowstate [--add PROPERTY] [--remove PROPERTY] [--toggle PROPERTY] [WINDOW] Change a property on a window. PROPERTY can be any of: ABOVE - Show window above all others (always on top) BELOW - Show window below all others SKIP_TASKBAR - hides the window from the taskbar SKIP_PAGER - hides the window from the window pager FULLSCREEN - makes window fullscreen SHADED - rolls the window up DEMANDS_ATTENTION - marks window urgent or needing attention get_desktop_for_window [WINDOW] Output the desktop number that a window is on. set_desktop_for_window [WINDOW] NUMBER Move a window to a different desktop. Global Commands: get_desktop Output the current desktop number. set_desktop <number> Change the current desktop to <number>. get_num_desktops Output the current number of desktops. set_num_desktops <number> (KDE 5 only) Change the number of desktops to <number>. "# ); } 0707010000000B000081A400000000000000000000000165D6E51E000068F9000000000000000000000000000000000000001E00000000kdotool-0.2.2-pre/src/main.rsmod templates; use templates::*; mod parser; use parser::*; mod help; use help::*; use std::io::Write; use std::process::Command; use std::sync::RwLock; use std::time::Duration; use anyhow::{anyhow, Context}; use dbus::{ blocking::{Connection, SyncConnection}, channel::MatchingReceiver, message::MatchRule, }; use serde::Serialize; #[derive(Default, Serialize)] struct Globals { dbus_addr: String, cmdline: String, debug: bool, kde5: bool, marker: String, script_name: String, shortcut: String, } struct StepResult { script: String, is_query: bool, next_arg: Option<String>, } static MESSAGES: RwLock<Vec<(String, String)>> = RwLock::new(vec![]); fn add_context<T>(render_context: &mut handlebars::Context, key: &str, value: T) where serde_json::Value: From<T>, { render_context .data_mut() .as_object_mut() .unwrap() .insert(key.into(), serde_json::Value::from(value)); } fn generate_script( globals: &Globals, mut parser: Parser, next_arg: &str, ) -> anyhow::Result<String> { use lexopt::prelude::*; let mut full_script = String::new(); let mut reg = handlebars::Handlebars::new(); reg.set_strict_mode(true); let render_context = handlebars::Context::wraps(globals)?; full_script.push_str(®.render_template_with_context(SCRIPT_HEADER, &render_context)?); let mut last_step_is_query; let mut command: String = next_arg.into(); loop { parser = reset_parser(parser)?; let step_result = generate_step(&command, &mut parser, ®, &render_context) .with_context(|| format!("in command '{command}'"))?; full_script.push_str(&step_result.script); last_step_is_query = step_result.is_query; if let Some(next_arg) = step_result.next_arg { command = next_arg; } else { match parser.next()? { Some(Value(val)) => { command = val.string()?; } None => { break; } Some(arg) => { return Err(arg.unexpected().into()); } } } } if last_step_is_query { full_script.push_str(®.render_template_with_context(STEP_LAST_OUTPUT, &render_context)?); } full_script.push_str(®.render_template_with_context(SCRIPT_FOOTER, &render_context)?); Ok(full_script) } fn generate_step( command: &str, parser: &mut Parser, reg: &handlebars::Handlebars, render_context: &handlebars::Context, ) -> anyhow::Result<StepResult> { use lexopt::prelude::*; let step_script; let mut is_query = false; let mut next_arg = None; let mut render_context = render_context.clone(); add_context(&mut render_context, "step_name", command); match command { "search" => { return step_search(parser, reg, &render_context); } "getactivewindow" => { step_script = reg.render_template_with_context(STEP_GETACTIVEWINDOW, &render_context)?; is_query = true; } "savewindowstack" | "loadwindowstack" => { let mut arg_name = None; while let Some(arg) = parser.next()? { match arg { Value(val) if arg_name.is_none() => { arg_name = Some(val.string()?); } Value(val) => { next_arg = Some(val.string()?); break; } _ => { return Err(arg.unexpected().into()); } } } let mut render_context = render_context.clone(); add_context( &mut render_context, "name", arg_name.ok_or(anyhow!("missing argument 'name'"))?.as_str(), ); step_script = reg.render_template_with_context( if command == "savewindowstack" { STEP_SAVEWINDOWSTACK } else { STEP_LOADWINDOWSTACK }, &render_context, )?; is_query = command == "loadwindowstack"; } _ => { if WINDOW_ACTIONS.contains_key(command) { let mut arg_window_id: Option<String> = None; let action_script; match command { "windowstate" => { let mut opt_windowstate = String::new(); while let Some(arg) = parser.next()? { match arg { Long(option) if option == "add" || option == "remove" || option == "toggle" => { let option: String = option.into(); let key = parser.value()?.string()?.to_lowercase(); if let Some(prop) = WINDOWSTATE_PROPERTIES.get(&key) { let js = match option.as_str() { "add" => format!("w.{prop} = true; "), "remove" => { format!("w.{prop} = false; ") } "toggle" => { format!("w.{prop} = !w.{prop}; ") } _ => unreachable!(), }; opt_windowstate.push_str(&js); } else { return Err(anyhow!("unsupported property '{key}'")); } } Value(val) if arg_window_id.is_none() => { let s = val.string()?; if let Some(id) = to_window_id(&s) { arg_window_id = Some(id); } else { next_arg = Some(s); break; } } Value(val) => { next_arg = Some(val.string()?); break; } _ => { return Err(arg.unexpected().into()); } } } let mut render_context = render_context.clone(); add_context(&mut render_context, "windowstate", opt_windowstate); action_script = reg.render_template_with_context( WINDOW_ACTIONS.get(command).unwrap(), &render_context, )?; } "windowmove" | "windowsize" => { let mut opt_relative = false; let mut arg_x: Option<String> = None; let mut arg_y: Option<String> = None; while let Some(arg) = next_maybe_num(parser)? { match arg { Long("relative") if command == "windowmove" => { opt_relative = true; } Value(val) if arg_window_id.is_none() && arg_x.is_none() => { let s = val.string()?; if let Some(id) = to_window_id(&s) { arg_window_id = Some(id); } else { arg_x = Some(s); } } Value(val) if arg_x.is_none() => { arg_x = Some(val.string()?); } Value(val) if arg_y.is_none() => { arg_y = Some(val.string()?); } Value(val) => { next_arg = Some(val.string()?); break; } _ => { return Err(arg.unexpected().into()); } } } let mut x = String::new(); let mut y = String::new(); let mut x_percent = String::new(); let mut y_percent = String::new(); if let Some(arg) = arg_x { if arg != "x" { if arg.ends_with('%') { let s = arg.strip_suffix('%').unwrap(); _ = s.parse::<i32>()?; x_percent = s.into(); } else { _ = arg.parse::<i32>()?; x = arg; } } } else { return Err(anyhow!("missing argument 'x'")); } if let Some(arg) = arg_y { if arg != "y" { if arg.ends_with('%') { let s = arg.strip_suffix('%').unwrap(); _ = s.parse::<i32>()?; y_percent = s.into(); } else { _ = arg.parse::<i32>()?; y = arg; } } } else { return Err(anyhow!("missing argument 'y'")); } let mut render_context = render_context.clone(); add_context(&mut render_context, "relative", opt_relative); add_context(&mut render_context, "x", x); add_context(&mut render_context, "y", y); add_context(&mut render_context, "x_percent", x_percent); add_context(&mut render_context, "y_percent", y_percent); action_script = reg.render_template_with_context( WINDOW_ACTIONS.get(command).unwrap(), &render_context, )?; } "set_desktop_for_window" => { let mut arg_desktop_id: Option<i32> = None; while let Some(arg) = next_maybe_num(parser)? { match arg { Value(val) if arg_window_id.is_none() && arg_desktop_id.is_none() => { let s = val.string()?; if let Some(id) = to_window_id(&s) { arg_window_id = Some(id); } else { arg_desktop_id = Some(s.parse()?); } } Value(val) if arg_desktop_id.is_none() => { arg_desktop_id = Some(val.parse()?); } Value(val) => { next_arg = Some(val.string()?); break; } _ => { return Err(arg.unexpected().into()); } } } let mut render_context = render_context.clone(); add_context(&mut render_context, "desktop_id", arg_desktop_id); action_script = reg.render_template_with_context( WINDOW_ACTIONS.get(command).unwrap(), &render_context, )?; } _ => { while let Some(arg) = next_maybe_num(parser)? { match arg { Value(val) if arg_window_id.is_none() => { let s = val.string()?; if let Some(id) = to_window_id(&s) { arg_window_id = Some(id); } else { next_arg = Some(s); break; } } Value(val) => { next_arg = Some(val.string()?); break; } _ => { return Err(arg.unexpected().into()); } } } action_script = reg.render_template_with_context( WINDOW_ACTIONS.get(command).unwrap(), &render_context, )?; } }; let window_id = arg_window_id.unwrap_or("%1".into()); let mut render_context = render_context.clone(); add_context(&mut render_context, "action", action_script); if window_id == "%@" { step_script = reg .render_template_with_context(STEP_ACTION_ON_STACK_ALL, &render_context)?; } else if let Some(s) = window_id.strip_prefix('%') { let index = s.parse::<i32>()?; let mut render_context = render_context.clone(); add_context(&mut render_context, "item_index", index); step_script = reg .render_template_with_context(STEP_ACTION_ON_STACK_ITEM, &render_context)?; } else { let mut render_context = render_context.clone(); add_context(&mut render_context, "window_id", window_id); step_script = reg .render_template_with_context(STEP_ACTION_ON_WINDOW_ID, &render_context)?; } } else if GLOBAL_ACTIONS.contains_key(command.as_ref()) { let action_script; match command { "set_desktop" | "set_num_desktops" => { let mut arg_n: Option<i32> = None; while let Some(arg) = next_maybe_num(parser)? { match arg { Value(val) if arg_n.is_none() => { arg_n = Some(val.parse()?); } Value(val) => { next_arg = Some(val.string()?); break; } _ => { return Err(arg.unexpected().into()); } } } if let Some(n) = arg_n { let mut render_context = render_context.clone(); add_context(&mut render_context, "n", n); action_script = reg.render_template_with_context( GLOBAL_ACTIONS.get(command).unwrap(), &render_context, )?; } else if command == "set_desktop" { return Err(anyhow!("missing argument 'desktop_id'")); } else { return Err(anyhow!("missing argument 'num'")); } } _ => { action_script = reg.render_template_with_context( GLOBAL_ACTIONS.get(command).unwrap(), &render_context, )?; } }; let mut render_context = render_context.clone(); add_context(&mut render_context, "action", action_script); step_script = reg.render_template_with_context(STEP_GLOBAL_ACTION, &render_context)?; } else { return Err(anyhow!("Unknown command: {command}")); } } } Ok(StepResult { script: step_script, is_query, next_arg, }) } fn step_search( parser: &mut Parser, reg: &handlebars::Handlebars, render_context: &handlebars::Context, ) -> anyhow::Result<StepResult> { use lexopt::prelude::*; #[derive(Default, Serialize)] struct Options { debug: bool, kde5: bool, match_class: bool, match_classname: bool, match_role: bool, match_name: bool, match_pid: bool, pid: i32, match_desktop: bool, desktop: i32, match_screen: bool, screen: i32, limit: u32, match_all: bool, search_term: String, } let mut opt = Options { debug: render_context .data() .as_object() .unwrap() .get("debug") .unwrap() .as_bool() .unwrap(), kde5: render_context .data() .as_object() .unwrap() .get("debug") .unwrap() .as_bool() .unwrap(), ..Default::default() }; let mut next_arg = None; while let Some(arg) = parser.next()? { match arg { Long("class") => { opt.match_class = true; } Long("classname") => { opt.match_classname = true; } Long("role") => { opt.match_role = true; } Long("name") => { opt.match_name = true; } Long("pid") => { opt.match_pid = true; opt.pid = parser.value()?.parse()?; } Long("desktop") => { opt.match_desktop = true; opt.desktop = parser.value()?.parse()?; } Long("screen") => { opt.match_screen = true; opt.screen = parser.value()?.parse()?; } Long("limit") => { opt.limit = parser.value()?.parse()?; } Long("all") => { opt.match_all = true; } Long("any") => { opt.match_all = false; } Value(val) if opt.search_term.is_empty() => { opt.search_term = val.string()?; } Value(val) => { next_arg = Some(val.string()?); break; } _ => { return Err(arg.unexpected().into()); } } } if !(opt.match_class || opt.match_classname || opt.match_role || opt.match_name) { opt.match_class = true; opt.match_classname = true; opt.match_role = true; opt.match_name = true; } let render_context = handlebars::Context::wraps(opt)?; Ok(StepResult { script: reg.render_template_with_context(STEP_SEARCH, &render_context)?, is_query: true, next_arg, }) } fn main() -> anyhow::Result<()> { let mut context = Globals { cmdline: std::env::args().collect::<Vec<String>>().join(" "), ..Default::default() }; let mut parser = Parser::from_env(); if let Ok(version) = std::env::var("KDE_SESSION_VERSION") { if version == "5" { context.kde5 = true; } } // Parse global options let mut next_arg: Option<String> = None; let mut opt_help = false; let mut opt_version = false; let mut opt_dry_run = false; let mut opt_remove = false; while let Some(arg) = parser.next()? { use lexopt::prelude::*; match arg { Short('h') | Long("help") => { opt_help = true; } Short('v') | Long("version") => { opt_version = true; } Short('d') | Long("debug") => { context.debug = true; } Short('n') | Long("dry-run") => { opt_dry_run = true; } Long("shortcut") => { context.shortcut = parser.value()?.string()?; } Long("name") => { context.script_name = parser.value()?.string()?; } Long("remove") => { opt_remove = true; context.script_name = parser.value()?.string()?; } Value(os_string) => { next_arg = Some(os_string.string()?); break; } _ => { return Err(arg.unexpected().into()); } } } if next_arg.is_none() || opt_help { help(); return Ok(()); } if opt_version { print_version(); return Ok(()); } env_logger::Builder::from_default_env() .filter( Some("kdotool"), if context.debug { log::LevelFilter::Debug } else { log::LevelFilter::Info }, ) .init(); let kwin_conn = Connection::new_session()?; let kwin_proxy = kwin_conn.with_proxy("org.kde.KWin", "/Scripting", Duration::from_millis(5000)); if opt_remove { kwin_proxy.method_call( "org.kde.kwin.Scripting", "unloadScript", (&context.script_name,), )?; return Ok(()); } let self_conn = SyncConnection::new_session()?; context.dbus_addr = self_conn.unique_name().to_string(); log::debug!("===== Generate KWin script ====="); let mut script_file = tempfile::NamedTempFile::with_prefix("kdotool-")?; context.marker = script_file .path() .file_name() .unwrap() .to_string_lossy() .into(); let script_contents = generate_script(&context, parser, &next_arg.unwrap())?; log::debug!("Script:{script_contents}"); script_file.write_all(script_contents.as_bytes())?; let script_file_path = script_file.into_temp_path(); if opt_dry_run { println!("{}", script_contents.trim()); return Ok(()); } log::debug!("===== Load script into KWin ====="); let script_id: i32; (script_id,) = kwin_proxy.method_call( "org.kde.kwin.Scripting", "loadScript", (script_file_path.to_str().unwrap(), &context.script_name), )?; log::debug!("Script ID: {script_id}"); log::debug!("===== Run script ====="); let script_proxy = kwin_conn.with_proxy( "org.kde.KWin", if context.kde5 { format!("/{script_id}") } else { format!("/Scripting/Script{script_id}") }, Duration::from_millis(5000), ); // setup message receiver let _receiver_thread = std::thread::spawn(move || { let _receiver = self_conn.start_receive( MatchRule::new_method_call(), Box::new(|message, _connection| -> bool { log::debug!("dbus message: {:?}", message); if let Some(member) = message.member() { if let Some(arg) = message.get1() { let mut messages = MESSAGES.write().unwrap(); messages.push((member.to_string(), arg)); } } true }), ); loop { self_conn.process(Duration::from_millis(1000)).unwrap(); } //FIXME: shut down this thread when the script is finished }); let start_time = chrono::Local::now(); script_proxy.method_call("org.kde.kwin.Script", "run", ())?; if context.shortcut.is_empty() { script_proxy.method_call("org.kde.kwin.Script", "stop", ())?; } let journal = Command::new("journalctl") .arg(format!( "--since={}", start_time.format("%Y-%m-%d %H:%M:%S") )) .arg("--user") .arg("--user-unit=plasma-kwin_wayland.service") .arg("--user-unit=plasma-kwin_x11.service") .arg("QT_CATEGORY=js") .arg("QT_CATEGORY=kwin_scripting") .arg("--output=cat") .output()?; let output = String::from_utf8(journal.stdout)?; log::debug!("KWin log from the systemd journal:\n{}", output.trim_end()); log::debug!("===== Output ====="); let messages = MESSAGES.read().unwrap(); for (msgtype, message) in messages.iter() { if msgtype == "result" { println!("{message}"); } else if msgtype == "error" { eprintln!("ERROR: {message}"); } else { println!("{msgtype}: {message}"); } } if !context.shortcut.is_empty() { println!("Shortcut registered: {}", context.shortcut); println!("Script ID: {script_id}"); if !context.script_name.is_empty() { println!("Script name: {}", context.script_name); } } Ok(()) } 0707010000000C000081A400000000000000000000000165D6E51E000005A7000000000000000000000000000000000000002000000000kdotool-0.2.2-pre/src/parser.rspub use lexopt::Parser; // Reset the parser at the current position, but with a new context. pub fn reset_parser(mut parser: Parser) -> anyhow::Result<Parser> { Ok(lexopt::Parser::from_args(parser.raw_args()?)) } pub fn next_maybe_num(parser: &mut Parser) -> anyhow::Result<Option<lexopt::Arg>> { if let Some(number) = try_get_number(parser) { Ok(Some(lexopt::Arg::Value(number.into()))) } else { Ok(parser.next()?) } } pub fn try_get_number(parser: &mut Parser) -> Option<String> { let mut raw = parser.try_raw_args()?; let arg = raw.peek()?.to_str()?; if arg.starts_with('-') && arg[1..].starts_with(|c: char| c.is_ascii_digit()) { raw.next() .map(|os_string| os_string.to_string_lossy().into()) } else { None } } #[allow(dead_code)] pub fn positional<T: std::str::FromStr>(parser: &mut Parser, name: &str) -> anyhow::Result<T> where T::Err: std::error::Error + Send + Sync + 'static, Result<T, anyhow::Error>: From<Result<T, <T as std::str::FromStr>::Err>>, { if let Some(os_string) = parser.raw_args()?.next() { Ok(os_string.to_string_lossy().parse::<T>()?) } else { Err(anyhow::Error::msg(format!( "missing positional argument '{name}'" ))) } } pub fn to_window_id(s: &str) -> Option<String> { if s.starts_with('%') || s.starts_with('{') { Some(s.into()) } else { None } } 0707010000000D000081A400000000000000000000000165D6E51E00002312000000000000000000000000000000000000002300000000kdotool-0.2.2-pre/src/templates.rspub const SCRIPT_HEADER: &str = r#" print("{{{marker}}} START"); function output_debug(message) { {{#if debug}} print("{{{marker}}} DEBUG", message); callDBus("{{{dbus_addr}}}", "/", "", "debug", message.toString()); {{/if}} } function output_error(message) { print("{{{marker}}} ERROR", message); callDBus("{{{dbus_addr}}}", "/", "", "error", message.toString()); } function output_result(message) { if (message == null) { print("{{{marker}}} RESULT null"); return; } print("{{{marker}}} RESULT", message); callDBus("{{{dbus_addr}}}", "/", "", "result", message.toString()); } {{#if kde5}} workspace_windowList = () => workspace.clientList(); workspace_activeWindow = () => workspace.activeClient; workspace_setActiveWindow = (window) => { workspace.activeClient = window; }; workspace_raiseWindow = (window) => { output_error("`windowraise` unsupported in KDE 5"); }; workspace_currentDesktop = () => workspace.currentDesktop; workspace_setCurrentDesktop = (desktop) => { workspace.currentDesktop = desktop; }; workspace_numDesktops = () => workspace.desktops; workspace_setNumDesktops = (n) => { workspace.desktops = n }; window_x11DesktopIds = (window) => window.x11DesktopIds; window_setX11DesktopId = (window, id) => { window.desktop = id; }; window_screen = (window) => window.screen; {{else}} workspace_windowList = () => workspace.windowList(); workspace_activeWindow = () => workspace.activeWindow; workspace_setActiveWindow = (window) => { workspace.activeWindow = window; }; workspace_raiseWindow = (window) => { workspace.raiseWindow(window); }; workspace_currentDesktop = () => workspace.currentDesktop.x11DesktopNumber; workspace_setCurrentDesktop = (id) => { let d = workspace.desktops.find((d) => d.x11DesktopNumber == id); if (d) { workspace.currentDesktop = d; } else { output_error(`Invalid desktop number ${id}`); } }; workspace_numDesktops = () => workspace.desktops.length; workspace_setNumDesktops = (n) => { output_error("`set_num_desktops` unsupported in KDE 6"); }; window_x11DesktopIds = (window) => window.desktops.map((d) => d.x11DesktopNumber); window_setX11DesktopId = (window, id) => { let d = workspace.desktops.find((d) => d.x11DesktopNumber == id); if (d) { window.desktops = [d]; } else { output_error(`Invalid desktop number ${id}`); } }; window_screen = (window) => { output_error("`search --screen` unsupported in KDE 6"); }; {{/if}} function run() { var window_stack = []; "#; pub const SCRIPT_FOOTER: &str = r#" } {{#if shortcut}} registerShortcut("{{#if script_name}}{{{script_name}}}{{else}}{{{marker}}}{{/if}}", "{{#if script_name}}{{{script_name}}}{{else}}{{{cmdline}}}{{/if}}", "{{{shortcut}}}", run); {{else}} run(); {{/if}} print("{{{marker}}} FINISH"); "#; pub const STEP_SEARCH: &str = r#" output_debug("STEP search {{{search_term}}}") const re = new RegExp(String.raw`{{{search_term}}}`, "i"); var t = workspace_windowList(); window_stack = []; for (var i=0; i<t.length; i++) { let w = t[i]; if ({{#if match_all}}true{{else}}false{{/if}} {{#if match_class}} {{#if match_all}}&&{{else}}||{{/if}} w.resourceClass.search(re) >= 0 {{/if}} {{#if match_classname}} {{#if match_all}}&&{{else}}||{{/if}} w.resourceName.search(re) >= 0 {{/if}} {{#if match_role}} {{#if match_all}}&&{{else}}||{{/if}} w.windowRole.search(re) >= 0 {{/if}} {{#if match_name}} {{#if match_all}}&&{{else}}||{{/if}} w.caption.search(re) >= 0 {{/if}} {{#if match_pid}} {{#if match_all}}&&{{else}}||{{/if}} w.pid == {{{pid}}} {{/if}} ) { {{#if match_desktop}} if (window_x11DesktopIds(w).indexOf({{{desktop}}}) < 0) continue; {{/if}} {{#if match_screen}} if (window_screen(w) != {{{screen}}}) continue; {{/if}} window_stack.push(w); if ({{{limit}}} > 0 && window_stack.length >= {{{limit}}}) { break; } } } "#; pub const STEP_GETACTIVEWINDOW: &str = r#" output_debug("STEP getactivewindow") var window_stack = [workspace_activeWindow()]; "#; pub const STEP_SAVEWINDOWSTACK: &str = r#" output_debug("STEP savewindowstack") var window_stack_{{{name}}} = window_stack; "#; pub const STEP_LOADWINDOWSTACK: &str = r#" output_debug("STEP loadwindowstack") var window_stack = window_stack_{{{name}}}; "#; pub const STEP_ACTION_ON_WINDOW_ID: &str = r#" output_debug("STEP {{{step_name}}}") var t = workspace_windowList(); for (var i=0; i<t.length; i++) { let w = t[i]; if (w.internalId == "{{{window_id}}}") { {{{action}}} break; } } "#; pub const STEP_ACTION_ON_STACK_ITEM: &str = r#" output_debug("STEP {{{step_name}}}") if (window_stack.length > 0) { if ({{{item_index}}} > window_stack.length || {{{item_index}}} < 1) { output_error("Invalid window stack selection '{{{item_index}}}' (out of range)"); } else { let w = window_stack[{{{item_index}}}-1]; {{{action}}} } } "#; pub const STEP_ACTION_ON_STACK_ALL: &str = r#" output_debug("STEP {{{step_name}}}") for (var i=0; i<window_stack.length; i++) { let w = window_stack[i]; {{{action}}} } "#; pub const STEP_LAST_OUTPUT: &str = r#" for (var i = 0; i < window_stack.length; ++i) { output_result(window_stack[i].internalId); } "#; pub const WINDOW_ACTIONS: phf::Map<&'static str, &'static str> = phf::phf_map! { "getwindowname" => "output_result(w.caption);", "getwindowclassname" => "output_result(w.resourceClass);", "getwindowgeometry" => "output_result(`Window ${w.internalId}`); output_result(` Position: ${w.x},${w.y}{{#if kde5}} (screen: ${window_screen(w)}){{/if}}`); output_result(` Geometry: ${w.width}x${w.height}`);", "getwindowpid" => "output_result(w.pid);", "windowminimize" => "w.minimized = true;", "windowraise" => "workspace_raiseWindow(w);", "windowclose" => "w.closeWindow();", "windowactivate" => "workspace_setActiveWindow(w);", "windowsize" => r#" output_debug(`Window: ${w.frameGeometry}`); output_debug(`Screen: ${workspace.virtualScreenSize}`); let q = Object.assign({}, w.frameGeometry); {{#if x_percent}}q.width=workspace.virtualScreenSize.width*{{{x_percent}}}/100;{{/if}} {{#if y_percent}}q.height=workspace.virtualScreenSize.height*{{{y_percent}}}/100;{{/if}} {{#if x}}q.width={{{x}}};{{/if}} {{#if y}}q.height={{{y}}};{{/if}} w.frameGeometry = q; "#, "windowmove" => r#" output_debug(`Window: ${w.frameGeometry}`); output_debug(`Screen: ${workspace.virtualScreenSize}`); {{#if x_percent}}w.frameGeometry.x={{#if relative}}w.x+{{/if}}workspace.virtualScreenSize.width*{{{x_percent}}}/100;{{/if}} {{#if y_percent}}w.frameGeometry.y={{#if relative}}w.y+{{/if}}workspace.virtualScreenSize.height*{{{y_percent}}}/100;{{/if}} {{#if x}}w.frameGeometry.x={{#if relative}}w.x+{{/if}}{{{x}}};{{/if}} {{#if y}}w.frameGeometry.y={{#if relative}}w.y+{{/if}}{{{y}}};{{/if}} "#, "windowstate" => "{{{windowstate}}}", "get_desktop_for_window"=> "output_result(window_x11DesktopIds(w)[0]);", "set_desktop_for_window"=> "window_setX11DesktopId(w, {{{desktop_id}}})", }; pub const WINDOWSTATE_PROPERTIES: phf::Map<&'static str, &'static str> = phf::phf_map! { "above" => "keepAbove", "below" => "keepBelow", "skip_taskbar" => "skipTaskbar", "skip_pager" => "skipPager", "fullscreen" => "fullScreen", "shaded" => "shade", "demands_attention" => "demandsAttention", }; pub const STEP_GLOBAL_ACTION: &str = r#" output_debug("STEP {{{step_name}}}") {{{action}}} "#; pub const GLOBAL_ACTIONS: phf::Map<&'static str, &'static str> = phf::phf_map! { "get_desktop" => "output_result(workspace_currentDesktop());", "set_desktop" => "workspace_setCurrentDesktop({{{n}}});", "get_num_desktops" => "output_result(workspace_numDesktops());", "set_num_desktops" => "workspace_setNumDesktops({{{n}}})", }; 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!163 blocks
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor