From 47c4119ab767e40fdac587d446d63a06e20c5324 Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Fri, 13 Sep 2019 14:45:14 +0000 Subject: [PATCH] Add a popover menu to switch languages --- Cargo.lock | 264 ++++++++++++++++++++++++++++++++ Cargo.toml | 22 +++ data/popup.ui | 19 +++ data/squeekboard.gresources.xml | 1 + debian/control | 5 + eek/eek-gtk-keyboard.c | 2 +- src/action.rs | 1 + src/data.rs | 5 +- src/layout.h | 5 +- src/layout.rs | 159 +++++++++++++++---- src/lib.rs | 6 + src/popover.h | 9 ++ src/popover.rs | 158 +++++++++++++++++++ src/submission.rs | 1 + 14 files changed, 623 insertions(+), 34 deletions(-) create mode 100644 data/popup.ui create mode 100644 src/popover.h create mode 100644 src/popover.rs diff --git a/Cargo.lock b/Cargo.lock index bee2b6b5..3302d5a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,15 +1,224 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "atk-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bitflags" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cairo-rs" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cairo-sys-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glib 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "glib 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cc" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "dtoa" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "fragile" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "gdk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cairo-rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cairo-sys-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gdk-pixbuf 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gdk-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "gio-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glib 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "pango 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gdk-pixbuf-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "gio-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glib 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gio-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gdk-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cairo-sys-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gdk-pixbuf-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gio-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "pango-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gio" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "fragile 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gio-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glib 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gio-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "glib" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "glib-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gobject-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gtk" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cairo-rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cairo-sys-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "gdk 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gdk-pixbuf 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gdk-pixbuf-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gdk-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "gio-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glib 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gtk-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "pango 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gtk-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atk-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cairo-sys-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gdk-pixbuf-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gdk-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gio-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "pango-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "libc" version = "0.2.62" @@ -34,6 +243,36 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "pango" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "glib 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "pango-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pango-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pkg-config" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "proc-macro2" version = "1.0.4" @@ -55,6 +294,11 @@ name = "rs" version = "0.1.0" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "gio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "glib 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gtk 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gtk-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -142,12 +386,32 @@ dependencies = [ ] [metadata] +"checksum atk-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7017e53393e713212aed7aea336b6553be4927f58c37070a56c2fe3d107e489" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum cairo-rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd940f0d609699e343ef71c4af5f66423afbf30d666f796dabd8fd15229cf5b6" +"checksum cairo-sys-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d25596627380be4381247dba06c69ad05ca21b3b065bd9827e416882ac41dcd2" +"checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be" "checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e" +"checksum fragile 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f8140122fa0d5dcb9fc8627cfce2b37cc1500f752636d46ea28bc26785c2f9" +"checksum gdk 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc52c7244046df9d959df87289f1fc5cca23f9f850bab0c967963e2ecb83a96" +"checksum gdk-pixbuf 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc3aa730cb4df3de5d9fed59f43afdf9e5fb2d3d10bfcbd04cec031435ce87f5" +"checksum gdk-pixbuf-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08284f16ce4d909b10d785a763ba190e222d2c1557b29908bf0a661e27a8ac3b" +"checksum gdk-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "108548ebf5329b551f2b97ab356908d14627905abb74b936c3372de1535aee81" +"checksum gio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "29a44b051990573448edc80b1995237f8b97b5734d2aec05105b9242aa10af11" +"checksum gio-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6975ada29f7924dc1c90b30ed3b32d777805a275556c05e420da4fbdc22eb250" +"checksum glib 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a333edf5b9f1411c246ef14e7881b087255f04c56dbef48c64a0cb039b4b340" +"checksum glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3573351e846caed9f11207b275cd67bc07f0c2c94fb628e5d7c92ca056c7882d" +"checksum gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08475e4a08f27e6e2287005950114735ed61cec2cb8c1187682a5aec8c69b715" +"checksum gtk 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56a6b30f194f09a17bb7ffa95c3ecdb405abd3b75ff981f831b1f6d18fe115ff" +"checksum gtk-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d487d333a4b87072e6bf9f2e55befa0ebef01b9496c2e263c0f4a1ff3d6c04b1" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" "checksum maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" +"checksum pango 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4c2cb169402a3eb1ba034a7cc7d95b8b1c106e9be5ba4be79a5a93dc1a2795f4" +"checksum pango-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6eb49268e69dd0c1da5d3001a61aac08e2e9d2bfbe4ae4b19b9963c998f6453" +"checksum pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "72d5370d90f49f70bd033c3d75e87fc529fbfff9d6f7cccef07d6170079d91ea" "checksum proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afdc77cc74ec70ed262262942ebb7dac3d479e9e5cfa2da1841c0806f6cdabcc" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" diff --git a/Cargo.toml b/Cargo.toml index 327eee53..d7a9d835 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,28 @@ serde = { version = "1.0.*", features = ["derive"] } serde_yaml = "0.8.*" xkbcommon = { version = "0.4.*", features = ["wayland"] } +[dependencies.gio] +version = "" +features = ["v2_44"] + +[dependencies.glib] +version = "" +features = ["v2_44"] + +[dependencies.glib-sys] +version = "" +features = ["v2_44"] + + +[dependencies.gtk] +version = "0.5.*" +features = ["v3_22"] + +[dependencies.gtk-sys] +version = "" +features = ["v3_22"] + + [lib] name = "rs" path = "src/lib.rs" diff --git a/data/popup.ui b/data/popup.ui new file mode 100644 index 00000000..9e76694d --- /dev/null +++ b/data/popup.ui @@ -0,0 +1,19 @@ + + + + + + False + + + True + False + vertical + + + main + 1 + + + + diff --git a/data/squeekboard.gresources.xml b/data/squeekboard.gresources.xml index 7287d3c1..8ccee29d 100644 --- a/data/squeekboard.gresources.xml +++ b/data/squeekboard.gresources.xml @@ -29,6 +29,7 @@ keyboards/symbols/ua.xml keyboards/symbols/ug.xml keyboards/symbols/zh-bopomofo.xml + popup.ui icons/key-enter.svg icons/key-shift.svg icons/keyboard-mode-symbolic.svg diff --git a/debian/control b/debian/control index dfa1060c..7dfac5ec 100644 --- a/debian/control +++ b/debian/control @@ -12,6 +12,11 @@ Build-Depends: libgtk-3-dev, libcroco3-dev, librust-bitflags-1-dev (>= 1.0), + librust-gio+v2-44-dev, + librust-glib+v2-44-dev, + librust-glib-sys-dev, + librust-gtk+v3-22-dev (>= 0.5), + librust-gtk-sys-dev, librust-maplit-1-dev (>= 1.0), librust-serde-derive-1-dev (>= 1.0), librust-serde-yaml-0.8-dev (>= 0.8), diff --git a/eek/eek-gtk-keyboard.c b/eek/eek-gtk-keyboard.c index 0674f103..5d28a764 100644 --- a/eek/eek-gtk-keyboard.c +++ b/eek/eek-gtk-keyboard.c @@ -145,7 +145,7 @@ static void release(EekGtkKeyboard *self, guint32 time) { EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self); - squeek_layout_release(priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard, time, self); + squeek_layout_release(priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard, eek_renderer_get_transformation(priv->renderer), time, self); } static gboolean diff --git a/src/action.rs b/src/action.rs index 06f789d8..61660653 100644 --- a/src/action.rs +++ b/src/action.rs @@ -36,4 +36,5 @@ pub enum Action { /// The key events this symbol submits when submitting text is not possible keys: Vec, }, + ShowPreferences, } diff --git a/src/data.rs b/src/data.rs index 0066b8ec..85276346 100644 --- a/src/data.rs +++ b/src/data.rs @@ -509,10 +509,7 @@ fn create_action( &view_names ), }, - Some(Action::ShowPrefs) => ::action::Action::Submit { - text: None, - keys: Vec::new(), - }, + Some(Action::ShowPrefs) => ::action::Action::ShowPreferences, None => ::action::Action::Submit { text: None, keys: keysyms.into_iter().map(::action::KeySym).collect(), diff --git a/src/layout.h b/src/layout.h index ea6ee949..c88bea30 100644 --- a/src/layout.h +++ b/src/layout.h @@ -62,7 +62,10 @@ const char *squeek_layout_get_keymap(const struct squeek_layout*); enum squeek_arrangement_kind squeek_layout_get_kind(const struct squeek_layout *); void squeek_layout_free(struct squeek_layout*); -void squeek_layout_release(struct squeek_layout *layout, struct zwp_virtual_keyboard_v1 *virtual_keyboard, uint32_t timestamp, EekGtkKeyboard *ui_keyboard); +void squeek_layout_release(struct squeek_layout *layout, struct zwp_virtual_keyboard_v1 *virtual_keyboard, + struct transformation widget_to_layout, + uint32_t timestamp, + EekGtkKeyboard *ui_keyboard); void squeek_layout_release_all_only(struct squeek_layout *layout, struct zwp_virtual_keyboard_v1 *virtual_keyboard, uint32_t timestamp); void squeek_layout_depress(struct squeek_layout *layout, struct zwp_virtual_keyboard_v1 *virtual_keyboard, double x_widget, double y_widget, diff --git a/src/layout.rs b/src/layout.rs index 442dc893..27e32cd5 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -37,6 +37,7 @@ pub mod c { use std::ffi::CStr; use std::os::raw::{ c_char, c_void }; use std::ptr; + use gtk_sys; // The following defined in C @@ -45,7 +46,7 @@ pub mod c { #[repr(transparent)] #[derive(Copy, Clone)] - pub struct EekGtkKeyboard(*const c_void); + pub struct EekGtkKeyboard(pub *const gtk_sys::GtkWidget); /// Defined in eek-types.h #[repr(C)] @@ -245,7 +246,7 @@ pub mod c { origin_y: f64, scale: f64, } - + impl Transformation { fn forward(&self, p: Point) -> Point { Point { @@ -253,6 +254,25 @@ pub mod c { y: (p.y - self.origin_y) / self.scale, } } + fn reverse(&self, p: Point) -> Point { + Point { + x: p.x * self.scale + self.origin_x, + y: p.y * self.scale + self.origin_y, + } + } + pub fn reverse_bounds(&self, b: Bounds) -> Bounds { + let start = self.reverse(Point { x: b.x, y: b.y }); + let end = self.reverse(Point { + x: b.x + b.width, + y: b.y + b.height, + }); + Bounds { + x: start.x, + y: start.y, + width: end.x - start.x, + height: end.y - start.y, + } + } } // This is constructed only in C, no need for warnings @@ -319,28 +339,30 @@ pub mod c { } } + /// Release pointer in the specified position #[no_mangle] pub extern "C" fn squeek_layout_release( layout: *mut Layout, virtual_keyboard: ZwpVirtualKeyboardV1, // TODO: receive a reference to the backend + widget_to_layout: Transformation, time: u32, ui_keyboard: EekGtkKeyboard, ) { + let time = Timestamp(time); let layout = unsafe { &mut *layout }; let virtual_keyboard = VirtualKeyboard(virtual_keyboard); // The list must be copied, // because it will be mutated in the loop for key in layout.pressed_keys.clone() { let key: &Rc> = key.borrow(); - layout.release_key( + ui::release_key( + layout, &virtual_keyboard, - &mut key.clone(), - Timestamp(time) - ); - let view = layout.get_current_view(); - ::layout::procedures::release_ui_buttons( - &view, key, ui_keyboard, + &widget_to_layout, + time, + ui_keyboard, + key ); } } @@ -418,6 +440,7 @@ pub mod c { time: u32, ui_keyboard: EekGtkKeyboard, ) { + let time = Timestamp(time); let layout = unsafe { &mut *layout }; let virtual_keyboard = VirtualKeyboard(virtual_keyboard); @@ -442,36 +465,30 @@ pub mod c { if Rc::ptr_eq(&state, &wrapped_key.0) { found = true; } else { - layout.release_key( + ui::release_key( + layout, &virtual_keyboard, - &mut key.clone(), - Timestamp(time), - ); - let view = layout.get_current_view(); - ::layout::procedures::release_ui_buttons( - &view, key, ui_keyboard, + &widget_to_layout, + time, + ui_keyboard, + key, ); } } if !found { - layout.press_key( - &virtual_keyboard, - &mut state, - Timestamp(time), - ); + layout.press_key(&virtual_keyboard, &mut state, time); unsafe { eek_gtk_on_button_pressed(c_place, ui_keyboard) }; } } else { for wrapped_key in pressed { let key: &Rc> = wrapped_key.borrow(); - layout.release_key( + ui::release_key( + layout, &virtual_keyboard, - &mut key.clone(), - Timestamp(time), - ); - let view = layout.get_current_view(); - ::layout::procedures::release_ui_buttons( - &view, key, ui_keyboard, + &widget_to_layout, + time, + ui_keyboard, + key, ); } } @@ -503,6 +520,28 @@ pub mod c { } } } + + #[cfg(test)] + mod test { + use super::*; + + fn near(a: f64, b: f64) -> bool { + (a - b).abs() < ((a + b) * 0.001f64).abs() + } + + #[test] + fn transform_back() { + let transform = Transformation { + origin_x: 10f64, + origin_y: 11f64, + scale: 12f64, + }; + let point = Point { x: 1f64, y: 1f64 }; + let transformed = transform.reverse(transform.forward(point.clone())); + assert!(near(point.x, transformed.x)); + assert!(near(point.y, transformed.y)); + } + } } } @@ -717,6 +756,12 @@ pub struct Layout { pub keymap_str: CString, // Changeable state // a Vec would be enough, but who cares, this will be small & fast enough + // TODO: turn those into per-input point *_buttons to track dragging. + // The renderer doesn't need the list of pressed keys any more, + // because it needs to iterate + // through all buttons of the current view anyway. + // When the list tracks actual location, + // it becomes possible to place popovers and other UI accurately. pub pressed_keys: HashSet<::util::Pointer>>, pub locked_keys: HashSet<::util::Pointer>>, } @@ -949,6 +994,64 @@ mod procedures { ); } } + + pub fn get_button_bounds( + view: &View, + row: &Row, + button: &Button + ) -> Option { + match &row.bounds { + Some(row) => Some(c::Bounds { + x: view.bounds.x + row.x + button.bounds.x, + y: view.bounds.y + row.y + button.bounds.y, + width: button.bounds.width, + height: button.bounds.height, + }), + _ => None, + } + } +} + +/// Top level UI procedures +mod ui { + use super::*; + + // TODO: turn into release_button + pub fn release_key( + layout: &mut Layout, + virtual_keyboard: &VirtualKeyboard, + widget_to_layout: &c::procedures::Transformation, + time: Timestamp, + ui_keyboard: c::EekGtkKeyboard, + key: &Rc>, + ) { + layout.release_key(virtual_keyboard, &mut key.clone(), time); + + let view = layout.get_current_view(); + let action = RefCell::borrow(key).action.clone(); + if let Action::ShowPreferences = action { + let paths = ::layout::procedures::find_key_paths( + view, key + ); + // getting first item will cause mispositioning + // with more than one button with the same key + // on the keyboard + if let Some((row, button)) = paths.get(0) { + let bounds = ::layout::procedures::get_button_bounds( + view, row, button + ).unwrap_or_else(|| { + eprintln!("BUG: Clicked button has no position?"); + c::Bounds { x: 0f64, y: 0f64, width: 0f64, height: 0f64 } + }); + ::popover::show( + ui_keyboard, + widget_to_layout.reverse_bounds(bounds) + ); + } + } + + procedures::release_ui_buttons(view, key, ui_keyboard); + } } #[cfg(test)] diff --git a/src/lib.rs b/src/lib.rs index d4652349..40de413d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,10 @@ #[macro_use] extern crate bitflags; +extern crate gio; +extern crate glib; +extern crate glib_sys; +extern crate gtk; +extern crate gtk_sys; #[allow(unused_imports)] #[macro_use] // only for tests extern crate maplit; @@ -13,6 +18,7 @@ pub mod imservice; mod keyboard; mod layout; mod outputs; +mod popover; mod resources; mod submission; mod util; diff --git a/src/popover.h b/src/popover.h new file mode 100644 index 00000000..1b164e5a --- /dev/null +++ b/src/popover.h @@ -0,0 +1,9 @@ +#ifndef POPOVER_H__ +#define POPOVER_H__ + +#include +#include "eek/eek-keyboard.h" + +void squeek_popover_show(GtkWidget*, struct button_place); + +#endif diff --git a/src/popover.rs b/src/popover.rs new file mode 100644 index 00000000..7f51b881 --- /dev/null +++ b/src/popover.rs @@ -0,0 +1,158 @@ +/*! The layout chooser popover */ + +use gio; +use gtk; +use ::layout::c::EekGtkKeyboard; + +use gio::ActionExt; +use gio::ActionMapExt; +use gio::SettingsExt; +use glib::translate::FromGlibPtrNone; +use glib::variant::ToVariant; +use gtk::PopoverExt; +use gtk::WidgetExt; +use std::io::Write; + +mod variants { + use glib; + use glib_sys; + + use glib::translate::FromGlibPtrFull; + use glib::translate::ToGlibPtr; + + /// Unpacks tuple & array variants + fn get_items(items: glib::Variant) -> Vec { + let variant_naked = items.to_glib_none().0; + let count = unsafe { glib_sys::g_variant_n_children(variant_naked) }; + (0..count).map(|index| + unsafe { + glib::Variant::from_glib_full( + glib_sys::g_variant_get_child_value(variant_naked, index) + ) + } + ).collect() + } + + /// Unpacks "a(ss)" variants + pub fn get_tuples(items: glib::Variant) -> Vec<(String, String)> { + get_items(items) + .into_iter() + .map(get_items) + .map(|v| { + ( + v[0].get::().unwrap(), + v[1].get::().unwrap(), + ) + }) + .collect() + } +} + +fn make_menu_builder(inputs: Vec<&str>) -> gtk::Builder { + let mut xml: Vec = Vec::new(); + writeln!( + xml, + " + + +
" + ).unwrap(); + for input in inputs { + writeln!( + xml, + " + + {} + layout + {0} + ", + input, + ).unwrap(); + } + writeln!( + xml, + " +
+
+
" + ).unwrap(); + gtk::Builder::new_from_string( + &String::from_utf8(xml).expect("Bad menu definition") + ) +} + +fn set_layout(kind: String, name: String) { + let settings = gio::Settings::new("org.gnome.desktop.input-sources"); + let inputs = settings.get_value("sources").unwrap(); + let inputs = variants::get_tuples(inputs).into_iter(); + for (index, (ikind, iname)) in inputs.enumerate() { + if (&ikind, &iname) == (&kind, &name) { + settings.set_uint("current", index as u32); + } + } + settings.apply(); +} + +pub fn show(window: EekGtkKeyboard, position: ::layout::c::Bounds) { + unsafe { gtk::set_initialized() }; + let window = unsafe { gtk::Widget::from_glib_none(window.0) }; + + let settings = gio::Settings::new("org.gnome.desktop.input-sources"); + let inputs = settings.get_value("sources").unwrap(); + let current = settings.get_uint("current") as usize; + let inputs = variants::get_tuples(inputs); + + let input_names: Vec<&str> = inputs.iter() + .map(|(_kind, name)| name.as_str()) + .collect(); + + let builder = make_menu_builder(input_names.clone()); + // Much more debuggable to populate the model & menu + // from a string representation + // than add items imperatively + let model: gio::MenuModel = builder.get_object("app-menu").unwrap(); + + let menu = gtk::Popover::new_from_model(Some(&window), &model); + menu.set_pointing_to(>k::Rectangle { + x: position.x.ceil() as i32, + y: position.y.ceil() as i32, + width: position.width.floor() as i32, + height: position.width.floor() as i32, + }); + + let initial_state = input_names[current].to_variant(); + + let layout_action = gio::SimpleAction::new_stateful( + "layout", + Some(initial_state.type_()), + &initial_state, + ); + + let action_group = gio::SimpleActionGroup::new(); + action_group.add_action(&layout_action); + + menu.insert_action_group("popup", Some(&action_group)); + menu.bind_model(Some(&model), Some("popup")); + + menu.connect_closed(move |_menu| { + let state = match layout_action.get_state() { + Some(v) => { + let s = v.get::().or_else(|| { + eprintln!("Variant is not string: {:?}", v); + None + }); + // FIXME: the `get_state` docs call for unrefing, + // but the function is nowhere to be found + // glib::Variant::unref(v); + s + }, + None => { + eprintln!("No variant selected"); + None + }, + }; + set_layout("xkb".into(), state.unwrap_or("us".into())); + }); + + menu.popup(); +} diff --git a/src/submission.rs b/src/submission.rs index 17b3bfa9..476605a8 100644 --- a/src/submission.rs +++ b/src/submission.rs @@ -23,6 +23,7 @@ pub mod c { } } +#[derive(Clone, Copy)] pub struct Timestamp(pub u32); /// Layout-independent backend. TODO: Have one instance per program or seat