From 8dc13a1ad65466104da7ab1aa2a17839c3541544 Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Fri, 26 Jun 2020 14:53:06 -0500 Subject: [PATCH] screen layout detection --- Cargo.lock | 135 +++++++++++++++++++++++++++++++- Cargo.toml | 4 +- src/lib.rs | 47 +++++------ src/main.rs | 44 ++++++++++- src/options.rs | 38 --------- src/platform/mod.rs | 29 +++++++ src/platform/x11.rs | 32 +++++++- x11/Cargo.toml | 1 + x11/src/lib.rs | 3 + x11/src/xinerama/mod.rs | 3 + x11/src/xinerama/screen_info.rs | 64 +++++++++++++++ x11/src/xlib/display.rs | 2 +- 12 files changed, 328 insertions(+), 74 deletions(-) delete mode 100644 src/options.rs create mode 100644 x11/src/xinerama/mod.rs create mode 100644 x11/src/xinerama/screen_info.rs diff --git a/Cargo.lock b/Cargo.lock index 990754c..33fbd74 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,11 +20,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "atty" -version = "0.2.14" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -53,13 +53,23 @@ name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "chrono" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "clap" version = "2.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -206,6 +216,11 @@ dependencies = [ "rayon 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lazy_static" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "lazy_static" version = "1.4.0" @@ -218,7 +233,9 @@ dependencies = [ "anyhow 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.23.5 (registry+https://github.com/rust-lang/crates.io-index)", "leanshot_x11 0.2.0", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "png 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", + "stderrlog 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -236,6 +253,14 @@ name = "libc" version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "log" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "lzw" version = "0.10.0" @@ -308,6 +333,11 @@ dependencies = [ "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "numtoa" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "pkg-config" version = "0.3.17" @@ -390,6 +420,19 @@ dependencies = [ "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_termios" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "scoped_threadpool" version = "0.1.9" @@ -400,6 +443,18 @@ name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "stderrlog" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "strsim" version = "0.8.0" @@ -445,6 +500,25 @@ dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "termcolor" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termion" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "textwrap" version = "0.11.0" @@ -471,6 +545,15 @@ dependencies = [ "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "thread_local" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tiff" version = "0.5.0" @@ -481,6 +564,15 @@ dependencies = [ "miniz_oxide 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "time" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-segmentation" version = "1.6.0" @@ -501,11 +593,24 @@ name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "vec_map" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi" version = "0.3.8" @@ -520,6 +625,14 @@ name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -538,12 +651,13 @@ dependencies = [ "checksum adler32 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "567b077b825e468cc974f0020d4082ee6e03132512f207ef1a02fd5d00d1f32d" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum anyhow 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f" -"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37fa13df2292ecb479ec23aa06f4507928bef07839be9ef15281411076629431" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" "checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" "checksum color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" @@ -560,8 +674,10 @@ dependencies = [ "checksum image 0.23.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d534e95ad8b9d5aa614322d02352b4f1bf962254adcf02ac6f2def8be18498e8" "checksum inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff" "checksum jpeg-decoder 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "5b47b4c4e017b01abdc5bcc126d2d1002e5a75bbe3ce73f9f4f311a916363704" +"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" +"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" "checksum memoffset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8" @@ -571,6 +687,7 @@ dependencies = [ "checksum num-rational 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" "checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" "checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" "checksum png 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "63daf481fdd0defa2d1d2be15c674fbfa1b0fd71882c303a91f9a79b3252c359" "checksum png 0.16.5 (registry+https://github.com/rust-lang/crates.io-index)" = "34ccdd66f6fe4b2433b07e4728e9a013e43233120427046e93ceb709c3a439bf" @@ -580,23 +697,33 @@ dependencies = [ "checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" "checksum rayon 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "62f02856753d04e03e26929f820d0a0a337ebe71f849801eea335d464b349080" "checksum rayon-core 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e92e15d89083484e11353891f1af602cc661426deb9564c298b270c726973280" +"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" "checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +"checksum stderrlog 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "32e5ee9b90a5452c570a0b0ac1c99ae9498db7e56e33d74366de7f2a7add7f25" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" "checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" "checksum syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6" +"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" +"checksum termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08" "checksum thiserror-impl 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793" +"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" "checksum tiff 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f3b8a87c4da944c3f27e5943289171ac71a6150a79ff6bacfff06d159dfff2f" +"checksum time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" "checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" "checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum x11 2.18.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77ecd092546cb16f25783a5451538e73afc8d32e242648d54f4ae5459ba1e773" diff --git a/Cargo.toml b/Cargo.toml index 1526a7c..5b9621a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,4 +24,6 @@ structopt = "0.2" anyhow = "1.0.31" image = "0.23.5" -leanshot_x11 = { version = "0.2", path = "x11", optional = true, features = ["xlib"] } +leanshot_x11 = { version = "0.2", path = "x11", optional = true, features = ["xlib", "xinerama"] } +log = "0.4.8" +stderrlog = "0.4.3" diff --git a/src/lib.rs b/src/lib.rs index 8c653b8..2d8c4d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,39 +4,34 @@ #[macro_use] extern crate anyhow; -#[macro_use] -extern crate structopt; extern crate leanshot_x11 as x11; +extern crate structopt; -mod options; mod platform; use anyhow::Result; -pub use crate::options::{Options, Region}; -use crate::platform::{x11::X11, Platform}; +pub use crate::platform::{x11::X11, Platform}; type Rectangle = x11::Rectangle; -/// The main capture routine -pub fn capture(opt: &Options) -> Result<()> { - let gui = X11::new()?; - - let image = match opt.region { - Region::ActiveWindow => { - let window = gui.get_active_window()?; - let image = gui.capture_window(window); - } - Region::Fullscreen | Region::Selection => { - let mut image = gui.capture_full_screen()?; - if let Region::Fullscreen = opt.region { - let rect = gui.show_interactive_selection(image)?; - // TODO: crop the image - } - } - }; - - unimplemented!("leanshot::capture") - // imlib2::context_set_image(&capture); - // capture.save_image(&opt.outfile)?; +/// A region option +#[allow(missing_docs)] +pub enum Region { + Fullscreen, + ActiveWindow, + Selection, +} + +impl Region { + /// Convert string to Region enum + // TODO: use FromStr trait + pub fn from_str(x: &str) -> Result { + match x { + "fullscreen" => Ok(Region::Fullscreen), + "window" => Ok(Region::ActiveWindow), + "select" | "selection" => Ok(Region::Selection), + _ => bail!("please choose a region from 'fullscreen', 'window', or 'select'"), + } + } } diff --git a/src/main.rs b/src/main.rs index 4d9b295..7e4dc34 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,49 @@ +use std::path::PathBuf; + use anyhow::Result; -use leanshot::{capture, Options}; +use leanshot::{Platform, Region, X11}; use structopt::StructOpt; #[allow(missing_docs)] pub fn main() -> Result<()> { + stderrlog::new().module(module_path!()).init().unwrap(); + let opt = Options::from_args(); - capture(&opt) + + let gui = X11::new()?; + + let screen_layout = gui.get_screen_layout()?; + println!("{:?}", screen_layout); + + let image = match opt.region { + Region::ActiveWindow => { + let window = gui.get_active_window()?; + let image = gui.capture_window(window); + } + Region::Fullscreen | Region::Selection => { + let mut image = gui.capture_full_screen()?; + if let Region::Fullscreen = opt.region { + let rect = gui.show_interactive_selection(image)?; + // TODO: crop the image + } + } + }; + + unimplemented!("leanshot::capture") +} + +/// Options for screenshot +#[derive(StructOpt)] +pub struct Options { + /// The region to select (fullscreen | window | select) + #[structopt(parse(try_from_str = "Region::from_str"))] + pub region: Region, + + /// The file to save the screenshot to + #[structopt(short = "o", long = "out", parse(from_os_str))] + pub outfile: PathBuf, + + /// Whether or not to also copy it to the clipboard + #[structopt(short = "c")] + pub clipboard: bool, } diff --git a/src/options.rs b/src/options.rs deleted file mode 100644 index fc6ceef..0000000 --- a/src/options.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::path::PathBuf; - -use anyhow::Result; - -/// A region option -#[allow(missing_docs)] -pub enum Region { - Fullscreen, - ActiveWindow, - Selection, -} - -/// Options for screenshot -#[derive(StructOpt)] -pub struct Options { - /// The region to select (fullscreen | window | select) - #[structopt(parse(try_from_str = "Region::from_str"))] - pub region: Region, - - /// The file to save the screenshot to - #[structopt(short = "o", long = "out", parse(from_os_str))] - pub outfile: PathBuf, - - /// Whether or not to also copy it to the clipboard - #[structopt(short = "c")] - pub clipboard: bool, -} - -impl Region { - pub(self) fn from_str(x: &str) -> Result { - match x { - "fullscreen" => Ok(Region::Fullscreen), - "window" => Ok(Region::ActiveWindow), - "select" | "selection" => Ok(Region::Selection), - _ => bail!("please choose a region from 'fullscreen', 'window', or 'select'"), - } - } -} diff --git a/src/platform/mod.rs b/src/platform/mod.rs index f3083d6..b2fb143 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -1,21 +1,50 @@ #[cfg(feature = "x11")] pub mod x11; +use std::collections::HashMap; +use std::hash::Hash; + use anyhow::Result; use image::RgbaImage; use crate::Rectangle; +#[derive(Debug)] +pub struct ScreenInfo { + pub width: u16, + pub height: u16, + pub x: i16, + pub y: i16, +} + +/// Set of functions that all platforms must implement pub trait Platform { + /// Type of window handles type Window; + + /// Type of images type Image: Image; + /// Type of screen handles + type ScreenId: Hash; + + /// Get a handle to the currently active window fn get_active_window(&self) -> Result; + + /// Capture a specific window by handle fn capture_window(&self, window: Self::Window) -> Result; + + /// Get the screen layout (list of screens, where they are) + fn get_screen_layout(&self) -> Result>; + + /// Capture full screen fn capture_full_screen(&self) -> Result; + + /// Open the interactive selection interface fn show_interactive_selection(&self, image: Self::Image) -> Result; } +/// Set of functions platform-specific images must implement pub trait Image { fn into_rgba_image(self) -> RgbaImage; } diff --git a/src/platform/x11.rs b/src/platform/x11.rs index c4f7250..609fc5e 100644 --- a/src/platform/x11.rs +++ b/src/platform/x11.rs @@ -1,17 +1,26 @@ +use std::collections::HashMap; + use anyhow::Result; use image::RgbaImage; -use x11::xlib::{Display, Window}; +use x11::{ + xinerama::ScreensInfo, + xlib::{Display, Window}, +}; -use crate::platform::{Image as ImageT, Platform}; +use crate::platform::{Image as ImageT, Platform, ScreenInfo}; use crate::Rectangle; +/// Interface to x11 pub struct X11 { inner: Display, } impl X11 { + /// Create a new x11 instace pub fn new() -> Result { + // TODO: configure connection string let display = Display::connect(":0")?; + Ok(X11 { inner: display }) } } @@ -19,6 +28,7 @@ impl X11 { impl Platform for X11 { type Window = Window; type Image = Image; + type ScreenId = i32; fn get_active_window(&self) -> Result { let (window, _) = self.inner.get_input_focus()?; @@ -35,6 +45,24 @@ impl Platform for X11 { unimplemented!() } + fn get_screen_layout(&self) -> Result> { + let screens_info = ScreensInfo::query(&self.inner)?; + Ok(screens_info + .iter() + .map(|(num, screen)| { + ( + num, + ScreenInfo { + x: screen.x, + y: screen.y, + width: screen.width as u16, + height: screen.height as u16, + }, + ) + }) + .collect()) + } + fn show_interactive_selection(&self, image: Self::Image) -> Result { let window = Window::create(&self.inner, None, Rectangle::new(0, 0, 500, 500))?; window.map(); diff --git a/x11/Cargo.toml b/x11/Cargo.toml index 6e5d6f0..58df0d3 100644 --- a/x11/Cargo.toml +++ b/x11/Cargo.toml @@ -9,6 +9,7 @@ authors = ["Michael Zhang "] default = [] xlib = ["x11/xlib"] xrender = ["x11/xrender"] +xinerama = ["x11/xlib", "x11/xinerama"] [dependencies] libc = "0.2" diff --git a/x11/src/lib.rs b/x11/src/lib.rs index d4de88a..240f905 100644 --- a/x11/src/lib.rs +++ b/x11/src/lib.rs @@ -11,6 +11,9 @@ pub mod xlib; #[cfg(feature = "xrender")] pub mod xrender; +#[cfg(feature = "xinerama")] +pub mod xinerama; + mod errors; mod rect; diff --git a/x11/src/xinerama/mod.rs b/x11/src/xinerama/mod.rs new file mode 100644 index 0000000..8e3b882 --- /dev/null +++ b/x11/src/xinerama/mod.rs @@ -0,0 +1,3 @@ +mod screen_info; + +pub use self::screen_info::ScreensInfo; diff --git a/x11/src/xinerama/screen_info.rs b/x11/src/xinerama/screen_info.rs new file mode 100644 index 0000000..a5909ca --- /dev/null +++ b/x11/src/xinerama/screen_info.rs @@ -0,0 +1,64 @@ +use x11::xinerama; + +use crate::errors::Result; +use crate::xlib::Display; + +pub struct ScreensInfo { + inner: *mut xinerama::XineramaScreenInfo, + heads: isize, +} + +impl ScreensInfo { + pub fn query(display: &Display) -> Result { + let mut heads = 0; + let inner = unsafe { xinerama::XineramaQueryScreens(display.inner, &mut heads as *mut _) }; + // TODO: check for error + Ok(ScreensInfo { + inner, + heads: heads as isize, + }) + } + + pub fn iter(&self) -> ScreenInfoIter { + ScreenInfoIter(self, 0) + } +} + +impl Drop for ScreensInfo { + fn drop(&mut self) { + unsafe { x11::xlib::XFree(self.inner as *mut _) }; + } +} + +pub struct ScreenInfoIter<'a>(&'a ScreensInfo, isize); + +pub struct ScreenInfo { + pub x: i16, + pub y: i16, + pub width: i16, + pub height: i16, +} + +impl<'a> Iterator for ScreenInfoIter<'a> { + type Item = (i32, ScreenInfo); + fn next(&mut self) -> Option { + if self.1 >= self.0.heads { + return None; + } + + let screen = unsafe { self.0.inner.offset(self.1) }; + self.1 += 1; + + unsafe { + Some(( + (*screen).screen_number as i32, + ScreenInfo { + x: (*screen).x_org as i16, + y: (*screen).y_org as i16, + width: (*screen).width as i16, + height: (*screen).height as i16, + }, + )) + } + } +} diff --git a/x11/src/xlib/display.rs b/x11/src/xlib/display.rs index 2993652..a5b6331 100644 --- a/x11/src/xlib/display.rs +++ b/x11/src/xlib/display.rs @@ -11,7 +11,7 @@ use super::window::Window; /// A connection to an X server. pub struct Display { - inner: *mut xlib::Display, + pub(crate) inner: *mut xlib::Display, } pub struct Grab(pub(crate) *mut xlib::Display);