Compare commits
412 commits
Author | SHA1 | Date | |
---|---|---|---|
|
330edacab9 | ||
|
ec6474a840 | ||
|
69e1749856 | ||
|
e93488af9b | ||
|
a8861c62ea | ||
|
e6651d55ff | ||
|
9c58913ee2 | ||
|
24ff2b7120 | ||
|
7c4f99c85d | ||
|
7cc5fd880e | ||
|
ed9edb5ad6 | ||
|
c0323ee329 | ||
|
40493475ba | ||
|
4098e8c0e5 | ||
|
ca234008b9 | ||
|
2ebb41a371 | ||
|
6cf4299f78 | ||
|
df0459da69 | ||
|
46accb1077 | ||
|
7a91ba5a84 | ||
|
f83ceb2a96 | ||
|
d332121d7c | ||
|
d151b47895 | ||
|
caa8731410 | ||
|
dc3ee66e3b | ||
|
289f9ab1d2 | ||
|
73747e05a7 | ||
|
3051ce5118 | ||
|
fb32fa2fd2 | ||
|
b3eab6085f | ||
|
835aecb79d | ||
|
6cba5d0487 | ||
|
50b78cee51 | ||
|
1b6f648a0b | ||
|
6b2f8f847e | ||
|
917f8b5812 | ||
|
a62fb95fbf | ||
|
c3b0d00a72 | ||
|
d6dfd678b8 | ||
|
8b215c1e73 | ||
|
96295a52de | ||
|
ccd0e8e64b | ||
|
3b3ec89306 | ||
|
373fe8e02a | ||
|
14d9793193 | ||
|
65ceab6323 | ||
|
6b2118ecf6 | ||
|
ca78025735 | ||
|
c5eb13145f | ||
|
946443bf8c | ||
|
ae33c2f1b0 | ||
|
c97c0d597b | ||
|
ee3713b16b | ||
|
ae39e71061 | ||
|
7e5cac9fa3 | ||
|
b61b2b1630 | ||
|
1b1d1db14d | ||
|
81ec0183ea | ||
|
f5046cea54 | ||
|
624f13b2d9 | ||
|
0d502f0e45 | ||
|
6549ca4e1d | ||
|
37578dde7b | ||
|
225ae1233e | ||
|
d8cb29c4d4 | ||
|
502785f233 | ||
|
e3cf87906b | ||
|
5c3821007d | ||
|
c02e084dcf | ||
|
85d4e0ac6d | ||
|
fbca9c9340 | ||
|
d9d0ac1830 | ||
|
3adb2a6fe7 | ||
|
742ad82b88 | ||
|
a1ce8f866a | ||
|
24e8942ac5 | ||
|
3163d68e9e | ||
|
a6e1a6877f | ||
|
ac1ed1873a | ||
|
2ccefe0883 | ||
|
06f09e1f2e | ||
|
c3e9fbb25a | ||
|
096b28318c | ||
|
562d071c62 | ||
|
474d4b1994 | ||
|
49b55768f7 | ||
|
640a4d72e0 | ||
|
0e37f97aa2 | ||
|
499ad4a3aa | ||
|
8b5bdc4c6a | ||
|
cfee938516 | ||
|
c024323eab | ||
|
a2ad4692a3 | ||
|
c50a341527 | ||
|
a68ebf3564 | ||
|
98b1982157 | ||
|
c86228a404 | ||
|
a389589fbb | ||
|
392e9b99cf | ||
|
51c7422f6e | ||
|
7c8d070ab5 | ||
|
aa89690788 | ||
|
c82cad87fa | ||
|
a5f3b915e5 | ||
|
395cbcd9db | ||
|
ee247cba8a | ||
|
bcc0aeeaa9 | ||
|
de5bea9cdf | ||
|
d846790905 | ||
|
13331ee5e7 | ||
|
5bb95053fb | ||
|
bd38e5e1d8 | ||
|
8b1250030b | ||
|
c0cb90bf79 | ||
|
c3723ac58a | ||
|
aad58b1c83 | ||
|
96034902d1 | ||
|
e918955210 | ||
|
5f746999c2 | ||
|
1c51407109 | ||
|
5f402464ad | ||
|
7a14d53ba0 | ||
|
ca72462125 | ||
|
11048f96fa | ||
|
144c19fab1 | ||
|
32bb391c2e | ||
|
d23ffd1972 | ||
|
9a75c5a986 | ||
|
82ac1c2daf | ||
|
6a256bb1a0 | ||
|
fafc8e4d7d | ||
|
fdc7e348f0 | ||
|
2bdef17e18 | ||
|
718741b036 | ||
|
8dc0a5bfaf | ||
|
6b0ea884cb | ||
|
a488a24514 | ||
|
fb3fc3bd8d | ||
|
8968a8cbce | ||
|
a7d2c67e67 | ||
|
40a575a5d6 | ||
|
f5b23c2e7e | ||
|
7993442a34 | ||
|
8f4acf3b60 | ||
|
c59627b661 | ||
|
705426d489 | ||
|
81ad7bdb46 | ||
|
f110cad24b | ||
|
f989d2ae83 | ||
|
686b37e630 | ||
|
1265307bd0 | ||
|
955167d37f | ||
|
1f83c35103 | ||
|
a517fedd96 | ||
|
732f34b595 | ||
|
eb2f004d45 | ||
|
8b6eff5fb8 | ||
|
af743fc62f | ||
|
2c33333000 | ||
|
2548134302 | ||
|
7a995706b7 | ||
|
47aca44551 | ||
|
08e069b3d9 | ||
|
6b7b4badcd | ||
|
a6cec46ecc | ||
|
5ae3d42d1f | ||
|
fedeaa5c0d | ||
|
ecca86a1ce | ||
|
ea08119fa3 | ||
|
c3b7ae3ab1 | ||
|
6bb1f00082 | ||
|
d6eea75b6a | ||
|
341f83f71f | ||
|
10be6d49cb | ||
|
09c0e488a8 | ||
|
57736b1fee | ||
|
e284c2e349 | ||
|
675fe02cb1 | ||
|
5fe631037c | ||
|
736f10eb8a | ||
|
c7c4237d10 | ||
|
5e6bd0b9bb | ||
|
c1699c2c79 | ||
|
d7364e1d80 | ||
|
d248aaf8b3 | ||
|
67dff741dd | ||
|
21fe180a84 | ||
|
3f83d74bac | ||
|
ec142556d8 | ||
|
fc426abfc0 | ||
|
6241c2e1de | ||
|
ba940d6df4 | ||
|
29f4d627d2 | ||
|
774fa969a3 | ||
|
f7d76eef98 | ||
|
63dc0179c1 | ||
|
0131476a5d | ||
|
1b89370c1c | ||
|
c8606126f0 | ||
|
52850ccf23 | ||
|
60540b87d0 | ||
|
db5ba12190 | ||
|
7cf050ff8e | ||
|
b9d8128880 | ||
|
3e10b25068 | ||
|
bb85f020d5 | ||
|
a9ab338060 | ||
|
c305bfd5a6 | ||
|
69551efde3 | ||
|
6dc9258a5b | ||
|
cfd1942b38 | ||
|
0efce33634 | ||
|
23eb71e337 | ||
|
9beece6105 | ||
|
b06d8e9727 | ||
|
0f9cd68b97 | ||
|
3b829ec433 | ||
|
0d6f5c6242 | ||
|
9d45975ddc | ||
|
41635e39bb | ||
|
9803f66cc2 | ||
|
08ee34c9a6 | ||
|
348685a025 | ||
|
0a7261d05d | ||
|
7556670f88 | ||
|
ac2ca5a81b | ||
|
c296eab191 | ||
|
7f23eed890 | ||
|
346e24d2f8 | ||
|
038eee5f42 | ||
|
904432ea82 | ||
|
126becf47a | ||
|
f9b0cc1d1e | ||
|
662d165beb | ||
|
ffd7879096 | ||
|
d2beb77288 | ||
|
3f489b3558 | ||
|
e0f7473ed4 | ||
|
6bc886f53a | ||
|
c6129b7713 | ||
|
7dda93db57 | ||
|
a80bfcc325 | ||
|
1a2ba0f200 | ||
|
d0b54f13c6 | ||
|
e3f6b73ab2 | ||
|
9e96f4183a | ||
|
9d8897d29c | ||
|
aa6533b37d | ||
|
9ead5c29cd | ||
|
22abca4578 | ||
|
7c1b66faf5 | ||
|
3e534fd536 | ||
|
f05435d694 | ||
|
68a5469b97 | ||
|
045d9ec2d2 | ||
|
9fc77f3bc9 | ||
|
f10bdc1634 | ||
|
574b0ebf0c | ||
|
3987569d55 | ||
|
b7362b3125 | ||
|
3d47b453a8 | ||
|
3b8adcbf98 | ||
|
0ca853edaf | ||
|
2ab1b900f4 | ||
|
696149096d | ||
|
292f452cfe | ||
|
33c2342c8a | ||
|
e6532ab706 | ||
|
8c6fb5df9b | ||
|
c379456221 | ||
|
e17c7ae13d | ||
|
7627c89162 | ||
|
71fb639c16 | ||
|
58c9c1a006 | ||
|
2237d5eff8 | ||
|
f343398479 | ||
|
433c9ca5e6 | ||
|
9ddb68c82b | ||
|
ff2f325c51 | ||
|
aa3d674242 | ||
|
a736f5f5c6 | ||
|
3593d8f400 | ||
|
dc98b702d6 | ||
|
f7a26eaf72 | ||
|
99dd0944cf | ||
|
177773eb66 | ||
|
c2b5a13f59 | ||
|
a2d60f6593 | ||
|
0c4c99b63b | ||
|
3ccf20e2ea | ||
|
518ce674e6 | ||
|
60e6f563c6 | ||
|
46875b24c3 | ||
|
75e137f0d0 | ||
|
2b6145ea4f | ||
|
c78007a1f3 | ||
|
a18aeab6c3 | ||
|
5f205ac49c | ||
|
4f5ad63bf9 | ||
|
4036d299eb | ||
|
8c80685686 | ||
|
fc004aa254 | ||
|
2771ba8773 | ||
|
b3b1ac1c47 | ||
|
c2ec2c5dc9 | ||
|
c2e335e439 | ||
|
38c3a3a816 | ||
|
7762e283db | ||
|
469c783a48 | ||
|
0869b4e456 | ||
|
cc9b8a9e6d | ||
|
5b679da427 | ||
|
fc7762c457 | ||
|
e53e70cc9b | ||
|
a7f7f5dec4 | ||
|
1c088cc925 | ||
|
ac598bb801 | ||
|
c399bc1068 | ||
|
2f14184928 | ||
|
80bb515438 | ||
|
f1b3fedb5f | ||
|
cd0c110df8 | ||
|
95fcb6bc62 | ||
|
eac6ec661e | ||
|
d8269441eb | ||
|
e7b0dd9e9e | ||
|
5cf37918e7 | ||
|
94a53abb00 | ||
|
99a10c4e25 | ||
|
9bfce25666 | ||
|
b758cc1918 | ||
|
f488dd9116 | ||
|
918172c252 | ||
|
b3a1c552ce | ||
|
b4fd07ff8b | ||
|
0346488e0f | ||
|
eb2e6c1cec | ||
|
eab5145f34 | ||
|
a2c7245e46 | ||
|
4aa57f2684 | ||
|
d8625fdb29 | ||
|
207180396f | ||
|
b544e6dfce | ||
|
bc2cac672a | ||
|
6003ffebec | ||
|
51b3781c09 | ||
|
14e3422423 | ||
|
0e5ab21205 | ||
|
a11dc3f4b2 | ||
|
f5255440e4 | ||
|
0dc196e76d | ||
|
136f877778 | ||
|
3b7731d44f | ||
|
b51e1f3b0c | ||
|
ae3c214c3f | ||
|
200f16ecf2 | ||
|
ecd840c03a | ||
|
7092116efd | ||
|
68c493b736 | ||
|
4f62d52e5e | ||
|
c8be1e4966 | ||
|
c964cd5349 | ||
|
3fbf58f64d | ||
|
bd4400a7f2 | ||
|
c0e4d48fae | ||
|
8668f2beb2 | ||
|
628da207d0 | ||
|
677f7df376 | ||
|
580675e8a0 | ||
|
900a9b3fac | ||
|
f8f1e824a1 | ||
|
441c32bc30 | ||
|
41a0fb3b10 | ||
|
a38912a348 | ||
|
d568e4e1b6 | ||
|
12849c8571 | ||
|
f7fb051b67 | ||
|
693a6bc0df | ||
|
ccd19edf2f | ||
|
f2f6bf30b3 | ||
|
45b3f1ebde | ||
|
b4af2f75b1 | ||
|
fdabaf3374 | ||
|
2e481507e8 | ||
|
9b4e0e29e4 | ||
|
80bd8e085d | ||
|
7d2748c0bc | ||
|
2c0b04559e | ||
|
4476741ace | ||
|
68f8be01ac | ||
|
d84ee4692d | ||
|
a0fe51f318 | ||
|
70810ce6a2 | ||
|
f75d1f546b | ||
|
6c8255b12b | ||
|
f39cdb393f | ||
|
d4fda0f5f3 | ||
|
9afefa75a0 | ||
|
32c21ae81b | ||
|
ca1c2fa5ba | ||
|
6619927a7d | ||
|
e805dd04cb | ||
|
dbc3bed669 | ||
|
55aab1683f | ||
|
33978bda4f | ||
|
4c9ece5025 | ||
|
a984d64add | ||
|
cb95e89773 | ||
|
f8361fb31c | ||
|
5ceac87e6e | ||
|
e058f3bad1 | ||
|
460a44ba34 |
174
.drone.yml
|
@ -1,162 +1,54 @@
|
|||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: linux-release
|
||||
name: linux-build
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: feather:linux
|
||||
- name: linux-build
|
||||
image: wowlet/wowlet-linux:v0.1
|
||||
volumes:
|
||||
- name: ccache_linux_release
|
||||
path: /root/.ccache
|
||||
- name: files_linux_release
|
||||
path: /files
|
||||
- name: cache
|
||||
path: /drone/src/monero
|
||||
- name: files
|
||||
path: /tmp/wowlet_linux
|
||||
commands:
|
||||
- git config --global url."http://gitea:3000/tor/".insteadOf https://git.torproject.org/
|
||||
- git config --global url."http://gitea:3000/".insteadOf https://github.com/
|
||||
- git config --global url."http://gitea:3000/".insteadOf https://git.wownero.com/
|
||||
- git submodule update --init monero
|
||||
- git submodule update --init --depth 1 --recursive monero
|
||||
- TOR_BIN="/usr/local/tor/bin/tor" make -j8 release-static
|
||||
environment:
|
||||
OPENSSL_ROOT_DIR: /usr/local/openssl/
|
||||
CMAKEFLAGS_EXTRA: -DFETCH_DEPS=Off
|
||||
- name: deploy
|
||||
image: feather:linux
|
||||
volumes:
|
||||
- name: ccache_linux_release
|
||||
path: /root/.ccache
|
||||
- name: files_linux_release
|
||||
path: /files
|
||||
commands:
|
||||
- export FN="feather-`echo $DRONE_COMMIT_AFTER | cut -c 1-7`.zip"
|
||||
- export TARGET_DIR="/files/$DRONE_SOURCE_BRANCH"
|
||||
- mkdir -p "$TARGET_DIR"
|
||||
- echo "writing to $TARGET_DIR/$FN"
|
||||
- strip -s build/bin/feather
|
||||
- zip -j "$TARGET_DIR/$FN" build/feather.log build/bin/feather
|
||||
- echo "[*] written to https://build.featherwallet.org/files/linux-release/$DRONE_SOURCE_BRANCH/$FN"
|
||||
|
||||
- make release-static -j3
|
||||
- export WOW="wowlet-`echo $DRONE_COMMIT_AFTER | cut -c 1-10`"
|
||||
- cp build/bin/wowlet /tmp/wowlet_linux/$WOW
|
||||
volumes:
|
||||
- name: ccache_linux_release
|
||||
- name: cache
|
||||
host:
|
||||
path: /var/drone/ccache_linux_release/
|
||||
- name: files_linux_release
|
||||
path: /home/wow/wowlet_wownero
|
||||
- name: files
|
||||
host:
|
||||
path: /build/feather_files/files/linux-release/
|
||||
path: /home/wow/wowlet_linux
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: linux-release-appimage
|
||||
name: windows-deploy
|
||||
steps:
|
||||
- name: build
|
||||
image: feather:appimage
|
||||
- name: windows-deploy
|
||||
image: wowlet/wowlet-win:v0.1
|
||||
volumes:
|
||||
- name: files_linux_release
|
||||
path: /files
|
||||
- name: cache
|
||||
path: /drone/src/monero
|
||||
- name: files
|
||||
path: /tmp/wowlet_windows
|
||||
commands:
|
||||
- export FN="feather-`echo $DRONE_COMMIT_AFTER | cut -c 1-7`.zip"
|
||||
- export BRANCH="$DRONE_SOURCE_BRANCH"
|
||||
- cp /files/$BRANCH/$FN feather.zip
|
||||
- bash ./contrib/build-appimage.sh
|
||||
- name: deploy
|
||||
image: feather:appimage
|
||||
volumes:
|
||||
- name: files_linux_appimage
|
||||
path: /files
|
||||
commands:
|
||||
- export FN="feather-`git rev-parse --short HEAD`.AppImage"
|
||||
- export TARGET_DIR="/files/$DRONE_SOURCE_BRANCH"
|
||||
- mkdir -p "$TARGET_DIR"
|
||||
- echo "writing to $TARGET_DIR/$FN"
|
||||
- mv "Feather-1.0-x86_64.AppImage" "$TARGET_DIR/$FN"
|
||||
- echo "[*] written to https://build.featherwallet.org/files/linux-release-appimage/$DRONE_SOURCE_BRANCH/$FN"
|
||||
- make depends root=/depends target=x86_64-w64-mingw32 tag=win-x64 -j3
|
||||
- export WOW="wowlet-`echo $DRONE_COMMIT_AFTER | cut -c 1-10`.exe"
|
||||
- cp build/x86_64-w64-mingw32/release/bin/wowlet.exe /tmp/wowlet_windows/$WOW
|
||||
volumes:
|
||||
- name: files_linux_appimage
|
||||
host:
|
||||
path: /build/feather_files/files/linux-release-appimage/
|
||||
- name: files_linux_release
|
||||
host:
|
||||
path: /build/feather_files/files/linux-release/
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: windows-mxe-release
|
||||
steps:
|
||||
- name: build
|
||||
image: feather:win
|
||||
volumes:
|
||||
- name: ccache_win_release
|
||||
path: /root/.ccache
|
||||
- name: files_win_release
|
||||
path: /files
|
||||
commands:
|
||||
- git config --global url."http://gitea:3000/tor/".insteadOf https://git.torproject.org/
|
||||
- git config --global url."http://gitea:3000/".insteadOf https://github.com/
|
||||
- git config --global url."http://gitea:3000/".insteadOf https://git.wownero.com/
|
||||
- git submodule update --init monero
|
||||
- git submodule update --init --depth 1 --recursive monero
|
||||
- PATH="/mxe/usr/bin/:$PATH" TOR_BIN="/mxe/usr/x86_64-w64-mingw32.static/bin/tor.exe" make -j8 windows-mxe-release
|
||||
environment:
|
||||
CMAKEFLAGS_EXTRA: -DFETCH_DEPS=Off
|
||||
- name: deploy
|
||||
image: feather:win
|
||||
volumes:
|
||||
- name: ccache_win_release
|
||||
path: /root/.ccache
|
||||
- name: files_win_release
|
||||
path: /files
|
||||
commands:
|
||||
- export FN="feather-`echo $DRONE_COMMIT_AFTER | cut -c 1-7`.zip"
|
||||
- export TARGET_DIR="/files/$DRONE_SOURCE_BRANCH"
|
||||
- mkdir -p "$TARGET_DIR"
|
||||
- echo "writing to $TARGET_DIR/$FN"
|
||||
- zip -j "$TARGET_DIR/$FN" build/feather.log build/bin/feather.exe
|
||||
- echo "[*] written to https://build.featherwallet.org/files/windows-mxe-release/$DRONE_SOURCE_BRANCH/$FN"
|
||||
volumes:
|
||||
- name: ccache_win_release
|
||||
- name: cache
|
||||
host:
|
||||
path: /var/drone/ccache_win_release/
|
||||
- name: files_win_release
|
||||
path: /home/wow/wowlet_wownero
|
||||
- name: files
|
||||
host:
|
||||
path: /build/feather_files/files/windows-mxe-release/
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: mac-release
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: feather:mac
|
||||
volumes:
|
||||
- name: files_mac_release
|
||||
path: /files
|
||||
commands:
|
||||
- mkdir -p build
|
||||
- ssh administrator@steve.jobs.xmr.pm "chmod +x build_macos.sh && PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin ~/build_macos.sh $DRONE_COMMIT_SHA"
|
||||
- scp -P22 administrator@steve.jobs.xmr.pm:feather.zip build/feather.zip
|
||||
- name: deploy
|
||||
image: feather:mac
|
||||
volumes:
|
||||
- name: files_mac_release
|
||||
path: /files
|
||||
commands:
|
||||
- export FN="feather-`echo $DRONE_COMMIT_AFTER | cut -c 1-7`.zip"
|
||||
- export TARGET_DIR="/files/$DRONE_SOURCE_BRANCH"
|
||||
- mkdir -p "$TARGET_DIR"
|
||||
- echo "writing to $TARGET_DIR/$FN"
|
||||
- mv build/feather.zip "$TARGET_DIR/$FN"
|
||||
- echo "[*] written to https://build.featherwallet.org/files/mac-release/$DRONE_SOURCE_BRANCH/$FN"
|
||||
|
||||
volumes:
|
||||
- name: files_mac_release
|
||||
host:
|
||||
path: /build/feather_files/files/mac-release/
|
||||
---
|
||||
kind: signature
|
||||
hmac: f16a0379280e2e89987930d635ec6fb938d67732fdaf4ddc488f2a9db64bda2c
|
||||
|
||||
path: /home/wow/wowlet_windows
|
||||
trigger:
|
||||
branch:
|
||||
- master
|
||||
event:
|
||||
- tag
|
||||
...
|
||||
|
|
6
.gitignore
vendored
|
@ -8,8 +8,8 @@ build/*
|
|||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
cmake_install.cmake
|
||||
feather_autogen/
|
||||
feather.cbp
|
||||
wowlet_autogen/
|
||||
wowlet.cbp
|
||||
src/tor/*
|
||||
!src/tor/.gitkeep
|
||||
src/config-feather.h
|
||||
src/config-wowlet.h
|
||||
|
|
12
.gitmodules
vendored
|
@ -1,9 +1,9 @@
|
|||
[submodule "monero"]
|
||||
path = monero
|
||||
url = https://git.wownero.com/feather/monero.git
|
||||
[submodule "contrib/tor"]
|
||||
path = contrib/tor
|
||||
url = https://git.torproject.org/tor.git
|
||||
[submodule "contrib/KDMacTouchBar"]
|
||||
path = contrib/KDMacTouchBar
|
||||
url = https://github.com/KDAB/KDMacTouchBar.git
|
||||
[submodule "contrib/quirc"]
|
||||
path = contrib/quirc
|
||||
url = https://github.com/dlbeer/quirc.git
|
||||
[submodule "wownero"]
|
||||
path = wownero
|
||||
url = https://git.wownero.com/wownero/wownero.git
|
||||
|
|
106
BUILDING.md
|
@ -1,106 +0,0 @@
|
|||
# Buildbot builds
|
||||
|
||||
The docker build bins can be found here: https://build.featherwallet.org/files/
|
||||
|
||||
## Docker static builds
|
||||
|
||||
Static builds via Docker are done in 3 steps:
|
||||
|
||||
1. Cloning this repository (+submodules)
|
||||
2. Creating a base Docker image
|
||||
3. Using the base image to compile a build
|
||||
|
||||
### Linux (reproducible)
|
||||
|
||||
The docker image for reproducible Linux static builds uses Ubuntu 16.04 and compiles the required libraries statically
|
||||
so that the resulting Feather binary is static. For more information, check the Dockerfile: `Dockerfile`.
|
||||
|
||||
#### 1. Clone
|
||||
|
||||
```bash
|
||||
git clone --branch master --recursive https://git.wownero.com/feather/feather.git
|
||||
cd feather
|
||||
```
|
||||
|
||||
Replace `master` with the desired version tag (e.g. `beta-1`) to build the release binary.
|
||||
|
||||
#### 2. Base image
|
||||
|
||||
```bash
|
||||
docker build --tag feather:linux --build-arg THREADS=4 .
|
||||
```
|
||||
|
||||
Building the base image takes a while. You only need to build the base image once.
|
||||
|
||||
#### 3. Build
|
||||
|
||||
```bash
|
||||
docker run --rm -it -v $PWD:/feather --env OPENSSL_ROOT_DIR=/usr/local/openssl/ -w /feather feather:linux sh -c 'TOR_BIN="/usr/local/tor/bin/tor" make release-static -j4'
|
||||
```
|
||||
|
||||
If you're re-running a build make sure to `rm -rf build/` first.
|
||||
|
||||
The resulting binary can be found in `build/bin/feather`.
|
||||
|
||||
Hashes for tagged commits should match:
|
||||
|
||||
```
|
||||
beta-1: d1a52e3bac1abbae4adda1fc88cb2a7a06fbd61085868421897c6a4f3f4eb091 feather
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
The docker image for Windows static compiles uses Ubuntu 18.04 and installs [mxe](https://mxe.cc) from [our git](https://git.wownero.com/feather/mxe/src/branch/feather-patch),
|
||||
which comes with: OpenSSL 1.1.1g, Qt 5.15.0 (OpenGL via mesa). For more information, check the Dockerfile: `Dockerfile_windows`.
|
||||
|
||||
#### 1. Clone
|
||||
|
||||
```bash
|
||||
git clone --recursive https://git.wownero.com/feather/feather.git
|
||||
cd feather
|
||||
```
|
||||
|
||||
#### 2. Base image
|
||||
|
||||
Warning: Building the MXE base image takes up to a hour, so go watch a movie.
|
||||
|
||||
```bash
|
||||
docker build -f Dockerfile_windows --tag feather:win --build-arg THREADS=8 .
|
||||
```
|
||||
|
||||
Note: You only need to build the base image once.
|
||||
|
||||
#### 3. Build
|
||||
|
||||
```bash
|
||||
docker run --rm -it -v /tmp/ccache:/root/.ccache -v PATH_TO_FEATHER:/feather -w /feather feather:win /bin/bash -c 'PATH="/mxe/usr/bin/:$PATH" TOR_BIN="/mxe/usr/x86_64-w64-mingw32.static/bin/tor.exe" make windows-mxe-release -j8'
|
||||
```
|
||||
|
||||
Replace `PATH_TO_FEATHER` with the absolute path to Feather locally.
|
||||
|
||||
The resulting binary can be found in `build/bin/feather.exe`.
|
||||
|
||||
## macOS
|
||||
|
||||
For MacOS it's easiest to leverage [brew](https://brew.sh) to install the required dependencies.
|
||||
|
||||
```bash
|
||||
HOMEBREW_OPTFLAGS="-march=core2" HOMEBREW_OPTIMIZATION_LEVEL="O0" \
|
||||
brew install boost zmq openssl libpgm miniupnpc libsodium expat libunwind-headers protobuf libgcrypt qrencode ccache cmake pkgconfig git
|
||||
```
|
||||
|
||||
Clone the repository.
|
||||
|
||||
```bash
|
||||
git clone --recursive https://git.wownero.com/feather/feather.git
|
||||
```
|
||||
|
||||
Get the latest LTS from here: https://www.qt.io/offline-installers and install.
|
||||
|
||||
Build Feather.
|
||||
|
||||
```bash
|
||||
CMAKE_PREFIX_PATH=~/Qt5.15.1/5.15.1/clang_64 make mac-release
|
||||
```
|
||||
|
||||
The resulting Mac OS application can be found `build/bin/feather.app` and will **not** have Tor embedded.
|
198
CMakeLists.txt
|
@ -1,23 +1,21 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
project(feather)
|
||||
project(wowlet)
|
||||
|
||||
message(STATUS "Initiating compile using CMake ${CMAKE_VERSION}")
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
set(VERSION_MAJOR "0")
|
||||
set(VERSION_MAJOR "4")
|
||||
set(VERSION_MINOR "1")
|
||||
set(VERSION_REVISION "0")
|
||||
set(VERSION "beta-2")
|
||||
set(VERSION_REVISION "1")
|
||||
set(VERSION "beta-8")
|
||||
|
||||
option(FETCH_DEPS "Download dependencies if they are not found" ON)
|
||||
option(XMRTO "Include Xmr.To module" ON)
|
||||
option(MORPHTOKEN "Include MorphToken module" ON)
|
||||
option(XMRIG "Include XMRig module" ON)
|
||||
option(TOR_BIN "Path to Tor binary to embed inside Feather" OFF)
|
||||
|
||||
option(OPENVR "Include OpenVR support")
|
||||
option(ANDROID "Android deployment")
|
||||
option(ANDROID_DEBUG "View the Android app on desktop")
|
||||
option(TOR_BIN "Path to Tor binary to embed inside WOWlet")
|
||||
option(STATIC "Link libraries statically, requires static Qt")
|
||||
option(USE_DEVICE_TREZOR "Trezor support compilation" OFF)
|
||||
option(DONATE_BEG "Prompt donation window every once in a while" ON)
|
||||
option(USE_DEVICE_TREZOR "Trezor support compilation")
|
||||
list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_SOURCE_DIR}/cmake")
|
||||
include(CheckCCompilerFlag)
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
@ -27,17 +25,20 @@ include(FindCcache)
|
|||
include(CheckIncludeFile)
|
||||
include(CheckSymbolExists)
|
||||
|
||||
if(DEBUG)
|
||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
endif()
|
||||
|
||||
set(MONERO_HEAD "85b0b4f73aa6114e3ff91207aa94ad2a15c939a2")
|
||||
set(WOWNERO_HEAD "a21819cc22587e16af00e2c3d8f70156c11310a0")
|
||||
set(BUILD_GUI_DEPS ON)
|
||||
set(ARCH "x86-64")
|
||||
set(BUILD_64 ON)
|
||||
set(BUILD_64 ON CACHE BOOL "Build 64-bit binaries")
|
||||
set(INSTALL_VENDORED_LIBUNBOUND ${STATIC})
|
||||
set(USE_SINGLE_BUILDDIR ON)
|
||||
|
||||
# Are we in debug mode?
|
||||
set(_CMAKE_BUILD_TYPE "")
|
||||
string(TOUPPER "${CMAKE_BUILD_TYPE}" _CMAKE_BUILD_TYPE)
|
||||
if("${_CMAKE_BUILD_TYPE}" STREQUAL "DEBUG")
|
||||
set(DEBUG ON)
|
||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
endif()
|
||||
|
||||
check_include_file(sys/prctl.h HAVE_SYS_PRCTL_H)
|
||||
check_symbol_exists(prctl "sys/prctl.h" HAVE_PRCTL)
|
||||
|
||||
|
@ -50,7 +51,7 @@ if(STATIC)
|
|||
# manually set the unbound submodule the right commit that has the fix.
|
||||
# This only works with -DMANUAL_SUBMODULES=1
|
||||
message(STATUS "applying unbound static build fix contrib/unbound_static.patch")
|
||||
execute_process(COMMAND bash -c "git -C ${CMAKE_SOURCE_DIR}/monero/external/unbound apply ${CMAKE_SOURCE_DIR}/contrib/unbound_static.patch")
|
||||
execute_process(COMMAND bash -c "git -C ${CMAKE_SOURCE_DIR}/wownero/external/unbound apply ${CMAKE_SOURCE_DIR}/contrib/unbound_static.patch")
|
||||
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
set(Boost_USE_STATIC_RUNTIME ON)
|
||||
|
@ -83,31 +84,18 @@ function (add_linker_flag_if_supported flag var)
|
|||
endfunction()
|
||||
|
||||
find_package(Git)
|
||||
if(GIT_FOUND)
|
||||
execute_process(COMMAND git rev-parse "HEAD" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/monero OUTPUT_VARIABLE _MONERO_HEAD OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT _MONERO_HEAD STREQUAL MONERO_HEAD)
|
||||
message(FATAL_ERROR "[submodule] Monero HEAD was at ${_MONERO_HEAD} but should be at ${MONERO_HEAD}")
|
||||
else()
|
||||
message(STATUS "[submodule] Monero HEAD @ ${MONERO_HEAD}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(monero)
|
||||
set_property(TARGET wallet_merged PROPERTY FOLDER "monero")
|
||||
get_directory_property(ARCH_WIDTH DIRECTORY "monero" DEFINITION ARCH_WIDTH)
|
||||
get_directory_property(UNBOUND_LIBRARY DIRECTORY "monero" DEFINITION UNBOUND_LIBRARY)
|
||||
add_subdirectory(wownero)
|
||||
get_directory_property(ARCH_WIDTH DIRECTORY "wownero" DEFINITION ARCH_WIDTH)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(VersionMonero)
|
||||
include(VersionFeather)
|
||||
include(VersionWowlet)
|
||||
|
||||
include_directories(${EASYLOGGING_INCLUDE})
|
||||
link_directories(${EASYLOGGING_LIBRARY_DIRS})
|
||||
|
||||
# OpenSSL
|
||||
if(APPLE AND NOT OPENSSL_ROOT_DIR)
|
||||
execute_process(COMMAND brew --prefix openssl OUTPUT_VARIABLE OPENSSL_ROOT_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endif()
|
||||
find_package(OpenSSL REQUIRED)
|
||||
message(STATUS "OpenSSL: Version ${OPENSSL_VERSION}")
|
||||
message(STATUS "OpenSSL: include dir at ${OPENSSL_INCLUDE_DIR}")
|
||||
|
@ -120,46 +108,28 @@ message(STATUS "libsodium: libraries at ${SODIUM_LIBRARY}")
|
|||
# HIDApi
|
||||
set(HIDAPI_FOUND OFF)
|
||||
|
||||
# Unbound
|
||||
find_package(Unbound REQUIRED)
|
||||
|
||||
# QrEncode
|
||||
find_package(QREncode REQUIRED)
|
||||
|
||||
# Tevador 14 word Monero seed
|
||||
find_package(monero-seed CONFIG)
|
||||
if(NOT monero-seed_FOUND)
|
||||
if(FETCH_DEPS)
|
||||
FetchContent_Declare(monero-seed
|
||||
GIT_REPOSITORY https://git.wownero.com/feather/monero-seed.git)
|
||||
FetchContent_GetProperties(monero-seed)
|
||||
if(NOT monero-seed_POPULATED)
|
||||
message(STATUS "Fetching monero-seed")
|
||||
FetchContent_Populate(monero-seed)
|
||||
add_subdirectory(${monero-seed_SOURCE_DIR} ${monero-seed_BINARY_DIR})
|
||||
endif()
|
||||
add_library(monero-seed::monero-seed ALIAS monero-seed)
|
||||
else()
|
||||
message(FATAL_ERROR "monero-seed was not installed and fetching deps is disabled")
|
||||
endif()
|
||||
endif()
|
||||
# Tevador 14 word seed (https://git.wownero.com/wowlet/wownero-seed)
|
||||
find_package(wownero-seed CONFIG REQUIRED)
|
||||
|
||||
# Boost
|
||||
if(DEBUG)
|
||||
set(Boost_DEBUG ON)
|
||||
endif()
|
||||
if(APPLE AND NOT BOOST_ROOT)
|
||||
execute_process(COMMAND brew --prefix boost OUTPUT_VARIABLE BOOST_ROOT OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endif()
|
||||
find_package(Boost 1.58 REQUIRED COMPONENTS
|
||||
system
|
||||
filesystem
|
||||
thread
|
||||
date_time
|
||||
chrono
|
||||
regex
|
||||
serialization
|
||||
program_options
|
||||
locale)
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
if(MINGW)
|
||||
set(Boost_THREADAPI win32)
|
||||
endif()
|
||||
set(_BOOST_COMPONENTS system filesystem thread date_time chrono regex serialization program_options locale)
|
||||
|
||||
find_package(Boost 1.58 REQUIRED COMPONENTS ${_BOOST_COMPONENTS})
|
||||
|
||||
if(UNIX AND NOT ANDROID)
|
||||
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
# https://github.com/monero-project/monero-gui/issues/3142#issuecomment-705940446
|
||||
set(CMAKE_SKIP_RPATH ON)
|
||||
|
@ -181,29 +151,57 @@ if("$ENV{DRONE}" STREQUAL "true")
|
|||
message(STATUS "We are inside a static compile with Drone CI")
|
||||
endif()
|
||||
|
||||
# To build Feather with embedded (and static) Tor, pass CMake -DTOR_BIN=/path/to/tor
|
||||
if(UNIX)
|
||||
if(NOT CMAKE_PREFIX_PATH AND DEFINED ENV{CMAKE_PREFIX_PATH})
|
||||
message(STATUS "Using CMAKE_PREFIX_PATH environment variable: '$ENV{CMAKE_PREFIX_PATH}'")
|
||||
set(CMAKE_PREFIX_PATH $ENV{CMAKE_PREFIX_PATH})
|
||||
endif()
|
||||
if(APPLE AND NOT CMAKE_PREFIX_PATH)
|
||||
execute_process(COMMAND brew --prefix qt5 OUTPUT_VARIABLE QT5_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
list(APPEND CMAKE_PREFIX_PATH ${QT5_DIR})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(TOR_BIN)
|
||||
if(APPLE)
|
||||
execute_process(COMMAND bash -c "touch ${CMAKE_CURRENT_SOURCE_DIR}/src/tor/libevent-2.1.7.dylib")
|
||||
# To build WOWlet with embedded & static Tor, pass CMake -DTOR_BIN=/path/to/tor_executable
|
||||
# The CMake below will copy the Tor binary into src/assets/exec
|
||||
#
|
||||
# For release:
|
||||
# ## Linux / Window
|
||||
# on the buildbot(s) Tor is baked into the image
|
||||
# - linux: See `Dockerfile`
|
||||
# - windows: See `Dockerfile.windows`
|
||||
if(NOT EXISTS "${TOR_BIN}")
|
||||
message(FATAL_ERROR "TOR_BIN is set, but file does not exist: '${TOR_BIN}'")
|
||||
endif()
|
||||
|
||||
# on the buildbot Tor is baked into the image
|
||||
# - linux: See `Dockerfile`
|
||||
# - windows: https://github.com/mxe/mxe/blob/1024dc7d2db5eb7d5d3c64a2c12b5f592572f1ce/plugins/apps/tor.mk
|
||||
# - macos: taken from Tor Browser official release
|
||||
# copy the Tor executable over
|
||||
set(TOR_COPY_CMD "cp ${TOR_BIN} ${CMAKE_CURRENT_SOURCE_DIR}/src/assets/exec/tor")
|
||||
message(STATUS "${TOR_COPY_CMD}")
|
||||
message(STATUS "Tor cmd: ${TOR_COPY_CMD}")
|
||||
|
||||
execute_process(COMMAND bash -c "${TOR_COPY_CMD}" RESULT_VARIABLE ret)
|
||||
if(ret EQUAL "1")
|
||||
message(FATAL_ERROR "Tor copy failure: ${TOR_COPY_CMD}")
|
||||
endif()
|
||||
|
||||
# get Tor version while we're at it
|
||||
if(NOT TOR_VERSION)
|
||||
execute_process(COMMAND bash -c "${TOR_BIN} --version --quiet | head -n1" OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE out RESULT_VARIABLE ret)
|
||||
if (ret EQUAL "0")
|
||||
set(TOR_VERSION "${out}")
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "Tor version: ${TOR_VERSION}")
|
||||
configure_file("cmake/config-wowlet.h.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/src/config-wowlet.h")
|
||||
|
||||
message(STATUS "Embedding Tor binary at ${TOR_BIN}")
|
||||
else()
|
||||
message(STATUS "Skipping Tor inclusion because -DTOR_BIN=Off")
|
||||
endif()
|
||||
|
||||
if(MINGW)
|
||||
find_package(Iconv REQUIRED)
|
||||
|
||||
string(REGEX MATCH "^[^/]:/[^/]*" msys2_install_path "${CMAKE_C_COMPILER}")
|
||||
message(STATUS "MSYS location: ${msys2_install_path}")
|
||||
set(CMAKE_INCLUDE_PATH "${msys2_install_path}/mingw${ARCH_WIDTH}/include")
|
||||
|
@ -224,12 +222,10 @@ if(MINGW)
|
|||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wa,-mbig-obj")
|
||||
set(EXTRA_LIBRARIES mswsock;ws2_32;iphlpapi;crypt32;bcrypt)
|
||||
if(DEPENDS)
|
||||
set(ICU_LIBRARIES icuio icui18n icuuc icudata icutu iconv)
|
||||
set(ICU_LIBRARIES iconv)
|
||||
else()
|
||||
set(ICU_LIBRARIES icuio icuin icuuc icudt icutu iconv)
|
||||
endif()
|
||||
elseif(APPLE)
|
||||
set(EXTRA_LIBRARIES "-framework AppKit")
|
||||
elseif(OPENBSD)
|
||||
set(EXTRA_LIBRARIES "")
|
||||
elseif(FREEBSD)
|
||||
|
@ -239,30 +235,13 @@ elseif(DRAGONFLY)
|
|||
set(EXTRA_LIBRARIES execinfo ${COMPAT})
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES "(SunOS|Solaris)")
|
||||
set(EXTRA_LIBRARIES socket nsl resolv)
|
||||
elseif(NOT MSVC AND NOT DEPENDS)
|
||||
elseif(NOT MSVC AND NOT DEPENDS AND NOT ANDROID)
|
||||
find_library(RT rt)
|
||||
set(EXTRA_LIBRARIES ${RT})
|
||||
endif()
|
||||
|
||||
list(APPEND EXTRA_LIBRARIES ${CMAKE_DL_LIBS})
|
||||
|
||||
if(APPLE)
|
||||
include_directories(SYSTEM /usr/include/malloc)
|
||||
if(POLICY CMP0042)
|
||||
cmake_policy(SET CMP0042 NEW)
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=x86-64 -fvisibility=default -std=c++11")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=default -DGTEST_HAS_TR1_TUPLE=0")
|
||||
endif()
|
||||
|
||||
if (APPLE AND NOT IOS)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=x86-64 -fvisibility=default -std=c++11")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=default -DGTEST_HAS_TR1_TUPLE=0")
|
||||
endif()
|
||||
|
||||
# warnings
|
||||
# @TODO: enable these 2 for migration to Qt 6
|
||||
#add_c_flag_if_supported(-Werror C_SECURITY_FLAGS)
|
||||
|
@ -297,12 +276,7 @@ if (NOT (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VER
|
|||
endif()
|
||||
|
||||
# linker
|
||||
if (APPLE)
|
||||
add_linker_flag_if_supported(-Wl,-bind_at_load LD_SECURITY_FLAGS)
|
||||
add_linker_flag_if_supported(-Wl,-dead_strip LD_SECURITY_FLAGS)
|
||||
add_linker_flag_if_supported(-Wl,-dead_strip_dylibs LD_SECURITY_FLAGS)
|
||||
endif()
|
||||
if (NOT APPLE AND NOT (WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "GNU"))
|
||||
if (NOT (WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "GNU"))
|
||||
# Windows binaries die on startup with PIE when compiled with GCC
|
||||
add_linker_flag_if_supported(-pie LD_SECURITY_FLAGS)
|
||||
endif()
|
||||
|
@ -332,6 +306,11 @@ if(STATIC)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
if(LINUX_ACTIVATION)
|
||||
find_package(Cairo REQUIRED)
|
||||
find_package(Xfixes REQUIRED)
|
||||
endif()
|
||||
|
||||
# With GCC 6.1.1 the compiled binary malfunctions due to aliasing. Until that
|
||||
# is fixed in the code (Issue #847), force compiler to be conservative.
|
||||
add_c_flag_if_supported(-fno-strict-aliasing C_SECURITY_FLAGS)
|
||||
|
@ -348,8 +327,21 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 ${C_SECURITY_FLAGS}")
|
|||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ${CXX_SECURITY_FLAGS}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LD_SECURITY_FLAGS} ${STATIC_FLAGS}")
|
||||
|
||||
if(APPLE)
|
||||
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/contrib/KDMacTouchBar")
|
||||
if(OPENVR)
|
||||
# Add contrib/openvr as library
|
||||
add_definitions(-DVR_API_PUBLIC)
|
||||
add_definitions(-DOPENVR_BUILD_STATIC) # is this needed?
|
||||
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/contrib/openvr")
|
||||
endif()
|
||||
|
||||
if(WITH_SCANNER)
|
||||
add_library(quirc STATIC
|
||||
contrib/quirc/lib/decode.c
|
||||
contrib/quirc/lib/identify.c
|
||||
contrib/quirc/lib/quirc.c
|
||||
contrib/quirc/lib/version_db.c
|
||||
)
|
||||
target_include_directories(quirc PUBLIC contrib/quirc/lib)
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
||||
|
|
261
Dockerfile
|
@ -1,21 +1,125 @@
|
|||
FROM ubuntu:16.04
|
||||
FROM ubuntu:18.04 AS tor
|
||||
|
||||
ENV CFLAGS="-fPIC"
|
||||
ENV CPPFLAGS="-fPIC"
|
||||
ENV CXXFLAGS="-fPIC"
|
||||
ENV SOURCE_DATE_EPOCH=1397818193
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y build-essential wget git automake pkg-config python python3 && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN wget https://www.openssl.org/source/openssl-1.1.1i.tar.gz && \
|
||||
echo "e8be6a35fe41d10603c3cc635e93289ed00bf34b79671a3a4de64fcee00d5242 openssl-1.1.1i.tar.gz" | sha256sum -c && \
|
||||
tar -xzf openssl-1.1.1i.tar.gz && \
|
||||
rm openssl-1.1.1i.tar.gz && \
|
||||
cd openssl-1.1.1i && \
|
||||
./config no-shared no-dso --prefix=/usr/local/openssl && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install_sw && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN wget https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz && \
|
||||
echo "92e6de1be9ec176428fd2367677e61ceffc2ee1cb119035037a27d346b0403bb libevent-2.1.12-stable.tar.gz" | sha256sum -c && \
|
||||
tar -zxvf libevent-2.1.12-stable.tar.gz && \
|
||||
cd libevent-2.1.12-stable && \
|
||||
PKG_CONFIG_PATH=/usr/local/openssl/lib/pkgconfig/ \
|
||||
./configure --prefix=/usr/local/libevent \
|
||||
--disable-shared \
|
||||
--enable-static \
|
||||
--with-pic && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b v1.2.11 --depth 1 https://github.com/madler/zlib && \
|
||||
cd zlib && \
|
||||
git reset --hard cacf7f1d4e3d44d871b605da3b647f07d718623f && \
|
||||
./configure --static --prefix=/usr/local/zlib && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b tor-0.4.5.5-rc --depth 1 https://git.torproject.org/tor.git && \
|
||||
cd tor && \
|
||||
git reset --hard b36a00e9a9d3eb4b2949951afaa72e45fb7e68cd && \
|
||||
./autogen.sh && \
|
||||
./configure \
|
||||
--disable-asciidoc \
|
||||
--disable-manpage \
|
||||
--disable-html-manual \
|
||||
--disable-system-torrc \
|
||||
--disable-module-relay \
|
||||
--disable-lzma \
|
||||
--disable-zstd \
|
||||
--enable-static-tor \
|
||||
--with-libevent-dir=/usr/local/libevent \
|
||||
--with-openssl-dir=/usr/local/openssl \
|
||||
--with-zlib-dir=/usr/local/zlib \
|
||||
--disable-tool-name-check \
|
||||
--enable-fatal-warnings \
|
||||
--prefix=/usr/local/tor && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd) && \
|
||||
strip -s -D /usr/local/tor/bin/tor
|
||||
|
||||
FROM ubuntu:18.04
|
||||
|
||||
ARG THREADS=1
|
||||
ARG QT_VERSION=5.15.2
|
||||
ARG QT_VERSION=v5.15.2
|
||||
|
||||
ENV CFLAGS="-fPIC"
|
||||
ENV CPPFLAGS="-fPIC"
|
||||
ENV CXXFLAGS="-fPIC"
|
||||
ENV SOURCE_DATE_EPOCH=1397818193
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y nano vim ccache software-properties-common
|
||||
ENV OPENSSL_ROOT_DIR=/usr/local/openssl/
|
||||
ENV TOR_BIN=/usr/local/tor/bin/tor
|
||||
|
||||
RUN add-apt-repository ppa:git-core/ppa
|
||||
RUN apt-get update
|
||||
COPY --from=tor ${TOR_BIN} /usr/local/tor/bin/tor
|
||||
|
||||
RUN apt install -y automake git pkg-config python xutils-dev && \
|
||||
git clone -b xorgproto-2020.1 --depth 1 https://gitlab.freedesktop.org/xorg/proto/xorgproto && \
|
||||
RUN apt-get update && \
|
||||
apt-get install -y \
|
||||
# dev tools
|
||||
nano vim ccache \
|
||||
# build tools
|
||||
software-properties-common automake pkg-config python \
|
||||
libtool-bin wget zip \
|
||||
# dependencies
|
||||
libusb-1.0-0-dev \
|
||||
# Qt
|
||||
libgl1-mesa-dev libglib2.0-dev mesa-common-dev \
|
||||
# libusb
|
||||
libudev-dev \
|
||||
# fontconfig
|
||||
autopoint gettext gperf libpng-dev \
|
||||
# libxcb
|
||||
libpthread-stubs0-dev \
|
||||
# xorgproto
|
||||
xutils-dev \
|
||||
# libxkbcommon
|
||||
bison \
|
||||
# zeromq
|
||||
libsodium-dev \
|
||||
# AppImage tools
|
||||
file squashfs-tools desktop-file-utils patchelf
|
||||
|
||||
RUN add-apt-repository ppa:git-core/ppa && \
|
||||
apt-get update && \
|
||||
apt-get install -y git && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN mkdir appimagetool && \
|
||||
cd appimagetool && \
|
||||
wget https://github.com/AppImage/AppImageKit/releases/download/12/appimagetool-x86_64.AppImage && \
|
||||
echo "d918b4df547b388ef253f3c9e7f6529ca81a885395c31f619d9aaf7030499a13 appimagetool-x86_64.AppImage" | sha256sum -c && \
|
||||
chmod +x appimagetool-x86_64.AppImage && \
|
||||
./appimagetool-x86_64.AppImage --appimage-extract && \
|
||||
rm appimagetool-x86_64.AppImage
|
||||
|
||||
RUN git clone -b xorgproto-2020.1 --depth 1 https://gitlab.freedesktop.org/xorg/proto/xorgproto && \
|
||||
cd xorgproto && \
|
||||
git reset --hard c62e8203402cafafa5ba0357b6d1c019156c9f36 && \
|
||||
./autogen.sh && \
|
||||
|
@ -31,8 +135,7 @@ RUN git clone -b 1.12 --depth 1 https://gitlab.freedesktop.org/xorg/proto/xcbpro
|
|||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN apt install -y libtool-bin && \
|
||||
git clone -b libXau-1.0.9 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxau && \
|
||||
RUN git clone -b libXau-1.0.9 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxau && \
|
||||
cd libxau && \
|
||||
git reset --hard d9443b2c57b512cfb250b35707378654d86c7dea && \
|
||||
./autogen.sh --enable-shared --disable-static && \
|
||||
|
@ -40,8 +143,7 @@ RUN apt install -y libtool-bin && \
|
|||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN apt install -y libpthread-stubs0-dev && \
|
||||
git clone -b 1.12 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb && \
|
||||
RUN git clone -b 1.12 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb && \
|
||||
cd libxcb && \
|
||||
git reset --hard d34785a34f28fa6a00f8ce00d87e3132ff0f6467 && \
|
||||
./autogen.sh --enable-shared --disable-static && \
|
||||
|
@ -58,7 +160,7 @@ RUN git clone -b 0.4.0 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb-
|
|||
cd libxcb-util && \
|
||||
git reset --hard acf790d7752f36e450d476ad79807d4012ec863b && \
|
||||
git submodule init && \
|
||||
git clone --depth 1 https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 m4 && \
|
||||
git clone https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 m4 && \
|
||||
git -C m4 reset --hard f662e3a93ebdec3d1c9374382dcc070093a42fed && \
|
||||
./autogen.sh --enable-shared --disable-static && \
|
||||
make -j$THREADS && \
|
||||
|
@ -69,7 +171,7 @@ RUN git clone -b 0.4.0 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb-
|
|||
cd libxcb-image && \
|
||||
git reset --hard d882052fb2ce439c6483fce944ba8f16f7294639 && \
|
||||
git submodule init && \
|
||||
git clone --depth 1 https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 m4 && \
|
||||
git clone https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 m4 && \
|
||||
git -C m4 reset --hard f662e3a93ebdec3d1c9374382dcc070093a42fed && \
|
||||
./autogen.sh --enable-shared --disable-static && \
|
||||
make -j$THREADS && \
|
||||
|
@ -80,7 +182,7 @@ RUN git clone -b 0.4.0 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb-
|
|||
cd libxcb-keysyms && \
|
||||
git reset --hard 0e51ee5570a6a80bdf98770b975dfe8a57f4eeb1 && \
|
||||
git submodule init && \
|
||||
git clone --depth 1 https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 m4 && \
|
||||
git clone https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 m4 && \
|
||||
git -C m4 reset --hard f662e3a93ebdec3d1c9374382dcc070093a42fed && \
|
||||
./autogen.sh --enable-shared --disable-static && \
|
||||
make -j$THREADS && \
|
||||
|
@ -91,7 +193,7 @@ RUN git clone -b 0.3.9 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb-
|
|||
cd libxcb-render-util && \
|
||||
git reset --hard 0317caf63de532fd7a0493ed6afa871a67253747 && \
|
||||
git submodule init && \
|
||||
git clone --depth 1 https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 m4 && \
|
||||
git clone https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 m4 && \
|
||||
git -C m4 reset --hard f662e3a93ebdec3d1c9374382dcc070093a42fed && \
|
||||
./autogen.sh --enable-shared --disable-static && \
|
||||
make -j$THREADS && \
|
||||
|
@ -102,15 +204,14 @@ RUN git clone -b 0.4.1 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb-
|
|||
cd libxcb-wm && \
|
||||
git reset --hard 24eb17df2e1245885e72c9d4bbb0a0f69f0700f2 && \
|
||||
git submodule init && \
|
||||
git clone --depth 1 https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 m4 && \
|
||||
git clone https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 m4 && \
|
||||
git -C m4 reset --hard f662e3a93ebdec3d1c9374382dcc070093a42fed && \
|
||||
./autogen.sh --enable-shared --disable-static && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN apt install -y bison && \
|
||||
git clone -b xkbcommon-0.5.0 --depth 1 https://github.com/xkbcommon/libxkbcommon && \
|
||||
RUN git clone -b xkbcommon-0.5.0 --depth 1 https://github.com/xkbcommon/libxkbcommon && \
|
||||
cd libxkbcommon && \
|
||||
git reset --hard c43c3c866eb9d52cd8f61e75cbef1c30d07f3a28 && \
|
||||
./autogen.sh --prefix=/usr --enable-shared --disable-static --enable-x11 --disable-docs && \
|
||||
|
@ -121,9 +222,6 @@ RUN apt install -y bison && \
|
|||
RUN git clone -b v1.2.11 --depth 1 https://github.com/madler/zlib && \
|
||||
cd zlib && \
|
||||
git reset --hard cacf7f1d4e3d44d871b605da3b647f07d718623f && \
|
||||
./configure --static && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
./configure --static --prefix=/usr/local/zlib && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
|
@ -147,8 +245,7 @@ RUN git clone -b R_2_2_9 --depth 1 https://github.com/libexpat/libexpat && \
|
|||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN apt install -y autopoint gettext gperf libpng12-dev && \
|
||||
git clone -b 2.13.92 --depth 1 https://gitlab.freedesktop.org/fontconfig/fontconfig && \
|
||||
RUN git clone -b 2.13.92 --depth 1 https://gitlab.freedesktop.org/fontconfig/fontconfig && \
|
||||
cd fontconfig && \
|
||||
git reset --hard b1df1101a643ae16cdfa1d83b939de2497b1bf27 && \
|
||||
./autogen.sh --disable-shared --enable-static --sysconfdir=/etc --localstatedir=/var && \
|
||||
|
@ -164,8 +261,7 @@ RUN git clone -b release-64-2 --depth 1 https://github.com/unicode-org/icu && \
|
|||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN apt install -y wget && \
|
||||
wget https://dl.bintray.com/boostorg/release/1.73.0/source/boost_1_73_0.tar.gz && \
|
||||
RUN wget https://boostorg.jfrog.io/artifactory/main/release/1.73.0/source/boost_1_73_0.tar.gz && \
|
||||
echo "9995e192e68528793755692917f9eb6422f3052a53c5e13ba278a228af6c7acf boost_1_73_0.tar.gz" | sha256sum -c && \
|
||||
tar -xzf boost_1_73_0.tar.gz && \
|
||||
rm boost_1_73_0.tar.gz && \
|
||||
|
@ -179,27 +275,48 @@ RUN wget https://www.openssl.org/source/openssl-1.1.1i.tar.gz && \
|
|||
tar -xzf openssl-1.1.1i.tar.gz && \
|
||||
rm openssl-1.1.1i.tar.gz && \
|
||||
cd openssl-1.1.1i && \
|
||||
./config no-shared no-zlib-dynamic --prefix=/usr/local/openssl && \
|
||||
./config no-shared no-dso --prefix=/usr/local/openssl && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
./config no-shared no-zlib-dynamic --openssldir=/usr && \
|
||||
make -j$THREADS install_sw && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN wget https://github.com/libexpat/libexpat/releases/download/R_2_4_8/expat-2.4.8.tar.bz2 && \
|
||||
echo "a247a7f6bbb21cf2ca81ea4cbb916bfb9717ca523631675f99b3d4a5678dcd16 expat-2.4.8.tar.bz2" | sha256sum -c && \
|
||||
tar -xf expat-2.4.8.tar.bz2 && \
|
||||
rm expat-2.4.8.tar.bz2 && \
|
||||
cd expat-2.4.8 && \
|
||||
./configure --enable-static --disable-shared --prefix=/usr/local/expat/ && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN apt install -y libgl1-mesa-dev libglib2.0-dev mesa-common-dev && \
|
||||
rm /usr/lib/x86_64-linux-gnu/libX11.a && \
|
||||
RUN wget https://www.nlnetlabs.nl/downloads/unbound/unbound-1.16.2.tar.gz && \
|
||||
echo "2e32f283820c24c51ca1dd8afecfdb747c7385a137abe865c99db4b257403581 unbound-1.16.2.tar.gz" | sha256sum -c && \
|
||||
tar -xzf unbound-1.16.2.tar.gz && \
|
||||
rm unbound-1.16.2.tar.gz && \
|
||||
cd unbound-1.16.2 && \
|
||||
./configure --disable-shared --enable-static --without-pyunbound --with-libexpat=/usr/local/expat/ --with-ssl=/usr/local/openssl/ --with-libevent=no --without-pythonmodule --disable-flto --with-pthreads --with-libunbound-only --with-pic && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN rm /usr/lib/x86_64-linux-gnu/libX11.a && \
|
||||
rm /usr/lib/x86_64-linux-gnu/libXext.a && \
|
||||
rm /usr/lib/x86_64-linux-gnu/libX11-xcb.a && \
|
||||
git clone git://code.qt.io/qt/qt5.git -b ${QT_VERSION} --depth 1 && \
|
||||
cd qt5 && \
|
||||
git clone git://code.qt.io/qt/qtbase.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtdeclarative.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtgraphicaleffects.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtimageformats.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtmultimedia.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtquickcontrols.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtquickcontrols2.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtsvg.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qttools.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qttranslations.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtx11extras.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtxmlpatterns.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtwebsockets.git -b ${QT_VERSION} --depth 1 && \
|
||||
sed -ri s/\(Libs:.*\)/\\1\ -lexpat/ /usr/local/lib/pkgconfig/fontconfig.pc && \
|
||||
sed -ri s/\(Libs:.*\)/\\1\ -lz/ /usr/local/lib/pkgconfig/freetype2.pc && \
|
||||
|
@ -207,18 +324,14 @@ RUN apt install -y libgl1-mesa-dev libglib2.0-dev mesa-common-dev && \
|
|||
sed -i s/\\/usr\\/X11R6\\/lib64/\\/usr\\/local\\/lib/ qtbase/mkspecs/linux-g++-64/qmake.conf && \
|
||||
OPENSSL_LIBS="-lssl -lcrypto -lpthread -ldl" \
|
||||
./configure --prefix=/usr -platform linux-g++-64 -opensource -confirm-license -release -static -no-avx \
|
||||
-no-opengl -qpa xcb --xcb -xcb-xlib -feature-xlib -openssl-linked -I /usr/local/openssl/include \
|
||||
-L /usr/local/openssl/lib -system-freetype -fontconfig -glib \
|
||||
-no-dbus -no-sql-sqlite -no-use-gold-linker -no-kms \
|
||||
-opengl desktop -qpa xcb -xcb -xcb-xlib -feature-xlib -system-freetype -fontconfig -glib \
|
||||
-no-dbus -no-feature-qml-worker-script -no-linuxfb -no-openssl -no-sql-sqlite -no-kms -no-use-gold-linker \
|
||||
-qt-harfbuzz -qt-libjpeg -qt-libpng -qt-pcre -qt-zlib \
|
||||
-skip qt3d -skip qtandroidextras -skip qtcanvas3d -skip qtcharts -skip qtconnectivity -skip qtdatavis3d \
|
||||
-skip qtdoc -skip qtquickcontrols -skip qtquickcontrols2 -skip qtspeech -skip qtgamepad \
|
||||
-skip qtlocation -skip qtmacextras -skip qtnetworkauth -skip qtpurchasing -optimize-size \
|
||||
-skip qtdoc -skip qtgamepad -skip qtlocation -skip qtmacextras -skip qtnetworkauth -skip qtpurchasing \
|
||||
-skip qtscript -skip qtscxml -skip qtsensors -skip qtserialbus -skip qtserialport -skip qtspeech -skip qttools \
|
||||
-skip qtvirtualkeyboard -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebview \
|
||||
-skip qtwinextras -skip qtx11extras -skip gamepad -skip serialbus -skip location -skip webengine \
|
||||
-skip qtdeclarative \
|
||||
-no-feature-cups -no-feature-ftp -no-feature-pdf -no-feature-animation \
|
||||
-nomake examples -nomake tests -nomake tools && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
|
@ -229,8 +342,7 @@ RUN apt install -y libgl1-mesa-dev libglib2.0-dev mesa-common-dev && \
|
|||
cd ../../../.. && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN apt install -y libudev-dev && \
|
||||
git clone -b v1.0.23 --depth 1 https://github.com/libusb/libusb && \
|
||||
RUN git clone -b v1.0.23 --depth 1 https://github.com/libusb/libusb && \
|
||||
cd libusb && \
|
||||
git reset --hard e782eeb2514266f6738e242cdcb18e3ae1ed06fa && \
|
||||
./autogen.sh --disable-shared --enable-static && \
|
||||
|
@ -247,8 +359,7 @@ RUN git clone -b hidapi-0.9.0 --depth 1 https://github.com/libusb/hidapi && \
|
|||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN apt install -y libsodium-dev && \
|
||||
git clone -b v4.3.2 --depth 1 https://github.com/zeromq/libzmq && \
|
||||
RUN git clone -b v4.3.2 --depth 1 https://github.com/zeromq/libzmq && \
|
||||
cd libzmq && \
|
||||
git reset --hard a84ffa12b2eb3569ced199660bac5ad128bff1f0 && \
|
||||
./autogen.sh && \
|
||||
|
@ -292,9 +403,7 @@ RUN git clone -b v3.18.4 --depth 1 https://github.com/Kitware/CMake && \
|
|||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN apt install -y libusb-1.0-0-dev
|
||||
|
||||
RUN apt install -y zip && git clone -b v4.0.2 --depth 1 https://github.com/fukuchi/libqrencode.git && \
|
||||
RUN git clone -b v4.0.2 --depth 1 https://github.com/fukuchi/libqrencode.git && \
|
||||
cd libqrencode && \
|
||||
git reset --hard 59ee597f913fcfda7a010a6e106fbee2595f68e4 && \
|
||||
cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX=/usr . && \
|
||||
|
@ -302,47 +411,29 @@ RUN apt install -y zip && git clone -b v4.0.2 --depth 1 https://github.com/fukuc
|
|||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN apt install -y libmbedtls-dev && git clone -b release-2.1.12-stable --depth 1 https://github.com/libevent/libevent.git && \
|
||||
cd libevent && \
|
||||
git reset --hard 5df3037d10556bfcb675bc73e516978b75fc7bc7 && \
|
||||
mkdir build && cd build && \
|
||||
cmake -DEVENT_LIBRARY_STATIC=ON -DOPENSSL_ROOT_DIR=/usr/local/openssl -DCMAKE_INSTALL_PREFIX=/usr/local/libevent .. && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b tor-0.4.4.6 --depth 1 https://git.torproject.org/tor.git && \
|
||||
cd tor && \
|
||||
git reset --hard 2a8b789ea6f308d081f369d78fa7cfdc9d00bf90 && \
|
||||
bash autogen.sh && \
|
||||
LDFLAGS="-L/usr/local/openssl/lib/" LIBS="-lssl -lcrypto -lpthread -ldl" CPPFLAGS="-I/usr/local/openssl/include/" ./configure \
|
||||
--enable-static-zlib \
|
||||
--enable-static-openssl \
|
||||
--enable-static-libevent \
|
||||
--disable-system-torrc \
|
||||
--with-libevent-dir=/usr/local/libevent \
|
||||
--with-openssl-dir=/usr/local/openssl/ \
|
||||
--with-zlib-dir=/usr/local/zlib \
|
||||
--disable-system-torrc \
|
||||
--disable-tool-name-check \
|
||||
--disable-systemd \
|
||||
--disable-lzma \
|
||||
--disable-unittests \
|
||||
--disable-zstd \
|
||||
--disable-seccomp \
|
||||
--disable-asciidoc \
|
||||
--disable-manpage \
|
||||
--disable-html-manual \
|
||||
--disable-system-torrc \
|
||||
--prefix=/usr/local/tor && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone https://git.wownero.com/feather/monero-seed.git && \
|
||||
cd monero-seed && \
|
||||
git reset --hard 4674ef09b6faa6fe602ab5ae0b9ca8e1fd7d5e1b && \
|
||||
RUN git clone https://git.wownero.com/wowlet/wownero-seed.git && \
|
||||
cd wownero-seed && \
|
||||
git reset --hard ef6910b6bb3b61757c36e2e5db0927d75f1731c8 && \
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -Bbuild && \
|
||||
make -Cbuild -j$THREADS && \
|
||||
make -Cbuild install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone https://github.com/plougher/squashfs-tools.git && \
|
||||
cd squashfs-tools/squashfs-tools && \
|
||||
git reset --hard 38fa0720526222827da44b3b6c3f7eb63e8f5c2f && \
|
||||
make && \
|
||||
make install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN mkdir linuxdeployqt && \
|
||||
cd linuxdeployqt && \
|
||||
wget https://github.com/probonopd/linuxdeployqt/releases/download/7/linuxdeployqt-7-x86_64.AppImage && \
|
||||
echo "645276306a801d7154d59e5b4b3c2fac3d34e09be57ec31f6d9a09814c6c162a linuxdeployqt-7-x86_64.AppImage" | sha256sum -c && \
|
||||
chmod +x linuxdeployqt-7-x86_64.AppImage && \
|
||||
./linuxdeployqt-7-x86_64.AppImage --appimage-extract && \
|
||||
rm linuxdeployqt-7-x86_64.AppImage
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get -o Dpkg::Options::="--force-confold" install -q -y --force-yes libcairo2-dev libxinerama-dev
|
||||
RUN git config --global --add safe.directory /wowlet
|
244
Dockerfile.android
Normal file
|
@ -0,0 +1,244 @@
|
|||
FROM debian:stretch
|
||||
|
||||
ARG THREADS=1
|
||||
ARG ANDROID_NDK_REVISION=21d
|
||||
ARG ANDROID_NDK_HASH=bcf4023eb8cb6976a4c7cff0a8a8f145f162bf4d
|
||||
ARG ANDROID_SDK_REVISION=4333796
|
||||
ARG ANDROID_SDK_HASH=92ffee5a1d98d856634e8b71132e8a95d96c83a63fde1099be3d86df3106def9
|
||||
ARG QT_VERSION=5.15.2
|
||||
|
||||
WORKDIR /opt/android
|
||||
ENV WORKDIR=/opt/android
|
||||
|
||||
ENV ANDROID_NATIVE_API_LEVEL=28
|
||||
ENV ANDROID_API=android-${ANDROID_NATIVE_API_LEVEL}
|
||||
ENV ANDROID_CLANG=aarch64-linux-android${ANDROID_NATIVE_API_LEVEL}-clang
|
||||
ENV ANDROID_CLANGPP=aarch64-linux-android${ANDROID_NATIVE_API_LEVEL}-clang++
|
||||
ENV ANDROID_NDK_ROOT=${WORKDIR}/android-ndk-r${ANDROID_NDK_REVISION}
|
||||
ENV ANDROID_SDK_ROOT=${WORKDIR}/tools
|
||||
ENV JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
|
||||
ENV PATH=${JAVA_HOME}/bin:${PATH}
|
||||
ENV PREFIX=${WORKDIR}/prefix
|
||||
ENV TOOLCHAIN_DIR=${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y ant automake build-essential ca-certificates-java file gettext git libc6 libncurses5 \
|
||||
libssl-dev libstdc++6 libtinfo5 libtool libz1 openjdk-8-jdk-headless openjdk-8-jre-headless pkg-config python3 \
|
||||
unzip wget
|
||||
|
||||
RUN wget -q https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_REVISION}.zip \
|
||||
&& unzip -q sdk-tools-linux-${ANDROID_SDK_REVISION}.zip \
|
||||
&& rm -f sdk-tools-linux-${ANDROID_SDK_REVISION}.zip
|
||||
|
||||
RUN wget -q https://dl.google.com/android/repository/android-ndk-r${ANDROID_NDK_REVISION}-linux-x86_64.zip \
|
||||
&& unzip -q android-ndk-r${ANDROID_NDK_REVISION}-linux-x86_64.zip \
|
||||
&& rm -f android-ndk-r${ANDROID_NDK_REVISION}-linux-x86_64.zip
|
||||
|
||||
RUN cd ${ANDROID_SDK_ROOT} && echo y | ./bin/sdkmanager "platform-tools" "platforms;${ANDROID_API}" "tools" > /dev/null
|
||||
RUN cp -r ${WORKDIR}/platforms ${WORKDIR}/platform-tools ${ANDROID_SDK_ROOT}
|
||||
|
||||
ENV HOST_PATH=${PATH}
|
||||
ENV PATH=${TOOLCHAIN_DIR}/aarch64-linux-android/bin:${TOOLCHAIN_DIR}/bin:${PATH}
|
||||
|
||||
ARG ZLIB_VERSION=1.2.11
|
||||
ARG ZLIB_HASH=c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1
|
||||
RUN wget -q https://zlib.net/zlib-${ZLIB_VERSION}.tar.gz \
|
||||
&& tar -xzf zlib-${ZLIB_VERSION}.tar.gz \
|
||||
&& rm zlib-${ZLIB_VERSION}.tar.gz \
|
||||
&& cd zlib-${ZLIB_VERSION} \
|
||||
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --prefix=${PREFIX} --static \
|
||||
&& make -j${THREADS} \
|
||||
&& make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
RUN git clone git://code.qt.io/qt/qt5.git -b ${QT_VERSION} --depth 1 \
|
||||
&& cd qt5 \
|
||||
&& perl init-repository --module-subset=default,-qtwebengine \
|
||||
&& PATH=${HOST_PATH} ./configure -v -developer-build -release \
|
||||
-xplatform android-clang \
|
||||
-android-ndk-platform ${ANDROID_API} \
|
||||
-android-ndk ${ANDROID_NDK_ROOT} \
|
||||
-android-sdk ${ANDROID_SDK_ROOT} \
|
||||
-android-ndk-host linux-x86_64 \
|
||||
-no-dbus \
|
||||
-opengl es2 \
|
||||
-no-use-gold-linker \
|
||||
-no-sql-mysql \
|
||||
-opensource -confirm-license \
|
||||
-android-arch arm64-v8a \
|
||||
-prefix ${PREFIX} \
|
||||
-nomake tools -nomake tests -nomake examples \
|
||||
-skip qtwebengine \
|
||||
-skip qtserialport \
|
||||
-skip qtconnectivity \
|
||||
-skip qttranslations \
|
||||
-skip qtpurchasing \
|
||||
-skip qtgamepad -skip qtscript -skip qtdoc \
|
||||
-no-warnings-are-errors \
|
||||
&& sed -i '213,215d' qtbase/src/3rdparty/pcre2/src/sljit/sljitConfigInternal.h \
|
||||
&& PATH=${HOST_PATH} make -j${THREADS} \
|
||||
&& PATH=${HOST_PATH} make -j${THREADS} install \
|
||||
&& cd qttools/src/linguist/lrelease \
|
||||
&& ../../../../qtbase/bin/qmake \
|
||||
&& PATH=${HOST_PATH} make -j${THREADS} install \
|
||||
&& cd ../../../.. \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
ARG ICONV_VERSION=1.16
|
||||
ARG ICONV_HASH=e6a1b1b589654277ee790cce3734f07876ac4ccfaecbee8afa0b649cf529cc04
|
||||
RUN wget -q http://ftp.gnu.org/pub/gnu/libiconv/libiconv-${ICONV_VERSION}.tar.gz \
|
||||
&& echo "${ICONV_HASH} libiconv-${ICONV_VERSION}.tar.gz" | sha256sum -c \
|
||||
&& tar -xzf libiconv-${ICONV_VERSION}.tar.gz \
|
||||
&& rm -f libiconv-${ICONV_VERSION}.tar.gz \
|
||||
&& cd libiconv-${ICONV_VERSION} \
|
||||
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --build=x86_64-linux-gnu --host=aarch64 --prefix=${PREFIX} --disable-rpath \
|
||||
&& make -j${THREADS} \
|
||||
&& make -j${THREADS} install
|
||||
|
||||
ARG BOOST_VERSION=1_74_0
|
||||
ARG BOOST_VERSION_DOT=1.74.0
|
||||
ARG BOOST_HASH=83bfc1507731a0906e387fc28b7ef5417d591429e51e788417fe9ff025e116b1
|
||||
RUN wget -q https://dl.bintray.com/boostorg/release/${BOOST_VERSION_DOT}/source/boost_${BOOST_VERSION}.tar.bz2 \
|
||||
&& echo "${BOOST_HASH} boost_${BOOST_VERSION}.tar.bz2" | sha256sum -c \
|
||||
&& tar -xf boost_${BOOST_VERSION}.tar.bz2 \
|
||||
&& rm -f boost_${BOOST_VERSION}.tar.bz2 \
|
||||
&& cd boost_${BOOST_VERSION} \
|
||||
&& PATH=${HOST_PATH} ./bootstrap.sh --prefix=${PREFIX} \
|
||||
&& PATH=${TOOLCHAIN_DIR}/bin:${HOST_PATH} ./b2 --build-type=minimal link=static runtime-link=static \
|
||||
--with-chrono --with-date_time --with-filesystem --with-program_options --with-regex --with-serialization \
|
||||
--with-system --with-thread --with-locale --build-dir=android --stagedir=android toolset=clang threading=multi \
|
||||
threadapi=pthread target-os=android -sICONV_PATH=${PREFIX} \
|
||||
cflags='--target=aarch64-linux-android' \
|
||||
cxxflags='--target=aarch64-linux-android' \
|
||||
linkflags='--target=aarch64-linux-android --sysroot=${ANDROID_NDK_ROOT}/platforms/${ANDROID_API}/arch-arm64 ${ANDROID_NDK_ROOT}/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so -nostdlib++' \
|
||||
install -j${THREADS} \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
ARG OPENSSL_VERSION=1.1.1g
|
||||
ARG OPENSSL_HASH=ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46
|
||||
RUN wget -q https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz \
|
||||
&& tar -xzf openssl-${OPENSSL_VERSION}.tar.gz \
|
||||
&& rm openssl-${OPENSSL_VERSION}.tar.gz \
|
||||
&& cd openssl-${OPENSSL_VERSION} \
|
||||
&& ANDROID_NDK_HOME=${ANDROID_NDK_ROOT} ./Configure CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} \
|
||||
android-arm64 no-asm no-shared --static \
|
||||
--with-zlib-include=${PREFIX}/include --with-zlib-lib=${PREFIX}/lib \
|
||||
--prefix=${PREFIX} --openssldir=${PREFIX} \
|
||||
&& sed -i 's/CNF_EX_LIBS=-ldl -pthread//g;s/BIN_CFLAGS=-pie $(CNF_CFLAGS) $(CFLAGS)//g' Makefile \
|
||||
&& ANDROID_NDK_HOME=${ANDROID_NDK_ROOT} make -j${THREADS} \
|
||||
&& make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
ARG ZMQ_VERSION=v4.3.3
|
||||
ARG ZMQ_HASH=04f5bbedee58c538934374dc45182d8fc5926fa3
|
||||
RUN git clone https://github.com/zeromq/libzmq.git -b ${ZMQ_VERSION} --depth 1 \
|
||||
&& cd libzmq \
|
||||
&& git checkout ${ZMQ_HASH} \
|
||||
&& ./autogen.sh \
|
||||
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --prefix=${PREFIX} --host=aarch64-linux-android \
|
||||
--enable-static --disable-shared \
|
||||
&& make -j${THREADS} \
|
||||
&& make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
ARG SODIUM_VERSION=1.0.18
|
||||
ARG SODIUM_HASH=4f5e89fa84ce1d178a6765b8b46f2b6f91216677
|
||||
RUN set -ex \
|
||||
&& git clone https://github.com/jedisct1/libsodium.git -b ${SODIUM_VERSION} --depth 1 \
|
||||
&& cd libsodium \
|
||||
&& test `git rev-parse HEAD` = ${SODIUM_HASH} || exit 1 \
|
||||
&& ./autogen.sh \
|
||||
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --prefix=${PREFIX} --host=aarch64-linux-android --enable-static --disable-shared \
|
||||
&& make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b libgpg-error-1.38 --depth 1 git://git.gnupg.org/libgpg-error.git \
|
||||
&& cd libgpg-error \
|
||||
&& git reset --hard 71d278824c5fe61865f7927a2ed1aa3115f9e439 \
|
||||
&& ./autogen.sh \
|
||||
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --host=aarch64-linux-android --prefix=${PREFIX} --disable-rpath --disable-shared --enable-static --disable-doc --disable-tests \
|
||||
&& PATH=${TOOLCHAIN_DIR}/bin:${HOST_PATH} make -j${THREADS} \
|
||||
&& make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b libgcrypt-1.8.5 --depth 1 git://git.gnupg.org/libgcrypt.git \
|
||||
&& cd libgcrypt \
|
||||
&& git reset --hard 56606331bc2a80536db9fc11ad53695126007298 \
|
||||
&& ./autogen.sh \
|
||||
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --host=aarch64-linux-android --prefix=${PREFIX} --with-gpg-error-prefix=${PREFIX} --disable-shared --enable-static --disable-doc --disable-tests \
|
||||
&& PATH=${TOOLCHAIN_DIR}/bin:${HOST_PATH} make -j${THREADS} \
|
||||
&& make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
RUN cd tools \
|
||||
&& wget -q http://dl-ssl.google.com/android/repository/tools_r25.2.5-linux.zip \
|
||||
&& unzip -q tools_r25.2.5-linux.zip \
|
||||
&& rm -f tools_r25.2.5-linux.zip \
|
||||
&& echo y | ${ANDROID_SDK_ROOT}/tools/android update sdk --no-ui --all --filter build-tools-28.0.3
|
||||
|
||||
RUN git clone -b v3.19.7 --depth 1 https://github.com/Kitware/CMake \
|
||||
&& cd CMake \
|
||||
&& git reset --hard 22612dd53a46c7f9b4c3f4b7dbe5c78f9afd9581 \
|
||||
&& PATH=${HOST_PATH} ./bootstrap \
|
||||
&& PATH=${HOST_PATH} make -j${THREADS} \
|
||||
&& PATH=${HOST_PATH} make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b v1.6.35 --depth 1 https://github.com/glennrp/libpng.git && \
|
||||
cd libpng && \
|
||||
git reset --hard c17d164b4467f099b4484dfd4a279da0bc1dbd4a \
|
||||
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --with-zlib-prefix="${PREFIX}" --host=aarch64-linux-android --prefix=${PREFIX} --disable-shared --enable-static \
|
||||
&& PATH=${TOOLCHAIN_DIR}/bin:${HOST_PATH} make -j${THREADS} \
|
||||
&& make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
# @TODO: don't hardcode ANDROID_PLATFORM
|
||||
RUN git clone -b v4.0.2 --depth 1 https://github.com/fukuchi/libqrencode.git && \
|
||||
cd libqrencode && \
|
||||
git reset --hard 59ee597f913fcfda7a010a6e106fbee2595f68e4 && \
|
||||
CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} cmake \
|
||||
-DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake" \
|
||||
-DANDROID_PLATFORM="28" \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DARCH="armv8-a" \
|
||||
-DANDROID_ABI="arm64-v8a" \
|
||||
-DANDROID_TOOLCHAIN=clang \
|
||||
-DCMAKE_PREFIX_PATH="${PREFIX}" \
|
||||
-DPNG_PNG_INCLUDE_DIR="${PREFIX}/include/libpng16/" \
|
||||
-DPNG_LIBRARY="${PREFIX}/lib/libqtlibpng_arm64-v8a.a" \
|
||||
-DICONV_LIBRARY=/opt/android/prefix/lib/libiconv.a \
|
||||
-DICONV_INCLUDE_DIR=/opt/android/prefix/include/ \
|
||||
-DCMAKE_INSTALL_PREFIX="${PREFIX}" && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN ls -al && uname -a
|
||||
|
||||
# @TODO: switch to Release
|
||||
CMD set -ex \
|
||||
&& cd /wowlet \
|
||||
&& mkdir -p build/Android/release \
|
||||
&& cd build/Android/release \
|
||||
&& E=1 cmake \
|
||||
-DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake" \
|
||||
-DCMAKE_PREFIX_PATH="${PREFIX}" \
|
||||
-DCMAKE_FIND_ROOT_PATH="${PREFIX}" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DARCH="armv8-a" \
|
||||
-DANDROID_NATIVE_API_LEVEL=${ANDROID_NATIVE_API_LEVEL} \
|
||||
-DANDROID_ABI="arm64-v8a" \
|
||||
-DANDROID_TOOLCHAIN=clang \
|
||||
-DBoost_USE_STATIC_RUNTIME=ON \
|
||||
-DLRELEASE_PATH="${PREFIX}/bin" \
|
||||
-DQT_ANDROID_APPLICATION_BINARY="wowlet" \
|
||||
-DWITH_SCANNER=ON \
|
||||
-DUSE_DEVICE_TREZOR=OFF \
|
||||
-DUSE_SINGLE_BUILDDIR=ON \
|
||||
-DMANUAL_SUBMODULES=1 \
|
||||
-DUSE_SINGLE_BUILDDIR=ON \
|
||||
-DANDROID=ON \
|
||||
../../.. \
|
||||
&& PATH=${HOST_PATH} make generate_translations_header \
|
||||
&& make -j${THREADS} -C src \
|
||||
&& make -j${THREADS} apk
|
189
Dockerfile.windows
Normal file
|
@ -0,0 +1,189 @@
|
|||
FROM ubuntu:20.04
|
||||
|
||||
ARG THREADS=1
|
||||
ARG QT_VERSION=v5.15.2
|
||||
ENV SOURCE_DATE_EPOCH=1397818193
|
||||
|
||||
ENV OPENSSL_ROOT_DIR=/usr/local/openssl/
|
||||
ENV TOR_BIN=/usr/local/tor/bin/tor.exe
|
||||
ENV TOR_VERSION='tor-0.4.5.7'
|
||||
|
||||
RUN apt update && \
|
||||
DEBIAN_FRONTEND=noninteractive apt install -y curl nano wget zip automake build-essential cmake gcc-mingw-w64 g++-mingw-w64 gettext git libtool pkg-config \
|
||||
python && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN update-alternatives --set x86_64-w64-mingw32-g++ $(which x86_64-w64-mingw32-g++-posix) && \
|
||||
update-alternatives --set x86_64-w64-mingw32-gcc $(which x86_64-w64-mingw32-gcc-posix)
|
||||
|
||||
RUN git clone -b v0.18.2.0 --depth 1 https://github.com/monero-project/monero && \
|
||||
cd monero && \
|
||||
git reset --hard 99be9a044f3854f339548e2d99c539c18d7b1b01 && \
|
||||
cp -a contrib/depends / && \
|
||||
cd .. && \
|
||||
rm -rf monero
|
||||
|
||||
RUN make -j$THREADS -C /depends HOST=x86_64-w64-mingw32 NO_QT=1
|
||||
|
||||
RUN git clone git://code.qt.io/qt/qt5.git -b ${QT_VERSION} --depth 1 && \
|
||||
cd qt5 && \
|
||||
git clone git://code.qt.io/qt/qtbase.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtdeclarative.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtgraphicaleffects.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtimageformats.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtmultimedia.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtquickcontrols.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtquickcontrols2.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtsvg.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qttools.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qttranslations.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtxmlpatterns.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtwebsockets.git -b ${QT_VERSION} --depth 1 && \
|
||||
OPENSSL_LIBS="-lssl -lcrypto -lpthread -ldl" \
|
||||
./configure --prefix=/depends/x86_64-w64-mingw32 -xplatform win32-g++ \
|
||||
-device-option CROSS_COMPILE=/usr/bin/x86_64-w64-mingw32- \
|
||||
-I $(pwd)/qtbase/src/3rdparty/angle/include \
|
||||
-opensource -confirm-license -release -static -static-runtime -opengl dynamic -no-angle \
|
||||
-no-feature-qml-worker-script -no-avx -openssl -I /depends/x86_64-w64-mingw32/include -L /depends/x86_64-w64-mingw32/lib \
|
||||
-qt-freetype -qt-harfbuzz -qt-libjpeg -qt-libpng -qt-pcre -qt-zlib \
|
||||
-skip gamepad -skip location -skip qt3d -skip qtactiveqt -skip qtandroidextras \
|
||||
-skip qtcanvas3d -skip qtcharts -skip qtconnectivity -skip qtdatavis3d -skip qtdoc \
|
||||
-skip qtgamepad -skip qtlocation -skip qtmacextras -skip qtnetworkauth -skip qtpurchasing \
|
||||
-skip qtscript -skip qtscxml -skip qtsensors -skip qtserialbus -skip qtserialport \
|
||||
-skip qtspeech -skip qttools -skip qtvirtualkeyboard -skip qtwayland -skip qtwebchannel \
|
||||
-skip qtwebengine -skip qtwebview -skip qtwinextras -skip qtx11extras \
|
||||
-skip serialbus -skip webengine \
|
||||
-nomake examples -nomake tests -nomake tools && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
cd qttools/src/linguist/lrelease && \
|
||||
../../../../qtbase/bin/qmake && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
cd ../../../.. && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b libgpg-error-1.38 --depth 1 git://git.gnupg.org/libgpg-error.git && \
|
||||
cd libgpg-error && \
|
||||
git reset --hard 71d278824c5fe61865f7927a2ed1aa3115f9e439 && \
|
||||
./autogen.sh && \
|
||||
./configure --disable-shared --enable-static --disable-doc --disable-tests \
|
||||
--host=x86_64-w64-mingw32 --prefix=/depends/x86_64-w64-mingw32 && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
cd .. && \
|
||||
rm -rf libgpg-error
|
||||
|
||||
RUN git clone -b libgcrypt-1.8.5 --depth 1 git://git.gnupg.org/libgcrypt.git && \
|
||||
cd libgcrypt && \
|
||||
git reset --hard 56606331bc2a80536db9fc11ad53695126007298 && \
|
||||
./autogen.sh && \
|
||||
./configure --disable-shared --enable-static --disable-doc \
|
||||
--host=x86_64-w64-mingw32 --prefix=/depends/x86_64-w64-mingw32 \
|
||||
--with-gpg-error-prefix=/depends/x86_64-w64-mingw32 && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
cd .. && \
|
||||
rm -rf libgcrypt
|
||||
|
||||
# zlib -> libpng, Tor
|
||||
RUN git clone -b v1.2.11 --depth 1 https://github.com/madler/zlib && \
|
||||
cd zlib && \
|
||||
git reset --hard cacf7f1d4e3d44d871b605da3b647f07d718623f && \
|
||||
CC=x86_64-w64-mingw32-gcc AR=x86_64-w64-mingw32-ar ./configure --static --prefix=/usr/x86_64-w64-mingw32 && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
# libpng -> libqrencode
|
||||
RUN git clone -b libpng16 https://github.com/glennrp/libpng.git && \
|
||||
cd libpng && \
|
||||
git reset --hard a37d4836519517bdce6cb9d956092321eca3e73b && \
|
||||
CPPFLAGS="-I/depends/x86_64-w64-mingw32/include" LDFLAGS="-L/depends/x86_64-w64-mingw32/lib" \
|
||||
./configure --host=x86_64-w64-mingw32 --prefix=/depends/x86_64-w64-mingw32 && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b v4.0.2 --depth 1 https://github.com/fukuchi/libqrencode.git && \
|
||||
cd libqrencode && \
|
||||
git reset --hard 59ee597f913fcfda7a010a6e106fbee2595f68e4 && \
|
||||
./autogen.sh && \
|
||||
CPPFLAGS="-I/depends/x86_64-w64-mingw32/include" LDFLAGS="-L/depends/x86_64-w64-mingw32/lib" \
|
||||
./configure --disable-shared --enable-static --host=x86_64-w64-mingw32 --prefix=/depends/x86_64-w64-mingw32 && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN wget https://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.16.tar.gz && \
|
||||
echo "e6a1b1b589654277ee790cce3734f07876ac4ccfaecbee8afa0b649cf529cc04 libiconv-1.16.tar.gz" | sha256sum -c && \
|
||||
tar -xzf libiconv-1.16.tar.gz && \
|
||||
rm libiconv-1.16.tar.gz && \
|
||||
cd libiconv-1.16 && \
|
||||
./configure --enable-static --host=x86_64-w64-mingw32 --prefix=/usr/x86_64-w64-mingw32 && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
# OpenSSL -> Tor
|
||||
RUN wget https://www.openssl.org/source/openssl-1.1.1k.tar.gz && \
|
||||
echo "892a0875b9872acd04a9fde79b1f943075d5ea162415de3047c327df33fbaee5 openssl-1.1.1k.tar.gz" | sha256sum -c && \
|
||||
tar -xzf openssl-1.1.1k.tar.gz && \
|
||||
rm openssl-1.1.1k.tar.gz && \
|
||||
cd openssl-1.1.1k && \
|
||||
./Configure mingw64 no-shared no-dso --cross-compile-prefix=x86_64-w64-mingw32- --prefix=/usr/local/openssl && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install_sw && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
# libevent -> Tor
|
||||
RUN wget https://github.com/libevent/libevent/releases/download/release-2.1.11-stable/libevent-2.1.11-stable.tar.gz && \
|
||||
echo "a65bac6202ea8c5609fd5c7e480e6d25de467ea1917c08290c521752f147283d libevent-2.1.11-stable.tar.gz" | sha256sum -c && \
|
||||
tar -zxvf libevent-2.1.11-stable.tar.gz && \
|
||||
cd libevent-2.1.11-stable && \
|
||||
./configure --prefix=/usr/local/libevent \
|
||||
--disable-shared \
|
||||
--enable-static \
|
||||
--with-pic \
|
||||
--host=x86_64-w64-mingw32 && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b tor-0.4.5.7 --depth 1 https://git.torproject.org/tor.git && \
|
||||
cd tor && \
|
||||
git reset --hard 83f895c015de55201e5f226f84a866f30f5ee14b && \
|
||||
./autogen.sh && \
|
||||
./configure --host=x86_64-w64-mingw32 \
|
||||
--disable-asciidoc \
|
||||
--disable-zstd \
|
||||
--disable-lzma \
|
||||
--disable-manpage \
|
||||
--disable-html-manual \
|
||||
--disable-system-torrc \
|
||||
--disable-module-relay \
|
||||
--enable-static-tor \
|
||||
--with-libevent-dir=/usr/local/libevent \
|
||||
--with-openssl-dir=/usr/local/openssl \
|
||||
--with-zlib-dir=/usr/x86_64-w64-mingw32 \
|
||||
--disable-tool-name-check \
|
||||
--enable-fatal-warnings \
|
||||
--prefix=/usr/local/tor \
|
||||
LIBS=-lcrypt32 && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd) && \
|
||||
strip -s -D /usr/local/tor/bin/tor.exe
|
||||
|
||||
RUN git clone https://git.wownero.com/wowlet/wownero-seed.git && \
|
||||
cd wownero-seed && \
|
||||
git reset --hard ef6910b6bb3b61757c36e2e5db0927d75f1731c8 && \
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/depends/x86_64-w64-mingw32 \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_TOOLCHAIN_FILE=/depends/x86_64-w64-mingw32/share/toolchain.cmake -Bbuild && \
|
||||
make -Cbuild -j$THREADS && \
|
||||
make -Cbuild install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git config --global --add safe.directory /wowlet
|
||||
RUN git config --global --add safe.directory /wowlet/wownero
|
|
@ -48,7 +48,7 @@ RUN apt install -y \
|
|||
wget \
|
||||
xz-utils
|
||||
|
||||
RUN git clone -b feather-patch --depth 1 https://git.wownero.com/feather/mxe.git && \
|
||||
RUN git clone -b wowlet-patch --depth 1 https://git.wownero.com/wowlet/mxe.git && \
|
||||
cd mxe && \
|
||||
make -j$THREADS MXE_TARGETS='x86_64-w64-mingw32.static' gcc libqrencode pkgconf libgpg_error libgcrypt cmake libsodium lzma readline libzmq boost qtbase qtsvg qtwebsockets qtimageformats qtmultimedia
|
||||
|
||||
|
@ -67,7 +67,7 @@ RUN ln -s /mxe/usr/x86_64-w64-mingw32.static/lib/libsicuin.a /mxe/usr/x86_64-w64
|
|||
|
||||
ENV PATH="/mxe/usr/bin/:$PATH"
|
||||
|
||||
RUN git clone https://git.wownero.com/feather/monero-seed.git && \
|
||||
RUN git clone https://git.wownero.com/wowlet/monero-seed.git && \
|
||||
cd monero-seed && \
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -Bbuild && \
|
||||
make -Cbuild -j$THREADS && \
|
|
@ -1,18 +0,0 @@
|
|||
FROM ubuntu:20.04
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt clean && apt update
|
||||
RUN apt install -y golang git build-essential wget curl ngrep unzip file squashfs-tools desktop-file-utils patchelf libxkbcommon-x11-dev libx11-xcb-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render0 libxcb-render-util0 libxcb-shape0 libxcb-sync1 libxcb-xfixes0 libxcb-shm0 libxcb-keysyms1 libxcb-xkb1
|
||||
|
||||
RUN go get github.com/probonopd/go-appimage/src/appimagetool
|
||||
RUN go build -trimpath -ldflags="-s -w" github.com/probonopd/go-appimage/src/appimagetool
|
||||
RUN chmod +x appimagetool
|
||||
|
||||
RUN cd /usr/bin && \
|
||||
wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh -O uploadtool && \
|
||||
chmod +x uploadtool
|
||||
|
||||
RUN cd / && \
|
||||
wget -c https://github.com/AppImage/AppImageKit/releases/download/continuous/runtime-x86_64 && \
|
||||
chmod +x runtime-x86_64
|
|
@ -1,13 +0,0 @@
|
|||
# this image is used internally for the buildbot
|
||||
FROM ubuntu:20.04
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt clean && apt update
|
||||
RUN apt install -y git build-essential wget curl ngrep unzip file ssh zip
|
||||
|
||||
RUN cat /dev/zero | ssh-keygen -q -N ""
|
||||
|
||||
RUN cat ~/.ssh/id_rsa.pub
|
||||
|
||||
RUN printf "Host *\n StrictHostKeyChecking no" > ~/.ssh/config
|
106
HACKING.md
|
@ -1,106 +0,0 @@
|
|||
# Documentation for developers
|
||||
|
||||
Feather is developed primarily on Linux. It uses Qt 5.15.* and chances are that your
|
||||
distro's package manager has a lower version. It is therefore recommended that you install
|
||||
Qt manually using the online installer, which can be found here: https://www.qt.io/download
|
||||
(under open-source).
|
||||
|
||||
## Jetbrains Clion
|
||||
|
||||
Feather was developed using JetBrains Clion since it integrates nicely
|
||||
with CMake and comes with a built-in debugger. To pass CMake flags to CLion,
|
||||
go to `File->Settings->Build->CMake`, set Build Type to `Debug` and set your
|
||||
preferred CMake options/definitions.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Ubuntu/Debian
|
||||
|
||||
```bash
|
||||
apt install -y git cmake libqrencode-dev build-essential cmake libboost-all-dev \
|
||||
miniupnpc libunbound-dev graphviz doxygen libunwind8-dev pkg-config libssl-dev \
|
||||
libzmq3-dev libsodium-dev libhidapi-dev libnorm-dev libusb-1.0-0-dev libpgm-dev \
|
||||
libprotobuf-dev protobuf-compiler libgcrypt20-dev
|
||||
```
|
||||
|
||||
## Mac OS
|
||||
|
||||
```bash
|
||||
brew install boost zmq openssl libpgm miniupnpc libsodium expat libunwind-headers \
|
||||
protobuf libgcrypt qrencode ccache cmake pkgconfig git
|
||||
```
|
||||
|
||||
## CMake
|
||||
|
||||
After installing Qt you might have a folder called `/home/$user/Qt/`. You need to pass this to CMake
|
||||
via the `CMAKE_PREFIX_PATH` definition. For me this is:
|
||||
|
||||
```
|
||||
-DCMAKE_PREFIX_PATH=/home/dsc/QtNew/5.15.0/gcc_64
|
||||
```
|
||||
|
||||
There are some Monero/Feather related options/definitions that you may pass:
|
||||
|
||||
- `-DXMRTO=OFF` - disable Xmr.To feature
|
||||
- `-DMORPHTOKEN=OFF` - disable MorphToken feature
|
||||
- `-DXMRIG=OFF` - disable XMRig feature
|
||||
- `-DTOR_BIN=/path/to/tor` - Embed a Tor executable inside Feather
|
||||
- `-DDONATE_BEG=OFF` - disable the dreaded donate requests
|
||||
|
||||
And:
|
||||
|
||||
```
|
||||
-DMANUAL_SUBMODULES=1
|
||||
-DUSE_DEVICE_TREZOR=OFF
|
||||
-DUSE_SINGLE_BUILDDIR=ON
|
||||
-DDEV_MODE=ON
|
||||
```
|
||||
|
||||
If you have OpenSSL installed in a custom location, try:
|
||||
|
||||
```
|
||||
-DOPENSSL_INCLUDE_DIR=/usr/local/lib/openssl-1.1.1g/include
|
||||
-DOPENSSL_SSL_LIBRARY=/usr/local/lib/openssl-1.1.1g/libssl.so.1.1
|
||||
-DOPENSSL_CRYPTO_LIBRARY=/usr/local/lib/openssl-1.1.1g/libcrypto.so.1.1
|
||||
```
|
||||
|
||||
I prefer also enabling verbose makefiles, which may be useful in some situations.
|
||||
|
||||
```
|
||||
-DCMAKE_VERBOSE_MAKEFILE=ON
|
||||
```
|
||||
|
||||
Enable debugging symbols:
|
||||
|
||||
```bash
|
||||
-DCMAKE_BUILD_TYPE=Debug
|
||||
```
|
||||
|
||||
## Feather
|
||||
|
||||
It's best to install Tor locally as a service and start Feather with `--use-local-tor`, this
|
||||
prevents the child process from starting up and saves time.
|
||||
|
||||
#### Ubuntu/Debian
|
||||
|
||||
```bash
|
||||
apt install -y tor
|
||||
sudo service tor start
|
||||
```
|
||||
|
||||
#### Mac OS
|
||||
|
||||
```bash
|
||||
brew install tor
|
||||
brew services start tor
|
||||
```
|
||||
|
||||
To skip the wizards and open a wallet directly use `--wallet-file`:
|
||||
|
||||
```bash
|
||||
./feather --use-local-tor --wallet-file /home/user/Monero/wallets/bla.keys
|
||||
```
|
||||
|
||||
It is recommended that you use `--stagenet` for development. Testnet is also possible,
|
||||
but you'll have to provide Feather a testnet node of your own.
|
||||
|
2
LICENSE
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2020, The Monero Project
|
||||
Copyright (c) 2020-2021, The Monero Project
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
|
28
Makefile
|
@ -27,12 +27,9 @@
|
|||
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
|
||||
CMAKEFLAGS = \
|
||||
-DARCH=x86_64 \
|
||||
-DBUILD_64=On \
|
||||
-DBUILD_TESTS=Off \
|
||||
-DXMRTO=On \
|
||||
-DMORPHTOKEN=On \
|
||||
-DXMRIG=On \
|
||||
-DOPENVR=Off \
|
||||
-DTOR_BIN=Off \
|
||||
-DCMAKE_CXX_STANDARD=11 \
|
||||
-DCMAKE_VERBOSE_MAKEFILE=On \
|
||||
|
@ -43,14 +40,27 @@ CMAKEFLAGS = \
|
|||
$(CMAKEFLAGS_EXTRA)
|
||||
|
||||
release-static: CMAKEFLAGS += -DBUILD_TAG="linux-x64"
|
||||
release-static: CMAKEFLAGS += -DXMRIG=OFF
|
||||
release-static: CMAKEFLAGS += -DARCH=x86-64
|
||||
release-static: CMAKEFLAGS += -DTOR_BIN=$(or ${TOR_BIN},OFF)
|
||||
release-static: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Release
|
||||
release-static: CMAKEFLAGS += -DREPRODUCIBLE=$(or ${SOURCE_DATE_EPOCH},OFF)
|
||||
release-static:
|
||||
cmake -Bbuild $(CMAKEFLAGS)
|
||||
$(MAKE) -Cbuild
|
||||
|
||||
depends:
|
||||
mkdir -p build/$(target)/release
|
||||
cd build/$(target)/release && cmake -D STATIC=ON -DREPRODUCIBLE=$(or ${SOURCE_DATE_EPOCH},OFF) -DTOR_VERSION=$(or ${TOR_VERSION}, OFF) -DTOR_BIN=$(or ${TOR_BIN},OFF) -D DEV_MODE=$(or ${DEV_MODE},OFF) -D BUILD_TAG=$(tag) -D CMAKE_BUILD_TYPE=Release -D CMAKE_TOOLCHAIN_FILE=$(root)/$(target)/share/toolchain.cmake ../../.. && $(MAKE)
|
||||
|
||||
windows:
|
||||
mkdir -p build/$(target)/release
|
||||
cd build/$(target)/release && cmake -D STATIC=ON -DZLIB_ROOT=/usr/x86_64-w64-mingw32/ -DREPRODUCIBLE=$(or ${SOURCE_DATE_EPOCH},OFF) -DTOR_VERSION=$(or ${TOR_VERSION}, OFF) -DOPENVR=ON -DWITH_SCANNER=ON -DTOR_BIN=$(or ${TOR_BIN},OFF) -D DEV_MODE=$(or ${DEV_MODE},OFF) -D BUILD_TAG=$(tag) -D CMAKE_BUILD_TYPE=Release -D CMAKE_TOOLCHAIN_FILE=$(root)/$(target)/share/toolchain.cmake ../../.. && $(MAKE)
|
||||
|
||||
|
||||
windows-mxe-release: CMAKEFLAGS += -DBUILD_TAG="win-x64"
|
||||
windows-mxe-release: CMAKEFLAGS += -DTOR_BIN=$(or ${TOR_BIN},OFF)
|
||||
windows-mxe-debug: CMAKEFLAGS += -DOPENVR=On
|
||||
windows-mxe-release: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Release
|
||||
windows-mxe-release:
|
||||
cmake -Bbuild $(CMAKEFLAGS)
|
||||
|
@ -58,16 +68,8 @@ windows-mxe-release:
|
|||
|
||||
windows-mxe-debug: CMAKEFLAGS += -DBUILD_TAG="win-x64"
|
||||
windows-mxe-debug: CMAKEFLAGS += -DTOR_BIN=$(or ${TOR_BIN},OFF)
|
||||
windows-mxe-debug: CMAKEFLAGS += -DOPENVR=On
|
||||
windows-mxe-debug: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Debug
|
||||
windows-mxe-debug:
|
||||
cmake -Bbuild $(CMAKEFLAGS)
|
||||
$(MAKE) -Cbuild
|
||||
|
||||
mac-release: CMAKEFLAGS += -DSTATIC=Off
|
||||
mac-release: CMAKEFLAGS += -DTOR_BIN=$(or ${TOR_BIN},OFF)
|
||||
mac-release: CMAKEFLAGS += -DBUILD_TAG="mac-x64"
|
||||
mac-release: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Release
|
||||
mac-release:
|
||||
cmake -Bbuild $(CMAKEFLAGS)
|
||||
$(MAKE) -Cbuild
|
||||
$(MAKE) -Cbuild deploy
|
37
README.md
|
@ -1,35 +1,14 @@
|
|||
# Feather - a free Monero desktop wallet
|
||||
# WOWlet- a free Wownero desktop wallet
|
||||
|
||||
[![Build Status](https://build.featherwallet.org/api/badges/feather/feather/status.svg)](https://build.featherwallet.org/feather/feather)
|
||||
WOWlet is a free, open-source Wownero client for Linux, Mac OS, and Windows.
|
||||
|
||||
Feather is a free, open-source Monero client Linux with ports for Mac OS and Windows written in C++ with the Qt framework. It is created and maintained by [dsc](dsc@xmr.pm) and [tobtoht](thotbot@protonmail.com).
|
||||
![https://i.imgur.com/l7fUf0f.png](https://i.imgur.com/l7fUf0f.png)
|
||||
|
||||
## Development resources
|
||||
* Web: [featherwallet.org](https://featherwallet.org)
|
||||
* Git: [git.wownero.com/feather/feather](https://git.wownero.com/feather/feather)
|
||||
* IRC: `#feather` on OFTC
|
||||
* Development builds: [build.featherwallet.org/files](https://build.featherwallet.org/files/)
|
||||
|
||||
* Git: [git.wownero.com/wowlet/wowlet](https://git.wownero.com/wowlet/wowlet)
|
||||
* IRC: `#wownero-dev` on [OFTC](https://oftc.net/)
|
||||
* [Building WOWlet from source](https://git.wownero.com/wowlet/wowlet/src/branch/master/docs/BUILDING.md)
|
||||
* [Working on WOWlet](https://git.wownero.com/wowlet/wowlet/src/branch/master/docs/HACKING.md)
|
||||
|
||||
Copyright (c) 2020-2021 The Monero Project.
|
||||
|
||||
## Compiling Feather from source
|
||||
|
||||
Feather uses Monero, as such it requires the same dependencies as outlined in [Monero's README](https://github.com/monero-project/monero#compiling-monero-from-source). Additionally, Feather uses:
|
||||
|
||||
- Qt 5.15.0
|
||||
- libqrencode
|
||||
- openpgp
|
||||
|
||||
See [BUILDING.md](https://git.wownero.com/feather/feather/src/branch/master/BUILDING.md) for information on how to compile a build.
|
||||
|
||||
## Supporting the project
|
||||
|
||||
Feather is a 100% community-sponsored endeavor. If you want to join our efforts, the easiest thing you can do is support the project financially.
|
||||
|
||||
`47ntfT2Z5384zku39pTM6hGcnLnvpRYW2Azm87GiAAH2bcTidtq278TL6HmwyL8yjMeERqGEBs3cqC8vvHPJd1cWQrGC65f`
|
||||
|
||||
## Developers
|
||||
|
||||
See [HACKING.md](https://git.wownero.com/feather/feather/src/branch/master/HACKING.md) for useful development resources.
|
||||
|
||||
It is HIGHLY recommended that you join the `#feather` IRC channel on OFTC if you are hacking on Feather. Due to the nature of this open source software project, joining this channel and idling is the best way to stay updated on best practices and new developments.
|
||||
|
|
|
@ -2,27 +2,4 @@ if(APPLE OR (WIN32 AND NOT STATIC))
|
|||
add_custom_target(deploy)
|
||||
get_target_property(_qmake_executable Qt5::qmake IMPORTED_LOCATION)
|
||||
get_filename_component(_qt_bin_dir "${_qmake_executable}" DIRECTORY)
|
||||
|
||||
if(APPLE AND NOT IOS)
|
||||
find_program(MACDEPLOYQT_EXECUTABLE macdeployqt HINTS "${_qt_bin_dir}")
|
||||
add_custom_command(TARGET deploy
|
||||
POST_BUILD
|
||||
COMMAND "${MACDEPLOYQT_EXECUTABLE}" "$<TARGET_FILE_DIR:feather>/../.." -always-overwrite
|
||||
COMMENT "Running macdeployqt..."
|
||||
)
|
||||
|
||||
# workaround for a Qt bug that requires manually adding libqsvg.dylib to bundle
|
||||
find_file(_qt_svg_dylib "libqsvg.dylib" PATHS "${CMAKE_PREFIX_PATH}/plugins/imageformats" NO_DEFAULT_PATH)
|
||||
if(_qt_svg_dylib)
|
||||
add_custom_command(TARGET deploy
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${_qt_svg_dylib} $<TARGET_FILE_DIR:feather>/../PlugIns/imageformats/
|
||||
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtGui.framework/Versions/5/QtGui" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" $<TARGET_FILE_DIR:feather>/../PlugIns/imageformats/libqsvg.dylib
|
||||
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtWidgets.framework/Versions/5/QtWidgets" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" $<TARGET_FILE_DIR:feather>/../PlugIns/imageformats/libqsvg.dylib
|
||||
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtSvg.framework/Versions/5/QtSvg" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" $<TARGET_FILE_DIR:feather>/../PlugIns/imageformats/libqsvg.dylib
|
||||
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtCore.framework/Versions/5/QtCore" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" $<TARGET_FILE_DIR:feather>/../PlugIns/imageformats/libqsvg.dylib
|
||||
COMMENT "Copying libqsvg.dylib, running install_name_tool"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
|
81
cmake/FindCairo.cmake
Normal file
|
@ -0,0 +1,81 @@
|
|||
# - Try to find Cairo
|
||||
# Once done, this will define
|
||||
#
|
||||
# CAIRO_FOUND - system has Cairo
|
||||
# CAIRO_INCLUDE_DIRS - the Cairo include directories
|
||||
# CAIRO_LIBRARIES - link these to use Cairo
|
||||
#
|
||||
# Copyright (C) 2012 Raphael Kubo da Costa <rakuco@webkit.org>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS
|
||||
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
FIND_PACKAGE(PkgConfig)
|
||||
PKG_CHECK_MODULES(PC_CAIRO cairo) # FIXME: After we require CMake 2.8.2 we can pass QUIET to this call.
|
||||
|
||||
FIND_PATH(CAIRO_INCLUDE_DIRS
|
||||
NAMES cairo.h
|
||||
HINTS ${PC_CAIRO_INCLUDEDIR}
|
||||
${PC_CAIRO_INCLUDE_DIRS}
|
||||
PATH_SUFFIXES cairo
|
||||
)
|
||||
|
||||
FIND_LIBRARY(CAIRO_LIBRARIES
|
||||
NAMES cairo
|
||||
HINTS ${PC_CAIRO_LIBDIR}
|
||||
${PC_CAIRO_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
IF (CAIRO_INCLUDE_DIRS)
|
||||
IF (EXISTS "${CAIRO_INCLUDE_DIRS}/cairo-version.h")
|
||||
FILE(READ "${CAIRO_INCLUDE_DIRS}/cairo-version.h" CAIRO_VERSION_CONTENT)
|
||||
|
||||
STRING(REGEX MATCH "#define +CAIRO_VERSION_MAJOR +([0-9]+)" _dummy "${CAIRO_VERSION_CONTENT}")
|
||||
SET(CAIRO_VERSION_MAJOR "${CMAKE_MATCH_1}")
|
||||
|
||||
STRING(REGEX MATCH "#define +CAIRO_VERSION_MINOR +([0-9]+)" _dummy "${CAIRO_VERSION_CONTENT}")
|
||||
SET(CAIRO_VERSION_MINOR "${CMAKE_MATCH_1}")
|
||||
|
||||
STRING(REGEX MATCH "#define +CAIRO_VERSION_MICRO +([0-9]+)" _dummy "${CAIRO_VERSION_CONTENT}")
|
||||
SET(CAIRO_VERSION_MICRO "${CMAKE_MATCH_1}")
|
||||
|
||||
SET(CAIRO_VERSION "${CAIRO_VERSION_MAJOR}.${CAIRO_VERSION_MINOR}.${CAIRO_VERSION_MICRO}")
|
||||
ENDIF ()
|
||||
ENDIF ()
|
||||
|
||||
# FIXME: Should not be needed anymore once we start depending on CMake 2.8.3
|
||||
SET(VERSION_OK TRUE)
|
||||
IF (Cairo_FIND_VERSION)
|
||||
IF (Cairo_FIND_VERSION_EXACT)
|
||||
IF ("${Cairo_FIND_VERSION}" VERSION_EQUAL "${CAIRO_VERSION}")
|
||||
# FIXME: Use IF (NOT ...) with CMake 2.8.2+ to get rid of the ELSE block
|
||||
ELSE ()
|
||||
SET(VERSION_OK FALSE)
|
||||
ENDIF ()
|
||||
ELSE ()
|
||||
IF ("${Cairo_FIND_VERSION}" VERSION_GREATER "${CAIRO_VERSION}")
|
||||
SET(VERSION_OK FALSE)
|
||||
ENDIF ()
|
||||
ENDIF ()
|
||||
ENDIF ()
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Cairo DEFAULT_MSG CAIRO_INCLUDE_DIRS CAIRO_LIBRARIES VERSION_OK)
|
|
@ -1,5 +1,8 @@
|
|||
find_path(QRENCODE_INCLUDE_DIR qrencode.h)
|
||||
message(STATUS "QRENCODE PATH ${QRENCODE_INCLUDE_DIR}")
|
||||
|
||||
find_library(QRENCODE_LIBRARY qrencode)
|
||||
message(STATUS "QRENCODE LIBARY ${QRENCODE_LIBRARY}")
|
||||
|
||||
mark_as_advanced(QRENCODE_LIBRARY QRENCODE_INCLUDE_DIR)
|
||||
|
||||
|
|
26
cmake/FindXfixes.cmake
Normal file
|
@ -0,0 +1,26 @@
|
|||
# - Find XFixes
|
||||
# Find the XFixes libraries
|
||||
#
|
||||
# This module defines the following variables:
|
||||
# XFIXES_FOUND - 1 if XFIXES_INCLUDE_DIR & XFIXES_LIBRARY are found, 0 otherwise
|
||||
# XFIXES_INCLUDE_DIR - where to find Xlib.h, etc.
|
||||
# XFIXES_LIBRARY - the X11 library
|
||||
#
|
||||
|
||||
find_path( XFIXES_INCLUDE_DIR
|
||||
NAMES X11/extensions/Xfixes.h
|
||||
PATH_SUFFIXES X11/extensions
|
||||
DOC "The XFixes include directory" )
|
||||
|
||||
find_library( XFIXES_LIBRARY
|
||||
NAMES Xfixes
|
||||
PATHS /usr/lib /lib
|
||||
DOC "The XFixes library" )
|
||||
|
||||
if( XFIXES_INCLUDE_DIR AND XFIXES_LIBRARY )
|
||||
set( XFIXES_FOUND 1 )
|
||||
else()
|
||||
set( XFIXES_FOUND 0 )
|
||||
endif()
|
||||
|
||||
mark_as_advanced( XFIXES_INCLUDE_DIR XFIXES_LIBRARY )
|
|
@ -35,7 +35,7 @@ if(RET)
|
|||
message(WARNING "Cannot determine current commit. Make sure that you are building either from a Git working tree or from a source archive.")
|
||||
set(VERSIONTAG "unknown")
|
||||
set(VERSION_IS_RELEASE "false")
|
||||
configure_file("monero/src/version.cpp.in" "${TO}")
|
||||
configure_file("wownero/src/version.cpp.in" "${TO}")
|
||||
else()
|
||||
string(SUBSTRING ${COMMIT} 0 9 COMMIT)
|
||||
message(STATUS "You are currently on commit ${COMMIT}")
|
||||
|
@ -61,5 +61,5 @@ else()
|
|||
set(VERSION_IS_RELEASE "false")
|
||||
endif()
|
||||
endif()
|
||||
configure_file("monero/src/version.cpp.in" "${TO}")
|
||||
configure_file("wownero/src/version.cpp.in" "${TO}")
|
||||
endif()
|
|
@ -4,7 +4,7 @@
|
|||
find_package(Git QUIET)
|
||||
# Check what commit we're on
|
||||
execute_process(COMMAND "${GIT_EXECUTABLE}" rev-parse --short=9 HEAD RESULT_VARIABLE RET OUTPUT_VARIABLE COMMIT OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/monero)
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/wownero)
|
||||
|
||||
if(RET)
|
||||
# Something went wrong, set the version tag to -unknown
|
||||
|
@ -37,7 +37,7 @@ endif()
|
|||
|
||||
# Check latest tagged release
|
||||
execute_process(COMMAND "${GIT_EXECUTABLE}" describe --abbrev=0 RESULT_VARIABLE RET OUTPUT_VARIABLE TAG OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/monero)
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/wownero)
|
||||
|
||||
if(RET)
|
||||
message(WARNING "Cannot determine most recent tag. Make sure that you are building either from a Git working tree or from a source archive.")
|
||||
|
@ -46,4 +46,4 @@ else ()
|
|||
set(MONERO_VERSION "${TAG}")
|
||||
endif()
|
||||
|
||||
configure_file("cmake/config-feather.h.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/src/config-feather.h")
|
||||
configure_file("cmake/config-wowlet.h.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/src/config-wowlet.h")
|
|
@ -10,8 +10,8 @@ if(RET)
|
|||
# Something went wrong, set the version tag to -unknown
|
||||
|
||||
message(WARNING "Cannot determine current commit. Make sure that you are building either from a Git working tree or from a source archive.")
|
||||
set(FEATHER_BRANCH "unknown")
|
||||
configure_file("cmake/config-feather.h.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/src/config-feather.h")
|
||||
set(WOWLET_BRANCH "unknown")
|
||||
configure_file("cmake/config-wowlet.h.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/src/config-wowlet.h")
|
||||
else()
|
||||
string(SUBSTRING ${COMMIT} 0 9 COMMIT)
|
||||
message(STATUS "You are currently on commit ${COMMIT}")
|
||||
|
@ -21,19 +21,19 @@ else()
|
|||
|
||||
if(NOT TAGGEDCOMMIT)
|
||||
message(STATUS "Cannot determine most recent tag. Make sure that you are building either from a Git working tree or from a source archive.")
|
||||
set(FEATHER_BRANCH "${COMMIT}")
|
||||
set(WOWLET_BRANCH "${COMMIT}")
|
||||
else()
|
||||
message(STATUS "The most recent tag was at ${TAGGEDCOMMIT}")
|
||||
|
||||
# Check if we're building that tagged commit or a different one
|
||||
if(COMMIT STREQUAL TAGGEDCOMMIT)
|
||||
message(STATUS "You are building a tagged release")
|
||||
set(FEATHER_BRANCH "release")
|
||||
set(WOWLET_BRANCH "release")
|
||||
else()
|
||||
message(STATUS "You are ahead of or behind a tagged release")
|
||||
set(FEATHER_BRANCH "${COMMIT}")
|
||||
set(WOWLET_BRANCH "${COMMIT}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
configure_file("cmake/config-feather.h.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/src/config-feather.h")
|
||||
configure_file("cmake/config-wowlet.h.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/src/config-wowlet.h")
|
||||
endif()
|
|
@ -1,10 +0,0 @@
|
|||
#ifndef FEATHER_VERSION_H
|
||||
#define FEATHER_VERSION_H
|
||||
|
||||
#define FEATHER_VERSION "@VERSION@"
|
||||
#define FEATHER_BRANCH "@FEATHER_BRANCH@"
|
||||
|
||||
#define MONERO_VERSION "@MONERO_VERSION@"
|
||||
#define MONERO_BRANCH "@MONERO_BRANCH@"
|
||||
|
||||
#endif //FEATHER_VERSION_H
|
13
cmake/config-wowlet.h.cmake
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef WOWLET_VERSION_H
|
||||
#define WOWLET_VERSION_H
|
||||
|
||||
#define WOWLET_VERSION "@VERSION@"
|
||||
#define WOWLET_BRANCH "@WOWLET_BRANCH@"
|
||||
#define WOWLET_VERSION_SEMVER "@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_REVISION@"
|
||||
|
||||
#define MONERO_VERSION "@MONERO_VERSION@"
|
||||
#define MONERO_BRANCH "@MONERO_BRANCH@"
|
||||
|
||||
#define TOR_VERSION "@TOR_VERSION@"
|
||||
|
||||
#endif //WOWLET_VERSION_H
|
|
@ -7,7 +7,7 @@ pkgrel=1
|
|||
pkgdesc='a free Monero desktop wallet'
|
||||
license=('BSD')
|
||||
arch=('x86_64')
|
||||
url="https://featherwallet.org"
|
||||
url="https://wownero.org"
|
||||
depends=('boost-libs' 'libunwind' 'openssl' 'readline' 'pcsclite' 'hidapi' 'protobuf' 'miniupnpc' 'libgcrypt' 'qrencode' 'libsodium' 'libpgm' 'expat' 'qt5-base' 'qt5-websockets' 'tor')
|
||||
makedepends=('git' 'cmake' 'boost')
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
APPDIR="$PWD/feather.AppDir"
|
||||
mkdir -p "$APPDIR"
|
||||
mkdir -p "$APPDIR/usr/share/applications/"
|
||||
mkdir -p "$APPDIR/usr/bin"
|
||||
|
||||
unzip -q feather.zip
|
||||
|
||||
cp "$PWD/src/assets/feather.desktop" "$APPDIR/usr/share/applications/feather.desktop"
|
||||
cp "$PWD/src/assets/images/appicons/64x64.png" "$APPDIR/feather.png"
|
||||
cp "$PWD/feather" "$APPDIR/usr/bin/feather"
|
||||
|
||||
/appimagetool deploy "$APPDIR/usr/share/applications/feather.desktop"
|
||||
VERSION=1.0 /appimagetool ./feather.AppDir
|
||||
|
46
contrib/debian/build-deb.sh
Executable file
|
@ -0,0 +1,46 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Make directories
|
||||
|
||||
DEBDIR="$PWD/wowlet.DebDir"
|
||||
mkdir -p "$DEBDIR"
|
||||
mkdir -p "$DEBDIR/DEBIAN/"
|
||||
mkdir -p "$DEBDIR/debian/"
|
||||
mkdir -p "$DEBDIR/usr/bin/"
|
||||
mkdir -p "$DEBDIR/usr/share/doc/wowlet/"
|
||||
mkdir -p "$DEBDIR/usr/share/metainfo/"
|
||||
mkdir -p "$DEBDIR/usr/share/applications/"
|
||||
mkdir -p "$DEBDIR/usr/share/man/man1/"
|
||||
mkdir -p "$DEBDIR/usr/share/icons/hicolor/scalable/apps/"
|
||||
mkdir -p "$DEBDIR/usr/share/icons/hicolor/48x48/apps/"
|
||||
mkdir -p "$DEBDIR/usr/share/icons/hicolor/64x64/apps/"
|
||||
mkdir -p "$DEBDIR/usr/share/icons/hicolor/96x96/apps/"
|
||||
mkdir -p "$DEBDIR/usr/share/icons/hicolor/128x128/apps/"
|
||||
mkdir -p "$DEBDIR/usr/share/icons/hicolor/192x192/apps/"
|
||||
mkdir -p "$DEBDIR/usr/share/icons/hicolor/256x256/apps/"
|
||||
|
||||
# Copy over assets
|
||||
|
||||
cp "$PWD/contrib/debian/control" "$DEBDIR/DEBIAN/control"
|
||||
cp "$PWD/contrib/debian/copyright" "$DEBDIR/debian/copyright"
|
||||
cp "$PWD/contrib/debian/copyright" "$DEBDIR/usr/share/doc/wowlet/copyright"
|
||||
cp "$PWD/contrib/debian/changelog.gz" "$DEBDIR/usr/share/doc/wowlet/changelog.gz"
|
||||
cp "$PWD/src/assets/org.wowlet.wowlet.metainfo.xml" "$DEBDIR/usr/share/metainfo/org.wowlet.wowlet.metainfo.xml"
|
||||
cp "$PWD/README.md" "$DEBDIR/usr/share/doc/wowlet/README"
|
||||
cp "$PWD/docs/SECURITY.md" "$DEBDIR/usr/share/doc/wowlet/SECURITY"
|
||||
cp "$PWD/build/bin/wowlet" "$DEBDIR/usr/bin/wowlet"
|
||||
cp "$PWD/src/assets/org.wowlet.wowlet.desktop" "$DEBDIR/usr/share/applications/org.wowlet.wowlet.desktop"
|
||||
cp "$PWD/src/assets/wowlet.1.gz" "$DEBDIR/usr/share/man/man1/wowlet.1.gz"
|
||||
cp "$PWD/src/assets/images/appicons/wowlet.svg" "$DEBDIR/usr/share/icons/hicolor/scalable/apps/wowlet.svg"
|
||||
cp "$PWD/src/assets/images/appicons/48x48.png" "$DEBDIR/usr/share/icons/hicolor/48x48/apps/wowlet.png"
|
||||
cp "$PWD/src/assets/images/appicons/64x64.png" "$DEBDIR/usr/share/icons/hicolor/64x64/apps/wowlet.png"
|
||||
cp "$PWD/src/assets/images/appicons/96x96.png" "$DEBDIR/usr/share/icons/hicolor/96x96/apps/wowlet.png"
|
||||
cp "$PWD/src/assets/images/appicons/128x128.png" "$DEBDIR/usr/share/icons/hicolor/128x128/apps/wowlet.png"
|
||||
cp "$PWD/src/assets/images/appicons/192x192.png" "$DEBDIR/usr/share/icons/hicolor/192x192/apps/wowlet.png"
|
||||
cp "$PWD/src/assets/images/appicons/256x256.png" "$DEBDIR/usr/share/icons/hicolor/256x256/apps/wowlet.png"
|
||||
|
||||
# Build deb package
|
||||
|
||||
dpkg-deb --build $DEBDIR
|
||||
mv wowlet.DebDir.deb wowlet_2.1_amd64.deb
|
BIN
contrib/debian/changelog.gz
Normal file
12
contrib/debian/control
Normal file
|
@ -0,0 +1,12 @@
|
|||
Package: wowlet
|
||||
Version: 2.1
|
||||
Section: net
|
||||
Priority: optional
|
||||
Architecture: amd64
|
||||
Essential: no
|
||||
Installed-Size: 76800
|
||||
Maintainer: wowario <wowario@protonmail.com>
|
||||
Description: WOWlet is a free, open-source Wownero client for Linux with ports for Mac OS and Windows.
|
||||
Tag: office::finance
|
||||
Homepage: https://git.wownero.com/wowlet/wowlet
|
||||
Depends: libxcb-icccm4, libxcb-image0, libxcb-keysyms1, libxcb-render-util0, libxcb-xkb1, libxkbcommon-x11-0
|
31
contrib/debian/copyright
Normal file
|
@ -0,0 +1,31 @@
|
|||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: wowlet
|
||||
Source: https://git.wownero.com/wowlet/wowlet
|
||||
|
||||
Files: *
|
||||
Copyright: (c) 2020-2021 The Monero Project
|
||||
License: BSD-3-clause
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
93
contrib/openvr/CMakeLists.txt
Executable file
|
@ -0,0 +1,93 @@
|
|||
# Set project name.
|
||||
project(OpenVRSDK)
|
||||
|
||||
# Fetch the version from the headers
|
||||
set(VERSION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/headers/openvr.h")
|
||||
|
||||
set(VERSION_MAJOR_REGEX "\tstatic const uint32_t k_nSteamVRVersionMajor = (.+);")
|
||||
set(VERSION_MINOR_REGEX "\tstatic const uint32_t k_nSteamVRVersionMinor = (.+);")
|
||||
set(VERSION_BUILD_REGEX "\tstatic const uint32_t k_nSteamVRVersionBuild = (.+);")
|
||||
|
||||
file(STRINGS "${VERSION_FILE}" VERSION_MAJOR_STRING REGEX "${VERSION_MAJOR_REGEX}")
|
||||
file(STRINGS "${VERSION_FILE}" VERSION_MINOR_STRING REGEX "${VERSION_MINOR_REGEX}")
|
||||
file(STRINGS "${VERSION_FILE}" VERSION_BUILD_STRING REGEX "${VERSION_BUILD_REGEX}")
|
||||
|
||||
string(REGEX REPLACE "${VERSION_MAJOR_REGEX}" "\\1" VERSION_MAJOR ${VERSION_MAJOR_STRING})
|
||||
string(REGEX REPLACE "${VERSION_MINOR_REGEX}" "\\1" VERSION_MINOR ${VERSION_MINOR_STRING})
|
||||
string(REGEX REPLACE "${VERSION_BUILD_REGEX}" "\\1" VERSION_BUILD ${VERSION_BUILD_STRING})
|
||||
|
||||
set(OPENVR_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_BUILD}")
|
||||
|
||||
# Setup some options.
|
||||
option(BUILD_SHARED "Builds the library as shared library" OFF)
|
||||
option(BUILD_FRAMEWORK "Builds the library as an apple Framework" OFF)
|
||||
option(BUILD_UNIVERSAL "Builds the shared or framework as a universal (fat, 32- & 64-bit) binary" ON)
|
||||
option(BUILD_OSX_I386 "Builds the shared or framework as a 32-bit binary, even on a 64-bit platform" OFF)
|
||||
option(USE_LIBCXX "Uses libc++ instead of libstdc++" ON)
|
||||
option(USE_CUSTOM_LIBCXX "Uses a custom libc++" OFF)
|
||||
|
||||
add_definitions( -DVR_API_PUBLIC )
|
||||
|
||||
# Check if 32 or 64 bit system.
|
||||
set(SIZEOF_VOIDP ${CMAKE_SIZEOF_VOID_P})
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(PROCESSOR_ARCH "64")
|
||||
else()
|
||||
set(PROCESSOR_ARCH "32")
|
||||
endif()
|
||||
|
||||
# Get platform.
|
||||
if(WIN32)
|
||||
set(PLATFORM_NAME "win")
|
||||
if(NOT BUILD_SHARED)
|
||||
add_definitions(-DOPENVR_BUILD_STATIC)
|
||||
endif()
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
if(CMAKE_SYSTEM_NAME MATCHES ".*Linux")
|
||||
set(PLATFORM_NAME "linux")
|
||||
add_definitions(-DLINUX -DPOSIX)
|
||||
if(PROCESSOR_ARCH MATCHES "64")
|
||||
add_definitions(-DLINUX64)
|
||||
endif()
|
||||
endif()
|
||||
elseif(APPLE)
|
||||
if(CMAKE_SYSTEM_NAME MATCHES ".*Darwin.*" OR CMAKE_SYSTEM_NAME MATCHES ".*MacOS.*")
|
||||
set(PLATFORM_NAME "osx")
|
||||
add_definitions(-DOSX -DPOSIX)
|
||||
if(BUILD_UNIVERSAL)
|
||||
set(CMAKE_OSX_ARCHITECTURES "i386;x86_64")
|
||||
endif()
|
||||
if(BUILD_OSX_I386)
|
||||
set(PROCESSOR_ARCH "32")
|
||||
set(CMAKE_OSX_ARCHITECTURES "i386")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Set output folder for static and shared libraries
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin/${PLATFORM_NAME}${PROCESSOR_ARCH})
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin/${PLATFORM_NAME}${PROCESSOR_ARCH})
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin/${PLATFORM_NAME}${PROCESSOR_ARCH})
|
||||
|
||||
# Enable some properties.
|
||||
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
# Enable c++11 and hide symbols which shouldn't be visible
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fPIC -fvisibility=hidden")
|
||||
|
||||
# Set custom libc++ usage here
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "Clang" AND USE_LIBCXX)
|
||||
if(USE_CUSTOM_LIBCXX)
|
||||
if(BUILD_SHARED)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -stdlib=libc++")
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdinc++")
|
||||
include_directories( ${LIBCXX_INCLUDE} ${LIBCXX_ABI_INCLUDE})
|
||||
message(STATUS "Using custom libc++")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||
message(STATUS "Using libc++")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
27
contrib/openvr/LICENSE
Executable file
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2015, Valve Corporation
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
19
contrib/openvr/README.md
Executable file
|
@ -0,0 +1,19 @@
|
|||
### Warning
|
||||
|
||||
**Hard forked from commit `4c85abcb7f7f1f02adaf3812018c99fc593bc341` @ openvr**.
|
||||
|
||||
At the time of writing, the above version does not compile. Had to make several changes. In addition,
|
||||
binary blobs where removed from the repository.
|
||||
|
||||
### OpenVR SDK
|
||||
|
||||
OpenVR is an API and runtime that allows access to VR hardware from multiple
|
||||
vendors without requiring that applications have specific knowledge of the
|
||||
hardware they are targeting. This repository is an SDK that contains the API
|
||||
and samples. The runtime is under SteamVR in Tools on Steam.
|
||||
|
||||
### Documentation
|
||||
|
||||
Documentation for the API is available on the [GitHub Wiki](https://github.com/ValveSoftware/openvr/wiki/API-Documentation)
|
||||
|
||||
More information on OpenVR and SteamVR can be found on http://steamvr.com
|
9
contrib/openvr/Toolchain-clang.cmake
Executable file
|
@ -0,0 +1,9 @@
|
|||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
|
||||
set(CMAKE_C_COMPILER clang)
|
||||
set(CMAKE_CXX_COMPILER clang++)
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
5624
contrib/openvr/headers/openvr.h
Executable file
8220
contrib/openvr/headers/openvr_api.cs
Executable file
5761
contrib/openvr/headers/openvr_api.json
Executable file
3125
contrib/openvr/headers/openvr_capi.h
Executable file
4212
contrib/openvr/headers/openvr_driver.h
Executable file
116
contrib/openvr/src/CMakeLists.txt
Executable file
|
@ -0,0 +1,116 @@
|
|||
# Project name.
|
||||
project(openvr_api)
|
||||
|
||||
set( LIBNAME "openvr_api" )
|
||||
set(OPENVR_HEADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../headers)
|
||||
|
||||
# Set some properies for specific files.
|
||||
if(APPLE)
|
||||
set(CMAKE_MACOSX_RPATH 1)
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||
set_source_files_properties(vrcommon/pathtools_public.cpp vrcommon/vrpathregistry_public.cpp PROPERTIES COMPILE_FLAGS "-x objective-c++")
|
||||
endif()
|
||||
if(BUILD_SHARED OR BUILD_FRAMEWORK)
|
||||
find_library(FOUNDATION_FRAMEWORK Foundation)
|
||||
mark_as_advanced(FOUNDATION_FRAMEWORK)
|
||||
set(EXTRA_LIBS ${EXTRA_LIBS} ${FOUNDATION_FRAMEWORK})
|
||||
endif(BUILD_SHARED OR BUILD_FRAMEWORK)
|
||||
elseif(WIN32)
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
add_definitions( -DWIN64 )
|
||||
set( LIBNAME "openvr_api64" )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Add include folders.
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../headers ${CMAKE_CURRENT_SOURCE_DIR}/vrcommon)
|
||||
|
||||
if(USE_CUSTOM_LIBCXX)
|
||||
link_directories(
|
||||
${LIBCXX_LIB_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
# Set the source group and files.
|
||||
set(CORE_FILES
|
||||
openvr_api_public.cpp
|
||||
jsoncpp.cpp
|
||||
)
|
||||
set(VRCOMMON_FILES
|
||||
vrcommon/dirtools_public.cpp
|
||||
vrcommon/envvartools_public.cpp
|
||||
vrcommon/pathtools_public.cpp
|
||||
vrcommon/sharedlibtools_public.cpp
|
||||
vrcommon/hmderrors_public.cpp
|
||||
vrcommon/vrpathregistry_public.cpp
|
||||
vrcommon/strtools_public.cpp
|
||||
)
|
||||
|
||||
set(SOURCE_FILES
|
||||
${CORE_FILES}
|
||||
${VRCOMMON_FILES}
|
||||
)
|
||||
|
||||
set(PUBLIC_HEADER_FILES
|
||||
${OPENVR_HEADER_DIR}/openvr_driver.h
|
||||
${OPENVR_HEADER_DIR}/openvr_capi.h
|
||||
${OPENVR_HEADER_DIR}/openvr.h
|
||||
)
|
||||
|
||||
source_group("Src" FILES
|
||||
${CORE_FILES}
|
||||
)
|
||||
|
||||
source_group("VRCommon" FILES
|
||||
${VRCOMMON_FILES}
|
||||
)
|
||||
|
||||
# Build the library.
|
||||
if(BUILD_SHARED)
|
||||
add_library(${LIBNAME} SHARED ${SOURCE_FILES})
|
||||
elseif(BUILD_FRAMEWORK)
|
||||
set( LIBNAME "OpenVR" )
|
||||
add_library( ${LIBNAME}
|
||||
SHARED ${SOURCE_FILES}
|
||||
${CMAKE_SOURCE_DIR}/headers/openvr.h
|
||||
${CMAKE_SOURCE_DIR}/headers/openvr_api.cs
|
||||
${CMAKE_SOURCE_DIR}/headers/openvr_api.json
|
||||
${CMAKE_SOURCE_DIR}/headers/openvr_capi.h
|
||||
${CMAKE_SOURCE_DIR}/headers/openvr_driver.h
|
||||
)
|
||||
set_target_properties(OpenVR PROPERTIES
|
||||
FRAMEWORK TRUE
|
||||
FRAMEWORK_VERSION A
|
||||
MACOSX_FRAMEWORK_IDENTIFIER com.valvesoftware.OpenVR.framework
|
||||
MACOSX_FRAMEWORK_INFO_PLIST ${CMAKE_SOURCE_DIR}/src/Info.plist
|
||||
# "current version" in semantic format in Mach-O binary file
|
||||
VERSION 1.0.6
|
||||
# "compatibility version" in semantic format in Mach-O binary file
|
||||
SOVERSION 1.0.0
|
||||
PUBLIC_HEADER "${CMAKE_SOURCE_DIR}/headers/openvr.h;${CMAKE_SOURCE_DIR}/headers/openvr_api.cs;${CMAKE_SOURCE_DIR}/headers/openvr_api.json;${CMAKE_SOURCE_DIR}/headers/openvr_capi.h;${CMAKE_SOURCE_DIR}/headers/openvr_driver.h"
|
||||
LINKER_LANGUAGE CXX
|
||||
)
|
||||
else()
|
||||
add_library(${LIBNAME} STATIC ${SOURCE_FILES})
|
||||
endif()
|
||||
|
||||
if(USE_CUSTOM_LIBCXX)
|
||||
set(EXTRA_LIBS ${EXTRA_LIBS} c++ c++abi)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${LIBNAME} ${EXTRA_LIBS} ${CMAKE_DL_LIBS})
|
||||
target_include_directories(${LIBNAME} PUBLIC ${OPENVR_HEADER_DIR})
|
||||
|
||||
install(TARGETS ${LIBNAME} DESTINATION lib)
|
||||
install(FILES ${PUBLIC_HEADER_FILES} DESTINATION include/openvr)
|
||||
|
||||
# Generate a .pc file for linux environments
|
||||
if(PLATFORM_NAME MATCHES "linux")
|
||||
set(INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/share/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files")
|
||||
CONFIGURE_FILE("openvr.pc.in" "openvr.pc" @ONLY)
|
||||
|
||||
set(OPENVR_PC ${CMAKE_CURRENT_BINARY_DIR}/openvr.pc)
|
||||
if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL )
|
||||
install(FILES ${OPENVR_PC} DESTINATION "${INSTALL_PKGCONFIG_DIR}")
|
||||
endif()
|
||||
endif()
|
18
contrib/openvr/src/Info.plist
Executable file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.valvesoftware.OpenVR.framework</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>OpenVR</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
</dict>
|
||||
</plist>
|
39
contrib/openvr/src/README
Executable file
|
@ -0,0 +1,39 @@
|
|||
This is the source code for the OpenVR API client binding library which connects
|
||||
OpenVR applications to the SteamVR runtime, taking into account the version
|
||||
of the OpenVR interface they were compiled against.
|
||||
|
||||
The client binding library - openvr_api.dll on Windows, openvr_api.so on
|
||||
Linux, and openvr_api.dylib or OpenVR.framework on macOS - knows how to find
|
||||
and read the SteamVR runtime installation information which allows it to
|
||||
find and dynamically connect to the installed runtime. In combination with the
|
||||
interface version identifiers from /include/openvr.h which are baked
|
||||
into applications at the time they are built, the OpenVR API client
|
||||
binding library captures and conveys to the SteamVR runtime the version
|
||||
of the OpenVR API interface behavior that the application expects.
|
||||
|
||||
Applications carry with them a private/local copy of the client binding
|
||||
library when they ship, and they should install it locally to their
|
||||
application. Applications should not install the client binding library
|
||||
globally or attempt to link to a globally installed client binding library.
|
||||
Doing so negates at least part of the ability for the client binding library
|
||||
to accurately reflect the version of the OpenVR API that the application
|
||||
was built against, and so hinders compatibility support in the face of
|
||||
API changes.
|
||||
|
||||
Most applications should simply link to and redistribute with their application
|
||||
the pre-built client binding library found in the /bin directory of this
|
||||
repository. Some small number of applications which have specific requirements
|
||||
around redistributing only binaries they build themselves should build
|
||||
the client library from this source and either statically link it into
|
||||
their application or redistribute the binary they build.
|
||||
|
||||
This is a cmake project, to build it use the version of cmake appropriate
|
||||
for your platform. For example, to build on a POSIX system simply perform
|
||||
|
||||
cd src; mkdir _build; cd _build; cmake ..; make
|
||||
|
||||
and you will end up with the static library /src/bin/<arch>/libopenvr_api.a
|
||||
|
||||
To build a shared library, pass -DBUILD_SHARED=1 to cmake.
|
||||
To build as a framework on apple platforms, pass -DBUILD_FRAMEWORK=1 to cmake.
|
||||
To see a complete list of configurable build options, use `cmake -LAH`
|
35
contrib/openvr/src/ivrclientcore.h
Executable file
|
@ -0,0 +1,35 @@
|
|||
//========= Copyright Valve Corporation ============//
|
||||
#pragma once
|
||||
|
||||
namespace vr
|
||||
{
|
||||
|
||||
class IVRClientCore
|
||||
{
|
||||
public:
|
||||
/** Initializes the system */
|
||||
virtual EVRInitError Init( vr::EVRApplicationType eApplicationType, const char *pStartupInfo ) = 0;
|
||||
|
||||
/** cleans up everything in vrclient.dll and prepares the DLL to be unloaded */
|
||||
virtual void Cleanup() = 0;
|
||||
|
||||
/** checks to see if the specified interface/version is supported in this vrclient.dll */
|
||||
virtual EVRInitError IsInterfaceVersionValid( const char *pchInterfaceVersion ) = 0;
|
||||
|
||||
/** Retrieves any interface from vrclient.dll */
|
||||
virtual void *GetGenericInterface( const char *pchNameAndVersion, EVRInitError *peError ) = 0;
|
||||
|
||||
/** Returns true if any driver has an HMD attached. Can be called outside of Init/Cleanup */
|
||||
virtual bool BIsHmdPresent() = 0;
|
||||
|
||||
/** Returns an English error string from inside vrclient.dll which might be newer than the API DLL */
|
||||
virtual const char *GetEnglishStringForHmdError( vr::EVRInitError eError ) = 0;
|
||||
|
||||
/** Returns an error symbol from inside vrclient.dll which might be newer than the API DLL */
|
||||
virtual const char *GetIDForVRInitError( vr::EVRInitError eError ) = 0;
|
||||
};
|
||||
|
||||
static const char * const IVRClientCore_Version = "IVRClientCore_003";
|
||||
|
||||
|
||||
}
|
284
contrib/openvr/src/json/json-forwards.h
Executable file
|
@ -0,0 +1,284 @@
|
|||
/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/).
|
||||
/// It is intended to be used with #include "json/json-forwards.h"
|
||||
/// This header provides forward declaration for all JsonCpp types.
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
// Beginning of content of file: LICENSE
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
The JsonCpp library's source code, including accompanying documentation,
|
||||
tests and demonstration applications, are licensed under the following
|
||||
conditions...
|
||||
|
||||
The author (Baptiste Lepilleur) explicitly disclaims copyright in all
|
||||
jurisdictions which recognize such a disclaimer. In such jurisdictions,
|
||||
this software is released into the Public Domain.
|
||||
|
||||
In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
|
||||
2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
|
||||
released under the terms of the MIT License (see below).
|
||||
|
||||
In jurisdictions which recognize Public Domain property, the user of this
|
||||
software may choose to accept it either as 1) Public Domain, 2) under the
|
||||
conditions of the MIT License (see below), or 3) under the terms of dual
|
||||
Public Domain/MIT License conditions described here, as they choose.
|
||||
|
||||
The MIT License is about as close to Public Domain as a license can get, and is
|
||||
described in clear, concise terms at:
|
||||
|
||||
http://en.wikipedia.org/wiki/MIT_License
|
||||
|
||||
The full text of the MIT License follows:
|
||||
|
||||
========================================================================
|
||||
Copyright (c) 2007-2010 Baptiste Lepilleur
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
========================================================================
|
||||
(END LICENSE TEXT)
|
||||
|
||||
The MIT license is compatible with both the GPL and commercial
|
||||
software, affording one all of the rights of Public Domain with the
|
||||
minor nuisance of being required to keep the above copyright notice
|
||||
and license text in the source code. Note also that by accepting the
|
||||
Public Domain "license" you can re-license your copy using whatever
|
||||
license you like.
|
||||
|
||||
*/
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
// End of content of file: LICENSE
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef JSON_FORWARD_AMALGATED_H_INCLUDED
|
||||
# define JSON_FORWARD_AMALGATED_H_INCLUDED
|
||||
/// If defined, indicates that the source file is amalgated
|
||||
/// to prevent private header inclusion.
|
||||
#define JSON_IS_AMALGAMATION
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
// Beginning of content of file: include/json/config.h
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Copyright 2007-2010 Baptiste Lepilleur
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_CONFIG_H_INCLUDED
|
||||
#define JSON_CONFIG_H_INCLUDED
|
||||
|
||||
/// If defined, indicates that json library is embedded in CppTL library.
|
||||
//# define JSON_IN_CPPTL 1
|
||||
|
||||
/// If defined, indicates that json may leverage CppTL library
|
||||
//# define JSON_USE_CPPTL 1
|
||||
/// If defined, indicates that cpptl vector based map should be used instead of
|
||||
/// std::map
|
||||
/// as Value container.
|
||||
//# define JSON_USE_CPPTL_SMALLMAP 1
|
||||
|
||||
// If non-zero, the library uses exceptions to report bad input instead of C
|
||||
// assertion macros. The default is to use exceptions.
|
||||
#ifndef JSON_USE_EXCEPTION
|
||||
#define JSON_USE_EXCEPTION 1
|
||||
#endif
|
||||
|
||||
/// If defined, indicates that the source file is amalgated
|
||||
/// to prevent private header inclusion.
|
||||
/// Remarks: it is automatically defined in the generated amalgated header.
|
||||
// #define JSON_IS_AMALGAMATION
|
||||
|
||||
#ifdef JSON_IN_CPPTL
|
||||
#include <cpptl/config.h>
|
||||
#ifndef JSON_USE_CPPTL
|
||||
#define JSON_USE_CPPTL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef JSON_IN_CPPTL
|
||||
#define JSON_API CPPTL_API
|
||||
#elif defined(JSON_DLL_BUILD)
|
||||
#if defined(_MSC_VER)
|
||||
#define JSON_API __declspec(dllexport)
|
||||
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
|
||||
#endif // if defined(_MSC_VER)
|
||||
#elif defined(JSON_DLL)
|
||||
#if defined(_MSC_VER)
|
||||
#define JSON_API __declspec(dllimport)
|
||||
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
|
||||
#endif // if defined(_MSC_VER)
|
||||
#endif // ifdef JSON_IN_CPPTL
|
||||
#if !defined(JSON_API)
|
||||
#define JSON_API
|
||||
#endif
|
||||
|
||||
// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
|
||||
// integer
|
||||
// Storages, and 64 bits integer support is disabled.
|
||||
// #define JSON_NO_INT64 1
|
||||
|
||||
#if defined(_MSC_VER) // MSVC
|
||||
# if _MSC_VER <= 1200 // MSVC 6
|
||||
// Microsoft Visual Studio 6 only support conversion from __int64 to double
|
||||
// (no conversion from unsigned __int64).
|
||||
# define JSON_USE_INT64_DOUBLE_CONVERSION 1
|
||||
// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255'
|
||||
// characters in the debug information)
|
||||
// All projects I've ever seen with VS6 were using this globally (not bothering
|
||||
// with pragma push/pop).
|
||||
# pragma warning(disable : 4786)
|
||||
# endif // MSVC 6
|
||||
|
||||
# if _MSC_VER >= 1500 // MSVC 2008
|
||||
/// Indicates that the following function is deprecated.
|
||||
# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
|
||||
# endif
|
||||
|
||||
#endif // defined(_MSC_VER)
|
||||
|
||||
|
||||
#ifndef JSON_HAS_RVALUE_REFERENCES
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010
|
||||
#define JSON_HAS_RVALUE_REFERENCES 1
|
||||
#endif // MSVC >= 2010
|
||||
|
||||
#ifdef __clang__
|
||||
#if __has_feature(cxx_rvalue_references)
|
||||
#define JSON_HAS_RVALUE_REFERENCES 1
|
||||
#endif // has_feature
|
||||
|
||||
#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
|
||||
#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
|
||||
#define JSON_HAS_RVALUE_REFERENCES 1
|
||||
#endif // GXX_EXPERIMENTAL
|
||||
|
||||
#endif // __clang__ || __GNUC__
|
||||
|
||||
#endif // not defined JSON_HAS_RVALUE_REFERENCES
|
||||
|
||||
#ifndef JSON_HAS_RVALUE_REFERENCES
|
||||
#define JSON_HAS_RVALUE_REFERENCES 0
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
|
||||
# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
|
||||
# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message)))
|
||||
# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
|
||||
# define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
|
||||
# endif // GNUC version
|
||||
#endif // __clang__ || __GNUC__
|
||||
|
||||
#if !defined(JSONCPP_DEPRECATED)
|
||||
#define JSONCPP_DEPRECATED(message)
|
||||
#endif // if !defined(JSONCPP_DEPRECATED)
|
||||
|
||||
namespace Json {
|
||||
typedef int Int;
|
||||
typedef unsigned int UInt;
|
||||
#if defined(JSON_NO_INT64)
|
||||
typedef int LargestInt;
|
||||
typedef unsigned int LargestUInt;
|
||||
#undef JSON_HAS_INT64
|
||||
#else // if defined(JSON_NO_INT64)
|
||||
// For Microsoft Visual use specific types as long long is not supported
|
||||
#if defined(_MSC_VER) // Microsoft Visual Studio
|
||||
typedef __int64 Int64;
|
||||
typedef unsigned __int64 UInt64;
|
||||
#else // if defined(_MSC_VER) // Other platforms, use long long
|
||||
typedef long long int Int64;
|
||||
typedef unsigned long long int UInt64;
|
||||
#endif // if defined(_MSC_VER)
|
||||
typedef Int64 LargestInt;
|
||||
typedef UInt64 LargestUInt;
|
||||
#define JSON_HAS_INT64
|
||||
#endif // if defined(JSON_NO_INT64)
|
||||
} // end namespace Json
|
||||
|
||||
#endif // JSON_CONFIG_H_INCLUDED
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
// End of content of file: include/json/config.h
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
// Beginning of content of file: include/json/forwards.h
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Copyright 2007-2010 Baptiste Lepilleur
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_FORWARDS_H_INCLUDED
|
||||
#define JSON_FORWARDS_H_INCLUDED
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
#include "config.h"
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
|
||||
namespace Json {
|
||||
|
||||
// writer.h
|
||||
class FastWriter;
|
||||
class StyledWriter;
|
||||
|
||||
// reader.h
|
||||
class Reader;
|
||||
|
||||
// features.h
|
||||
class Features;
|
||||
|
||||
// value.h
|
||||
typedef unsigned int ArrayIndex;
|
||||
class StaticString;
|
||||
class Path;
|
||||
class PathArgument;
|
||||
class Value;
|
||||
class ValueIteratorBase;
|
||||
class ValueIterator;
|
||||
class ValueConstIterator;
|
||||
|
||||
} // namespace Json
|
||||
|
||||
#endif // JSON_FORWARDS_H_INCLUDED
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
// End of content of file: include/json/forwards.h
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif //ifndef JSON_FORWARD_AMALGATED_H_INCLUDED
|
2077
contrib/openvr/src/json/json.h
Executable file
5266
contrib/openvr/src/jsoncpp.cpp
Executable file
11
contrib/openvr/src/openvr.pc.in
Executable file
|
@ -0,0 +1,11 @@
|
|||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/lib
|
||||
includedir=${prefix}/include/openvr
|
||||
|
||||
Name: openvr
|
||||
Description: OpenVR is an API and runtime that allos access to VR hardware.
|
||||
Version: @OPENVR_VERSION@
|
||||
|
||||
Libs: -L${libdir} -lopenvr_api -ldl
|
||||
Cflags: -I${includedir}
|
356
contrib/openvr/src/openvr_api_public.cpp
Executable file
|
@ -0,0 +1,356 @@
|
|||
//========= Copyright Valve Corporation ============//
|
||||
#define VR_API_EXPORT 1
|
||||
#define VR_API_PUBLIC 1
|
||||
#include "openvr.h"
|
||||
#include "ivrclientcore.h"
|
||||
#include <vrcommon/pathtools_public.h>
|
||||
#include <vrcommon/sharedlibtools_public.h>
|
||||
#include <vrcommon/envvartools_public.h>
|
||||
#include "hmderrors_public.h"
|
||||
#include <vrcommon/strtools_public.h>
|
||||
#include <vrcommon/vrpathregistry_public.h>
|
||||
#include <mutex>
|
||||
|
||||
using vr::EVRInitError;
|
||||
using vr::IVRSystem;
|
||||
using vr::IVRClientCore;
|
||||
using vr::VRInitError_None;
|
||||
|
||||
// figure out how to import from the VR API dll
|
||||
#if defined(_WIN32)
|
||||
#define DYNAMIC_LIB_EXT ".dll"
|
||||
#define PROGRAM_EXT ".exe"
|
||||
|
||||
#if !defined(OPENVR_BUILD_STATIC)
|
||||
#define VR_EXPORT_INTERFACE extern "C" __declspec( dllexport )
|
||||
#else
|
||||
#define VR_EXPORT_INTERFACE extern "C"
|
||||
#endif
|
||||
|
||||
#elif defined(__GNUC__) || defined(COMPILER_GCC) || defined(__APPLE__)
|
||||
|
||||
#define VR_EXPORT_INTERFACE extern "C" __attribute__((visibility("default")))
|
||||
|
||||
#else
|
||||
#error "Unsupported Platform."
|
||||
#endif
|
||||
|
||||
namespace vr
|
||||
{
|
||||
|
||||
static void *g_pVRModule = NULL;
|
||||
static IVRClientCore *g_pHmdSystem = NULL;
|
||||
static std::recursive_mutex g_mutexSystem;
|
||||
|
||||
|
||||
typedef void* (*VRClientCoreFactoryFn)(const char *pInterfaceName, int *pReturnCode);
|
||||
|
||||
static uint32_t g_nVRToken = 0;
|
||||
|
||||
uint32_t VR_GetInitToken()
|
||||
{
|
||||
return g_nVRToken;
|
||||
}
|
||||
|
||||
EVRInitError VR_LoadHmdSystemInternal();
|
||||
void CleanupInternalInterfaces();
|
||||
|
||||
|
||||
uint32_t VR_InitInternal2( EVRInitError *peError, vr::EVRApplicationType eApplicationType, const char *pStartupInfo )
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock( g_mutexSystem );
|
||||
|
||||
EVRInitError err = VR_LoadHmdSystemInternal();
|
||||
if ( err == vr::VRInitError_None )
|
||||
{
|
||||
err = g_pHmdSystem->Init( eApplicationType, pStartupInfo );
|
||||
}
|
||||
|
||||
if ( peError )
|
||||
*peError = err;
|
||||
|
||||
if ( err != VRInitError_None )
|
||||
{
|
||||
SharedLib_Unload( g_pVRModule );
|
||||
g_pHmdSystem = NULL;
|
||||
g_pVRModule = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ++g_nVRToken;
|
||||
}
|
||||
|
||||
VR_INTERFACE uint32_t VR_CALLTYPE VR_InitInternal( EVRInitError *peError, EVRApplicationType eApplicationType );
|
||||
|
||||
uint32_t VR_InitInternal( EVRInitError *peError, vr::EVRApplicationType eApplicationType )
|
||||
{
|
||||
return VR_InitInternal2( peError, eApplicationType, nullptr );
|
||||
}
|
||||
|
||||
void VR_ShutdownInternal()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock( g_mutexSystem );
|
||||
|
||||
#if !defined( VR_API_PUBLIC )
|
||||
CleanupInternalInterfaces();
|
||||
#endif
|
||||
|
||||
if ( g_pHmdSystem )
|
||||
{
|
||||
g_pHmdSystem->Cleanup();
|
||||
g_pHmdSystem = NULL;
|
||||
}
|
||||
|
||||
if ( g_pVRModule )
|
||||
{
|
||||
SharedLib_Unload( g_pVRModule );
|
||||
g_pVRModule = NULL;
|
||||
}
|
||||
|
||||
++g_nVRToken;
|
||||
}
|
||||
|
||||
EVRInitError VR_LoadHmdSystemInternal()
|
||||
{
|
||||
std::string sRuntimePath, sConfigPath, sLogPath;
|
||||
|
||||
bool bReadPathRegistry = CVRPathRegistry_Public::GetPaths( &sRuntimePath, &sConfigPath, &sLogPath, NULL, NULL );
|
||||
if( !bReadPathRegistry )
|
||||
{
|
||||
return vr::VRInitError_Init_PathRegistryNotFound;
|
||||
}
|
||||
|
||||
// figure out where we're going to look for vrclient.dll
|
||||
// see if the specified path actually exists.
|
||||
if( !Path_IsDirectory( sRuntimePath ) )
|
||||
{
|
||||
return vr::VRInitError_Init_InstallationNotFound;
|
||||
}
|
||||
|
||||
// Because we don't have a way to select debug vs. release yet we'll just
|
||||
// use debug if it's there
|
||||
#if defined( LINUX64 ) || defined( LINUXARM64 )
|
||||
std::string sTestPath = Path_Join( sRuntimePath, "bin", PLATSUBDIR );
|
||||
#else
|
||||
std::string sTestPath = Path_Join( sRuntimePath, "bin" );
|
||||
#endif
|
||||
if( !Path_IsDirectory( sTestPath ) )
|
||||
{
|
||||
return vr::VRInitError_Init_InstallationCorrupt;
|
||||
}
|
||||
|
||||
#if defined( WIN64 )
|
||||
std::string sDLLPath = Path_Join( sTestPath, "vrclient_x64" DYNAMIC_LIB_EXT );
|
||||
#else
|
||||
std::string sDLLPath = Path_Join( sTestPath, "vrclient" DYNAMIC_LIB_EXT );
|
||||
#endif
|
||||
|
||||
// only look in the override
|
||||
void *pMod = SharedLib_Load( sDLLPath.c_str() );
|
||||
// nothing more to do if we can't load the DLL
|
||||
if( !pMod )
|
||||
{
|
||||
return vr::VRInitError_Init_VRClientDLLNotFound;
|
||||
}
|
||||
|
||||
VRClientCoreFactoryFn fnFactory = ( VRClientCoreFactoryFn )( SharedLib_GetFunction( pMod, "VRClientCoreFactory" ) );
|
||||
if( !fnFactory )
|
||||
{
|
||||
SharedLib_Unload( pMod );
|
||||
return vr::VRInitError_Init_FactoryNotFound;
|
||||
}
|
||||
|
||||
int nReturnCode = 0;
|
||||
g_pHmdSystem = static_cast< IVRClientCore * > ( fnFactory( vr::IVRClientCore_Version, &nReturnCode ) );
|
||||
if( !g_pHmdSystem )
|
||||
{
|
||||
SharedLib_Unload( pMod );
|
||||
return vr::VRInitError_Init_InterfaceNotFound;
|
||||
}
|
||||
|
||||
g_pVRModule = pMod;
|
||||
return VRInitError_None;
|
||||
}
|
||||
|
||||
|
||||
void *VR_GetGenericInterface(const char *pchInterfaceVersion, EVRInitError *peError)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock( g_mutexSystem );
|
||||
|
||||
if (!g_pHmdSystem)
|
||||
{
|
||||
if (peError)
|
||||
*peError = vr::VRInitError_Init_NotInitialized;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return g_pHmdSystem->GetGenericInterface(pchInterfaceVersion, peError);
|
||||
}
|
||||
|
||||
bool VR_IsInterfaceVersionValid(const char *pchInterfaceVersion)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock( g_mutexSystem );
|
||||
|
||||
if (!g_pHmdSystem)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return g_pHmdSystem->IsInterfaceVersionValid(pchInterfaceVersion) == VRInitError_None;
|
||||
}
|
||||
|
||||
bool VR_IsHmdPresent()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock( g_mutexSystem );
|
||||
|
||||
if( g_pHmdSystem )
|
||||
{
|
||||
// if we're already initialized, just call through
|
||||
return g_pHmdSystem->BIsHmdPresent();
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise we need to do a bit more work
|
||||
EVRInitError err = VR_LoadHmdSystemInternal();
|
||||
if( err != VRInitError_None )
|
||||
return false;
|
||||
|
||||
bool bHasHmd = g_pHmdSystem->BIsHmdPresent();
|
||||
|
||||
g_pHmdSystem = NULL;
|
||||
SharedLib_Unload( g_pVRModule );
|
||||
g_pVRModule = NULL;
|
||||
|
||||
return bHasHmd;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns true if the OpenVR runtime is installed. */
|
||||
bool VR_IsRuntimeInstalled()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock( g_mutexSystem );
|
||||
|
||||
if( g_pHmdSystem )
|
||||
{
|
||||
// if we're already initialized, OpenVR is obviously installed
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise we need to do a bit more work
|
||||
std::string sRuntimePath, sConfigPath, sLogPath;
|
||||
|
||||
bool bReadPathRegistry = CVRPathRegistry_Public::GetPaths( &sRuntimePath, &sConfigPath, &sLogPath, NULL, NULL );
|
||||
if( !bReadPathRegistry )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// figure out where we're going to look for vrclient.dll
|
||||
// see if the specified path actually exists.
|
||||
if( !Path_IsDirectory( sRuntimePath ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// the installation may be corrupt in some way, but it certainly looks installed
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Purpose: This is the old Runtime Path interface that is no longer exported in the
|
||||
// latest header. We still want to export it from the DLL, though, so updating
|
||||
// to a new DLL doesn't break old compiled code. This version was not thread
|
||||
// safe and could change the buffer pointer to by a previous result on a
|
||||
// subsequent call
|
||||
// -------------------------------------------------------------------------------
|
||||
VR_EXPORT_INTERFACE const char *VR_CALLTYPE VR_RuntimePath();
|
||||
|
||||
/** Returns where OpenVR runtime is installed. */
|
||||
const char *VR_RuntimePath()
|
||||
{
|
||||
static char rchBuffer[1024];
|
||||
uint32_t unRequiredSize;
|
||||
if ( VR_GetRuntimePath( rchBuffer, sizeof( rchBuffer ), &unRequiredSize ) && unRequiredSize < sizeof( rchBuffer ) )
|
||||
{
|
||||
return rchBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Returns where OpenVR runtime is installed. */
|
||||
bool VR_GetRuntimePath( char *pchPathBuffer, uint32_t unBufferSize, uint32_t *punRequiredBufferSize )
|
||||
{
|
||||
// otherwise we need to do a bit more work
|
||||
std::string sRuntimePath;
|
||||
|
||||
*punRequiredBufferSize = 0;
|
||||
|
||||
bool bReadPathRegistry = CVRPathRegistry_Public::GetPaths( &sRuntimePath, nullptr, nullptr, nullptr, nullptr );
|
||||
if ( !bReadPathRegistry )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// figure out where we're going to look for vrclient.dll
|
||||
// see if the specified path actually exists.
|
||||
if ( !Path_IsDirectory( sRuntimePath ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*punRequiredBufferSize = (uint32_t)sRuntimePath.size() + 1;
|
||||
if ( sRuntimePath.size() >= unBufferSize )
|
||||
{
|
||||
*pchPathBuffer = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy_safe( pchPathBuffer, unBufferSize, sRuntimePath.c_str() );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** Returns the symbol version of an HMD error. */
|
||||
const char *VR_GetVRInitErrorAsSymbol( EVRInitError error )
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock( g_mutexSystem );
|
||||
|
||||
if( g_pHmdSystem )
|
||||
return g_pHmdSystem->GetIDForVRInitError( error );
|
||||
else
|
||||
return GetIDForVRInitError( error );
|
||||
}
|
||||
|
||||
|
||||
/** Returns the english string version of an HMD error. */
|
||||
const char *VR_GetVRInitErrorAsEnglishDescription( EVRInitError error )
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock( g_mutexSystem );
|
||||
|
||||
if ( g_pHmdSystem )
|
||||
return g_pHmdSystem->GetEnglishStringForHmdError( error );
|
||||
else
|
||||
return GetEnglishStringForHmdError( error );
|
||||
}
|
||||
|
||||
|
||||
VR_INTERFACE const char *VR_CALLTYPE VR_GetStringForHmdError( vr::EVRInitError error );
|
||||
|
||||
/** Returns the english string version of an HMD error. */
|
||||
const char *VR_GetStringForHmdError( EVRInitError error )
|
||||
{
|
||||
return VR_GetVRInitErrorAsEnglishDescription( error );
|
||||
}
|
||||
|
||||
}
|
||||
|
101
contrib/openvr/src/vrcommon/dirtools_public.cpp
Executable file
|
@ -0,0 +1,101 @@
|
|||
//========= Copyright Valve Corporation ============//
|
||||
#include <vrcommon/dirtools_public.h>
|
||||
#include <vrcommon/strtools_public.h>
|
||||
#include <vrcommon/pathtools_public.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "windows.h"
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#if defined( OSX )
|
||||
#include <sys/syslimits.h>
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: utility function to create dirs & subdirs
|
||||
//-----------------------------------------------------------------------------
|
||||
bool BCreateDirectoryRecursive( const char *pchPath )
|
||||
{
|
||||
// Does it already exist?
|
||||
if ( Path_IsDirectory( pchPath ) )
|
||||
return true;
|
||||
|
||||
// copy the path into something we can munge
|
||||
int len = (int)strlen( pchPath );
|
||||
char *path = (char *)malloc( len + 1 );
|
||||
strcpy( path, pchPath );
|
||||
|
||||
// Walk backwards to first non-existing dir that we find
|
||||
char *s = path + len - 1;
|
||||
|
||||
const char slash = Path_GetSlash();
|
||||
while ( s > path )
|
||||
{
|
||||
if ( *s == slash )
|
||||
{
|
||||
*s = '\0';
|
||||
bool bExists = Path_IsDirectory( path );
|
||||
*s = slash;
|
||||
|
||||
if ( bExists )
|
||||
{
|
||||
++s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
--s;
|
||||
}
|
||||
|
||||
// and then move forwards from there
|
||||
|
||||
while ( *s )
|
||||
{
|
||||
if ( *s == slash )
|
||||
{
|
||||
*s = '\0';
|
||||
BCreateDirectory( path );
|
||||
*s = slash;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
|
||||
bool bRetVal = BCreateDirectory( path );
|
||||
free( path );
|
||||
return bRetVal;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Creates the directory, returning true if it is created, or if it already existed
|
||||
//-----------------------------------------------------------------------------
|
||||
bool BCreateDirectory( const char *pchPath )
|
||||
{
|
||||
#ifdef WIN32
|
||||
std::wstring wPath = UTF8to16( pchPath );
|
||||
if ( ::CreateDirectoryW( wPath.c_str(), NULL ) )
|
||||
return true;
|
||||
|
||||
if ( ::GetLastError() == ERROR_ALREADY_EXISTS )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
#else
|
||||
int i = mkdir( pchPath, S_IRWXU | S_IRWXG | S_IRWXO );
|
||||
if ( i == 0 )
|
||||
return true;
|
||||
if ( errno == EEXIST )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
17
contrib/openvr/src/vrcommon/dirtools_public.h
Executable file
|
@ -0,0 +1,17 @@
|
|||
//========= Copyright Valve Corporation ============//
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
|
||||
extern bool BCreateDirectoryRecursive( const char *pchPath );
|
||||
extern bool BCreateDirectory( const char *pchPath );
|
||||
|
||||
|
88
contrib/openvr/src/vrcommon/envvartools_public.cpp
Executable file
|
@ -0,0 +1,88 @@
|
|||
//========= Copyright Valve Corporation ============//
|
||||
#include <vrcommon/envvartools_public.h>
|
||||
#include <vrcommon/strtools_public.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <cctype>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
|
||||
#undef GetEnvironmentVariable
|
||||
#undef SetEnvironmentVariable
|
||||
#endif
|
||||
|
||||
|
||||
std::string GetEnvironmentVariable( const char *pchVarName )
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
char rchValue[32767]; // max size for an env var on Windows
|
||||
DWORD cChars = GetEnvironmentVariableA( pchVarName, rchValue, sizeof( rchValue ) );
|
||||
if( cChars == 0 )
|
||||
return "";
|
||||
else
|
||||
return rchValue;
|
||||
#elif defined(POSIX)
|
||||
char *pchValue = getenv( pchVarName );
|
||||
if( pchValue )
|
||||
return pchValue;
|
||||
else
|
||||
return "";
|
||||
#else
|
||||
#error "Unsupported Platform"
|
||||
#endif
|
||||
}
|
||||
|
||||
bool GetEnvironmentVariableAsBool( const char *pchVarName, bool bDefault )
|
||||
{
|
||||
std::string sValue = GetEnvironmentVariable( pchVarName );
|
||||
|
||||
if ( sValue.empty() )
|
||||
{
|
||||
return bDefault;
|
||||
}
|
||||
|
||||
sValue = StringToLower( sValue );
|
||||
std::string sYesValues[] = { "y", "yes", "true" };
|
||||
std::string sNoValues[] = { "n", "no", "false" };
|
||||
|
||||
for ( std::string &sMatch : sYesValues )
|
||||
{
|
||||
if ( sMatch == sValue )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for ( std::string &sMatch : sNoValues )
|
||||
{
|
||||
if ( sMatch == sValue )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( std::isdigit( sValue.at(0) ) )
|
||||
{
|
||||
return atoi( sValue.c_str() ) != 0;
|
||||
}
|
||||
|
||||
fprintf( stderr,
|
||||
"GetEnvironmentVariableAsBool(%s): Unable to parse value '%s', using default %d\n",
|
||||
pchVarName, sValue.c_str(), bDefault );
|
||||
return bDefault;
|
||||
}
|
||||
|
||||
bool SetEnvironmentVariable( const char *pchVarName, const char *pchVarValue )
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return 0 != SetEnvironmentVariableA( pchVarName, pchVarValue );
|
||||
#elif defined(POSIX)
|
||||
if( pchVarValue == NULL )
|
||||
return 0 == unsetenv( pchVarName );
|
||||
else
|
||||
return 0 == setenv( pchVarName, pchVarValue, 1 );
|
||||
#else
|
||||
#error "Unsupported Platform"
|
||||
#endif
|
||||
}
|
8
contrib/openvr/src/vrcommon/envvartools_public.h
Executable file
|
@ -0,0 +1,8 @@
|
|||
//========= Copyright Valve Corporation ============//
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string GetEnvironmentVariable( const char *pchVarName );
|
||||
bool GetEnvironmentVariableAsBool( const char *pchVarName, bool bDefault );
|
||||
bool SetEnvironmentVariable( const char *pchVarName, const char *pchVarValue );
|
338
contrib/openvr/src/vrcommon/hmderrors_public.cpp
Executable file
|
@ -0,0 +1,338 @@
|
|||
//========= Copyright Valve Corporation ============//
|
||||
#include "openvr.h"
|
||||
#include "hmderrors_public.h"
|
||||
#include <stdio.h>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace vr;
|
||||
|
||||
#define RETURN_ENUM_AS_STRING(enumValue) case enumValue: return #enumValue;
|
||||
|
||||
|
||||
const char *GetEnglishStringForHmdError( vr::EVRInitError eError )
|
||||
{
|
||||
switch( eError )
|
||||
{
|
||||
case VRInitError_None: return "No Error (0)";
|
||||
|
||||
case VRInitError_Init_InstallationNotFound: return "Installation Not Found (100)";
|
||||
case VRInitError_Init_InstallationCorrupt: return "Installation Corrupt (101)";
|
||||
case VRInitError_Init_VRClientDLLNotFound: return "vrclient Shared Lib Not Found (102)";
|
||||
case VRInitError_Init_FileNotFound: return "File Not Found (103)";
|
||||
case VRInitError_Init_FactoryNotFound: return "Factory Function Not Found (104)";
|
||||
case VRInitError_Init_InterfaceNotFound: return "Interface Not Found (105)";
|
||||
case VRInitError_Init_InvalidInterface: return "Invalid Interface (106)";
|
||||
case VRInitError_Init_UserConfigDirectoryInvalid: return "User Config Directory Invalid (107)";
|
||||
case VRInitError_Init_HmdNotFound: return "Hmd Not Found (108)";
|
||||
case VRInitError_Init_NotInitialized: return "Not Initialized (109)";
|
||||
case VRInitError_Init_PathRegistryNotFound: return "Installation path could not be located (110)";
|
||||
case VRInitError_Init_NoConfigPath: return "Config path could not be located (111)";
|
||||
case VRInitError_Init_NoLogPath: return "Log path could not be located (112)";
|
||||
case VRInitError_Init_PathRegistryNotWritable: return "Unable to write path registry (113)";
|
||||
case VRInitError_Init_AppInfoInitFailed: return "App info manager init failed (114)";
|
||||
case VRInitError_Init_Retry: return "Internal Retry (115)";
|
||||
case VRInitError_Init_InitCanceledByUser: return "User Canceled Init (116)";
|
||||
case VRInitError_Init_AnotherAppLaunching: return "Another app was already launching (117)";
|
||||
case VRInitError_Init_SettingsInitFailed: return "Settings manager init failed (118)";
|
||||
case VRInitError_Init_ShuttingDown: return "VR system shutting down (119)";
|
||||
case VRInitError_Init_TooManyObjects: return "Too many tracked objects (120)";
|
||||
case VRInitError_Init_NoServerForBackgroundApp: return "Not starting vrserver for background app (121)";
|
||||
case VRInitError_Init_NotSupportedWithCompositor: return "The requested interface is incompatible with the compositor and the compositor is running (122)";
|
||||
case VRInitError_Init_NotAvailableToUtilityApps: return "This interface is not available to utility applications (123)";
|
||||
case VRInitError_Init_Internal: return "vrserver internal error (124)";
|
||||
case VRInitError_Init_HmdDriverIdIsNone: return "Hmd DriverId is invalid (125)";
|
||||
case VRInitError_Init_HmdNotFoundPresenceFailed: return "Hmd Not Found Presence Failed (126)";
|
||||
case VRInitError_Init_VRMonitorNotFound: return "VR Monitor Not Found (127)";
|
||||
case VRInitError_Init_VRMonitorStartupFailed: return "VR Monitor startup failed (128)";
|
||||
case VRInitError_Init_LowPowerWatchdogNotSupported: return "Low Power Watchdog Not Supported (129)";
|
||||
case VRInitError_Init_InvalidApplicationType: return "Invalid Application Type (130)";
|
||||
case VRInitError_Init_NotAvailableToWatchdogApps: return "Not available to watchdog apps (131)";
|
||||
case VRInitError_Init_WatchdogDisabledInSettings: return "Watchdog disabled in settings (132)";
|
||||
case VRInitError_Init_VRDashboardNotFound: return "VR Dashboard Not Found (133)";
|
||||
case VRInitError_Init_VRDashboardStartupFailed: return "VR Dashboard startup failed (134)";
|
||||
case VRInitError_Init_VRHomeNotFound: return "VR Home Not Found (135)";
|
||||
case VRInitError_Init_VRHomeStartupFailed: return "VR home startup failed (136)";
|
||||
case VRInitError_Init_RebootingBusy: return "Rebooting In Progress (137)";
|
||||
case VRInitError_Init_FirmwareUpdateBusy: return "Firmware Update In Progress (138)";
|
||||
case VRInitError_Init_FirmwareRecoveryBusy: return "Firmware Recovery In Progress (139)";
|
||||
case VRInitError_Init_USBServiceBusy: return "USB Service Busy (140)";
|
||||
|
||||
case VRInitError_Driver_Failed: return "Driver Failed (200)";
|
||||
case VRInitError_Driver_Unknown: return "Driver Not Known (201)";
|
||||
case VRInitError_Driver_HmdUnknown: return "HMD Not Known (202)";
|
||||
case VRInitError_Driver_NotLoaded: return "Driver Not Loaded (203)";
|
||||
case VRInitError_Driver_RuntimeOutOfDate: return "Driver runtime is out of date (204)";
|
||||
case VRInitError_Driver_HmdInUse: return "HMD already in use by another application (205)";
|
||||
case VRInitError_Driver_NotCalibrated: return "Device is not calibrated (206)";
|
||||
case VRInitError_Driver_CalibrationInvalid: return "Device Calibration is invalid (207)";
|
||||
case VRInitError_Driver_HmdDisplayNotFound: return "HMD detected over USB, but Monitor not found (208)";
|
||||
case VRInitError_Driver_TrackedDeviceInterfaceUnknown: return "Driver Tracked Device Interface unknown (209)";
|
||||
// case VRInitError_Driver_HmdDisplayNotFoundAfterFix: return "HMD detected over USB, but Monitor not found after attempt to fix (210)"; // taken out upon Ben's request: He thinks that there is no need to separate that error from 208
|
||||
case VRInitError_Driver_HmdDriverIdOutOfBounds: return "Hmd DriverId is our of bounds (211)";
|
||||
case VRInitError_Driver_HmdDisplayMirrored: return "HMD detected over USB, but Monitor may be mirrored instead of extended (212)";
|
||||
case VRInitError_Driver_HmdDisplayNotFoundLaptop: return "On laptop, HMD detected over USB, but Monitor not found (213)";
|
||||
|
||||
case VRInitError_IPC_ServerInitFailed: return "VR Server Init Failed (300)";
|
||||
case VRInitError_IPC_ConnectFailed: return "Connect to VR Server Failed (301)";
|
||||
case VRInitError_IPC_SharedStateInitFailed: return "Shared IPC State Init Failed (302)";
|
||||
case VRInitError_IPC_CompositorInitFailed: return "Shared IPC Compositor Init Failed (303)";
|
||||
case VRInitError_IPC_MutexInitFailed: return "Shared IPC Mutex Init Failed (304)";
|
||||
case VRInitError_IPC_Failed: return "Shared IPC Failed (305)";
|
||||
case VRInitError_IPC_CompositorConnectFailed: return "Shared IPC Compositor Connect Failed (306)";
|
||||
case VRInitError_IPC_CompositorInvalidConnectResponse: return "Shared IPC Compositor Invalid Connect Response (307)";
|
||||
case VRInitError_IPC_ConnectFailedAfterMultipleAttempts: return "Shared IPC Connect Failed After Multiple Attempts (308)";
|
||||
case VRInitError_IPC_ConnectFailedAfterTargetExited: return "Shared IPC Connect Failed After Target Exited (309)";
|
||||
case VRInitError_IPC_NamespaceUnavailable: return "Shared IPC Namespace Unavailable (310)";
|
||||
|
||||
case VRInitError_Compositor_Failed: return "Compositor failed to initialize (400)";
|
||||
case VRInitError_Compositor_D3D11HardwareRequired: return "Compositor failed to find DX11 hardware (401)";
|
||||
case VRInitError_Compositor_FirmwareRequiresUpdate: return "Compositor requires mandatory firmware update (402)";
|
||||
case VRInitError_Compositor_OverlayInitFailed: return "Compositor initialization succeeded, but overlay init failed (403)";
|
||||
case VRInitError_Compositor_ScreenshotsInitFailed: return "Compositor initialization succeeded, but screenshot init failed (404)";
|
||||
case VRInitError_Compositor_UnableToCreateDevice: return "Compositor unable to create graphics device (405)";
|
||||
|
||||
// Oculus
|
||||
case VRInitError_VendorSpecific_UnableToConnectToOculusRuntime: return "Unable to connect to Oculus Runtime (1000)";
|
||||
case VRInitError_VendorSpecific_OculusRuntimeBadInstall: return "Unable to connect to Oculus Runtime, possible bad install (1114)";
|
||||
|
||||
// Lighthouse
|
||||
case VRInitError_VendorSpecific_HmdFound_CantOpenDevice: return "HMD found, but can not open device (1101)";
|
||||
case VRInitError_VendorSpecific_HmdFound_UnableToRequestConfigStart: return "HMD found, but unable to request config (1102)";
|
||||
case VRInitError_VendorSpecific_HmdFound_NoStoredConfig: return "HMD found, but no stored config (1103)";
|
||||
case VRInitError_VendorSpecific_HmdFound_ConfigFailedSanityCheck: return "HMD found, but failed configuration check (1113)";
|
||||
case VRInitError_VendorSpecific_HmdFound_ConfigTooBig: return "HMD found, but config too big (1104)";
|
||||
case VRInitError_VendorSpecific_HmdFound_ConfigTooSmall: return "HMD found, but config too small (1105)";
|
||||
case VRInitError_VendorSpecific_HmdFound_UnableToInitZLib: return "HMD found, but unable to init ZLib (1106)";
|
||||
case VRInitError_VendorSpecific_HmdFound_CantReadFirmwareVersion: return "HMD found, but problems with the data (1107)";
|
||||
case VRInitError_VendorSpecific_HmdFound_UnableToSendUserDataStart: return "HMD found, but problems with the data (1108)";
|
||||
case VRInitError_VendorSpecific_HmdFound_UnableToGetUserDataStart: return "HMD found, but problems with the data (1109)";
|
||||
case VRInitError_VendorSpecific_HmdFound_UnableToGetUserDataNext: return "HMD found, but problems with the data (1110)";
|
||||
case VRInitError_VendorSpecific_HmdFound_UserDataAddressRange: return "HMD found, but problems with the data (1111)";
|
||||
case VRInitError_VendorSpecific_HmdFound_UserDataError: return "HMD found, but problems with the data (1112)";
|
||||
|
||||
case VRInitError_Steam_SteamInstallationNotFound: return "Unable to find Steam installation (2000)";
|
||||
|
||||
default:
|
||||
return GetIDForVRInitError( eError );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
const char *GetIDForVRInitError( vr::EVRInitError eError )
|
||||
{
|
||||
switch( eError )
|
||||
{
|
||||
RETURN_ENUM_AS_STRING( VRInitError_None );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Unknown );
|
||||
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_InstallationNotFound );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_InstallationCorrupt );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_VRClientDLLNotFound );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_FileNotFound );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_FactoryNotFound );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_InterfaceNotFound );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_InvalidInterface );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_UserConfigDirectoryInvalid );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_HmdNotFound );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_NotInitialized );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_PathRegistryNotFound );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_NoConfigPath );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_NoLogPath );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_PathRegistryNotWritable );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_AppInfoInitFailed );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_Retry );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_InitCanceledByUser );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_AnotherAppLaunching );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_SettingsInitFailed );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_ShuttingDown );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_TooManyObjects );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_NoServerForBackgroundApp );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_NotSupportedWithCompositor );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_NotAvailableToUtilityApps );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_Internal );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_HmdDriverIdIsNone );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_HmdNotFoundPresenceFailed );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_VRMonitorNotFound );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_VRMonitorStartupFailed );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_LowPowerWatchdogNotSupported );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_InvalidApplicationType );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_NotAvailableToWatchdogApps );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_WatchdogDisabledInSettings );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_VRDashboardNotFound );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_VRDashboardStartupFailed );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_VRHomeNotFound );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_VRHomeStartupFailed );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_RebootingBusy );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_FirmwareUpdateBusy );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_FirmwareRecoveryBusy );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_USBServiceBusy );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_VRWebHelperStartupFailed );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_TrackerManagerInitFailed );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_AlreadyRunning );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_FailedForVrMonitor);
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_PropertyManagerInitFailed );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_WebServerFailed );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_IllegalTypeTransition );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_MismatchedRuntimes );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_InvalidProcessId );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_VRServiceStartupFailed );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_PrismNeedsNewDrivers );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_PrismStartupTimedOut );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_CouldNotStartPrism );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_CreateDriverDirectDeviceFailed );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Init_PrismExitedUnexpectedly );
|
||||
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Driver_Failed );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Driver_Unknown );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdUnknown);
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Driver_NotLoaded);
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Driver_RuntimeOutOfDate);
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdInUse);
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Driver_NotCalibrated);
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Driver_CalibrationInvalid);
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdDisplayNotFound);
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Driver_TrackedDeviceInterfaceUnknown );
|
||||
// RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdDisplayNotFoundAfterFix );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdDriverIdOutOfBounds );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdDisplayMirrored );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdDisplayNotFoundLaptop );
|
||||
|
||||
RETURN_ENUM_AS_STRING( VRInitError_IPC_ServerInitFailed);
|
||||
RETURN_ENUM_AS_STRING( VRInitError_IPC_ConnectFailed);
|
||||
RETURN_ENUM_AS_STRING( VRInitError_IPC_SharedStateInitFailed);
|
||||
RETURN_ENUM_AS_STRING( VRInitError_IPC_CompositorInitFailed);
|
||||
RETURN_ENUM_AS_STRING( VRInitError_IPC_MutexInitFailed);
|
||||
RETURN_ENUM_AS_STRING( VRInitError_IPC_Failed);
|
||||
RETURN_ENUM_AS_STRING( VRInitError_IPC_CompositorConnectFailed);
|
||||
RETURN_ENUM_AS_STRING( VRInitError_IPC_CompositorInvalidConnectResponse);
|
||||
RETURN_ENUM_AS_STRING( VRInitError_IPC_ConnectFailedAfterMultipleAttempts );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_IPC_ConnectFailedAfterTargetExited );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_IPC_NamespaceUnavailable );
|
||||
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_Failed );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_D3D11HardwareRequired );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FirmwareRequiresUpdate );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_OverlayInitFailed );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_ScreenshotsInitFailed );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_UnableToCreateDevice );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_SharedStateIsNull );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_NotificationManagerIsNull );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_ResourceManagerClientIsNull );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_MessageOverlaySharedStateInitFailure );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_PropertiesInterfaceIsNull );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateFullscreenWindowFailed );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_SettingsInterfaceIsNull );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToShowWindow );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_DistortInterfaceIsNull );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_DisplayFrequencyFailure );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_RendererInitializationFailed );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_DXGIFactoryInterfaceIsNull );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_DXGIFactoryCreateFailed );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_DXGIFactoryQueryFailed );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_InvalidAdapterDesktop );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_InvalidHmdAttachment );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_InvalidOutputDesktop );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_InvalidDeviceProvided );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_D3D11RendererInitializationFailed );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToFindDisplayMode );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToCreateSwapChain );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToGetBackBuffer );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToCreateRenderTarget );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToCreateDXGI2SwapChain );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedtoGetDXGI2BackBuffer );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToCreateDXGI2RenderTarget );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToGetDXGIDeviceInterface );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_SelectDisplayMode );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToCreateNvAPIRenderTargets );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_NvAPISetDisplayMode );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToCreateDirectModeDisplay );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_InvalidHmdPropertyContainer );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_UpdateDisplayFrequency );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateRasterizerState );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateWireframeRasterizerState );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateSamplerState );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateClampToBorderSamplerState );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateAnisoSamplerState );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateOverlaySamplerState );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreatePanoramaSamplerState );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateFontSamplerState );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateNoBlendState );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateBlendState );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateAlphaBlendState );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateBlendStateMaskR );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateBlendStateMaskG );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateBlendStateMaskB );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateDepthStencilState );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateDepthStencilStateNoWrite );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateDepthStencilStateNoDepth );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateFlushTexture );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateDistortionSurfaces );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateConstantBuffer );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateHmdPoseConstantBuffer );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateHmdPoseStagingConstantBuffer );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateSharedFrameInfoConstantBuffer );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateOverlayConstantBuffer );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateSceneTextureIndexConstantBuffer );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateReadableSceneTextureIndexConstantBuffer );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateLayerGraphicsTextureIndexConstantBuffer );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateLayerComputeTextureIndexConstantBuffer );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateLayerComputeSceneTextureIndexConstantBuffer );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateComputeHmdPoseConstantBuffer );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateGeomConstantBuffer );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreatePanelMaskConstantBuffer );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreatePixelSimUBO );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateMSAARenderTextures );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateResolveRenderTextures );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateComputeResolveRenderTextures );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateDriverDirectModeResolveTextures );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_OpenDriverDirectModeResolveTextures );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateFallbackSyncTexture );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_ShareFallbackSyncTexture );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateOverlayIndexBuffer );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateOverlayVertexBuffer );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateTextVertexBuffer );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateTextIndexBuffer );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateMirrorTextures );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateLastFrameRenderTexture );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateMirrorOverlay );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToCreateVirtualDisplayBackbuffer );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_DisplayModeNotSupported );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateOverlayInvalidCall );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateOverlayAlreadyInitialized );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToCreateMailbox );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_WindowInterfaceIsNull );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_SystemLayerCreateInstance );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Compositor_SystemLayerCreateSession );
|
||||
|
||||
// Vendor-specific errors
|
||||
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_UnableToConnectToOculusRuntime);
|
||||
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_WindowsNotInDevMode );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_OculusRuntimeBadInstall );
|
||||
|
||||
// Lighthouse
|
||||
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_CantOpenDevice);
|
||||
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UnableToRequestConfigStart);
|
||||
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_NoStoredConfig);
|
||||
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_ConfigFailedSanityCheck );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_ConfigTooBig );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_ConfigTooSmall );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UnableToInitZLib );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_CantReadFirmwareVersion );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UnableToSendUserDataStart );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UnableToGetUserDataStart );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UnableToGetUserDataNext );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UserDataAddressRange );
|
||||
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UserDataError );
|
||||
|
||||
RETURN_ENUM_AS_STRING( VRInitError_Steam_SteamInstallationNotFound );
|
||||
|
||||
default:
|
||||
{
|
||||
static char buf[128];
|
||||
sprintf( buf, "Unknown error (%d)", eError );
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
6
contrib/openvr/src/vrcommon/hmderrors_public.h
Executable file
|
@ -0,0 +1,6 @@
|
|||
//========= Copyright Valve Corporation ============//
|
||||
#pragma once
|
||||
|
||||
const char *GetEnglishStringForHmdError( vr::EVRInitError eError );
|
||||
const char *GetIDForVRInitError( vr::EVRInitError eError );
|
||||
|
988
contrib/openvr/src/vrcommon/pathtools_public.cpp
Executable file
|
@ -0,0 +1,988 @@
|
|||
//========= Copyright Valve Corporation ============//
|
||||
#include <vrcommon/strtools_public.h>
|
||||
#include <vrcommon/pathtools_public.h>
|
||||
|
||||
#if defined( _WIN32)
|
||||
#include <windows.h>
|
||||
#include <direct.h>
|
||||
#include <shobjidl.h>
|
||||
#include <knownfolders.h>
|
||||
#include <shlobj.h>
|
||||
#include <share.h>
|
||||
|
||||
#undef GetEnvironmentVariable
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
|
||||
#if defined OSX
|
||||
#include <Foundation/Foundation.h>
|
||||
#include <AppKit/AppKit.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#define _S_IFDIR S_IFDIR // really from tier0/platform.h which we dont have yet
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
/** Returns the path (including filename) to the current executable */
|
||||
std::string Path_GetExecutablePath()
|
||||
{
|
||||
#if defined( _WIN32 )
|
||||
wchar_t *pwchPath = new wchar_t[MAX_UNICODE_PATH];
|
||||
char *pchPath = new char[MAX_UNICODE_PATH_IN_UTF8];
|
||||
::GetModuleFileNameW( NULL, pwchPath, MAX_UNICODE_PATH );
|
||||
WideCharToMultiByte( CP_UTF8, 0, pwchPath, -1, pchPath, MAX_UNICODE_PATH_IN_UTF8, NULL, NULL );
|
||||
delete[] pwchPath;
|
||||
|
||||
std::string sPath = pchPath;
|
||||
delete[] pchPath;
|
||||
return sPath;
|
||||
#elif defined( OSX )
|
||||
char rchPath[1024];
|
||||
uint32_t nBuff = sizeof( rchPath );
|
||||
bool bSuccess = _NSGetExecutablePath(rchPath, &nBuff) == 0;
|
||||
rchPath[nBuff-1] = '\0';
|
||||
if( bSuccess )
|
||||
return rchPath;
|
||||
else
|
||||
return "";
|
||||
#elif defined LINUX
|
||||
char rchPath[1024];
|
||||
size_t nBuff = sizeof( rchPath );
|
||||
ssize_t nRead = readlink("/proc/self/exe", rchPath, nBuff-1 );
|
||||
if ( nRead != -1 )
|
||||
{
|
||||
rchPath[ nRead ] = 0;
|
||||
return rchPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
#else
|
||||
AssertMsg( false, "Implement Plat_GetExecutablePath" );
|
||||
return "";
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/** Returns the path of the current working directory */
|
||||
std::string Path_GetWorkingDirectory()
|
||||
{
|
||||
std::string sPath;
|
||||
#if defined( _WIN32 )
|
||||
wchar_t buf[MAX_UNICODE_PATH];
|
||||
sPath = UTF16to8( _wgetcwd( buf, MAX_UNICODE_PATH ) );
|
||||
#else
|
||||
char buf[ 1024 ];
|
||||
sPath = getcwd( buf, sizeof( buf ) );
|
||||
#endif
|
||||
return sPath;
|
||||
}
|
||||
|
||||
/** Sets the path of the current working directory. Returns true if this was successful. */
|
||||
bool Path_SetWorkingDirectory( const std::string & sPath )
|
||||
{
|
||||
bool bSuccess;
|
||||
#if defined( _WIN32 )
|
||||
std::wstring wsPath = UTF8to16( sPath.c_str() );
|
||||
bSuccess = 0 == _wchdir( wsPath.c_str() );
|
||||
#else
|
||||
bSuccess = 0 == chdir( sPath.c_str() );
|
||||
#endif
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
/** Gets the path to a temporary directory. */
|
||||
std::string Path_GetTemporaryDirectory()
|
||||
{
|
||||
#if defined( _WIN32 )
|
||||
wchar_t buf[MAX_UNICODE_PATH];
|
||||
if ( GetTempPathW( MAX_UNICODE_PATH, buf ) == 0 )
|
||||
return Path_GetWorkingDirectory();
|
||||
return UTF16to8( buf );
|
||||
#else
|
||||
const char *pchTmpDir = getenv( "TMPDIR" );
|
||||
if ( pchTmpDir == NULL )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return pchTmpDir;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Returns the specified path without its filename */
|
||||
std::string Path_StripFilename( const std::string & sPath, char slash )
|
||||
{
|
||||
if( slash == 0 )
|
||||
slash = Path_GetSlash();
|
||||
|
||||
std::string::size_type n = sPath.find_last_of( slash );
|
||||
if( n == std::string::npos )
|
||||
return sPath;
|
||||
else
|
||||
return std::string( sPath.begin(), sPath.begin() + n );
|
||||
}
|
||||
|
||||
/** returns just the filename from the provided full or relative path. */
|
||||
std::string Path_StripDirectory( const std::string & sPath, char slash )
|
||||
{
|
||||
if( slash == 0 )
|
||||
slash = Path_GetSlash();
|
||||
|
||||
std::string::size_type n = sPath.find_last_of( slash );
|
||||
if( n == std::string::npos )
|
||||
return sPath;
|
||||
else
|
||||
return std::string( sPath.begin() + n + 1, sPath.end() );
|
||||
}
|
||||
|
||||
/** returns just the filename with no extension of the provided filename.
|
||||
* If there is a path the path is left intact. */
|
||||
std::string Path_StripExtension( const std::string & sPath )
|
||||
{
|
||||
for( std::string::const_reverse_iterator i = sPath.rbegin(); i != sPath.rend(); i++ )
|
||||
{
|
||||
if( *i == '.' )
|
||||
{
|
||||
return std::string( sPath.begin(), i.base() - 1 );
|
||||
}
|
||||
|
||||
// if we find a slash there is no extension
|
||||
if( *i == '\\' || *i == '/' )
|
||||
break;
|
||||
}
|
||||
|
||||
// we didn't find an extension
|
||||
return sPath;
|
||||
}
|
||||
|
||||
/** returns just extension of the provided filename (if any). */
|
||||
std::string Path_GetExtension( const std::string & sPath )
|
||||
{
|
||||
for ( std::string::const_reverse_iterator i = sPath.rbegin(); i != sPath.rend(); i++ )
|
||||
{
|
||||
if ( *i == '.' )
|
||||
{
|
||||
return std::string( i.base(), sPath.end() );
|
||||
}
|
||||
|
||||
// if we find a slash there is no extension
|
||||
if ( *i == '\\' || *i == '/' )
|
||||
break;
|
||||
}
|
||||
|
||||
// we didn't find an extension
|
||||
return "";
|
||||
}
|
||||
|
||||
bool Path_IsAbsolute( const std::string & sPath )
|
||||
{
|
||||
if( sPath.empty() )
|
||||
return false;
|
||||
|
||||
#ifdef _WIN32
|
||||
if ( sPath.size() < 3 ) // must be c:\x or \\x at least
|
||||
return false;
|
||||
|
||||
if ( sPath[1] == ':' ) // drive letter plus slash, but must test both slash cases
|
||||
{
|
||||
if ( sPath[2] == '\\' || sPath[2] == '/' )
|
||||
return true;
|
||||
}
|
||||
else if ( sPath[0] == '\\' && sPath[1] == '\\' ) // UNC path
|
||||
return true;
|
||||
#else
|
||||
if( sPath[0] == '\\' || sPath[0] == '/' ) // any leading slash
|
||||
return true;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/** Makes an absolute path from a relative path and a base path */
|
||||
std::string Path_MakeAbsolute( const std::string & sRelativePath, const std::string & sBasePath )
|
||||
{
|
||||
if( Path_IsAbsolute( sRelativePath ) )
|
||||
return Path_Compact( sRelativePath );
|
||||
else
|
||||
{
|
||||
if( !Path_IsAbsolute( sBasePath ) )
|
||||
return "";
|
||||
|
||||
std::string sCompacted = Path_Compact( Path_Join( sBasePath, sRelativePath ) );
|
||||
if( Path_IsAbsolute( sCompacted ) )
|
||||
return sCompacted;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Fixes the directory separators for the current platform */
|
||||
std::string Path_FixSlashes( const std::string & sPath, char slash )
|
||||
{
|
||||
if( slash == 0 )
|
||||
slash = Path_GetSlash();
|
||||
|
||||
std::string sFixed = sPath;
|
||||
for( std::string::iterator i = sFixed.begin(); i != sFixed.end(); i++ )
|
||||
{
|
||||
if( *i == '/' || *i == '\\' )
|
||||
*i = slash;
|
||||
}
|
||||
|
||||
return sFixed;
|
||||
}
|
||||
|
||||
|
||||
char Path_GetSlash()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return '\\';
|
||||
#else
|
||||
return '/';
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Jams two paths together with the right kind of slash */
|
||||
std::string Path_Join( const std::string & first, const std::string & second, char slash )
|
||||
{
|
||||
if( slash == 0 )
|
||||
slash = Path_GetSlash();
|
||||
|
||||
// only insert a slash if we don't already have one
|
||||
std::string::size_type nLen = first.length();
|
||||
if( !nLen )
|
||||
return second;
|
||||
#if defined(_WIN32)
|
||||
if( first.back() == '\\' || first.back() == '/' )
|
||||
nLen--;
|
||||
#else
|
||||
char last_char = first[first.length()-1];
|
||||
if (last_char == '\\' || last_char == '/')
|
||||
nLen--;
|
||||
#endif
|
||||
|
||||
return first.substr( 0, nLen ) + std::string( 1, slash ) + second;
|
||||
}
|
||||
|
||||
|
||||
std::string Path_Join( const std::string & first, const std::string & second, const std::string & third, char slash )
|
||||
{
|
||||
return Path_Join( Path_Join( first, second, slash ), third, slash );
|
||||
}
|
||||
|
||||
std::string Path_Join( const std::string & first, const std::string & second, const std::string & third, const std::string &fourth, char slash )
|
||||
{
|
||||
return Path_Join( Path_Join( Path_Join( first, second, slash ), third, slash ), fourth, slash );
|
||||
}
|
||||
|
||||
std::string Path_Join(
|
||||
const std::string & first,
|
||||
const std::string & second,
|
||||
const std::string & third,
|
||||
const std::string & fourth,
|
||||
const std::string & fifth,
|
||||
char slash )
|
||||
{
|
||||
return Path_Join( Path_Join( Path_Join( Path_Join( first, second, slash ), third, slash ), fourth, slash ), fifth, slash );
|
||||
}
|
||||
|
||||
|
||||
std::string Path_RemoveTrailingSlash( const std::string & sRawPath, char slash )
|
||||
{
|
||||
if ( slash == 0 )
|
||||
slash = Path_GetSlash();
|
||||
|
||||
std::string sPath = sRawPath;
|
||||
std::string::size_type nCurrent = sRawPath.length();
|
||||
if ( nCurrent == 0 )
|
||||
return sPath;
|
||||
|
||||
int nLastFound = -1;
|
||||
nCurrent--;
|
||||
while( nCurrent != 0 )
|
||||
{
|
||||
if ( sRawPath[ nCurrent ] == slash )
|
||||
{
|
||||
nLastFound = (int)nCurrent;
|
||||
nCurrent--;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( nLastFound >= 0 )
|
||||
{
|
||||
sPath.erase( nLastFound, std::string::npos );
|
||||
}
|
||||
|
||||
return sPath;
|
||||
}
|
||||
|
||||
|
||||
/** Removes redundant <dir>/.. elements in the path. Returns an empty path if the
|
||||
* specified path has a broken number of directories for its number of ..s */
|
||||
std::string Path_Compact( const std::string & sRawPath, char slash )
|
||||
{
|
||||
if( slash == 0 )
|
||||
slash = Path_GetSlash();
|
||||
|
||||
std::string sPath = Path_FixSlashes( sRawPath, slash );
|
||||
std::string sSlashString( 1, slash );
|
||||
|
||||
// strip out all /./
|
||||
for( std::string::size_type i = 0; (i + 3) < sPath.length(); )
|
||||
{
|
||||
if( sPath[ i ] == slash && sPath[ i+1 ] == '.' && sPath[ i+2 ] == slash )
|
||||
{
|
||||
sPath.replace( i, 3, sSlashString );
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// get rid of trailing /. but leave the path separator
|
||||
if( sPath.length() > 2 )
|
||||
{
|
||||
std::string::size_type len = sPath.length();
|
||||
if( sPath[ len-1 ] == '.' && sPath[ len-2 ] == slash )
|
||||
{
|
||||
sPath.pop_back();
|
||||
//Not sure why the following line of code was used for a while. It causes problems with strlen.
|
||||
//sPath[len-1] = 0; // for now, at least
|
||||
}
|
||||
}
|
||||
|
||||
// get rid of leading ./
|
||||
if( sPath.length() > 2 )
|
||||
{
|
||||
if( sPath[ 0 ] == '.' && sPath[ 1 ] == slash )
|
||||
{
|
||||
sPath.replace( 0, 2, "" );
|
||||
}
|
||||
}
|
||||
|
||||
// each time we encounter .. back up until we've found the previous directory name
|
||||
// then get rid of both
|
||||
std::string::size_type i = 0;
|
||||
while( i < sPath.length() )
|
||||
{
|
||||
if( i > 0 && sPath.length() - i >= 2
|
||||
&& sPath[i] == '.'
|
||||
&& sPath[i+1] == '.'
|
||||
&& ( i + 2 == sPath.length() || sPath[ i+2 ] == slash )
|
||||
&& sPath[ i-1 ] == slash )
|
||||
{
|
||||
// check if we've hit the start of the string and have a bogus path
|
||||
if( i == 1 )
|
||||
return "";
|
||||
|
||||
// find the separator before i-1
|
||||
std::string::size_type iDirStart = i-2;
|
||||
while( iDirStart > 0 && sPath[ iDirStart - 1 ] != slash )
|
||||
--iDirStart;
|
||||
|
||||
// remove everything from iDirStart to i+2
|
||||
sPath.replace( iDirStart, (i - iDirStart) + 3, "" );
|
||||
|
||||
// start over
|
||||
i = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
return sPath;
|
||||
}
|
||||
|
||||
|
||||
/** Returns true if these two paths are the same without respect for internal . or ..
|
||||
* sequences, slash type, or case (on case-insensitive platforms). */
|
||||
bool Path_IsSamePath( const std::string & sPath1, const std::string & sPath2 )
|
||||
{
|
||||
std::string sCompact1 = Path_Compact( sPath1 );
|
||||
std::string sCompact2 = Path_Compact( sPath2 );
|
||||
#if defined(WIN32)
|
||||
return !stricmp( sCompact1.c_str(), sCompact2.c_str() );
|
||||
#else
|
||||
return !strcmp( sCompact1.c_str(), sCompact2.c_str() );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/** Returns the path to the current DLL or exe */
|
||||
std::string Path_GetThisModulePath()
|
||||
{
|
||||
// gets the path of vrclient.dll itself
|
||||
#ifdef WIN32
|
||||
HMODULE hmodule = NULL;
|
||||
|
||||
::GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast<LPCTSTR>(Path_GetThisModulePath), &hmodule );
|
||||
|
||||
wchar_t *pwchPath = new wchar_t[MAX_UNICODE_PATH];
|
||||
char *pchPath = new char[ MAX_UNICODE_PATH_IN_UTF8 ];
|
||||
::GetModuleFileNameW( hmodule, pwchPath, MAX_UNICODE_PATH );
|
||||
WideCharToMultiByte( CP_UTF8, 0, pwchPath, -1, pchPath, MAX_UNICODE_PATH_IN_UTF8, NULL, NULL );
|
||||
delete[] pwchPath;
|
||||
|
||||
std::string sPath = pchPath;
|
||||
delete [] pchPath;
|
||||
return sPath;
|
||||
|
||||
#elif defined( OSX ) || defined( LINUX )
|
||||
// get the addr of a function in vrclient.so and then ask the dlopen system about it
|
||||
Dl_info info;
|
||||
dladdr( (void *)Path_GetThisModulePath, &info );
|
||||
return info.dli_fname;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** returns true if the specified path exists and is a directory */
|
||||
bool Path_IsDirectory( const std::string & sPath )
|
||||
{
|
||||
std::string sFixedPath = Path_FixSlashes( sPath );
|
||||
if( sFixedPath.empty() )
|
||||
return false;
|
||||
char cLast = sFixedPath[ sFixedPath.length() - 1 ];
|
||||
if( cLast == '/' || cLast == '\\' )
|
||||
sFixedPath.erase( sFixedPath.end() - 1, sFixedPath.end() );
|
||||
|
||||
// see if the specified path actually exists.
|
||||
|
||||
#if defined(POSIX)
|
||||
struct stat buf;
|
||||
if ( stat( sFixedPath.c_str(), &buf ) == -1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined( LINUX ) || defined( OSX )
|
||||
return S_ISDIR( buf.st_mode );
|
||||
#else
|
||||
return (buf.st_mode & _S_IFDIR) != 0;
|
||||
#endif
|
||||
|
||||
#else
|
||||
struct _stat buf;
|
||||
std::wstring wsFixedPath = UTF8to16( sFixedPath.c_str() );
|
||||
if ( _wstat( wsFixedPath.c_str(), &buf ) == -1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return (buf.st_mode & _S_IFDIR) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** returns true if the specified path represents an app bundle */
|
||||
bool Path_IsAppBundle( const std::string & sPath )
|
||||
{
|
||||
#if defined(OSX)
|
||||
@autoreleasepool {
|
||||
NSBundle *bundle = [ NSBundle bundleWithPath: [ NSString stringWithUTF8String:sPath.c_str() ] ];
|
||||
bool bisAppBundle = ( nullptr != bundle );
|
||||
return bisAppBundle;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns true if the the path exists
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Path_Exists( const std::string & sPath )
|
||||
{
|
||||
std::string sFixedPath = Path_FixSlashes( sPath );
|
||||
if( sFixedPath.empty() )
|
||||
return false;
|
||||
|
||||
#ifdef _WIN32
|
||||
struct _stat buf;
|
||||
std::wstring wsFixedPath = UTF8to16( sFixedPath.c_str() );
|
||||
if ( _wstat( wsFixedPath.c_str(), &buf ) == -1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
struct stat buf;
|
||||
if ( stat ( sFixedPath.c_str(), &buf ) == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: helper to find a directory upstream from a given path
|
||||
//-----------------------------------------------------------------------------
|
||||
std::string Path_FindParentDirectoryRecursively( const std::string &strStartDirectory, const std::string &strDirectoryName )
|
||||
{
|
||||
std::string strFoundPath = "";
|
||||
std::string strCurrentPath = Path_FixSlashes( strStartDirectory );
|
||||
if ( strCurrentPath.length() == 0 )
|
||||
return "";
|
||||
|
||||
bool bExists = Path_Exists( strCurrentPath );
|
||||
std::string strCurrentDirectoryName = Path_StripDirectory( strCurrentPath );
|
||||
if ( bExists && stricmp( strCurrentDirectoryName.c_str(), strDirectoryName.c_str() ) == 0 )
|
||||
return strCurrentPath;
|
||||
|
||||
while( bExists && strCurrentPath.length() != 0 )
|
||||
{
|
||||
strCurrentPath = Path_StripFilename( strCurrentPath );
|
||||
strCurrentDirectoryName = Path_StripDirectory( strCurrentPath );
|
||||
bExists = Path_Exists( strCurrentPath );
|
||||
if ( bExists && stricmp( strCurrentDirectoryName.c_str(), strDirectoryName.c_str() ) == 0 )
|
||||
return strCurrentPath;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: helper to find a subdirectory upstream from a given path
|
||||
//-----------------------------------------------------------------------------
|
||||
std::string Path_FindParentSubDirectoryRecursively( const std::string &strStartDirectory, const std::string &strDirectoryName )
|
||||
{
|
||||
std::string strFoundPath = "";
|
||||
std::string strCurrentPath = Path_FixSlashes( strStartDirectory );
|
||||
if ( strCurrentPath.length() == 0 )
|
||||
return "";
|
||||
|
||||
bool bExists = Path_Exists( strCurrentPath );
|
||||
while( bExists && strCurrentPath.length() != 0 )
|
||||
{
|
||||
strCurrentPath = Path_StripFilename( strCurrentPath );
|
||||
bExists = Path_Exists( strCurrentPath );
|
||||
|
||||
if( Path_Exists( Path_Join( strCurrentPath, strDirectoryName ) ) )
|
||||
{
|
||||
strFoundPath = Path_Join( strCurrentPath, strDirectoryName );
|
||||
break;
|
||||
}
|
||||
}
|
||||
return strFoundPath;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: reading and writing files in the vortex directory
|
||||
//-----------------------------------------------------------------------------
|
||||
std::vector<uint8_t> Path_ReadBinaryFile( const std::string & strFilename )
|
||||
{
|
||||
FILE *f;
|
||||
#if defined( POSIX )
|
||||
f = fopen( strFilename.c_str(), "rb" );
|
||||
#else
|
||||
std::wstring wstrFilename = UTF8to16( strFilename.c_str() );
|
||||
// the open operation needs to be sharable, therefore use of _wfsopen instead of _wfopen_s
|
||||
f = _wfsopen( wstrFilename.c_str(), L"rb", _SH_DENYNO );
|
||||
#endif
|
||||
|
||||
std::vector<uint8_t> vecFileContents;
|
||||
|
||||
if ( f != NULL )
|
||||
{
|
||||
fseek( f, 0, SEEK_END );
|
||||
int size = ftell( f );
|
||||
fseek( f, 0, SEEK_SET );
|
||||
|
||||
vecFileContents.resize( size );
|
||||
if ( fread( &vecFileContents[ 0 ], size, 1, f ) == 1 )
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
vecFileContents.clear();
|
||||
}
|
||||
|
||||
fclose( f );
|
||||
}
|
||||
|
||||
return vecFileContents ;
|
||||
}
|
||||
|
||||
|
||||
unsigned char * Path_ReadBinaryFile( const std::string &strFilename, int *pSize )
|
||||
{
|
||||
FILE *f;
|
||||
#if defined( POSIX )
|
||||
f = fopen( strFilename.c_str(), "rb" );
|
||||
#else
|
||||
std::wstring wstrFilename = UTF8to16( strFilename.c_str() );
|
||||
// the open operation needs to be sharable, therefore use of _wfsopen instead of _wfopen_s
|
||||
f = _wfsopen( wstrFilename.c_str(), L"rb", _SH_DENYNO );
|
||||
#endif
|
||||
|
||||
unsigned char* buf = NULL;
|
||||
|
||||
if ( f != NULL )
|
||||
{
|
||||
fseek(f, 0, SEEK_END);
|
||||
int size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
buf = new unsigned char[size];
|
||||
if (buf && fread(buf, size, 1, f) == 1)
|
||||
{
|
||||
if (pSize)
|
||||
*pSize = size;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete[] buf;
|
||||
buf = 0;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
uint32_t Path_ReadBinaryFile( const std::string &strFilename, unsigned char *pBuffer, uint32_t unSize )
|
||||
{
|
||||
FILE *f;
|
||||
#if defined( POSIX )
|
||||
f = fopen( strFilename.c_str(), "rb" );
|
||||
#else
|
||||
std::wstring wstrFilename = UTF8to16( strFilename.c_str() );
|
||||
errno_t err = _wfopen_s( &f, wstrFilename.c_str(), L"rb" );
|
||||
if ( err != 0 )
|
||||
{
|
||||
f = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t unSizeToReturn = 0;
|
||||
|
||||
if ( f != NULL )
|
||||
{
|
||||
fseek( f, 0, SEEK_END );
|
||||
uint32_t size = (uint32_t)ftell( f );
|
||||
fseek( f, 0, SEEK_SET );
|
||||
|
||||
if ( size > unSize || !pBuffer )
|
||||
{
|
||||
unSizeToReturn = (uint32_t)size;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( fread( pBuffer, size, 1, f ) == 1 )
|
||||
{
|
||||
unSizeToReturn = (uint32_t)size;
|
||||
}
|
||||
}
|
||||
|
||||
fclose( f );
|
||||
}
|
||||
|
||||
return unSizeToReturn;
|
||||
}
|
||||
|
||||
bool Path_WriteBinaryFile(const std::string &strFilename, unsigned char *pData, unsigned nSize)
|
||||
{
|
||||
FILE *f;
|
||||
#if defined( POSIX )
|
||||
f = fopen(strFilename.c_str(), "wb");
|
||||
#else
|
||||
std::wstring wstrFilename = UTF8to16( strFilename.c_str() );
|
||||
errno_t err = _wfopen_s( &f, wstrFilename.c_str(), L"wb" );
|
||||
if (err != 0)
|
||||
{
|
||||
f = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t written = 0;
|
||||
if (f != NULL) {
|
||||
written = fwrite(pData, sizeof(unsigned char), nSize, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
return written == nSize ? true : false;
|
||||
}
|
||||
|
||||
std::string Path_ReadTextFile( const std::string &strFilename )
|
||||
{
|
||||
// doing it this way seems backwards, but I don't
|
||||
// see an easy way to do this with C/C++ style IO
|
||||
// that isn't worse...
|
||||
int size;
|
||||
unsigned char* buf = Path_ReadBinaryFile( strFilename, &size );
|
||||
if (!buf)
|
||||
return "";
|
||||
|
||||
// convert CRLF -> LF
|
||||
size_t outsize = 1;
|
||||
for (int i=1; i < size; i++)
|
||||
{
|
||||
if (buf[i] == '\n' && buf[i-1] == '\r') // CRLF
|
||||
buf[outsize-1] = '\n'; // ->LF
|
||||
else
|
||||
buf[outsize++] = buf[i]; // just copy
|
||||
}
|
||||
|
||||
std::string ret((char *)buf, outsize);
|
||||
delete[] buf;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool Path_MakeWritable( const std::string &strFilename )
|
||||
{
|
||||
#if defined ( _WIN32 )
|
||||
std::wstring wstrFilename = UTF8to16( strFilename.c_str() );
|
||||
|
||||
DWORD dwAttrs = GetFileAttributesW( wstrFilename.c_str() );
|
||||
if ( dwAttrs != INVALID_FILE_ATTRIBUTES && ( dwAttrs & FILE_ATTRIBUTE_READONLY ) )
|
||||
{
|
||||
return SetFileAttributesW( wstrFilename.c_str(), dwAttrs & ~FILE_ATTRIBUTE_READONLY );
|
||||
}
|
||||
#else
|
||||
struct stat sb;
|
||||
|
||||
if ( stat( strFilename.c_str(), &sb ) == 0 && !( sb.st_mode & S_IWUSR ) )
|
||||
{
|
||||
return ( chmod( strFilename.c_str(), sb.st_mode | S_IWUSR ) == 0 );
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Path_WriteStringToTextFile( const std::string &strFilename, const char *pchData )
|
||||
{
|
||||
FILE *f;
|
||||
#if defined( POSIX )
|
||||
f = fopen( strFilename.c_str(), "w" );
|
||||
#else
|
||||
std::wstring wstrFilename = UTF8to16( strFilename.c_str() );
|
||||
errno_t err = _wfopen_s( &f, wstrFilename.c_str(), L"w" );
|
||||
if ( err != 0 )
|
||||
{
|
||||
f = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ok = false;
|
||||
|
||||
if ( f != NULL )
|
||||
{
|
||||
ok = fputs( pchData, f) >= 0;
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool Path_WriteStringToTextFileAtomic( const std::string &strFilename, const char *pchData )
|
||||
{
|
||||
std::string strTmpFilename = strFilename + ".tmp";
|
||||
|
||||
if ( !Path_WriteStringToTextFile( strTmpFilename, pchData ) )
|
||||
return false;
|
||||
|
||||
// Platform specific atomic file replacement
|
||||
#if defined( _WIN32 )
|
||||
std::wstring wsFilename = UTF8to16( strFilename.c_str() );
|
||||
std::wstring wsTmpFilename = UTF8to16( strTmpFilename.c_str() );
|
||||
if ( !::ReplaceFileW( wsFilename.c_str(), wsTmpFilename.c_str(), nullptr, 0, 0, 0 ) )
|
||||
{
|
||||
// if we couldn't ReplaceFile, try a non-atomic write as a fallback
|
||||
if ( !Path_WriteStringToTextFile( strFilename, pchData ) )
|
||||
return false;
|
||||
}
|
||||
#elif defined( POSIX )
|
||||
if ( rename( strTmpFilename.c_str(), strFilename.c_str() ) == -1 )
|
||||
return false;
|
||||
#else
|
||||
#error Do not know how to write atomic file
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#if defined(WIN32)
|
||||
#define FILE_URL_PREFIX "file:///"
|
||||
#else
|
||||
#define FILE_URL_PREFIX "file://"
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------------------------------
|
||||
// Purpose: Turns a path to a file on disk into a URL (or just returns the value if it's already a URL)
|
||||
// ----------------------------------------------------------------------------------------------------------------------------
|
||||
std::string Path_FilePathToUrl( const std::string & sRelativePath, const std::string & sBasePath )
|
||||
{
|
||||
if ( StringHasPrefix( sRelativePath, "http://" )
|
||||
|| StringHasPrefix( sRelativePath, "https://" )
|
||||
|| StringHasPrefix( sRelativePath, "vr-input-workshop://" )
|
||||
|| StringHasPrefix( sRelativePath, "file://" )
|
||||
)
|
||||
{
|
||||
return sRelativePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string sAbsolute = Path_MakeAbsolute( sRelativePath, sBasePath );
|
||||
if ( sAbsolute.empty() )
|
||||
return sAbsolute;
|
||||
sAbsolute = Path_FixSlashes( sAbsolute, '/' );
|
||||
|
||||
size_t unBufferSize = sAbsolute.length() * 3;
|
||||
char *pchBuffer = (char *)alloca( unBufferSize );
|
||||
V_URLEncodeFullPath( pchBuffer, (int)unBufferSize, sAbsolute.c_str(), (int)sAbsolute.length() );
|
||||
|
||||
return std::string( FILE_URL_PREFIX ) + pchBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// Purpose: Strips off file:// off a URL and returns the path. For other kinds of URLs an empty string is returned
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
std::string Path_UrlToFilePath( const std::string & sFileUrl )
|
||||
{
|
||||
if ( !strnicmp( sFileUrl.c_str(), FILE_URL_PREFIX, strlen( FILE_URL_PREFIX ) ) )
|
||||
{
|
||||
char *pchBuffer = (char *)alloca( sFileUrl.length() );
|
||||
V_URLDecodeNoPlusForSpace( pchBuffer, (int)sFileUrl.length(),
|
||||
sFileUrl.c_str() + strlen( FILE_URL_PREFIX ), (int)( sFileUrl.length() - strlen( FILE_URL_PREFIX ) ) );
|
||||
|
||||
return Path_FixSlashes( pchBuffer );
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// Purpose: Returns the root of the directory the system wants us to store user documents in
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
std::string GetUserDocumentsPath()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WCHAR rwchPath[MAX_PATH];
|
||||
|
||||
if ( !SUCCEEDED( SHGetFolderPathW( NULL, CSIDL_MYDOCUMENTS | CSIDL_FLAG_CREATE, NULL, 0, rwchPath ) ) )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
// Convert the path to UTF-8 and store in the output
|
||||
std::string sUserPath = UTF16to8( rwchPath );
|
||||
|
||||
return sUserPath;
|
||||
#elif defined( OSX )
|
||||
@autoreleasepool {
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES );
|
||||
if ( [paths count] == 0 )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
return [[paths objectAtIndex:0] UTF8String];
|
||||
}
|
||||
#elif defined( LINUX )
|
||||
// @todo: not solved/changed as part of OSX - still not real - just removed old class based steam cut and paste
|
||||
const char *pchHome = getenv( "HOME" );
|
||||
if ( pchHome == NULL )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return pchHome;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// Purpose: deletes / unlinks a single file
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
bool Path_UnlinkFile( const std::string &strFilename )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
std::wstring wsFilename = UTF8to16( strFilename.c_str() );
|
||||
return ( 0 != DeleteFileW( wsFilename.c_str() ) );
|
||||
#else
|
||||
return ( 0 == unlink( strFilename.c_str() ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// Limits the set of characters that are allowed in filenames
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
std::string Path_SanitizeFilename( const std::string& sFilename )
|
||||
{
|
||||
std::string sFixed = sFilename;
|
||||
std::string::iterator iLastDot = sFixed.end();
|
||||
for ( std::string::iterator i = sFixed.begin(); i != sFixed.end(); i++ )
|
||||
{
|
||||
if ( *i == '.' )
|
||||
{
|
||||
iLastDot = i;
|
||||
}
|
||||
|
||||
// path-related characters are forbidden (except the last period)
|
||||
switch ( *i )
|
||||
{
|
||||
case '\0':
|
||||
case '.':
|
||||
case '\\':
|
||||
case '/':
|
||||
case ':':
|
||||
case '|':
|
||||
case '?':
|
||||
case '>':
|
||||
case '<':
|
||||
case '&':
|
||||
case '%':
|
||||
case '@':
|
||||
case '$':
|
||||
case '*':
|
||||
case '\"':
|
||||
*i = '_';
|
||||
break;
|
||||
|
||||
default:
|
||||
if ( *i < 32 )
|
||||
{
|
||||
*i = '_';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( iLastDot != sFixed.end() && iLastDot != sFixed.begin()
|
||||
&& iLastDot+1 != sFixed.end() )
|
||||
{
|
||||
*iLastDot = '.';
|
||||
}
|
||||
|
||||
return sFixed;
|
||||
}
|
153
contrib/openvr/src/vrcommon/pathtools_public.h
Executable file
|
@ -0,0 +1,153 @@
|
|||
//========= Copyright Valve Corporation ============//
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
|
||||
/** Returns the path (including filename) to the current executable */
|
||||
std::string Path_GetExecutablePath();
|
||||
|
||||
/** Returns the path of the current working directory */
|
||||
std::string Path_GetWorkingDirectory();
|
||||
|
||||
/** Sets the path of the current working directory. Returns true if this was successful. */
|
||||
bool Path_SetWorkingDirectory( const std::string & sPath );
|
||||
|
||||
/** Gets the path to a temporary directory. */
|
||||
std::string Path_GetTemporaryDirectory();
|
||||
|
||||
/** returns the path (including filename) of the current shared lib or DLL */
|
||||
std::string Path_GetThisModulePath();
|
||||
|
||||
/** Returns the specified path without its filename.
|
||||
* If slash is unspecified the native path separator of the current platform
|
||||
* will be used. */
|
||||
std::string Path_StripFilename( const std::string & sPath, char slash = 0 );
|
||||
|
||||
/** returns just the filename from the provided full or relative path. */
|
||||
std::string Path_StripDirectory( const std::string & sPath, char slash = 0 );
|
||||
|
||||
/** returns just the filename with no extension of the provided filename.
|
||||
* If there is a path the path is left intact. */
|
||||
std::string Path_StripExtension( const std::string & sPath );
|
||||
|
||||
/** returns just extension of the provided filename (if any). */
|
||||
std::string Path_GetExtension( const std::string & sPath );
|
||||
|
||||
/** Returns true if the path is absolute */
|
||||
bool Path_IsAbsolute( const std::string & sPath );
|
||||
|
||||
/** Makes an absolute path from a relative path and a base path */
|
||||
std::string Path_MakeAbsolute( const std::string & sRelativePath, const std::string & sBasePath );
|
||||
|
||||
/** Fixes the directory separators for the current platform.
|
||||
* If slash is unspecified the native path separator of the current platform
|
||||
* will be used. */
|
||||
std::string Path_FixSlashes( const std::string & sPath, char slash = 0 );
|
||||
|
||||
/** Returns the path separator for the current platform */
|
||||
char Path_GetSlash();
|
||||
|
||||
/** Jams two paths together with the right kind of slash */
|
||||
std::string Path_Join( const std::string & first, const std::string & second, char slash = 0 );
|
||||
std::string Path_Join( const std::string & first, const std::string & second, const std::string & third, char slash = 0 );
|
||||
std::string Path_Join( const std::string & first, const std::string & second, const std::string & third, const std::string &fourth, char slash = 0 );
|
||||
std::string Path_Join(
|
||||
const std::string & first,
|
||||
const std::string & second,
|
||||
const std::string & third,
|
||||
const std::string & fourth,
|
||||
const std::string & fifth,
|
||||
char slash = 0 );
|
||||
|
||||
|
||||
/** Removes redundant <dir>/.. elements in the path. Returns an empty path if the
|
||||
* specified path has a broken number of directories for its number of ..s.
|
||||
* If slash is unspecified the native path separator of the current platform
|
||||
* will be used. */
|
||||
std::string Path_Compact( const std::string & sRawPath, char slash = 0 );
|
||||
|
||||
/** Returns true if these two paths are the same without respect for internal . or ..
|
||||
* sequences, slash type, or case (on case-insensitive platforms). */
|
||||
bool Path_IsSamePath( const std::string & sPath1, const std::string & sPath2 );
|
||||
|
||||
//** Removed trailing slashes */
|
||||
std::string Path_RemoveTrailingSlash( const std::string & sRawPath, char slash = 0 );
|
||||
|
||||
/** returns true if the specified path exists and is a directory */
|
||||
bool Path_IsDirectory( const std::string & sPath );
|
||||
|
||||
/** returns true if the specified path represents an app bundle */
|
||||
bool Path_IsAppBundle( const std::string & sPath );
|
||||
|
||||
/** returns true if the the path exists */
|
||||
bool Path_Exists( const std::string & sPath );
|
||||
|
||||
/** Helper functions to find parent directories or subdirectories of parent directories */
|
||||
std::string Path_FindParentDirectoryRecursively( const std::string &strStartDirectory, const std::string &strDirectoryName );
|
||||
std::string Path_FindParentSubDirectoryRecursively( const std::string &strStartDirectory, const std::string &strDirectoryName );
|
||||
|
||||
/** Make a text file writable. */
|
||||
bool Path_MakeWritable( const std::string &strFilename );
|
||||
|
||||
/** Path operations to read or write text/binary files */
|
||||
unsigned char * Path_ReadBinaryFile( const std::string &strFilename, int *pSize );
|
||||
uint32_t Path_ReadBinaryFile( const std::string &strFilename, unsigned char *pBuffer, uint32_t unSize );
|
||||
std::vector<uint8_t> Path_ReadBinaryFile( const std::string & strFilename );
|
||||
bool Path_WriteBinaryFile( const std::string &strFilename, unsigned char *pData, unsigned nSize );
|
||||
std::string Path_ReadTextFile( const std::string &strFilename );
|
||||
bool Path_WriteStringToTextFile( const std::string &strFilename, const char *pchData );
|
||||
bool Path_WriteStringToTextFileAtomic( const std::string &strFilename, const char *pchData );
|
||||
|
||||
/** Returns a file:// url for paths, or an http or https url if that's what was provided */
|
||||
std::string Path_FilePathToUrl( const std::string & sRelativePath, const std::string & sBasePath );
|
||||
|
||||
/** Strips off file:// off a URL and returns the path. For other kinds of URLs an empty string is returned */
|
||||
std::string Path_UrlToFilePath( const std::string & sFileUrl );
|
||||
|
||||
/** Returns the root of the directory the system wants us to store user documents in */
|
||||
std::string GetUserDocumentsPath();
|
||||
|
||||
/** deletes / unlinks a single file */
|
||||
bool Path_UnlinkFile( const std::string &strFilename );
|
||||
|
||||
std::string Path_SanitizeFilename( const std::string& sFilename );
|
||||
|
||||
#ifndef MAX_UNICODE_PATH
|
||||
#define MAX_UNICODE_PATH 32767
|
||||
#endif
|
||||
|
||||
#ifndef MAX_UNICODE_PATH_IN_UTF8
|
||||
#define MAX_UNICODE_PATH_IN_UTF8 (MAX_UNICODE_PATH * 4)
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
#if defined(WIN32)
|
||||
#define DYNAMIC_LIB_EXT ".dll"
|
||||
#define PROGRAM_EXT ".exe"
|
||||
#ifdef _WIN64
|
||||
#define PLATSUBDIR "win64"
|
||||
#else
|
||||
#define PLATSUBDIR "win32"
|
||||
#endif
|
||||
#elif defined(OSX)
|
||||
#define DYNAMIC_LIB_EXT ".dylib"
|
||||
#define PLATSUBDIR "osx32"
|
||||
#define PROGRAM_EXT ""
|
||||
#elif defined(LINUX)
|
||||
#define DYNAMIC_LIB_EXT ".so"
|
||||
#define PROGRAM_EXT ""
|
||||
#if defined( LINUX32 )
|
||||
#define PLATSUBDIR "linux32"
|
||||
#elif defined( ANDROIDARM64 )
|
||||
#define PLATSUBDIR "androidarm64"
|
||||
#elif defined( LINUXARM64 )
|
||||
#define PLATSUBDIR "linuxarm64"
|
||||
#else
|
||||
#define PLATSUBDIR "linux64"
|
||||
#endif
|
||||
#else
|
||||
#warning "Unknown platform for PLATSUBDIR"
|
||||
#define PLATSUBDIR "unknown_platform"
|
||||
#endif
|
63
contrib/openvr/src/vrcommon/sharedlibtools_public.cpp
Executable file
|
@ -0,0 +1,63 @@
|
|||
//========= Copyright Valve Corporation ============//
|
||||
#include <vrcommon/sharedlibtools_public.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined(POSIX)
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
|
||||
SharedLibHandle SharedLib_Load( const char *pchPath, uint32_t *pErrorCode )
|
||||
{
|
||||
SharedLibHandle pHandle = nullptr;
|
||||
#if defined( _WIN32)
|
||||
pHandle = ( SharedLibHandle )LoadLibraryEx( pchPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
|
||||
#elif defined(POSIX)
|
||||
pHandle = (SharedLibHandle) dlopen(pchPath, RTLD_LOCAL|RTLD_NOW);
|
||||
#endif
|
||||
|
||||
if ( pErrorCode )
|
||||
{
|
||||
if ( pHandle == nullptr )
|
||||
{
|
||||
#if defined( _WIN32)
|
||||
*pErrorCode = ( uint32_t ) GetLastError();
|
||||
#elif defined(POSIX)
|
||||
*pErrorCode = 1;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
*pErrorCode = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return pHandle;
|
||||
}
|
||||
|
||||
void *SharedLib_GetFunction( SharedLibHandle lib, const char *pchFunctionName)
|
||||
{
|
||||
#if defined( _WIN32)
|
||||
return (void*)GetProcAddress( (HMODULE)lib, pchFunctionName );
|
||||
#elif defined(POSIX)
|
||||
return dlsym( lib, pchFunctionName );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void SharedLib_Unload( SharedLibHandle lib )
|
||||
{
|
||||
if ( !lib )
|
||||
return;
|
||||
#if defined( _WIN32)
|
||||
FreeLibrary( (HMODULE)lib );
|
||||
#elif defined(POSIX)
|
||||
dlclose( lib );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
12
contrib/openvr/src/vrcommon/sharedlibtools_public.h
Executable file
|
@ -0,0 +1,12 @@
|
|||
//========= Copyright Valve Corporation ============//
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef void *SharedLibHandle;
|
||||
|
||||
SharedLibHandle SharedLib_Load( const char *pchPath, uint32_t *pErrorCode = nullptr );
|
||||
void *SharedLib_GetFunction( SharedLibHandle lib, const char *pchFunctionName);
|
||||
void SharedLib_Unload( SharedLibHandle lib );
|
||||
|
||||
|
606
contrib/openvr/src/vrcommon/strtools_public.cpp
Executable file
|
@ -0,0 +1,606 @@
|
|||
//========= Copyright Valve Corporation ============//
|
||||
#include <vrcommon/strtools_public.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sstream>
|
||||
#include <codecvt>
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
#include <locale>
|
||||
#include <codecvt>
|
||||
#include <stdarg.h>
|
||||
|
||||
#if defined( _WIN32 )
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined( OSX ) || defined( LINUX )
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: stricmp -> strcasecmp bridge
|
||||
//-----------------------------------------------------------------------------
|
||||
int stricmp( const char *pStr1, const char *pStr2 )
|
||||
{
|
||||
return strcasecmp( pStr1, pStr2 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: strincmp -> strncasecmp bridge
|
||||
//-----------------------------------------------------------------------------
|
||||
int strnicmp( const char *pStr1, const char *pStr2, size_t unBufferLen )
|
||||
{
|
||||
return strncasecmp( pStr1, pStr2, unBufferLen );
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool StringHasPrefix( const std::string & sString, const std::string & sPrefix )
|
||||
{
|
||||
return 0 == strnicmp( sString.c_str(), sPrefix.c_str(), sPrefix.length() );
|
||||
}
|
||||
|
||||
bool StringHasPrefixCaseSensitive( const std::string & sString, const std::string & sPrefix )
|
||||
{
|
||||
return 0 == strncmp( sString.c_str(), sPrefix.c_str(), sPrefix.length() );
|
||||
}
|
||||
|
||||
|
||||
bool StringHasSuffix( const std::string &sString, const std::string &sSuffix )
|
||||
{
|
||||
size_t cStrLen = sString.length();
|
||||
size_t cSuffixLen = sSuffix.length();
|
||||
|
||||
if ( cSuffixLen > cStrLen )
|
||||
return false;
|
||||
|
||||
std::string sStringSuffix = sString.substr( cStrLen - cSuffixLen, cSuffixLen );
|
||||
|
||||
return 0 == stricmp( sStringSuffix.c_str(), sSuffix.c_str() );
|
||||
}
|
||||
|
||||
bool StringHasSuffixCaseSensitive( const std::string &sString, const std::string &sSuffix )
|
||||
{
|
||||
size_t cStrLen = sString.length();
|
||||
size_t cSuffixLen = sSuffix.length();
|
||||
|
||||
if ( cSuffixLen > cStrLen )
|
||||
return false;
|
||||
|
||||
std::string sStringSuffix = sString.substr( cStrLen - cSuffixLen, cSuffixLen );
|
||||
|
||||
return 0 == strncmp( sStringSuffix.c_str(), sSuffix.c_str(),cSuffixLen );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef std::codecvt_utf8< wchar_t > convert_type;
|
||||
|
||||
std::string UTF16to8(const wchar_t * in)
|
||||
{
|
||||
static std::wstring_convert< convert_type, wchar_t > s_converter; // construction of this can be expensive (or even serialized) depending on locale
|
||||
|
||||
try
|
||||
{
|
||||
return s_converter.to_bytes( in );
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
std::string UTF16to8( const std::wstring & in ) { return UTF16to8( in.c_str() ); }
|
||||
|
||||
|
||||
std::wstring UTF8to16(const char * in)
|
||||
{
|
||||
static std::wstring_convert< convert_type, wchar_t > s_converter; // construction of this can be expensive (or even serialized) depending on locale
|
||||
|
||||
try
|
||||
{
|
||||
return s_converter.from_bytes( in );
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
return std::wstring();
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring UTF8to16( const std::string & in ) { return UTF8to16( in.c_str() ); }
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Format string to std::string converter
|
||||
//-----------------------------------------------------------------------------
|
||||
std::string Format( const char *pchFormat, ... )
|
||||
{
|
||||
static constexpr size_t k_ulMaxStackString = 4096;
|
||||
|
||||
va_list args;
|
||||
char pchBuffer[k_ulMaxStackString];
|
||||
|
||||
va_start( args, pchFormat );
|
||||
int unSize = vsnprintf( pchBuffer, sizeof( pchBuffer ), pchFormat, args );
|
||||
va_end( args );
|
||||
|
||||
// Something went fairly wrong
|
||||
if ( unSize < 0 )
|
||||
{
|
||||
//AssertMsg( false, "Format string parse failure" );
|
||||
return "";
|
||||
}
|
||||
|
||||
// Processing on the stack worked, success
|
||||
if ( unSize < k_ulMaxStackString )
|
||||
{
|
||||
return pchBuffer;
|
||||
}
|
||||
|
||||
// If processing on the stack failed, fallback to a dynamic allocation
|
||||
std::vector< char > vecChar{};
|
||||
vecChar.resize( unSize + 1 );
|
||||
|
||||
va_start( args, pchFormat );
|
||||
unSize = vsnprintf( vecChar.data(), vecChar.size(), pchFormat, args );
|
||||
va_end( args );
|
||||
|
||||
// Double check, just in case
|
||||
if ( unSize < 0 )
|
||||
{
|
||||
//AssertMsg( false, "Format string parse failure" );
|
||||
return "";
|
||||
}
|
||||
|
||||
return vecChar.data();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#if defined( _WIN32 )
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Convert LPSTR in the default CodePage to UTF8
|
||||
//-----------------------------------------------------------------------------
|
||||
std::string DefaultACPtoUTF8( const char *pszStr )
|
||||
{
|
||||
if ( GetACP() == CP_UTF8 )
|
||||
{
|
||||
return pszStr;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<wchar_t> vecBuf( strlen( pszStr ) + 1 ); // should be guaranteed to be enough
|
||||
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pszStr, -1, vecBuf.data(), (int) vecBuf.size() );
|
||||
return UTF16to8( vecBuf.data() );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// --------------------------------------------------------------------
|
||||
void strcpy_safe( char *pchBuffer, size_t unBufferSizeBytes, const char *pchSource )
|
||||
{
|
||||
strncpy( pchBuffer, pchSource, unBufferSizeBytes - 1 );
|
||||
pchBuffer[unBufferSizeBytes - 1] = '\0';
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Purpose: converts a string to upper case
|
||||
// --------------------------------------------------------------------
|
||||
std::string StringToUpper( const std::string & sString )
|
||||
{
|
||||
std::string sOut;
|
||||
sOut.reserve( sString.size() + 1 );
|
||||
for( std::string::const_iterator i = sString.begin(); i != sString.end(); i++ )
|
||||
{
|
||||
sOut.push_back( (char)toupper( *i ) );
|
||||
}
|
||||
|
||||
return sOut;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Purpose: converts a string to lower case
|
||||
// --------------------------------------------------------------------
|
||||
std::string StringToLower( const std::string & sString )
|
||||
{
|
||||
std::string sOut;
|
||||
sOut.reserve( sString.size() + 1 );
|
||||
for( std::string::const_iterator i = sString.begin(); i != sString.end(); i++ )
|
||||
{
|
||||
sOut.push_back( (char)tolower( *i ) );
|
||||
}
|
||||
|
||||
return sOut;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ReturnStdString( const std::string & sValue, char *pchBuffer, uint32_t unBufferLen )
|
||||
{
|
||||
uint32_t unLen = (uint32_t)sValue.length() + 1;
|
||||
if( !pchBuffer || !unBufferLen )
|
||||
return unLen;
|
||||
|
||||
if( unBufferLen < unLen )
|
||||
{
|
||||
pchBuffer[0] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy( pchBuffer, sValue.c_str(), unLen );
|
||||
}
|
||||
|
||||
return unLen;
|
||||
}
|
||||
|
||||
|
||||
/** Returns a std::string from a uint64_t */
|
||||
std::string Uint64ToString( uint64_t ulValue )
|
||||
{
|
||||
char buf[ 22 ];
|
||||
#if defined( _WIN32 )
|
||||
sprintf_s( buf, "%llu", ulValue );
|
||||
#else
|
||||
snprintf( buf, sizeof( buf ), "%llu", (long long unsigned int ) ulValue );
|
||||
#endif
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/** returns a uint64_t from a string */
|
||||
uint64_t StringToUint64( const std::string & sValue )
|
||||
{
|
||||
return strtoull( sValue.c_str(), NULL, 0 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Helper for converting a numeric value to a hex digit, value should be 0-15.
|
||||
//-----------------------------------------------------------------------------
|
||||
char cIntToHexDigit( int nValue )
|
||||
{
|
||||
//Assert( nValue >= 0 && nValue <= 15 );
|
||||
return "0123456789ABCDEF"[ nValue & 15 ];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Helper for converting a hex char value to numeric, return -1 if the char
|
||||
// is not a valid hex digit.
|
||||
//-----------------------------------------------------------------------------
|
||||
int iHexCharToInt( char cValue )
|
||||
{
|
||||
int32_t iValue = cValue;
|
||||
if ( (uint32_t)( iValue - '0' ) < 10 )
|
||||
return iValue - '0';
|
||||
|
||||
iValue |= 0x20;
|
||||
if ( (uint32_t)( iValue - 'a' ) < 6 )
|
||||
return iValue - 'a' + 10;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: These define the set of characters to filter for components (which
|
||||
// need all the escaping we can muster) vs. paths (which don't want
|
||||
// / and : escaped so we don't break less compliant URL handling code.
|
||||
//-----------------------------------------------------------------------------
|
||||
static bool CharNeedsEscape_Component( const char c )
|
||||
{
|
||||
return (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9')
|
||||
&& c != '-' && c != '_' && c != '.');
|
||||
}
|
||||
static bool CharNeedsEscape_FullPath( const char c )
|
||||
{
|
||||
return (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9')
|
||||
&& c != '-' && c != '_' && c != '.' && c != '/' && c != ':' );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Internal implementation of encode, works in the strict RFC manner, or
|
||||
// with spaces turned to + like HTML form encoding.
|
||||
//-----------------------------------------------------------------------------
|
||||
void V_URLEncodeInternal( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen,
|
||||
bool bUsePlusForSpace, std::function< bool(const char)> fnNeedsEscape )
|
||||
{
|
||||
//AssertMsg( nDestLen > 3*nSourceLen, "Target buffer for V_URLEncode should be 3x source length, plus one for terminating null\n" );
|
||||
|
||||
int iDestPos = 0;
|
||||
for ( int i=0; i < nSourceLen; ++i )
|
||||
{
|
||||
// worst case we need 3 additional chars
|
||||
if( (iDestPos+3) > nDestLen )
|
||||
{
|
||||
pchDest[0] = '\0';
|
||||
// AssertMsg( false, "Target buffer too short\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
// We allow only a-z, A-Z, 0-9, period, underscore, and hyphen to pass through unescaped.
|
||||
// These are the characters allowed by both the original RFC 1738 and the latest RFC 3986.
|
||||
// Current specs also allow '~', but that is forbidden under original RFC 1738.
|
||||
if ( fnNeedsEscape( pchSource[i] ) )
|
||||
{
|
||||
if ( bUsePlusForSpace && pchSource[i] == ' ' )
|
||||
{
|
||||
pchDest[iDestPos++] = '+';
|
||||
}
|
||||
else
|
||||
{
|
||||
pchDest[iDestPos++] = '%';
|
||||
uint8_t iValue = pchSource[i];
|
||||
if ( iValue == 0 )
|
||||
{
|
||||
pchDest[iDestPos++] = '0';
|
||||
pchDest[iDestPos++] = '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
char cHexDigit1 = cIntToHexDigit( iValue % 16 );
|
||||
iValue /= 16;
|
||||
char cHexDigit2 = cIntToHexDigit( iValue );
|
||||
pchDest[iDestPos++] = cHexDigit2;
|
||||
pchDest[iDestPos++] = cHexDigit1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pchDest[iDestPos++] = pchSource[i];
|
||||
}
|
||||
}
|
||||
|
||||
if( (iDestPos+1) > nDestLen )
|
||||
{
|
||||
pchDest[0] = '\0';
|
||||
//AssertMsg( false, "Target buffer too short to terminate\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
// Null terminate
|
||||
pchDest[iDestPos++] = 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Internal implementation of decode, works in the strict RFC manner, or
|
||||
// with spaces turned to + like HTML form encoding.
|
||||
//
|
||||
// Returns the amount of space used in the output buffer.
|
||||
//-----------------------------------------------------------------------------
|
||||
size_t V_URLDecodeInternal( char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen, bool bUsePlusForSpace )
|
||||
{
|
||||
if ( nDecodeDestLen < nEncodedSourceLen )
|
||||
{
|
||||
//AssertMsg( false, "V_URLDecode needs a dest buffer at least as large as the source" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iDestPos = 0;
|
||||
for( int i=0; i < nEncodedSourceLen; ++i )
|
||||
{
|
||||
if ( bUsePlusForSpace && pchEncodedSource[i] == '+' )
|
||||
{
|
||||
pchDecodeDest[ iDestPos++ ] = ' ';
|
||||
}
|
||||
else if ( pchEncodedSource[i] == '%' )
|
||||
{
|
||||
// Percent signifies an encoded value, look ahead for the hex code, convert to numeric, and use that
|
||||
|
||||
// First make sure we have 2 more chars
|
||||
if ( i < nEncodedSourceLen - 2 )
|
||||
{
|
||||
char cHexDigit1 = pchEncodedSource[i+1];
|
||||
char cHexDigit2 = pchEncodedSource[i+2];
|
||||
|
||||
// Turn the chars into a hex value, if they are not valid, then we'll
|
||||
// just place the % and the following two chars direct into the string,
|
||||
// even though this really shouldn't happen, who knows what bad clients
|
||||
// may do with encoding.
|
||||
bool bValid = false;
|
||||
int iValue = iHexCharToInt( cHexDigit1 );
|
||||
if ( iValue != -1 )
|
||||
{
|
||||
iValue *= 16;
|
||||
int iValue2 = iHexCharToInt( cHexDigit2 );
|
||||
if ( iValue2 != -1 )
|
||||
{
|
||||
iValue += iValue2;
|
||||
pchDecodeDest[ iDestPos++ ] = (char)iValue;
|
||||
bValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !bValid )
|
||||
{
|
||||
pchDecodeDest[ iDestPos++ ] = '%';
|
||||
pchDecodeDest[ iDestPos++ ] = cHexDigit1;
|
||||
pchDecodeDest[ iDestPos++ ] = cHexDigit2;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip ahead
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
pchDecodeDest[ iDestPos++ ] = pchEncodedSource[i];
|
||||
}
|
||||
}
|
||||
|
||||
// We may not have extra room to NULL terminate, since this can be used on raw data, but if we do
|
||||
// go ahead and do it as this can avoid bugs.
|
||||
if ( iDestPos < nDecodeDestLen )
|
||||
{
|
||||
pchDecodeDest[iDestPos] = 0;
|
||||
}
|
||||
|
||||
return (size_t)iDestPos;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Encodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2.
|
||||
// This version of the call isn't a strict RFC implementation, but uses + for space as is
|
||||
// the standard in HTML form encoding, despite it not being part of the RFC.
|
||||
//
|
||||
// Dest buffer should be at least as large as source buffer to guarantee room for decode.
|
||||
//-----------------------------------------------------------------------------
|
||||
void V_URLEncode( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen )
|
||||
{
|
||||
return V_URLEncodeInternal( pchDest, nDestLen, pchSource, nSourceLen, true, CharNeedsEscape_Component );
|
||||
}
|
||||
|
||||
|
||||
void V_URLEncodeNoPlusForSpace( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen )
|
||||
{
|
||||
return V_URLEncodeInternal( pchDest, nDestLen, pchSource, nSourceLen, false, CharNeedsEscape_Component );
|
||||
}
|
||||
|
||||
void V_URLEncodeFullPath( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen )
|
||||
{
|
||||
return V_URLEncodeInternal( pchDest, nDestLen, pchSource, nSourceLen, false, CharNeedsEscape_FullPath );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Decodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2.
|
||||
// This version of the call isn't a strict RFC implementation, but uses + for space as is
|
||||
// the standard in HTML form encoding, despite it not being part of the RFC.
|
||||
//
|
||||
// Dest buffer should be at least as large as source buffer to guarantee room for decode.
|
||||
// Dest buffer being the same as the source buffer (decode in-place) is explicitly allowed.
|
||||
//-----------------------------------------------------------------------------
|
||||
size_t V_URLDecode( char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen )
|
||||
{
|
||||
return V_URLDecodeInternal( pchDecodeDest, nDecodeDestLen, pchEncodedSource, nEncodedSourceLen, true );
|
||||
}
|
||||
|
||||
size_t V_URLDecodeNoPlusForSpace( char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen )
|
||||
{
|
||||
return V_URLDecodeInternal( pchDecodeDest, nDecodeDestLen, pchEncodedSource, nEncodedSourceLen, false );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void V_StripExtension( std::string &in )
|
||||
{
|
||||
// Find the last dot. If it's followed by a dot or a slash, then it's part of a
|
||||
// directory specifier like ../../somedir/./blah.
|
||||
std::string::size_type test = in.rfind( '.' );
|
||||
if ( test != std::string::npos )
|
||||
{
|
||||
// This handles things like ".\blah" or "c:\my@email.com\abc\def\geh"
|
||||
// Which would otherwise wind up with "" and "c:\my@email", respectively.
|
||||
if ( in.rfind( '\\' ) < test && in.rfind( '/' ) < test )
|
||||
{
|
||||
in.resize( test );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Tokenizes a string into a vector of strings
|
||||
//-----------------------------------------------------------------------------
|
||||
std::vector<std::string> TokenizeString( const std::string & sString, char cToken )
|
||||
{
|
||||
std::vector<std::string> vecStrings;
|
||||
std::istringstream stream( sString );
|
||||
std::string s;
|
||||
while ( std::getline( stream, s, cToken ) )
|
||||
{
|
||||
vecStrings.push_back( s );
|
||||
}
|
||||
|
||||
if ( !sString.empty() && sString.back() == cToken )
|
||||
{
|
||||
vecStrings.push_back( "" );
|
||||
}
|
||||
|
||||
return vecStrings;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Repairs a should-be-UTF-8 string to a for-sure-is-UTF-8 string, plus return boolean if we subbed in '?' somewhere
|
||||
//-----------------------------------------------------------------------------
|
||||
bool RepairUTF8( const char *pbegin, const char *pend, std::string & sOutputUtf8 )
|
||||
{
|
||||
typedef std::codecvt_utf8<char32_t> facet_type;
|
||||
facet_type myfacet;
|
||||
|
||||
std::mbstate_t mystate = std::mbstate_t();
|
||||
|
||||
sOutputUtf8.clear();
|
||||
sOutputUtf8.reserve( pend - pbegin );
|
||||
bool bSqueakyClean = true;
|
||||
|
||||
const char *pmid = pbegin;
|
||||
while ( pmid != pend )
|
||||
{
|
||||
bool bHasError = false;
|
||||
bool bHasValidData = false;
|
||||
|
||||
char32_t out = 0xdeadbeef, *pout;
|
||||
pbegin = pmid;
|
||||
switch ( myfacet.in( mystate, pbegin, pend, pmid, &out, &out + 1, pout ) )
|
||||
{
|
||||
case facet_type::ok:
|
||||
bHasValidData = true;
|
||||
break;
|
||||
|
||||
case facet_type::noconv:
|
||||
// unexpected! always converting type
|
||||
bSqueakyClean = false;
|
||||
break;
|
||||
|
||||
case facet_type::partial:
|
||||
bHasError = pbegin == pmid;
|
||||
if ( bHasError )
|
||||
{
|
||||
bSqueakyClean = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
bHasValidData = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case facet_type::error:
|
||||
bHasError = true;
|
||||
bSqueakyClean = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( bHasValidData )
|
||||
{
|
||||
// could convert back, but no need
|
||||
for ( const char *p = pbegin; p != pmid; ++p )
|
||||
{
|
||||
sOutputUtf8 += *p;
|
||||
}
|
||||
}
|
||||
|
||||
if ( bHasError )
|
||||
{
|
||||
sOutputUtf8 += '?';
|
||||
}
|
||||
|
||||
if ( pmid == pbegin )
|
||||
{
|
||||
pmid++;
|
||||
}
|
||||
}
|
||||
|
||||
return bSqueakyClean;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Repairs a should-be-UTF-8 string to a for-sure-is-UTF-8 string, plus return boolean if we subbed in '?' somewhere
|
||||
//-----------------------------------------------------------------------------
|
||||
bool RepairUTF8( const std::string & sInputUtf8, std::string & sOutputUtf8 )
|
||||
{
|
||||
return RepairUTF8( sInputUtf8.data(), sInputUtf8.data() + sInputUtf8.size(), sOutputUtf8 );
|
||||
}
|
154
contrib/openvr/src/vrcommon/strtools_public.h
Executable file
|
@ -0,0 +1,154 @@
|
|||
//========= Copyright Valve Corporation ============//
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <vector>
|
||||
|
||||
/** returns true if the string has the prefix */
|
||||
bool StringHasPrefix( const std::string & sString, const std::string & sPrefix );
|
||||
bool StringHasPrefixCaseSensitive( const std::string & sString, const std::string & sPrefix );
|
||||
|
||||
/** returns if the string has the suffix */
|
||||
bool StringHasSuffix( const std::string &sString, const std::string &sSuffix );
|
||||
bool StringHasSuffixCaseSensitive( const std::string &sString, const std::string &sSuffix );
|
||||
|
||||
/** converts a UTF-16 string to a UTF-8 string */
|
||||
std::string UTF16to8( const wchar_t * in );
|
||||
std::string UTF16to8( const std::wstring & in );
|
||||
|
||||
/** converts a UTF-8 string to a UTF-16 string */
|
||||
std::wstring UTF8to16(const char * in);
|
||||
std::wstring UTF8to16( const std::string & in );
|
||||
#define Utf16FromUtf8 UTF8to16
|
||||
|
||||
#if defined( _WIN32 )
|
||||
std::string DefaultACPtoUTF8( const char *pszStr );
|
||||
#endif
|
||||
|
||||
/** Repairs a should-be-UTF-8 string to a for-sure-is-UTF-8 string, plus return boolean if we subbed in '?' somewhere */
|
||||
bool RepairUTF8( const char *begin, const char *end, std::string & sOutputUtf8 );
|
||||
bool RepairUTF8( const std::string & sInputUtf8, std::string & sOutputUtf8 );
|
||||
|
||||
/** safely copy a string into a buffer */
|
||||
void strcpy_safe( char *pchBuffer, size_t unBufferSizeBytes, const char *pchSource );
|
||||
template< size_t bufferSize >
|
||||
void strcpy_safe( char (& buffer) [ bufferSize ], const char *pchSource )
|
||||
{
|
||||
strcpy_safe( buffer, bufferSize, pchSource );
|
||||
}
|
||||
|
||||
/** Turns printf-style format args into a std::string */
|
||||
std::string Format( const char *pchFormat, ... );
|
||||
|
||||
|
||||
/** converts a string to upper case */
|
||||
std::string StringToUpper( const std::string & sString );
|
||||
|
||||
/** converts a string to lower case */
|
||||
std::string StringToLower( const std::string & sString );
|
||||
|
||||
// we stricmp (from WIN) but it isn't POSIX - OSX/LINUX have strcasecmp so just inline bridge to it
|
||||
#if defined( OSX ) || defined( LINUX )
|
||||
int stricmp(const char *pStr1, const char *pStr2);
|
||||
#ifndef _stricmp
|
||||
#define _stricmp stricmp
|
||||
#endif
|
||||
int strnicmp( const char *pStr1, const char *pStr2, size_t unBufferLen );
|
||||
#ifndef _strnicmp
|
||||
#define _strnicmp strnicmp
|
||||
#endif
|
||||
|
||||
#ifndef _vsnprintf_s
|
||||
#define _vsnprintf_s vsnprintf
|
||||
#endif
|
||||
|
||||
#define _TRUNCATE ((size_t)-1)
|
||||
|
||||
#endif
|
||||
|
||||
#if defined( OSX )
|
||||
// behaviors ensure NULL-termination at least as well as _TRUNCATE does, but
|
||||
// wcsncpy_s/strncpy_s can non-NULL-terminate, wcslcpy/strlcpy can not.
|
||||
inline errno_t wcsncpy_s(wchar_t *strDest, size_t numberOfElements, const wchar_t *strSource, size_t count)
|
||||
{
|
||||
return wcslcpy(strDest, strSource, numberOfElements);
|
||||
}
|
||||
|
||||
inline errno_t strncpy_s(char *strDest, size_t numberOfElements, const char *strSource, size_t count)
|
||||
{
|
||||
return strlcpy(strDest, strSource, numberOfElements);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined( LINUX )
|
||||
// this implementation does not return whether or not the destination was
|
||||
// truncated, but that is straightforward to fix if anybody actually needs the
|
||||
// return code.
|
||||
#include "string.h"
|
||||
inline void wcsncpy_s(wchar_t *strDest, size_t numberOfElements, const wchar_t *strSource, size_t count)
|
||||
{
|
||||
wcsncpy(strDest, strSource, numberOfElements);
|
||||
strDest[numberOfElements-1] = '\0';
|
||||
}
|
||||
|
||||
inline void strncpy_s(char *strDest, size_t numberOfElements, const char *strSource, size_t count)
|
||||
{
|
||||
strncpy(strDest, strSource, numberOfElements);
|
||||
strDest[numberOfElements-1] = '\0';
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined( _WIN32 ) && _MSC_VER < 1800
|
||||
inline uint64_t strtoull(const char *str, char **endptr, int base) { return _strtoui64( str, endptr, base ); }
|
||||
#endif
|
||||
|
||||
/* Handles copying a std::string into a buffer as would be provided in an API */
|
||||
uint32_t ReturnStdString( const std::string & sValue, char *pchBuffer, uint32_t unBufferLen );
|
||||
|
||||
/** Returns a std::string from a uint64_t */
|
||||
std::string Uint64ToString( uint64_t ulValue );
|
||||
|
||||
/** returns a uint64_t from a string */
|
||||
uint64_t StringToUint64( const std::string & sValue );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Encodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2.
|
||||
// This version of the call isn't a strict RFC implementation, but uses + for space as is
|
||||
// the standard in HTML form encoding, despite it not being part of the RFC.
|
||||
//
|
||||
// Dest buffer should be at least as large as source buffer to guarantee room for decode.
|
||||
//-----------------------------------------------------------------------------
|
||||
void V_URLEncode( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen );
|
||||
|
||||
/** Same as V_URLEncode, but without plus for space. */
|
||||
void V_URLEncodeNoPlusForSpace( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen );
|
||||
|
||||
/** Same as V_URLEncodeNoPlusForSpace, but without escaping / and : */
|
||||
void V_URLEncodeFullPath( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Decodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2.
|
||||
// This version of the call isn't a strict RFC implementation, but uses + for space as is
|
||||
// the standard in HTML form encoding, despite it not being part of the RFC.
|
||||
//
|
||||
// Dest buffer should be at least as large as source buffer to guarantee room for decode.
|
||||
// Dest buffer being the same as the source buffer (decode in-place) is explicitly allowed.
|
||||
//-----------------------------------------------------------------------------
|
||||
size_t V_URLDecode( char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen );
|
||||
|
||||
/** Same as V_URLDecode, but without plus for space. */
|
||||
size_t V_URLDecodeNoPlusForSpace( char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: strip extension from a path
|
||||
//-----------------------------------------------------------------------------
|
||||
void V_StripExtension( std::string &in );
|
||||
|
||||
|
||||
/** Tokenizes a string into a vector of strings */
|
||||
std::vector<std::string> TokenizeString( const std::string & sString, char cToken );
|
483
contrib/openvr/src/vrcommon/vrpathregistry_public.cpp
Executable file
|
@ -0,0 +1,483 @@
|
|||
//========= Copyright Valve Corporation ============//
|
||||
|
||||
#include <vrcommon/vrpathregistry_public.h>
|
||||
#include <json/json.h>
|
||||
#include <vrcommon/pathtools_public.h>
|
||||
#include <vrcommon/envvartools_public.h>
|
||||
#include <vrcommon/strtools_public.h>
|
||||
#include <vrcommon/dirtools_public.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
#undef GetEnvironmentVariable
|
||||
#elif defined OSX
|
||||
#include <Foundation/Foundation.h>
|
||||
#include <AppKit/AppKit.h>
|
||||
#elif defined(LINUX)
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
#ifndef VRLog
|
||||
#if defined( __MINGW32__ )
|
||||
#define VRLog(args...) fprintf(stderr, args)
|
||||
#elif defined( WIN32 )
|
||||
#define VRLog(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
|
||||
#else
|
||||
#define VRLog(args...) fprintf(stderr, args)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** Returns the root of the directory the system wants us to store user config data in */
|
||||
static std::string GetAppSettingsPath()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WCHAR rwchPath[MAX_PATH];
|
||||
|
||||
if( !SUCCEEDED( SHGetFolderPathW( NULL, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, rwchPath ) ) )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
// Convert the path to UTF-8 and store in the output
|
||||
std::string sUserPath = UTF16to8( rwchPath );
|
||||
|
||||
return sUserPath;
|
||||
#elif defined( OSX )
|
||||
std::string sSettingsDir;
|
||||
@autoreleasepool {
|
||||
// Search for the path
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSApplicationSupportDirectory, NSUserDomainMask, YES );
|
||||
if ( [paths count] == 0 )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
NSString *resolvedPath = [paths objectAtIndex:0];
|
||||
resolvedPath = [resolvedPath stringByAppendingPathComponent: @"OpenVR"];
|
||||
|
||||
if ( ![[NSFileManager defaultManager] createDirectoryAtPath: resolvedPath withIntermediateDirectories:YES attributes:nil error:nil] )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
sSettingsDir.assign( [resolvedPath UTF8String] );
|
||||
}
|
||||
return sSettingsDir;
|
||||
#elif defined( LINUX )
|
||||
|
||||
// As defined by XDG Base Directory Specification
|
||||
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
|
||||
const char *pchHome = getenv("XDG_CONFIG_HOME");
|
||||
if ( ( pchHome != NULL) && ( pchHome[0] != '\0' ) )
|
||||
{
|
||||
return pchHome;
|
||||
}
|
||||
|
||||
//
|
||||
// XDG_CONFIG_HOME is not defined, use ~/.config instead
|
||||
//
|
||||
pchHome = getenv( "HOME" );
|
||||
if ( pchHome == NULL )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string sUserPath( pchHome );
|
||||
sUserPath = Path_Join( sUserPath, ".config" );
|
||||
return sUserPath;
|
||||
#else
|
||||
#warning "Unsupported platform"
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
// ---------------------------------------------------------------------------
|
||||
CVRPathRegistry_Public::CVRPathRegistry_Public()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Purpose: Computes the registry filename
|
||||
// ---------------------------------------------------------------------------
|
||||
std::string CVRPathRegistry_Public::GetOpenVRConfigPath()
|
||||
{
|
||||
std::string sConfigPath = GetAppSettingsPath();
|
||||
if( sConfigPath.empty() )
|
||||
return "";
|
||||
|
||||
#if defined( _WIN32 ) || defined( LINUX )
|
||||
sConfigPath = Path_Join( sConfigPath, "openvr" );
|
||||
#elif defined ( OSX )
|
||||
sConfigPath = Path_Join( sConfigPath, ".openvr" );
|
||||
#else
|
||||
#warning "Unsupported platform"
|
||||
#endif
|
||||
sConfigPath = Path_FixSlashes( sConfigPath );
|
||||
return sConfigPath;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
std::string CVRPathRegistry_Public::GetVRPathRegistryFilename()
|
||||
{
|
||||
std::string sOverridePath = GetEnvironmentVariable( "VR_PATHREG_OVERRIDE" );
|
||||
if ( !sOverridePath.empty() )
|
||||
return sOverridePath;
|
||||
|
||||
std::string sPath = GetOpenVRConfigPath();
|
||||
if ( sPath.empty() )
|
||||
return "";
|
||||
|
||||
#if defined( _WIN32 )
|
||||
sPath = Path_Join( sPath, "openvrpaths.vrpath" );
|
||||
#elif defined ( POSIX )
|
||||
sPath = Path_Join( sPath, "openvrpaths.vrpath" );
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
sPath = Path_FixSlashes( sPath );
|
||||
return sPath;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Purpose: Converts JSON to a history array
|
||||
// ---------------------------------------------------------------------------
|
||||
static void ParseStringListFromJson( std::vector< std::string > *pvecHistory, const Json::Value & root, const char *pchArrayName )
|
||||
{
|
||||
if( !root.isMember( pchArrayName ) )
|
||||
return;
|
||||
|
||||
const Json::Value & arrayNode = root[ pchArrayName ];
|
||||
if( !arrayNode )
|
||||
{
|
||||
VRLog( "VR Path Registry node %s is not an array\n", pchArrayName );
|
||||
return;
|
||||
}
|
||||
|
||||
pvecHistory->clear();
|
||||
pvecHistory->reserve( arrayNode.size() );
|
||||
for( uint32_t unIndex = 0; unIndex < arrayNode.size(); unIndex++ )
|
||||
{
|
||||
std::string sPath( arrayNode[ unIndex ].asString() );
|
||||
pvecHistory->push_back( sPath );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Purpose: Converts a history array to JSON
|
||||
// ---------------------------------------------------------------------------
|
||||
static void StringListToJson( const std::vector< std::string > & vecHistory, Json::Value & root, const char *pchArrayName )
|
||||
{
|
||||
Json::Value & arrayNode = root[ pchArrayName ];
|
||||
for( auto i = vecHistory.begin(); i != vecHistory.end(); i++ )
|
||||
{
|
||||
arrayNode.append( *i );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CVRPathRegistry_Public::ToJsonString( std::string &sJsonString )
|
||||
{
|
||||
std::string sRegPath = GetVRPathRegistryFilename();
|
||||
if( sRegPath.empty() )
|
||||
return false;
|
||||
|
||||
std::string sRegistryContents = Path_ReadTextFile( sRegPath );
|
||||
if( sRegistryContents.empty() )
|
||||
return false;
|
||||
|
||||
sJsonString = sRegistryContents;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Purpose: Loads the config file from its well known location
|
||||
// ---------------------------------------------------------------------------
|
||||
bool CVRPathRegistry_Public::BLoadFromFile( std::string *psLoadError )
|
||||
{
|
||||
std::string sRegPath = GetVRPathRegistryFilename();
|
||||
if( sRegPath.empty() )
|
||||
{
|
||||
if ( psLoadError )
|
||||
{
|
||||
*psLoadError = "Unable to determine VR Path Registry filename";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string sRegistryContents = Path_ReadTextFile( sRegPath );
|
||||
if( sRegistryContents.empty() )
|
||||
{
|
||||
if ( psLoadError )
|
||||
{
|
||||
*psLoadError = "Unable to read VR Path Registry from " + sRegPath;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Json::Value root;
|
||||
Json::CharReaderBuilder builder;
|
||||
std::istringstream istream( sRegistryContents );
|
||||
std::string sErrors;
|
||||
|
||||
try {
|
||||
if ( !parseFromStream( builder, istream, &root, &sErrors ) )
|
||||
{
|
||||
if ( psLoadError )
|
||||
{
|
||||
*psLoadError = "Unable to parse " + sRegPath + ": " + sErrors;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ParseStringListFromJson( &m_vecRuntimePath, root, "runtime" );
|
||||
ParseStringListFromJson( &m_vecConfigPath, root, "config" );
|
||||
ParseStringListFromJson( &m_vecLogPath, root, "log" );
|
||||
if ( root.isMember( "external_drivers" ) && root["external_drivers"].isArray() )
|
||||
{
|
||||
ParseStringListFromJson( &m_vecExternalDrivers, root, "external_drivers" );
|
||||
}
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
if ( psLoadError )
|
||||
{
|
||||
*psLoadError = "Unable to parse " + sRegPath + ": exception thrown in JSON library";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Purpose: Saves the config file to its well known location
|
||||
// ---------------------------------------------------------------------------
|
||||
bool CVRPathRegistry_Public::BSaveToFile() const
|
||||
{
|
||||
std::string sRegPath = GetVRPathRegistryFilename();
|
||||
if( sRegPath.empty() )
|
||||
return false;
|
||||
|
||||
Json::Value root;
|
||||
|
||||
root[ "version" ] = 1;
|
||||
root[ "jsonid" ] = "vrpathreg";
|
||||
|
||||
StringListToJson( m_vecRuntimePath, root, "runtime" );
|
||||
StringListToJson( m_vecConfigPath, root, "config" );
|
||||
StringListToJson( m_vecLogPath, root, "log" );
|
||||
StringListToJson( m_vecExternalDrivers, root, "external_drivers" );
|
||||
|
||||
Json::StreamWriterBuilder builder;
|
||||
std::string sRegistryContents = Json::writeString( builder, root );
|
||||
|
||||
// make sure the directory we're writing into actually exists
|
||||
std::string sRegDirectory = Path_StripFilename( sRegPath );
|
||||
if( !BCreateDirectoryRecursive( sRegDirectory.c_str() ) )
|
||||
{
|
||||
VRLog( "Unable to create path registry directory %s\n", sRegDirectory.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !Path_WriteStringToTextFile( sRegPath, sRegistryContents.c_str() ) )
|
||||
{
|
||||
VRLog( "Unable to write VR path registry to %s\n", sRegPath.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Purpose: Returns the current runtime path or NULL if no path is configured.
|
||||
// ---------------------------------------------------------------------------
|
||||
std::string CVRPathRegistry_Public::GetRuntimePath() const
|
||||
{
|
||||
if( m_vecRuntimePath.empty() )
|
||||
return "";
|
||||
else
|
||||
return m_vecRuntimePath.front().c_str();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Purpose: Returns the current config path or NULL if no path is configured.
|
||||
// ---------------------------------------------------------------------------
|
||||
std::string CVRPathRegistry_Public::GetConfigPath() const
|
||||
{
|
||||
if( m_vecConfigPath.empty() )
|
||||
return "";
|
||||
else
|
||||
return m_vecConfigPath.front().c_str();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Purpose: Returns the current log path or NULL if no path is configured.
|
||||
// ---------------------------------------------------------------------------
|
||||
std::string CVRPathRegistry_Public::GetLogPath() const
|
||||
{
|
||||
if( m_vecLogPath.empty() )
|
||||
return "";
|
||||
else
|
||||
return m_vecLogPath.front().c_str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Purpose: Returns paths using the path registry and the provided override
|
||||
// values. Pass NULL for any paths you don't care about.
|
||||
// ---------------------------------------------------------------------------
|
||||
bool CVRPathRegistry_Public::GetPaths( std::string *psRuntimePath, std::string *psConfigPath, std::string *psLogPath, const char *pchConfigPathOverride, const char *pchLogPathOverride, std::vector<std::string> *pvecExternalDrivers )
|
||||
{
|
||||
std::string sLoadError;
|
||||
CVRPathRegistry_Public pathReg;
|
||||
bool bLoadedRegistry = pathReg.BLoadFromFile( &sLoadError );
|
||||
int nCountEnvironmentVariables = 0;
|
||||
int nRequestedPaths = 0;
|
||||
|
||||
if( psRuntimePath )
|
||||
{
|
||||
nRequestedPaths++;
|
||||
if ( GetEnvironmentVariable( k_pchRuntimeOverrideVar ).length() != 0 )
|
||||
{
|
||||
*psRuntimePath = GetEnvironmentVariable( k_pchRuntimeOverrideVar );
|
||||
nCountEnvironmentVariables++;
|
||||
}
|
||||
else if( !pathReg.GetRuntimePath().empty() )
|
||||
{
|
||||
*psRuntimePath = pathReg.GetRuntimePath();
|
||||
}
|
||||
else
|
||||
{
|
||||
*psRuntimePath = "";
|
||||
}
|
||||
}
|
||||
|
||||
if( psConfigPath )
|
||||
{
|
||||
nRequestedPaths++;
|
||||
if ( GetEnvironmentVariable( k_pchConfigOverrideVar ).length() != 0 )
|
||||
{
|
||||
*psConfigPath = GetEnvironmentVariable( k_pchConfigOverrideVar );
|
||||
nCountEnvironmentVariables++;
|
||||
}
|
||||
else if( pchConfigPathOverride )
|
||||
{
|
||||
*psConfigPath = pchConfigPathOverride;
|
||||
}
|
||||
else if( !pathReg.GetConfigPath().empty() )
|
||||
{
|
||||
*psConfigPath = pathReg.GetConfigPath();
|
||||
}
|
||||
else
|
||||
{
|
||||
*psConfigPath = "";
|
||||
}
|
||||
}
|
||||
|
||||
if( psLogPath )
|
||||
{
|
||||
nRequestedPaths++;
|
||||
if ( GetEnvironmentVariable( k_pchLogOverrideVar ).length() != 0 )
|
||||
{
|
||||
*psLogPath = GetEnvironmentVariable( k_pchLogOverrideVar );
|
||||
nCountEnvironmentVariables++;
|
||||
}
|
||||
else if( pchLogPathOverride )
|
||||
{
|
||||
*psLogPath = pchLogPathOverride;
|
||||
}
|
||||
else if( !pathReg.GetLogPath().empty() )
|
||||
{
|
||||
*psLogPath = pathReg.GetLogPath();
|
||||
}
|
||||
else
|
||||
{
|
||||
*psLogPath = "";
|
||||
}
|
||||
}
|
||||
|
||||
if ( pvecExternalDrivers )
|
||||
{
|
||||
*pvecExternalDrivers = pathReg.m_vecExternalDrivers;
|
||||
}
|
||||
|
||||
if ( nCountEnvironmentVariables == nRequestedPaths )
|
||||
{
|
||||
// all three environment variables were set, so we don't need the physical file
|
||||
return true;
|
||||
}
|
||||
else if( !bLoadedRegistry )
|
||||
{
|
||||
VRLog( "%s\n", sLoadError.c_str() );
|
||||
}
|
||||
|
||||
return bLoadedRegistry;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32_t CVRPathRegistry_Public::GetSteamAppId()
|
||||
{
|
||||
#if !defined( REL_BRANCH_ONLY )
|
||||
uint32_t nSteamAppId = k_unSteamVRMainAppId;
|
||||
#else
|
||||
uint32_t nSteamAppId = k_unSteamVRAppId;
|
||||
#endif
|
||||
|
||||
return nSteamAppId;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CVRPathRegistry_Public::IsSteamVRMain()
|
||||
{
|
||||
#if defined( REL_BRANCH_ONLY )
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32_t CVRPathRegistry_Public::InitSteamAppId()
|
||||
{
|
||||
uint32_t nSteamAppId = CVRPathRegistry_Public::GetSteamAppId();
|
||||
|
||||
// Forcefully setting to what it should be before SteamAPI_Init() since SteamVR is more often
|
||||
// started as child processes of the game app and otherwise Steam then considers us as the
|
||||
// wrong app id.
|
||||
SetEnvironmentVariable( "SteamAppId", std::to_string( nSteamAppId ).c_str() );
|
||||
SetEnvironmentVariable( "SteamGameId", std::to_string( nSteamAppId ).c_str() );
|
||||
|
||||
return nSteamAppId;
|
||||
}
|
||||
|
52
contrib/openvr/src/vrcommon/vrpathregistry_public.h
Executable file
|
@ -0,0 +1,52 @@
|
|||
//========= Copyright Valve Corporation ============//
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
|
||||
static const char *k_pchRuntimeOverrideVar = "VR_OVERRIDE";
|
||||
static const char *k_pchConfigOverrideVar = "VR_CONFIG_PATH";
|
||||
static const char *k_pchLogOverrideVar = "VR_LOG_PATH";
|
||||
|
||||
static const uint32_t k_unSteamVRAppId = 250820;
|
||||
static const uint32_t k_unSteamVRMainAppId = 330050;
|
||||
|
||||
|
||||
class CVRPathRegistry_Public
|
||||
{
|
||||
public:
|
||||
static std::string GetVRPathRegistryFilename();
|
||||
static std::string GetOpenVRConfigPath();
|
||||
static uint32_t GetSteamAppId();
|
||||
static bool IsSteamVRMain();
|
||||
static uint32_t InitSteamAppId();
|
||||
|
||||
public:
|
||||
CVRPathRegistry_Public();
|
||||
|
||||
/** Returns paths using the path registry and the provided override values. Pass NULL for any paths you don't care about.
|
||||
* Returns false if the path registry could not be read. Valid paths might still be returned based on environment variables. */
|
||||
static bool GetPaths( std::string *psRuntimePath, std::string *psConfigPath, std::string *psLogPath, const char *pchConfigPathOverride, const char *pchLogPathOverride, std::vector<std::string> *pvecExternalDrivers = NULL );
|
||||
|
||||
bool BLoadFromFile( std::string *psError = nullptr );
|
||||
bool BSaveToFile() const;
|
||||
|
||||
bool ToJsonString( std::string &sJsonString );
|
||||
|
||||
// methods to get the current values
|
||||
std::string GetRuntimePath() const;
|
||||
std::string GetConfigPath() const;
|
||||
std::string GetLogPath() const;
|
||||
|
||||
protected:
|
||||
typedef std::vector< std::string > StringVector_t;
|
||||
|
||||
// index 0 is the current setting
|
||||
StringVector_t m_vecRuntimePath;
|
||||
StringVector_t m_vecLogPath;
|
||||
StringVector_t m_vecConfigPath;
|
||||
|
||||
// full list of external drivers
|
||||
StringVector_t m_vecExternalDrivers;
|
||||
};
|
1
contrib/quirc
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 9c0f555acb2531d818f2c405044418fc75379fb2
|
|
@ -1 +0,0 @@
|
|||
Subproject commit e68770719ef4d3d3b83398715b1e10391ab6a1b4
|
71
docs/BUILDING.md
Normal file
|
@ -0,0 +1,71 @@
|
|||
# Building WOWlet
|
||||
|
||||
Building for Linux and Windows via Docker is done in 3 steps:
|
||||
|
||||
1. Cloning this repository (+submodules)
|
||||
2. Creating a base Docker image
|
||||
3. Using the base image to compile a build
|
||||
|
||||
**important:** you only have to do step 2 (base docker image) once.
|
||||
|
||||
For Mac OS, scroll down.
|
||||
|
||||
# Linux
|
||||
|
||||
For more information, check the Dockerfile: `Dockerfile`.
|
||||
|
||||
### 1. Clone
|
||||
|
||||
```bash
|
||||
git clone --branch master --recursive https://git.wownero.com/wowlet/wowlet.git
|
||||
cd wowlet
|
||||
```
|
||||
|
||||
Replace `master` with the desired version tag (e.g. `v3.1.0`) to build the release binary.
|
||||
|
||||
### 2. Base image
|
||||
|
||||
```bash
|
||||
docker build --tag wowlet:linux --build-arg THREADS=6 .
|
||||
```
|
||||
|
||||
Building the base image takes a while. **You only need to build the base image once.**
|
||||
|
||||
### 3. Build
|
||||
|
||||
```bash
|
||||
docker run --rm -it -v $PWD:/wowlet -w /wowlet wowlet:linux sh -c 'make release-static -j6'
|
||||
```
|
||||
|
||||
If you're re-running a build make sure to `rm -rf build/` first.
|
||||
|
||||
The resulting binary can be found in `build/bin/wowlet`.
|
||||
|
||||
# Windows
|
||||
|
||||
### 1. Clone
|
||||
|
||||
```bash
|
||||
git clone --branch master --recursive https://git.wownero.com/wowlet/wowlet.git
|
||||
cd wowlet
|
||||
```
|
||||
|
||||
Replace `master` with the desired version tag (e.g. `v3.1.0`) to build the release binary.
|
||||
|
||||
### 2. Base image
|
||||
|
||||
```bash
|
||||
docker build -f Dockerfile.windows --tag wowlet:win --build-arg THREADS=6 .
|
||||
```
|
||||
|
||||
Building the base image takes a while. **You only need to build the base image once.**
|
||||
|
||||
### 3. Build
|
||||
|
||||
```bash
|
||||
docker run --rm -it -v $PWD:/wowlet -w /wowlet wowlet:win sh -c 'make windows root=/depends target=x86_64-w64-mingw32 tag=win-x64 -j6'
|
||||
```
|
||||
|
||||
If you're re-running a build make sure to `rm -rf build/` first.
|
||||
|
||||
The resulting binary can be found in `build/x86_64-w64-mingw32/release/bin/wowlet.exe`.
|
89
docs/HACKING.md
Normal file
|
@ -0,0 +1,89 @@
|
|||
# Documentation for developers
|
||||
|
||||
WOWlet is developed primarily on Linux. It uses Qt 5.15.* and chances are that your
|
||||
distro's package manager has a lower version. It is therefore recommended that you install
|
||||
Qt manually using the online installer, which can be found here: https://www.qt.io/download
|
||||
(under open-source).
|
||||
|
||||
## Jetbrains Clion
|
||||
|
||||
WOWlet was developed using JetBrains Clion since it integrates nicely
|
||||
with CMake and comes with a built-in debugger. To pass CMake flags to CLion,
|
||||
go to `File->Settings->Build->CMake`, set Build Type to `Debug` and set your
|
||||
preferred CMake options/definitions.
|
||||
|
||||
## Man Page
|
||||
|
||||
There is a WOWlet's manual page, which can be accessed with: `man wowlet`
|
||||
|
||||
If a new option is introduced, please be sure to update the options section in
|
||||
`src/assets/wowlet.1.md`, the month and year in line 3, and "manify" the document
|
||||
by running this command: `pandoc wowlet.1.md -s -t man -o wowlet.1 && gzip wowlet.1`
|
||||
|
||||
## Requirements
|
||||
|
||||
(Possibly out-of-date)
|
||||
|
||||
### Ubuntu/Debian
|
||||
|
||||
```bash
|
||||
apt install -y git cmake libqrencode-dev build-essential cmake libboost-all-dev \
|
||||
miniupnpc libunbound-dev graphviz doxygen libunwind8-dev pkg-config libssl-dev \
|
||||
libzmq3-dev libsodium-dev libhidapi-dev libnorm-dev libusb-1.0-0-dev libpgm-dev \
|
||||
libprotobuf-dev protobuf-compiler libgcrypt20-dev libpng-dev
|
||||
```
|
||||
|
||||
## CMake
|
||||
|
||||
After installing Qt you might have a folder called `/home/$USER/Qt/`. You need to pass this to CMake
|
||||
via the `CMAKE_PREFIX_PATH` definition.
|
||||
|
||||
```
|
||||
-DCMAKE_PREFIX_PATH=/home/$USER/QtFooBar/5.15.0/gcc_64
|
||||
```
|
||||
|
||||
There are some Wownero/WOWlet related options/definitions that you may pass, see also `CMakeLists.txt`.
|
||||
|
||||
At a bare minimum, recommended:
|
||||
|
||||
`-DMANUAL_SUBMODULES=1 -DUSE_DEVICE_TREZOR=OFF -DUSE_SINGLE_BUILDDIR=ON -DDEV_MODE=ON`
|
||||
|
||||
If you have OpenSSL installed at a custom location, try:
|
||||
|
||||
```
|
||||
-DOPENSSL_INCLUDE_DIR=/usr/local/lib/openssl-1.1.1g/include
|
||||
-DOPENSSL_SSL_LIBRARY=/usr/local/lib/openssl-1.1.1g/libssl.so.1.1
|
||||
-DOPENSSL_CRYPTO_LIBRARY=/usr/local/lib/openssl-1.1.1g/libcrypto.so.1.1
|
||||
```
|
||||
|
||||
I prefer also enabling verbose makefiles, which may be useful in some situations.
|
||||
|
||||
```
|
||||
-DCMAKE_VERBOSE_MAKEFILE=ON
|
||||
```
|
||||
|
||||
Enable debugging symbols:
|
||||
|
||||
```bash
|
||||
-DCMAKE_BUILD_TYPE=Debug
|
||||
```
|
||||
|
||||
## Wowlet
|
||||
|
||||
It's best to install Tor locally as a service and start `wowlet` with `--use-local-tor`, this
|
||||
prevents the child process from starting up each time you launch WOWlet and thus saves time.
|
||||
|
||||
#### Ubuntu/Debian
|
||||
|
||||
```bash
|
||||
apt install -y tor
|
||||
sudo service tor start
|
||||
```
|
||||
|
||||
To skip the wizards and open a wallet directly use `--wallet-file`:
|
||||
|
||||
```bash
|
||||
./wowlet --use-local-tor --wallet-file /home/user/Wownero/wallets/bla.keys
|
||||
```
|
||||
|
||||
|
|
@ -4,13 +4,12 @@
|
|||
|
||||
Please do not open an issue to report security issues.
|
||||
|
||||
To report a vulnerability send an email to dev@featherwallet.org
|
||||
To report a vulnerability send an email to dev@wownero.org
|
||||
|
||||
The following keys may be used to communicate sensitive information to developers:
|
||||
|
||||
| Name | Fingerprint |
|
||||
|------|-------------|
|
||||
| dsc | 1BFD 40F9 B0E2 B40D C8C7 FD4A 521F 1E79 91AA 42DC |
|
||||
| tobtoht | C5AB E5C0 E50F A2B3 F14A B92D 1CAD D27F 41F4 5C3C |
|
||||
|
||||
Public keys can be found in `utils/pubkeys`.
|
1
monero
|
@ -1 +0,0 @@
|
|||
Subproject commit 85b0b4f73aa6114e3ff91207aa94ad2a15c939a2
|
|
@ -2,19 +2,11 @@ set(CMAKE_AUTOMOC ON)
|
|||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
|
||||
# pthread
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_package(PNG REQUIRED)
|
||||
|
||||
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui Network Svg Xml WebSockets)
|
||||
|
||||
add_subdirectory(libwalletqt)
|
||||
add_subdirectory(model)
|
||||
add_subdirectory(utils)
|
||||
add_subdirectory(openpgp)
|
||||
|
||||
qt5_add_resources(RESOURCES assets.qrc)
|
||||
|
||||
# Compile source files (.h/.cpp)
|
||||
# Compile these source files (.h/.cpp)
|
||||
file(GLOB SOURCE_FILES
|
||||
"*.h"
|
||||
"*.cpp"
|
||||
|
@ -42,12 +34,43 @@ file(GLOB SOURCE_FILES
|
|||
"dialog/*.cpp"
|
||||
)
|
||||
|
||||
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui Network Svg Xml WebSockets Quick QuickWidgets Qml QuickControls2 QuickCompiler QmlImportScanner Multimedia)
|
||||
|
||||
if(OPENVR)
|
||||
# include some extra files
|
||||
qt5_add_resources(RESOURCES vr/qml.qrc)
|
||||
file(GLOB SOURCE_FILES_QML
|
||||
"vr/*.h"
|
||||
"vr/*.cpp"
|
||||
"vr/utils/*.h"
|
||||
"vr/utils/*.cpp"
|
||||
)
|
||||
list(APPEND SOURCE_FILES ${SOURCE_FILES_QML})
|
||||
endif()
|
||||
|
||||
if(ANDROID OR ANDROID_DEBUG)
|
||||
qt5_add_resources(RESOURCES mobile/qml.qrc)
|
||||
file(GLOB SOURCE_FILES_QML
|
||||
"mobile/*.h"
|
||||
"mobile/*.cpp"
|
||||
)
|
||||
list(APPEND SOURCE_FILES ${SOURCE_FILES_QML})
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wno-deprecated-declarations") # @TODO: removeme
|
||||
|
||||
add_subdirectory(libwalletqt)
|
||||
add_subdirectory(model)
|
||||
add_subdirectory(utils)
|
||||
|
||||
if(WITH_SCANNER)
|
||||
add_subdirectory(QR-Code-scanner)
|
||||
endif()
|
||||
|
||||
qt5_add_resources(RESOURCES assets.qrc)
|
||||
|
||||
if(TOR_BIN)
|
||||
if(APPLE)
|
||||
set(ASSETS_TOR "assets_tor_macos.qrc")
|
||||
else()
|
||||
set(ASSETS_TOR "assets_tor.qrc")
|
||||
endif()
|
||||
set(ASSETS_TOR "assets_tor.qrc")
|
||||
endif()
|
||||
|
||||
set(EXECUTABLE_FLAG)
|
||||
|
@ -58,7 +81,8 @@ if(MINGW)
|
|||
set(ICON_RC ${CMAKE_CURRENT_BINARY_DIR}/icon.rc)
|
||||
set(ICON_RES ${CMAKE_CURRENT_BINARY_DIR}/icon.o)
|
||||
file(WRITE ${ICON_RC} "IDI_ICON1 ICON DISCARDABLE \"${ICON}\"")
|
||||
add_custom_command(OUTPUT ${ICON_RES} COMMAND windres ${ICON_RC} ${ICON_RES} MAIN_DEPENDENCY ${ICON_RC})
|
||||
find_program(Qt5_WINDRES_EXECUTABLE NAMES windres x86_64-w64-mingw32-windres REQUIRED CMAKE_FIND_ROOT_PATH_BOTH)
|
||||
add_custom_command(OUTPUT ${ICON_RES} COMMAND ${Qt5_WINDRES_EXECUTABLE} ${ICON_RC} ${ICON_RES} MAIN_DEPENDENCY ${ICON_RC})
|
||||
list(APPEND RESOURCES ${ICON_RES})
|
||||
endif()
|
||||
|
||||
|
@ -69,33 +93,39 @@ if(APPLE)
|
|||
list(APPEND RESOURCES ${ICON})
|
||||
endif()
|
||||
|
||||
add_executable(feather ${EXECUTABLE_FLAG} main.cpp
|
||||
${SOURCE_FILES}
|
||||
${RESOURCES}
|
||||
${ASSETS_TOR}
|
||||
)
|
||||
if(NOT ANDROID)
|
||||
add_executable(wowlet ${EXECUTABLE_FLAG} main.cpp
|
||||
${SOURCE_FILES}
|
||||
${RESOURCES}
|
||||
${ASSETS_TOR}
|
||||
)
|
||||
else()
|
||||
add_library(wowlet SHARED ${SOURCE_FILES} ${RESOURCES})
|
||||
set_target_properties(wowlet PROPERTIES COMPILE_DEFINITIONS "ANDROID")
|
||||
endif()
|
||||
|
||||
# mac os bundle
|
||||
set_target_properties(feather PROPERTIES
|
||||
set_target_properties(wowlet PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/utils/Info.plist"
|
||||
LINK_FLAGS_RELEASE -s
|
||||
)
|
||||
|
||||
set_property(TARGET feather PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||
set_property(TARGET wowlet PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||
|
||||
target_include_directories(feather PUBLIC ${OPENGL_INCLUDE_DIR})
|
||||
target_include_directories(feather PUBLIC ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
|
||||
target_include_directories(wowlet PUBLIC ${OPENGL_INCLUDE_DIR})
|
||||
target_include_directories(wowlet PUBLIC ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
|
||||
|
||||
file(GLOB_RECURSE SRC_SOURCES *.cpp)
|
||||
file(GLOB_RECURSE SRC_HEADERS *.h)
|
||||
|
||||
target_include_directories(feather PUBLIC
|
||||
${CMAKE_BINARY_DIR}/src/feather_autogen/include
|
||||
${CMAKE_SOURCE_DIR}/monero/include
|
||||
${CMAKE_SOURCE_DIR}/monero/src
|
||||
${CMAKE_SOURCE_DIR}/monero/external/easylogging++
|
||||
${CMAKE_SOURCE_DIR}/monero/contrib/epee/include
|
||||
target_include_directories(wowlet PUBLIC
|
||||
${CMAKE_BINARY_DIR}/src/wowlet_autogen/include
|
||||
${CMAKE_SOURCE_DIR}/wownero/include
|
||||
${CMAKE_SOURCE_DIR}/wownero/src
|
||||
${CMAKE_SOURCE_DIR}/wownero/external/easylogging++
|
||||
${CMAKE_SOURCE_DIR}/wownero/contrib/epee/include
|
||||
${CMAKE_SOURCE_DIR}/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/daemon
|
||||
|
@ -105,7 +135,9 @@ target_include_directories(feather PUBLIC
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/tor
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/qrcode
|
||||
${X11_INCLUDE_DIR}
|
||||
${QRENCODE_INCLUDE_DIR}
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${Iconv_INCLUDE_DIRS}
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
${Qt5Core_INCLUDE_DIRS}
|
||||
${Qt5Widgets_INCLUDE_DIRS}
|
||||
|
@ -116,43 +148,64 @@ target_include_directories(feather PUBLIC
|
|||
${Qt5WebSockets_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
if(DONATE_BEG)
|
||||
target_compile_definitions(feather PRIVATE DONATE_BEG=1)
|
||||
if(LINUX_ACTIVATION)
|
||||
target_include_directories(wowlet PUBLIC
|
||||
${CAIRO_INCLUDE_DIRS}
|
||||
${XFIXES_INCLUDE_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(XMRTO)
|
||||
target_compile_definitions(feather PRIVATE HAS_XMRTO=1)
|
||||
endif()
|
||||
|
||||
if(MORPHTOKEN)
|
||||
target_compile_definitions(feather PRIVATE HAS_MORPHTOKEN=1)
|
||||
if(OPENVR)
|
||||
target_include_directories(wowlet PUBLIC ${CMAKE_SOURCE_DIR}/contrib/)
|
||||
endif()
|
||||
|
||||
if(TOR_BIN)
|
||||
target_compile_definitions(feather PRIVATE HAS_TOR_BIN=1)
|
||||
target_compile_definitions(wowlet PRIVATE HAS_TOR_BIN=1)
|
||||
endif()
|
||||
|
||||
if(XMRIG)
|
||||
target_compile_definitions(feather PRIVATE HAS_XMRIG=1)
|
||||
if(ANDROID)
|
||||
target_compile_definitions(wowlet PRIVATE HAS_ANDROID=1)
|
||||
endif()
|
||||
|
||||
if(ANDROID_DEBUG)
|
||||
target_compile_definitions(wowlet PRIVATE HAS_ANDROID_DEBUG=1)
|
||||
endif()
|
||||
|
||||
if(OPENVR)
|
||||
target_compile_definitions(wowlet PRIVATE HAS_OPENVR=1)
|
||||
target_compile_definitions(wowlet PUBLIC VR_API_PUBLIC)
|
||||
endif()
|
||||
|
||||
if(HAVE_SYS_PRCTL_H)
|
||||
target_compile_definitions(feather PRIVATE HAVE_SYS_PRCTL_H=1)
|
||||
target_compile_definitions(wowlet PRIVATE HAVE_SYS_PRCTL_H=1)
|
||||
endif()
|
||||
|
||||
if(STATIC)
|
||||
target_compile_definitions(feather PRIVATE STATIC=1)
|
||||
target_compile_definitions(wowlet PRIVATE STATIC=1)
|
||||
endif()
|
||||
|
||||
if(LINUX_ACTIVATION)
|
||||
target_compile_definitions(wowlet PRIVATE LINUX_ACTIVATION=1)
|
||||
endif()
|
||||
|
||||
if("$ENV{DRONE}" STREQUAL "true")
|
||||
target_compile_definitions(feather PRIVATE DRONE=1)
|
||||
target_compile_definitions(wowlet PRIVATE DRONE=1)
|
||||
endif()
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
target_compile_definitions(feather PRIVATE QT_NO_DEBUG=1)
|
||||
target_compile_definitions(wowlet PRIVATE QT_NO_DEBUG=1)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(feather
|
||||
add_definitions(${QT_DEFINITIONS})
|
||||
if(NOT "${CMAKE_BUILD_TYPE}" EQUAL "Debug")
|
||||
add_definitions(-DQT_NO_DEBUG)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(wowlet PUBLIC VR_API_PUBLIC)
|
||||
|
||||
qt5_import_qml_plugins(${PROJECT_NAME})
|
||||
|
||||
target_compile_definitions(wowlet
|
||||
PUBLIC
|
||||
${Qt5Core_DEFINITIONS}
|
||||
${Qt5Widgets_DEFINITIONS}
|
||||
|
@ -165,74 +218,181 @@ target_compile_definitions(feather
|
|||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
if(UNIX)
|
||||
# https://stackoverflow.com/questions/57766620/cmake-add-library-doesnt-initialize-static-global-variable
|
||||
# so that contrib/monero-seed/src/gf_elem.cpp properly initializes. A better solution is welcome.
|
||||
target_link_libraries(feather -Wl,--whole-archive monero-seed::monero-seed -Wl,--no-whole-archive)
|
||||
else()
|
||||
target_link_libraries(feather monero-seed::monero-seed)
|
||||
target_link_libraries(wowlet PUBLIC -Wl,--whole-archive wownero-seed::wownero-seed -Wl,--no-whole-archive)
|
||||
endif()
|
||||
|
||||
target_link_libraries(feather
|
||||
wallet_merged
|
||||
${LMDB_LIBRARY}
|
||||
if(ANDROID)
|
||||
# yolo some hardcoded paths
|
||||
target_include_directories(wowlet PUBLIC
|
||||
/opt/android/prefix/include/QtAndroidExtras/
|
||||
)
|
||||
endif()
|
||||
|
||||
# Link Wownero core libraries
|
||||
target_link_libraries(wowlet PUBLIC
|
||||
epee
|
||||
${UNBOUND_LIBRARY}
|
||||
${SODIUM_LIBRARY}
|
||||
wallet_api
|
||||
easylogging
|
||||
blockchain_db
|
||||
randomx
|
||||
hardforks
|
||||
${Boost_LIBRARIES}
|
||||
${OPENSSL_LIBRARIES}
|
||||
${CMAKE_DL_LIBS}
|
||||
${EXTRA_LIBRARIES}
|
||||
${Iconv_LIBRARIES}
|
||||
${UNBOUND_LIBRARIES}
|
||||
# /usr/local/lib/libunbound.a
|
||||
${EXTRA_LIBRARIES})
|
||||
|
||||
# Link Qt libraries
|
||||
target_link_libraries(wowlet PUBLIC
|
||||
Qt5::Core
|
||||
Qt5::Widgets
|
||||
Qt5::Gui
|
||||
Qt5::Network
|
||||
Qt5::Svg
|
||||
Qt5::QSvgPlugin
|
||||
Qt5::QSvgIconPlugin
|
||||
Qt5::Xml
|
||||
Qt5::WebSockets
|
||||
${ICU_LIBRARIES}
|
||||
openpgp
|
||||
Qt5::Quick
|
||||
Qt5::Qml
|
||||
Qt5::QuickControls2
|
||||
Qt5::QuickWidgets)
|
||||
|
||||
if(ANDROID)
|
||||
# yolo some hardcoded paths
|
||||
target_link_libraries(wowlet PUBLIC
|
||||
/opt/android/prefix/lib/libQt5QuickTemplates2_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5Quick_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5QmlModels_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5Qml_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5Svg_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5Widgets_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5Gui_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5Xml_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5XmlPatterns_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5Network_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5Core_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5VirtualKeyboard_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5AndroidExtras_arm64-v8a.so
|
||||
/opt/android/prefix/plugins/bearer/libplugins_bearer_qandroidbearer_arm64-v8a.so
|
||||
GLESv2
|
||||
log
|
||||
z
|
||||
jnigraphics
|
||||
android
|
||||
EGL
|
||||
c++_shared
|
||||
)
|
||||
endif()
|
||||
|
||||
# Link random other stuff
|
||||
target_link_libraries(wowlet PUBLIC
|
||||
Threads::Threads
|
||||
${QRENCODE_LIBRARY}
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
target_link_libraries(feather
|
||||
KDMacTouchBar
|
||||
# Link Cairo and Xfixes
|
||||
if(LINUX_ACTIVATION)
|
||||
target_link_libraries(wowlet PUBLIC
|
||||
${CAIRO_LIBRARIES}
|
||||
${XFIXES_LIBRARY}
|
||||
${X11_Xinerama_LIB}
|
||||
)
|
||||
target_include_directories(feather
|
||||
PUBLIC ../contrib/KDMacTouchBar)
|
||||
endif()
|
||||
|
||||
if(NOT APPLE)
|
||||
target_link_libraries(feather
|
||||
Qt5::QSvgIconPlugin
|
||||
Qt5::QSvgPlugin
|
||||
)
|
||||
# Link scanner
|
||||
if(WITH_SCANNER)
|
||||
target_link_libraries(wowlet PUBLIC qrdecoder qrscanner)
|
||||
if(LINUX AND NOT ANDROID)
|
||||
target_link_libraries(wowlet PUBLIC
|
||||
jpeg
|
||||
v4l2
|
||||
v4lconvert
|
||||
rt
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Link OpenVR
|
||||
if(OPENVR)
|
||||
if(MINGW)
|
||||
target_link_libraries(wowlet PUBLIC
|
||||
openvr_api64
|
||||
gcc stdc++ winpthread ssp glu32 opengl32 glmf32 -dynamic)
|
||||
else()
|
||||
target_link_libraries(wowlet PUBLIC openvr_api)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_link_libraries(wowlet PUBLIC
|
||||
Qt5::QSvgIconPlugin
|
||||
Qt5::QSvgPlugin
|
||||
)
|
||||
|
||||
if(STATIC)
|
||||
target_link_libraries(feather
|
||||
target_link_libraries(wowlet PUBLIC
|
||||
Qt5::QSvgIconPlugin
|
||||
Qt5::QSvgPlugin)
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries(feather
|
||||
Qt5::QXcbIntegrationPlugin)
|
||||
if(UNIX)
|
||||
target_link_libraries(wowlet PUBLIC
|
||||
Qt5::QXcbIntegrationPlugin)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(X11_FOUND)
|
||||
target_link_libraries(feather ${X11_LIBRARIES})
|
||||
target_link_libraries(wowlet PUBLIC ${X11_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
include(Deploy)
|
||||
endif()
|
||||
|
||||
install(TARGETS feather
|
||||
install(TARGETS wowlet
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX}
|
||||
)
|
||||
|
||||
|
||||
message(STATUS "\n====================================== SUMMARY")
|
||||
if(GIT_FOUND)
|
||||
execute_process(COMMAND git rev-parse "HEAD" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/wownero OUTPUT_VARIABLE _WOWNERO_HEAD OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT _WOWNERO_HEAD STREQUAL WOWNERO_HEAD)
|
||||
message(STATUS "[+] WOWNERO HEAD: ${_WOWNERO_HEAD} ... while CMake requested ${WOWNERO_HEAD}")
|
||||
else()
|
||||
message(STATUS "[+] WOWNERO HEAD: ${WOWNERO_HEAD}")
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "[+] VERSION: ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}-${VERSION}")
|
||||
message(STATUS "[+] STATIC: ${STATIC}")
|
||||
message(STATUS "[+] Include Valve's OpenVR library: ${OPENVR}")
|
||||
message(STATUS "[+] This build is for Android: ${ANDROID}")
|
||||
message(STATUS "[+] This build is for testing the Android app on desktop: ${ANDROID_DEBUG}")
|
||||
message(STATUS "[+] TOR_BIN: ${TOR_BIN}")
|
||||
message(STATUS "[+] LINUX_ACTIVATION: ${LINUX_ACTIVATION}")
|
||||
|
||||
message(STATUS "[+] OpenSSL")
|
||||
message(STATUS " - version: ${OPENSSL_VERSION}")
|
||||
message(STATUS " - dirs: ${OPENSSL_INCLUDE_DIR}")
|
||||
message(STATUS " - libs: ${OPENSSL_LIBRARIES} ${OPENSSL_SSL_LIBRARIES}")
|
||||
|
||||
if(CAIRO_FOUND)
|
||||
message(STATUS "[+] Cairo")
|
||||
message(STATUS " - version: ${CAIRO_VERSION}")
|
||||
message(STATUS " - dirs: ${CAIRO_INCLUDE_DIRS}")
|
||||
message(STATUS " - libs: ${CAIRO_LIBRARIES}")
|
||||
endif()
|
||||
|
||||
if(XFIXES_FOUND)
|
||||
message(STATUS "[+] Xfixes")
|
||||
message(STATUS " - dirs: ${XFIXES_INCLUDE_DIR}")
|
||||
message(STATUS " - libs: ${XFIXES_LIBRARY}")
|
||||
endif()
|
||||
|
||||
message(STATUS "[+] Boost")
|
||||
message(STATUS " - version: ${Boost_VERSION}")
|
||||
message(STATUS " - dirs: ${Boost_INCLUDE_DIRS}")
|
||||
message(STATUS " - libs: ${Boost_LIBRARIES}")
|
||||
|
||||
if(Iconv_FOUND)
|
||||
message(STATUS "[+] Iconv")
|
||||
message(STATUS " - version: ${Iconv_VERSION}")
|
||||
message(STATUS " - libs: ${Iconv_LIBRARIES}")
|
||||
message(STATUS " - dirs: ${Iconv_INCLUDE_DIRS}")
|
||||
endif()
|
||||
|
|
|
@ -1,230 +0,0 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
#include "MorphTokenWidget.h"
|
||||
#include "ui_MorphTokenWidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "qrcode/QrCode.h"
|
||||
#include "dialog/qrcodedialog.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
MorphTokenWidget::MorphTokenWidget(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::MorphTokenWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
m_ctx = MainWindow::getContext();
|
||||
|
||||
m_network = new UtilsNetworking(this->m_ctx->network);
|
||||
m_api = new MorphTokenApi(this, m_network);
|
||||
|
||||
connect(ui->btnCreateTrade, &QPushButton::clicked, this, &MorphTokenWidget::createTrade);
|
||||
connect(ui->btn_lookupTrade, &QPushButton::clicked, this, &MorphTokenWidget::lookupTrade);
|
||||
connect(ui->btn_getRates, &QPushButton::clicked, this, &MorphTokenWidget::getRates);
|
||||
|
||||
connect(m_api, &MorphTokenApi::ApiResponse, this, &MorphTokenWidget::onApiResponse);
|
||||
|
||||
connect(ui->combo_From, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index){
|
||||
this->displayRate();
|
||||
ui->label_refundAddress->setText(QString("Refund address (%1):").arg(ui->combo_From->currentText()));
|
||||
});
|
||||
connect(ui->combo_To, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index){
|
||||
this->displayRate();
|
||||
ui->label_destinationAddress->setText(QString("Destination address (%1):").arg(ui->combo_To->currentText()));
|
||||
});
|
||||
|
||||
connect(ui->check_autorefresh, &QCheckBox::toggled, [this](bool toggled){
|
||||
m_countdown = 30;
|
||||
toggled ? m_countdownTimer.start(1000) : m_countdownTimer.stop();
|
||||
ui->check_autorefresh->setText("Autorefresh");
|
||||
});
|
||||
connect(&m_countdownTimer, &QTimer::timeout, this, &MorphTokenWidget::onCountdown);
|
||||
|
||||
connect(ui->line_Id, &QLineEdit::textChanged, [this](const QString &text){
|
||||
ui->btn_lookupTrade->setEnabled(!text.isEmpty());
|
||||
ui->check_autorefresh->setEnabled(!text.isEmpty());
|
||||
});
|
||||
|
||||
// Default to BTC -> XMR
|
||||
ui->combo_From->setCurrentIndex(1);
|
||||
ui->combo_To->setCurrentIndex(0);
|
||||
|
||||
ui->label_rate->setVisible(false);
|
||||
m_ratesTimer.setSingleShot(true);
|
||||
connect(&m_ratesTimer, &QTimer::timeout, [this]{
|
||||
ui->label_rate->setVisible(false);
|
||||
});
|
||||
|
||||
ui->qrCode->setVisible(false);
|
||||
ui->label_depositAddress->setVisible(false);
|
||||
connect(ui->qrCode, &ClickableLabel::clicked, this, &MorphTokenWidget::showQrCodeDialog);
|
||||
|
||||
ui->tabWidget->setTabVisible(2, false);
|
||||
}
|
||||
|
||||
void MorphTokenWidget::createTrade() {
|
||||
QString inputAsset = ui->combo_From->currentText();
|
||||
QString outputAsset = ui->combo_To->currentText();
|
||||
QString refundAddress = ui->line_refundAddress->text();
|
||||
QString destinationAddress = ui->line_destinationAddress->text();
|
||||
|
||||
m_api->createTrade(inputAsset, outputAsset, refundAddress, destinationAddress);
|
||||
}
|
||||
|
||||
void MorphTokenWidget::lookupTrade() {
|
||||
QString morphId = ui->line_Id->text();
|
||||
|
||||
if (!morphId.isEmpty())
|
||||
m_api->getTrade(morphId);
|
||||
}
|
||||
|
||||
void MorphTokenWidget::getRates() {
|
||||
m_api->getRates();
|
||||
}
|
||||
|
||||
void MorphTokenWidget::onApiResponse(const MorphTokenApi::MorphTokenResponse &resp) {
|
||||
if (!resp.ok) {
|
||||
ui->check_autorefresh->setChecked(false);
|
||||
QMessageBox::warning(this, "MorphToken error", QString("Request failed:\n\n%1").arg(resp.message));
|
||||
return;
|
||||
}
|
||||
|
||||
ui->debugInfo->setPlainText(QJsonDocument(resp.obj).toJson(QJsonDocument::Indented));
|
||||
|
||||
bool shouldShowQr = (resp.endpoint == MorphTokenApi::Endpoint::CREATE_TRADE || resp.endpoint == MorphTokenApi::Endpoint::GET_TRADE);
|
||||
ui->qrCode->setVisible(shouldShowQr);
|
||||
ui->label_depositAddress->setVisible(shouldShowQr);
|
||||
|
||||
if (resp.endpoint == MorphTokenApi::Endpoint::CREATE_TRADE || resp.endpoint == MorphTokenApi::Endpoint::GET_TRADE) {
|
||||
ui->tabWidget->setCurrentIndex(1);
|
||||
ui->line_Id->setText(resp.obj.value("id").toString());
|
||||
|
||||
auto obj = resp.obj;
|
||||
auto input = obj["input"].toObject();
|
||||
auto output = obj["output"].toArray()[0].toObject();
|
||||
QString state = obj.value("state").toString();
|
||||
QString statusText;
|
||||
|
||||
ui->trade->setTitle(QString("Trade (%1)").arg(state));
|
||||
|
||||
statusText += QString("Morph ID: %1\n\n").arg(obj["id"].toString());
|
||||
|
||||
if (state == "PENDING") {
|
||||
statusText += QString("Waiting for a deposit, send %1 to %2\n").arg(input["asset"].toString(),
|
||||
input["deposit_address"].toString());
|
||||
statusText += QString("Rate: 1 %1 -> %2 %3\n\n").arg(input["asset"].toString(),
|
||||
output["seen_rate"].toString(),
|
||||
output["asset"].toString());
|
||||
statusText += "Limits:\n";
|
||||
statusText += QString(" Minimum amount accepted: %1 %2\n").arg(formatAmount(input["asset"].toString(), input["limits"].toObject()["min"].toDouble()),
|
||||
input["asset"].toString());
|
||||
statusText += QString(" Maximum amount accepted: %1 %2\n").arg(formatAmount(input["asset"].toString(), input["limits"].toObject()["max"].toDouble()),
|
||||
input["asset"].toString());
|
||||
statusText += QString("\nSend a single deposit. If the amount is outside the limits, a refund will happen.");
|
||||
|
||||
m_depositAddress = input["deposit_address"].toString();
|
||||
|
||||
const QrCode qrc(m_depositAddress, QrCode::Version::AUTO, QrCode::ErrorCorrectionLevel::MEDIUM);
|
||||
int width = ui->qrCode->width();
|
||||
if (qrc.isValid()) {
|
||||
ui->qrCode->setPixmap(qrc.toPixmap(1).scaled(width, width, Qt::KeepAspectRatio));
|
||||
}
|
||||
} else if (state == "PROCESSING" || state == "TRADING" || state == "CONFIRMING") {
|
||||
if (state == "CONFIRMING") {
|
||||
statusText += QString("Waiting for confirmations\n");
|
||||
} else if (state == "TRADING") {
|
||||
statusText += QString("Your transaction has been received and is confirmed. MorphToken is now executing your trade.\n"
|
||||
"Usually this step takes no longer than a minute, "
|
||||
"but in rare cases it can take a couple hours.\n"
|
||||
"Wait a bit before contacting support.\n");
|
||||
}
|
||||
statusText += QString("Converting %1 to %2\n").arg(input["asset"].toString(), output["asset"].toString());
|
||||
statusText += QString("Sending to %1\n").arg(output["address"].toString());
|
||||
statusText += QString("Stuck? Contact support at contact@morphtoken.com");
|
||||
} else if (state == "COMPLETE") {
|
||||
if (output["txid"].toString().isEmpty()) {
|
||||
statusText += QString("MorphToken is sending your transaction.\n");
|
||||
statusText += QString("MorphToken will send %1 %2 to %2").arg(this->formatAmount(output["asset"].toString(), output["converted_amount"].toDouble() - output["network_fee"].toObject()["fee"].toDouble()),
|
||||
output["asset"].toString(),
|
||||
output["address"].toString());
|
||||
} else {
|
||||
statusText += QString("Sent %1 %2 to %3\ntxid: {}").arg(this->formatAmount(output["asset"].toString(), output["converted_amount"].toDouble() - output["network_fee"].toObject()["fee"].toDouble()),
|
||||
output["asset"].toString(),
|
||||
output["address"].toString(),
|
||||
output["txid"].toString());
|
||||
}
|
||||
} else if (state == "PROCESSING_REFUND" || state == "COMPLETE_WITH_REFUND") {
|
||||
statusText += QString("MorphToken will refund %1 %2\nReason: %3\n").arg(obj["final_amount"].toString(),
|
||||
obj["asset"].toString(),
|
||||
obj["reason"].toString());
|
||||
|
||||
if (obj.contains("txid")) {
|
||||
statusText += QString("txid: %1").arg(obj["txid"].toString());
|
||||
}
|
||||
} else if (state == "COMPLETE_WITHOUT_REFUND") {
|
||||
statusText += "Deposit amount below network fee, too small to refund.";
|
||||
} else if (state == "PROCESSING_DELAY") {
|
||||
statusText += "Please enter in contact with support.\n\ncontact@morphtoken.com";
|
||||
} else if (state == "CANCELLED") {
|
||||
statusText += "The trade was cancelled. If this is unexpected, please contact support at contact@morphtoken.com";
|
||||
}
|
||||
|
||||
ui->label_status->setText(statusText);
|
||||
} else if (resp.endpoint == MorphTokenApi::Endpoint::GET_RATES) {
|
||||
m_rates = resp.obj.value("data").toObject();
|
||||
this->displayRate();
|
||||
ui->label_rate->setVisible(true);
|
||||
m_ratesTimer.start(120 * 1000);
|
||||
}
|
||||
|
||||
if (resp.endpoint == MorphTokenApi::Endpoint::CREATE_TRADE) {
|
||||
QMessageBox::information(this, "MorphToken", "Trade created!\n\nMake sure to save your Morph ID. You may need it in case something goes wrong.");
|
||||
}
|
||||
}
|
||||
|
||||
void MorphTokenWidget::onCountdown() {
|
||||
if (m_countdown > 0) {
|
||||
m_countdown -= 1;
|
||||
} else {
|
||||
this->lookupTrade();
|
||||
m_countdown = 30;
|
||||
}
|
||||
ui->check_autorefresh->setText(QString("Autorefresh (%1)").arg(m_countdown));
|
||||
}
|
||||
|
||||
void MorphTokenWidget::displayRate() {
|
||||
QString inputAsset = ui->combo_From->currentText();
|
||||
QString outputAsset = ui->combo_To->currentText();
|
||||
QString outputRate = m_rates.value(inputAsset).toObject().value(outputAsset).toString("1");
|
||||
|
||||
QString rateStr = QString("1 %1 -> %2 %3").arg(inputAsset, outputRate, outputAsset);
|
||||
ui->label_rate->setText(rateStr);
|
||||
}
|
||||
|
||||
void MorphTokenWidget::showQrCodeDialog() {
|
||||
QrCode qr(m_depositAddress, QrCode::Version::AUTO, QrCode::ErrorCorrectionLevel::HIGH);
|
||||
auto *dialog = new QrCodeDialog(this, qr, "Deposit address");
|
||||
dialog->exec();
|
||||
dialog->deleteLater();
|
||||
}
|
||||
|
||||
QString MorphTokenWidget::formatAmount(const QString &asset, double amount) {
|
||||
double displayAmount;
|
||||
double div;
|
||||
|
||||
if (asset == "ETH")
|
||||
div = 1e18;
|
||||
else if (asset == "XMR")
|
||||
div = 1e12;
|
||||
else
|
||||
div = 1e8;
|
||||
|
||||
displayAmount = amount / div;
|
||||
|
||||
return QString::number(displayAmount, 'f', 8);
|
||||
}
|
||||
|
||||
MorphTokenWidget::~MorphTokenWidget() {
|
||||
delete ui;
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
#ifndef FEATHER_MORPHTOKENWIDGET_H
|
||||
#define FEATHER_MORPHTOKENWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "appcontext.h"
|
||||
#include "utils/MorphTokenApi.h"
|
||||
|
||||
namespace Ui {
|
||||
class MorphTokenWidget;
|
||||
}
|
||||
|
||||
class MorphTokenWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MorphTokenWidget(QWidget *parent = nullptr);
|
||||
~MorphTokenWidget() override;
|
||||
|
||||
private:
|
||||
void createTrade();
|
||||
void lookupTrade();
|
||||
void getRates();
|
||||
void onApiResponse(const MorphTokenApi::MorphTokenResponse &resp);
|
||||
|
||||
void onCountdown();
|
||||
void displayRate();
|
||||
void showQrCodeDialog();
|
||||
|
||||
QString formatAmount(const QString &asset, double amount);
|
||||
|
||||
Ui::MorphTokenWidget *ui;
|
||||
|
||||
AppContext *m_ctx;
|
||||
MorphTokenApi *m_api;
|
||||
UtilsNetworking *m_network;
|
||||
QTimer m_countdownTimer;
|
||||
int m_countdown = 30;
|
||||
QJsonObject m_rates;
|
||||
QTimer m_ratesTimer;
|
||||
QString m_depositAddress;
|
||||
};
|
||||
|
||||
#endif //FEATHER_MORPHTOKENWIDGET_H
|
|
@ -1,423 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MorphTokenWidget</class>
|
||||
<widget class="QWidget" name="MorphTokenWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1036</width>
|
||||
<height>614</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tabCreateTrade">
|
||||
<attribute name="title">
|
||||
<string>Create trade</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>From:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="combo_From">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>XMR</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>BTC</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>ETH</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>BCH</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>LTC</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>DASH</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>To:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="combo_To">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>XMR</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>BTC</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>ETH</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>BCH</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>LTC</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>DASH</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_rate">
|
||||
<property name="text">
|
||||
<string>rate</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_refundAddress">
|
||||
<property name="text">
|
||||
<string>Refund address (XMR):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="line_refundAddress"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_destinationAddress">
|
||||
<property name="text">
|
||||
<string>Destination address (XMR):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="line_destinationAddress"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Powered by MorphToken.com</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_getRates">
|
||||
<property name="text">
|
||||
<string>Get Rates</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnCreateTrade">
|
||||
<property name="text">
|
||||
<string>Create Trade</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabLookupTrade">
|
||||
<attribute name="title">
|
||||
<string>Lookup trade</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Morph ID or MorphToken deposit address:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="line_Id"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="check_autorefresh">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Autorefresh</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_lookupTrade">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Lookup trade</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="trade">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Trade</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_status">
|
||||
<property name="text">
|
||||
<string>No trade loaded.</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="ClickableLabel" name="qrCode">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>qrcode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_depositAddress">
|
||||
<property name="text">
|
||||
<string>Deposit address</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabDebug">
|
||||
<attribute name="title">
|
||||
<string>Debug</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="debugInfo">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ClickableLabel</class>
|
||||
<extends>QLabel</extends>
|
||||
<header>components.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
22
src/QR-Code-scanner/CMakeLists.txt
Normal file
|
@ -0,0 +1,22 @@
|
|||
add_library(qrdecoder STATIC
|
||||
Decoder.cpp
|
||||
)
|
||||
target_link_libraries(qrdecoder
|
||||
PUBLIC
|
||||
Qt5::Gui
|
||||
PNG::PNG
|
||||
PRIVATE
|
||||
quirc
|
||||
)
|
||||
|
||||
if(WITH_SCANNER)
|
||||
add_library(qrscanner
|
||||
QrCodeScanner.cpp
|
||||
QrScanThread.cpp
|
||||
)
|
||||
target_link_libraries(qrscanner
|
||||
PUBLIC
|
||||
Qt5::Multimedia
|
||||
qrdecoder
|
||||
)
|
||||
endif()
|
359
src/QR-Code-scanner/Decoder.cpp
Normal file
|
@ -0,0 +1,359 @@
|
|||
// Copyright (c) 2020, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits>
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include "Decoder.h"
|
||||
#include "quirc.h"
|
||||
|
||||
|
||||
QrDecoder::QrDecoder()
|
||||
: m_qr(quirc_new())
|
||||
{
|
||||
if (m_qr == nullptr)
|
||||
{
|
||||
throw std::runtime_error("QUIRC: failed to allocate memory");
|
||||
}
|
||||
}
|
||||
|
||||
QrDecoder::~QrDecoder()
|
||||
{
|
||||
quirc_destroy(m_qr);
|
||||
}
|
||||
|
||||
std::vector<std::string> QrDecoder::decode(const QImage &image)
|
||||
{
|
||||
if (image.format() == QImage::Format_Grayscale8)
|
||||
{
|
||||
return decodeGrayscale8(image);
|
||||
}
|
||||
return decodeGrayscale8(image.convertToFormat(QImage::Format_Grayscale8));
|
||||
}
|
||||
|
||||
std::vector<std::string> QrDecoder::decodePNG(QString pngPath) {
|
||||
struct quirc *q;
|
||||
std::vector<std::string> result;
|
||||
auto pngPathStd = pngPath.toStdString();
|
||||
auto pngPathCstr = pngPathStd.c_str();
|
||||
|
||||
q = quirc_new();
|
||||
if (!q) {
|
||||
qWarning() << "can't create quirc object";
|
||||
return result;
|
||||
}
|
||||
|
||||
int status = -1;
|
||||
if (check_if_png(pngPathCstr)) {
|
||||
status = load_png(q, pngPathCstr);
|
||||
} else {
|
||||
qWarning() << QString("Image is not a PNG: %1").arg(pngPath);
|
||||
return result;
|
||||
}
|
||||
if (status < 0) {
|
||||
quirc_destroy(q);
|
||||
return result;
|
||||
}
|
||||
|
||||
quirc_end(q);
|
||||
auto count = quirc_count(q);
|
||||
result.reserve(static_cast<size_t>(count));
|
||||
|
||||
for (int index = 0; index < count; ++index)
|
||||
{
|
||||
quirc_code code;
|
||||
quirc_extract(q, index, &code);
|
||||
|
||||
quirc_data data;
|
||||
const quirc_decode_error_t err = quirc_decode(&code, &data);
|
||||
if (err == QUIRC_SUCCESS)
|
||||
{
|
||||
result.emplace_back(&data.payload[0], &data.payload[data.payload_len]);
|
||||
}
|
||||
}
|
||||
|
||||
quirc_destroy(q);
|
||||
return result;
|
||||
}
|
||||
|
||||
// I can't seem to get this function to work, we'll use dgbutil.h instead
|
||||
std::vector<std::string> QrDecoder::decodeGrayscale8(const QImage &image)
|
||||
{
|
||||
if (quirc_resize(m_qr, image.width(), image.height()) < 0)
|
||||
{
|
||||
throw std::runtime_error("QUIRC: failed to allocate video memory");
|
||||
}
|
||||
|
||||
uint8_t *rawImage = quirc_begin(m_qr, nullptr, nullptr);
|
||||
if (rawImage == nullptr)
|
||||
{
|
||||
throw std::runtime_error("QUIRC: failed to get image buffer");
|
||||
}
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
std::copy(image.constBits(), image.constBits() + image.sizeInBytes(), rawImage);
|
||||
#else
|
||||
std::copy(image.constBits(), image.constBits() + image.byteCount(), rawImage);
|
||||
#endif
|
||||
quirc_end(m_qr);
|
||||
|
||||
const int count = quirc_count(m_qr);
|
||||
if (count < 0)
|
||||
{
|
||||
throw std::runtime_error("QUIRC: failed to get the number of recognized QR-codes");
|
||||
}
|
||||
|
||||
std::vector<std::string> result;
|
||||
result.reserve(static_cast<size_t>(count));
|
||||
for (int index = 0; index < count; ++index)
|
||||
{
|
||||
quirc_code code;
|
||||
quirc_extract(m_qr, index, &code);
|
||||
|
||||
quirc_data data;
|
||||
const quirc_decode_error_t err = quirc_decode(&code, &data);
|
||||
if (err == QUIRC_SUCCESS)
|
||||
{
|
||||
result.emplace_back(&data.payload[0], &data.payload[data.payload_len]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* quirc -- QR-code recognition library
|
||||
* Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
static const char *data_type_str(int dt)
|
||||
{
|
||||
switch (dt) {
|
||||
case QUIRC_DATA_TYPE_NUMERIC: return "NUMERIC";
|
||||
case QUIRC_DATA_TYPE_ALPHA: return "ALPHA";
|
||||
case QUIRC_DATA_TYPE_BYTE: return "BYTE";
|
||||
case QUIRC_DATA_TYPE_KANJI: return "KANJI";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
void QrDecoder::dump_data(const struct quirc_data *data)
|
||||
{
|
||||
printf(" Version: %d\n", data->version);
|
||||
printf(" ECC level: %c\n", "MLHQ"[data->ecc_level]);
|
||||
printf(" Mask: %d\n", data->mask);
|
||||
printf(" Data type: %d (%s)\n",
|
||||
data->data_type, data_type_str(data->data_type));
|
||||
printf(" Length: %d\n", data->payload_len);
|
||||
printf(" Payload: %s\n", data->payload);
|
||||
|
||||
if (data->eci)
|
||||
printf(" ECI: %d\n", data->eci);
|
||||
}
|
||||
|
||||
void QrDecoder::dump_cells(const struct quirc_code *code)
|
||||
{
|
||||
int u, v;
|
||||
|
||||
printf(" %d cells, corners:", code->size);
|
||||
for (u = 0; u < 4; u++)
|
||||
printf(" (%d,%d)", code->corners[u].x,
|
||||
code->corners[u].y);
|
||||
printf("\n");
|
||||
|
||||
for (v = 0; v < code->size; v++) {
|
||||
printf(" ");
|
||||
for (u = 0; u < code->size; u++) {
|
||||
int p = v * code->size + u;
|
||||
|
||||
if (code->cell_bitmap[p >> 3] & (1 << (p & 7)))
|
||||
printf("[]");
|
||||
else
|
||||
printf(" ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* hacked from https://dev.w3.org/Amaya/libpng/example.c
|
||||
*
|
||||
* Check if a file is a PNG image using png_sig_cmp(). Returns 1 if the given
|
||||
* file is a PNG and 0 otherwise.
|
||||
*/
|
||||
#define PNG_BYTES_TO_CHECK 4
|
||||
int QrDecoder::check_if_png(const char *filename)
|
||||
{
|
||||
int ret = 0;
|
||||
FILE *infile = NULL;
|
||||
unsigned char buf[PNG_BYTES_TO_CHECK];
|
||||
|
||||
/* Open the prospective PNG file. */
|
||||
if ((infile = fopen(filename, "rb")) == NULL)
|
||||
goto out;
|
||||
|
||||
/* Read in some of the signature bytes */
|
||||
if (fread(buf, 1, PNG_BYTES_TO_CHECK, infile) != PNG_BYTES_TO_CHECK)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Compare the first PNG_BYTES_TO_CHECK bytes of the signature.
|
||||
* png_sig_cmp() returns zero if the image is a PNG and nonzero if it
|
||||
* isn't a PNG.
|
||||
*/
|
||||
if (png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK) == 0)
|
||||
ret = 1;
|
||||
|
||||
/* FALLTHROUGH */
|
||||
out:
|
||||
if (infile)
|
||||
fclose(infile);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int QrDecoder::load_png(struct quirc *q, const char *filename)
|
||||
{
|
||||
int width, height, rowbytes, interlace_type, number_passes = 1;
|
||||
png_uint_32 trns;
|
||||
png_byte color_type, bit_depth;
|
||||
png_structp png_ptr = NULL;
|
||||
png_infop info_ptr = NULL;
|
||||
FILE *infile = NULL;
|
||||
uint8_t *image;
|
||||
int ret = -1;
|
||||
int pass;
|
||||
|
||||
if ((infile = fopen(filename, "rb")) == NULL)
|
||||
goto out;
|
||||
|
||||
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (!png_ptr)
|
||||
goto out;
|
||||
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!info_ptr)
|
||||
goto out;
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
goto out;
|
||||
|
||||
png_init_io(png_ptr, infile);
|
||||
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
|
||||
color_type = png_get_color_type(png_ptr, info_ptr);
|
||||
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
|
||||
interlace_type = png_get_interlace_type(png_ptr, info_ptr);
|
||||
|
||||
// Read any color_type into 8bit depth, Grayscale format.
|
||||
// See http://www.libpng.org/pub/png/libpng-manual.txt
|
||||
|
||||
// PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth.
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
|
||||
png_set_expand_gray_1_2_4_to_8(png_ptr);
|
||||
|
||||
if ((trns = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
|
||||
png_set_tRNS_to_alpha(png_ptr);
|
||||
|
||||
if (bit_depth == 16)
|
||||
#if PNG_LIBPNG_VER >= 10504
|
||||
png_set_scale_16(png_ptr);
|
||||
#else
|
||||
png_set_strip_16(png_ptr);
|
||||
#endif
|
||||
|
||||
if ((trns) || color_type & PNG_COLOR_MASK_ALPHA)
|
||||
png_set_strip_alpha(png_ptr);
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
png_set_palette_to_rgb(png_ptr);
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_PALETTE ||
|
||||
color_type == PNG_COLOR_TYPE_RGB ||
|
||||
color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
|
||||
png_set_rgb_to_gray_fixed(png_ptr, 1, -1, -1);
|
||||
}
|
||||
|
||||
if (interlace_type != PNG_INTERLACE_NONE)
|
||||
number_passes = png_set_interlace_handling(png_ptr);
|
||||
|
||||
png_read_update_info(png_ptr, info_ptr);
|
||||
|
||||
width = png_get_image_width(png_ptr, info_ptr);
|
||||
height = png_get_image_height(png_ptr, info_ptr);
|
||||
rowbytes = png_get_rowbytes(png_ptr, info_ptr);
|
||||
if (rowbytes != width) {
|
||||
fprintf(stderr,
|
||||
"load_png: expected rowbytes to be %u but got %u\n",
|
||||
width, rowbytes);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (quirc_resize(q, width, height) < 0)
|
||||
goto out;
|
||||
|
||||
image = quirc_begin(q, NULL, NULL);
|
||||
|
||||
for (pass = 0; pass < number_passes; pass++) {
|
||||
int y;
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
png_bytep row_pointer = image + y * width;
|
||||
png_read_rows(png_ptr, &row_pointer, NULL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
png_read_end(png_ptr, info_ptr);
|
||||
|
||||
ret = 0;
|
||||
/* FALLTHROUGH */
|
||||
out:
|
||||
/* cleanup */
|
||||
if (png_ptr) {
|
||||
if (info_ptr)
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
|
||||
else
|
||||
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
|
||||
}
|
||||
if (infile)
|
||||
fclose(infile);
|
||||
return (ret);
|
||||
}
|
|
@ -26,63 +26,47 @@
|
|||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
#include <QImage>
|
||||
|
||||
#include <vector>
|
||||
#include <png.h>
|
||||
|
||||
#include <span.h>
|
||||
struct quirc;
|
||||
|
||||
#include "serialization.h"
|
||||
|
||||
namespace openpgp
|
||||
{
|
||||
|
||||
class packet_stream
|
||||
class QrDecoder
|
||||
{
|
||||
public:
|
||||
packet_stream(const epee::span<const uint8_t> buffer)
|
||||
: packet_stream(deserializer<epee::span<const uint8_t>>(buffer))
|
||||
{
|
||||
}
|
||||
QrDecoder(const QrDecoder &) = delete;
|
||||
QrDecoder &operator=(const QrDecoder &) = delete;
|
||||
|
||||
template <
|
||||
typename byte_container,
|
||||
typename = typename std::enable_if<(sizeof(typename byte_container::value_type) == 1)>::type>
|
||||
packet_stream(deserializer<byte_container> buffer)
|
||||
{
|
||||
while (!buffer.empty())
|
||||
{
|
||||
packet_tag tag = buffer.read_packet_tag();
|
||||
packets.push_back({std::move(tag), buffer.read(tag.length)});
|
||||
}
|
||||
}
|
||||
QrDecoder();
|
||||
~QrDecoder();
|
||||
|
||||
const std::vector<uint8_t> *find_first(packet_tag::type type) const
|
||||
{
|
||||
for (const auto &packet : packets)
|
||||
{
|
||||
if (packet.first.packet_type == type)
|
||||
{
|
||||
return &packet.second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename Callback>
|
||||
void for_each(packet_tag::type type, Callback &callback) const
|
||||
{
|
||||
for (const auto &packet : packets)
|
||||
{
|
||||
if (packet.first.packet_type == type)
|
||||
{
|
||||
callback(packet.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::vector<std::string> decode(const QImage &image);
|
||||
std::vector<std::string> decodePNG(QString pngPath);
|
||||
|
||||
private:
|
||||
std::vector<std::pair<packet_tag, std::vector<uint8_t>>> packets;
|
||||
};
|
||||
/* Dump decoded information on stdout. */
|
||||
void dump_data(const struct quirc_data *data);
|
||||
|
||||
} // namespace openpgp
|
||||
/* Dump a grid cell map on stdout. */
|
||||
void dump_cells(const struct quirc_code *code);
|
||||
|
||||
/* Check if a file is a PNG image.
|
||||
*
|
||||
* returns 1 if the given file is a PNG and 0 otherwise.
|
||||
*/
|
||||
int check_if_png(const char *filename);
|
||||
|
||||
/* Read a PNG image into the decoder.
|
||||
*
|
||||
* Note that you must call quirc_end() if the function returns
|
||||
* successfully (0).
|
||||
*/
|
||||
int load_png(struct quirc *q, const char *filename);
|
||||
|
||||
private:
|
||||
std::vector<std::string> decodeGrayscale8(const QImage &image);
|
||||
|
||||
private:
|
||||
quirc *m_qr;
|
||||
};
|
92
src/QR-Code-scanner/QrCodeScanner.cpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
// Copyright (c) 2014-2019, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "QrCodeScanner.h"
|
||||
#include <QVideoProbe>
|
||||
#include <QCamera>
|
||||
|
||||
QrCodeScanner::QrCodeScanner(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_processTimerId(-1)
|
||||
, m_processInterval(750)
|
||||
, m_enabled(true)
|
||||
{
|
||||
m_probe = new QVideoProbe(this);
|
||||
m_thread = new QrScanThread(this);
|
||||
m_thread->start();
|
||||
QObject::connect(m_thread, SIGNAL(decoded(QString)), this, SIGNAL(decoded(QString)));
|
||||
QObject::connect(m_thread, SIGNAL(notifyError(const QString &, bool)), this, SIGNAL(notifyError(const QString &, bool)));
|
||||
connect(m_probe, SIGNAL(videoFrameProbed(QVideoFrame)), this, SLOT(processFrame(QVideoFrame)));
|
||||
}
|
||||
void QrCodeScanner::setSource(QCamera *camera)
|
||||
{
|
||||
m_probe->setSource(camera);
|
||||
}
|
||||
void QrCodeScanner::processFrame(QVideoFrame frame)
|
||||
{
|
||||
if(frame.isValid()){
|
||||
m_curFrame = frame;
|
||||
}
|
||||
}
|
||||
bool QrCodeScanner::enabled() const
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
void QrCodeScanner::setEnabled(bool enabled)
|
||||
{
|
||||
m_enabled = enabled;
|
||||
if(!enabled && (m_processTimerId != -1) )
|
||||
{
|
||||
this->killTimer(m_processTimerId);
|
||||
m_processTimerId = -1;
|
||||
}
|
||||
else if (enabled && (m_processTimerId == -1) )
|
||||
{
|
||||
m_processTimerId = this->startTimer(m_processInterval);
|
||||
}
|
||||
emit enabledChanged();
|
||||
}
|
||||
void QrCodeScanner::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
if( (event->timerId() == m_processTimerId) ){
|
||||
m_thread->addFrame(m_curFrame);
|
||||
}
|
||||
}
|
||||
|
||||
QrCodeScanner::~QrCodeScanner()
|
||||
{
|
||||
m_thread->stop();
|
||||
m_thread->quit();
|
||||
if(!m_thread->wait(5000))
|
||||
{
|
||||
m_thread->terminate();
|
||||
m_thread->wait();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2020, The Monero Project
|
||||
// Copyright (c) 2014-2019, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -26,53 +26,48 @@
|
|||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
#ifndef QRCODESCANNER_H_
|
||||
#define QRCODESCANNER_H_
|
||||
|
||||
#include <gcrypt.h>
|
||||
#include <QImage>
|
||||
#include <QVideoFrame>
|
||||
#include "QrScanThread.h"
|
||||
|
||||
namespace openpgp
|
||||
class QVideoProbe;
|
||||
class QCamera;
|
||||
|
||||
class QrCodeScanner : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
|
||||
|
||||
class mpi
|
||||
{
|
||||
public:
|
||||
mpi(const mpi &) = delete;
|
||||
mpi &operator=(const mpi &) = delete;
|
||||
QrCodeScanner(QObject *parent = Q_NULLPTR);
|
||||
~QrCodeScanner();
|
||||
void setSource(QCamera*);
|
||||
|
||||
mpi(mpi &&other)
|
||||
: data(other.data)
|
||||
{
|
||||
other.data = nullptr;
|
||||
}
|
||||
bool enabled() const;
|
||||
void setEnabled(bool enabled);
|
||||
|
||||
template <
|
||||
typename byte_container,
|
||||
typename = typename std::enable_if<(sizeof(typename byte_container::value_type) == 1)>::type>
|
||||
mpi(const byte_container &buffer, gcry_mpi_format format = GCRYMPI_FMT_USG)
|
||||
: mpi(&buffer[0], buffer.size(), format)
|
||||
{
|
||||
}
|
||||
public Q_SLOTS:
|
||||
void processFrame(QVideoFrame);
|
||||
|
||||
mpi(const void *buffer, size_t size, gcry_mpi_format format = GCRYMPI_FMT_USG)
|
||||
{
|
||||
if (gcry_mpi_scan(&data, format, buffer, size, nullptr) != GPG_ERR_NO_ERROR)
|
||||
{
|
||||
throw std::runtime_error("failed to read mpi from buffer");
|
||||
}
|
||||
}
|
||||
Q_SIGNALS:
|
||||
void enabledChanged();
|
||||
|
||||
~mpi()
|
||||
{
|
||||
gcry_mpi_release(data);
|
||||
}
|
||||
void decoded(const QString &data);
|
||||
void notifyError(const QString &error, bool warning = false);
|
||||
|
||||
const gcry_mpi_t &get() const
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
private:
|
||||
gcry_mpi_t data;
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *);
|
||||
QrScanThread *m_thread;
|
||||
int m_processTimerId;
|
||||
int m_processInterval;
|
||||
int m_enabled;
|
||||
QVideoFrame m_curFrame;
|
||||
QVideoProbe *m_probe;
|
||||
};
|
||||
|
||||
} // namespace openpgp
|
||||
#endif
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2020, The Monero Project
|
||||
// Copyright (c) 2014-2019, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -26,82 +26,65 @@
|
|||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
#include "QrScanThread.h"
|
||||
#include <QtGlobal>
|
||||
#include <QDebug>
|
||||
|
||||
#include <vector>
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
|
||||
extern QImage qt_imageFromVideoFrame(const QVideoFrame &f);
|
||||
#endif
|
||||
|
||||
#include <gcrypt.h>
|
||||
#include <span.h>
|
||||
|
||||
namespace openpgp
|
||||
QrScanThread::QrScanThread(QObject *parent)
|
||||
: QThread(parent)
|
||||
,m_running(true)
|
||||
{
|
||||
|
||||
class hash
|
||||
{
|
||||
public:
|
||||
enum algorithm : uint8_t
|
||||
{
|
||||
sha256 = 8,
|
||||
};
|
||||
|
||||
hash(const hash &) = delete;
|
||||
hash &operator=(const hash &) = delete;
|
||||
|
||||
hash(uint8_t algorithm)
|
||||
: algo(algorithm)
|
||||
, consumed(0)
|
||||
{
|
||||
if (gcry_md_open(&md, algo, 0) != GPG_ERR_NO_ERROR)
|
||||
{
|
||||
throw std::runtime_error("failed to create message digest object");
|
||||
}
|
||||
}
|
||||
|
||||
~hash()
|
||||
{
|
||||
gcry_md_close(md);
|
||||
}
|
||||
|
||||
hash &operator<<(uint8_t byte)
|
||||
{
|
||||
gcry_md_putc(md, byte);
|
||||
++consumed;
|
||||
return *this;
|
||||
}
|
||||
|
||||
hash &operator<<(const epee::span<const uint8_t> &bytes)
|
||||
{
|
||||
gcry_md_write(md, &bytes[0], bytes.size());
|
||||
consumed += bytes.size();
|
||||
return *this;
|
||||
}
|
||||
|
||||
hash &operator<<(const std::vector<uint8_t> &bytes)
|
||||
{
|
||||
return *this << epee::to_span(bytes);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> finish() const
|
||||
{
|
||||
std::vector<uint8_t> result(gcry_md_get_algo_dlen(algo));
|
||||
const void *digest = gcry_md_read(md, algo);
|
||||
if (digest == nullptr)
|
||||
{
|
||||
throw std::runtime_error("failed to read the digest");
|
||||
}
|
||||
memcpy(&result[0], digest, result.size());
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t consumed_bytes() const
|
||||
{
|
||||
return consumed;
|
||||
}
|
||||
|
||||
private:
|
||||
const uint8_t algo;
|
||||
gcry_md_hd_t md;
|
||||
size_t consumed;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void QrScanThread::processQImage(const QImage &qimg)
|
||||
{
|
||||
try {
|
||||
for (const std::string &code : m_decoder.decode(qimg))
|
||||
{
|
||||
emit decoded(QString::fromStdString(code));
|
||||
}
|
||||
}
|
||||
catch(std::exception &e) {
|
||||
qDebug() << "ERROR: " << e.what();
|
||||
emit notifyError(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void QrScanThread::processVideoFrame(const QVideoFrame &frame)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
|
||||
processQImage( qt_imageFromVideoFrame(frame) );
|
||||
#else
|
||||
processQImage(frame.image());
|
||||
#endif
|
||||
}
|
||||
|
||||
void QrScanThread::stop()
|
||||
{
|
||||
m_running = false;
|
||||
m_waitCondition.wakeOne();
|
||||
}
|
||||
|
||||
void QrScanThread::addFrame(const QVideoFrame &frame)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
m_queue.append(frame);
|
||||
m_waitCondition.wakeOne();
|
||||
}
|
||||
|
||||
void QrScanThread::run()
|
||||
{
|
||||
QVideoFrame frame;
|
||||
while(m_running) {
|
||||
QMutexLocker locker(&m_mutex);
|
||||
while(m_queue.isEmpty() && m_running)
|
||||
m_waitCondition.wait(&m_mutex);
|
||||
if(!m_queue.isEmpty())
|
||||
processVideoFrame(m_queue.takeFirst());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2020, The Monero Project
|
||||
// Copyright (c) 2014-2019, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -26,53 +26,41 @@
|
|||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
#ifndef _QRSCANTHREAD_H_
|
||||
#define _QRSCANTHREAD_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <QThread>
|
||||
#include <QMutex>
|
||||
#include <QWaitCondition>
|
||||
#include <QEvent>
|
||||
#include <QVideoFrame>
|
||||
#include <QCamera>
|
||||
|
||||
#include <gcrypt.h>
|
||||
#include "Decoder.h"
|
||||
|
||||
namespace openpgp
|
||||
class QrScanThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
class s_expression
|
||||
{
|
||||
public:
|
||||
s_expression(const s_expression &) = delete;
|
||||
s_expression &operator=(const s_expression &) = delete;
|
||||
QrScanThread(QObject *parent = Q_NULLPTR);
|
||||
void addFrame(const QVideoFrame &frame);
|
||||
virtual void stop();
|
||||
|
||||
template <typename... Args>
|
||||
s_expression(Args... args)
|
||||
{
|
||||
if (gcry_sexp_build(&data, nullptr, args...) != GPG_ERR_NO_ERROR)
|
||||
{
|
||||
throw std::runtime_error("failed to build S-expression");
|
||||
}
|
||||
}
|
||||
Q_SIGNALS:
|
||||
void decoded(const QString &data);
|
||||
void notifyError(const QString &error, bool warning = false);
|
||||
|
||||
s_expression(s_expression &&other)
|
||||
{
|
||||
std::swap(data, other.data);
|
||||
}
|
||||
|
||||
s_expression(gcry_sexp_t data)
|
||||
: data(data)
|
||||
{
|
||||
}
|
||||
|
||||
~s_expression()
|
||||
{
|
||||
gcry_sexp_release(data);
|
||||
}
|
||||
|
||||
const gcry_sexp_t &get() const
|
||||
{
|
||||
return data;
|
||||
}
|
||||
protected:
|
||||
virtual void run();
|
||||
void processVideoFrame(const QVideoFrame &);
|
||||
void processQImage(const QImage &);
|
||||
|
||||
private:
|
||||
gcry_sexp_t data = nullptr;
|
||||
QrDecoder m_decoder;
|
||||
bool m_running;
|
||||
QMutex m_mutex;
|
||||
QWaitCondition m_waitCondition;
|
||||
QList<QVideoFrame> m_queue;
|
||||
};
|
||||
|
||||
} // namespace openpgp
|
||||
#endif
|
|
@ -1,35 +1,19 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
// Copyright (c) 2020-2021, The Monero Project.
|
||||
|
||||
#include <stdexcept>
|
||||
#include <QDir>
|
||||
#include <QStandardPaths>
|
||||
#include <QMessageBox>
|
||||
#include <QClipboard>
|
||||
#include <QDesktopWidget>
|
||||
|
||||
#include "appcontext.h"
|
||||
#include "globals.h"
|
||||
#include "utils/tails.h"
|
||||
#include "utils/whonix.h"
|
||||
#include "utils/utils.h"
|
||||
#include "utils/prices.h"
|
||||
#include "utils/networktype.h"
|
||||
#include "utils/wsclient.h"
|
||||
#include "utils/config.h"
|
||||
#include "config-wowlet.h"
|
||||
|
||||
// libwalletqt
|
||||
#include "libwalletqt/WalletManager.h"
|
||||
#include "libwalletqt/Wallet.h"
|
||||
#include "libwalletqt/TransactionHistory.h"
|
||||
#include "libwalletqt/SubaddressAccount.h"
|
||||
#include "libwalletqt/Subaddress.h"
|
||||
#include "libwalletqt/Coins.h"
|
||||
#include "model/TransactionHistoryModel.h"
|
||||
#include "model/SubaddressAccountModel.h"
|
||||
#include "model/SubaddressModel.h"
|
||||
#include "utils/keysfiles.h"
|
||||
#include "utils/networktype.h"
|
||||
|
||||
|
||||
Prices *AppContext::prices = nullptr;
|
||||
|
@ -38,75 +22,77 @@ TxFiatHistory *AppContext::txFiatHistory = nullptr;
|
|||
double AppContext::balance = 0;
|
||||
QMap<QString, QString> AppContext::txDescriptionCache;
|
||||
QMap<QString, QString> AppContext::txCache;
|
||||
bool AppContext::isQML = false;
|
||||
|
||||
AppContext::AppContext(QCommandLineParser *cmdargs) {
|
||||
this->m_walletKeysFilesModel = new WalletKeysFilesModel(this, this);
|
||||
this->network = new QNetworkAccessManager();
|
||||
this->networkClearnet = new QNetworkAccessManager();
|
||||
this->cmdargs = cmdargs;
|
||||
AppContext::isQML = false;
|
||||
|
||||
// OS & env
|
||||
#if defined(Q_OS_MAC)
|
||||
this->isMac = true;
|
||||
this->isTorSocks = qgetenv("DYLD_INSERT_LIBRARIES").indexOf("libtorsocks") >= 0;
|
||||
#elif __ANDROID__
|
||||
this->isAndroid = true;
|
||||
#elif defined(Q_OS_LINUX)
|
||||
this->isLinux = true;
|
||||
this->isTorSocks = qgetenv("LD_PRELOAD").indexOf("libtorsocks") >= 0;
|
||||
#elif defined(Q_OS_WIN)
|
||||
this->isTorSocks = false;
|
||||
#endif
|
||||
|
||||
this->isTails = TailsOS::detect();
|
||||
this->isWhonix = WhonixOS::detect();
|
||||
#elif defined(Q_OS_WIN)
|
||||
this->isWindows = true;
|
||||
this->isTorSocks = false;
|
||||
#endif
|
||||
this->androidDebug = cmdargs->isSet("android-debug");
|
||||
|
||||
//Paths
|
||||
// Paths
|
||||
this->pathGenericData = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
|
||||
this->configRoot = QDir::homePath();
|
||||
if (isTails) { // #if defined(PORTABLE)
|
||||
QString portablePath = []{
|
||||
QString appImagePath = qgetenv("APPIMAGE");
|
||||
if (appImagePath.isEmpty()) {
|
||||
qDebug() << "Not an appimage, using currentPath()";
|
||||
return QDir::currentPath() + "/.feather";
|
||||
}
|
||||
|
||||
QFileInfo appImageDir(appImagePath);
|
||||
return appImageDir.absoluteDir().path() + "/.feather";
|
||||
}();
|
||||
|
||||
|
||||
if (QDir().mkpath(portablePath)) {
|
||||
this->configRoot = portablePath;
|
||||
} else {
|
||||
qCritical() << "Unable to create portable directory: " << portablePath;
|
||||
}
|
||||
}
|
||||
|
||||
this->accountName = Utils::getUnixAccountName();
|
||||
this->homeDir = QDir::homePath();
|
||||
|
||||
#if defined(Q_OS_LINUX) or defined(Q_OS_MAC)
|
||||
this->defaultWalletDir = QString("%1/Monero/wallets").arg(this->configRoot);
|
||||
this->defaultWalletDirRoot = QString("%1/Monero").arg(this->configRoot);
|
||||
#elif defined(Q_OS_WIN)
|
||||
this->defaultWalletDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/Monero";
|
||||
this->defaultWalletDirRoot = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
||||
this->configDirectory = QString("%1/.config/wowlet/").arg(this->configRoot);
|
||||
this->configDirectoryVR = QString("%1%2").arg(this->configDirectory, "vr");
|
||||
|
||||
if (isTails) this->setupPathsTails();
|
||||
|
||||
QString walletDir = config()->get(Config::walletDirectory).toString();
|
||||
if(walletDir.isEmpty()) {
|
||||
if (isAndroid && !androidDebug) setupPathsAndroid();
|
||||
else if (isWindows) setupPathsWindows();
|
||||
else if (isLinux || isMac) setupPathsUnix();
|
||||
} else {
|
||||
this->defaultWalletDir = walletDir;
|
||||
this->defaultWalletDirRoot = walletDir;
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
// can haz disk I/O?
|
||||
QVector<QString> perms = {
|
||||
"android.permission.WRITE_EXTERNAL_STORAGE",
|
||||
"android.permission.READ_EXTERNAL_STORAGE"
|
||||
};
|
||||
Utils::androidAskPermissions(perms);
|
||||
#endif
|
||||
|
||||
// Create wallet dirs
|
||||
qDebug() << "creating " << defaultWalletDir;
|
||||
if (!QDir().mkpath(defaultWalletDir))
|
||||
qCritical() << "Unable to create dir: " << defaultWalletDir;
|
||||
|
||||
this->configDirectory = QString("%1/.config/feather/").arg(this->configRoot);
|
||||
#if defined(Q_OS_UNIX)
|
||||
if(!this->configDirectory.endsWith('/'))
|
||||
this->configDirectory = QString("%1/").arg(this->configDirectory);
|
||||
#endif
|
||||
|
||||
// Config
|
||||
// Create some directories
|
||||
createConfigDirectory(this->configDirectory);
|
||||
this->networkType = NetworkType::MAINNET;
|
||||
|
||||
if(this->cmdargs->isSet("stagenet"))
|
||||
this->networkType = NetworkType::STAGENET;
|
||||
else if(this->cmdargs->isSet("testnet"))
|
||||
this->networkType = NetworkType::TESTNET;
|
||||
else
|
||||
this->networkType = NetworkType::MAINNET;
|
||||
qDebug() << "configRoot: " << this->configRoot;
|
||||
qDebug() << "homeDir: " << this->homeDir;
|
||||
qDebug() << "customWalletDir: " << walletDir;
|
||||
qDebug() << "defaultWalletDir: " << this->defaultWalletDir;
|
||||
qDebug() << "defaultWalletDirRoot: " << this->defaultWalletDirRoot;
|
||||
qDebug() << "configDirectory: " << this->configDirectory;
|
||||
|
||||
// auto nodeSourceUInt = config()->get(Config::nodeSource).toUInt();
|
||||
// AppContext::nodeSource = static_cast<NodeSource>(nodeSourceUInt);
|
||||
|
@ -114,17 +100,47 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
|
|||
connect(this, &AppContext::nodeSourceChanged, this->nodes, &Nodes::onNodeSourceChanged);
|
||||
connect(this, &AppContext::setCustomNodes, this->nodes, &Nodes::setCustomNodes);
|
||||
|
||||
// Tor & socks proxy
|
||||
this->ws = new WSClient(this, m_wsUrl);
|
||||
connect(this->ws, &WSClient::WSMessage, this, &AppContext::onWSMessage);
|
||||
// init backend URLs
|
||||
if(cmdargs->isSet("backend-host"))
|
||||
this->backendHost = cmdargs->value("backend-host");
|
||||
if(cmdargs->isSet("backend-host"))
|
||||
this->backendPort = cmdargs->value("backend-port").toUInt();
|
||||
if(cmdargs->isSet("backend-tls"))
|
||||
this->backendTLS = true;
|
||||
|
||||
// timers
|
||||
m_storeTimer->setSingleShot(true);
|
||||
connect(this->m_storeTimer, &QTimer::timeout, [this](){
|
||||
if (!this->currentWallet)
|
||||
return;
|
||||
qDebug() << "Storing wallet";
|
||||
this->currentWallet->store();
|
||||
backendWSUrl = this->backendTLS ? "wss://" : "ws://";
|
||||
backendWSUrl += QString("%1:%2").arg(this->backendHost).arg(this->backendPort);
|
||||
backendHTTPUrl = this->backendTLS ? "https://" : "http://";
|
||||
backendHTTPUrl += QString("%1:%2").arg(this->backendHost).arg(this->backendPort);
|
||||
|
||||
// init websocket client
|
||||
this->ws = new WSClient(this);
|
||||
connect(this->ws, &WSClient::WSMessage, this, &AppContext::onWSMessage);
|
||||
connect(this->ws, &WSClient::connectionEstablished, this, &AppContext::wsConnected);
|
||||
connect(this->ws, &WSClient::closed, this, &AppContext::wsDisconnected);
|
||||
|
||||
// Store the wallet every 2 minutes
|
||||
m_storeTimer.start(2 * 60 * 1000);
|
||||
connect(&m_storeTimer, &QTimer::timeout, [this](){
|
||||
this->storeWallet();
|
||||
});
|
||||
|
||||
// If system clock skewed for >= 300 seconds, assume a wake-up from hibernate and reload the websocket connection
|
||||
if(!this->isAndroid)
|
||||
m_hibernateTimer.start(3 * 1000);
|
||||
|
||||
m_hibernatePreviousTime = std::chrono::steady_clock::now();
|
||||
connect(&m_hibernateTimer, &QTimer::timeout, [this]() {
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
const auto elapsed = now - m_hibernatePreviousTime;
|
||||
|
||||
if(elapsed >= m_hibernateDetectInterval) {
|
||||
qCritical() << "Clock skew detected, resetting websocket connection";
|
||||
this->ws->webSocket.abort();
|
||||
this->ws->start();
|
||||
}
|
||||
|
||||
m_hibernatePreviousTime = now;
|
||||
});
|
||||
|
||||
// restore height lookup
|
||||
|
@ -134,11 +150,11 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
|
|||
auto genesis_timestamp = this->restoreHeights[NetworkType::Type::MAINNET]->data.firstKey();
|
||||
AppContext::txFiatHistory = new TxFiatHistory(genesis_timestamp, this->configDirectory);
|
||||
connect(this->ws, &WSClient::connectionEstablished, AppContext::txFiatHistory, &TxFiatHistory::onUpdateDatabase);
|
||||
connect(AppContext::txFiatHistory, &TxFiatHistory::requestYear, [=](unsigned int year){
|
||||
connect(AppContext::txFiatHistory, &TxFiatHistory::requestYear, [=](int year){
|
||||
QByteArray data = QString(R"({"cmd": "txFiatHistory", "data": {"year": %1}})").arg(year).toUtf8();
|
||||
this->ws->sendMsg(data);
|
||||
});
|
||||
connect(AppContext::txFiatHistory, &TxFiatHistory::requestYearMonth, [=](unsigned int year, unsigned int month) {
|
||||
connect(AppContext::txFiatHistory, &TxFiatHistory::requestYearMonth, [=](int year, int month) {
|
||||
QByteArray data = QString(R"({"cmd": "txFiatHistory", "data": {"year": %1, "month": %2}})").arg(year).arg(month).toUtf8();
|
||||
this->ws->sendMsg(data);
|
||||
});
|
||||
|
@ -146,21 +162,14 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
|
|||
// fiat/crypto lookup
|
||||
AppContext::prices = new Prices();
|
||||
|
||||
// xmr.to
|
||||
#ifdef HAS_XMRTO
|
||||
this->XMRTo = new XmrTo(this);
|
||||
#endif
|
||||
|
||||
// XMRig
|
||||
#ifdef HAS_XMRIG
|
||||
this->XMRig = new XmRig(this->configDirectory, this);
|
||||
this->XMRig->prepare();
|
||||
#endif
|
||||
|
||||
this->walletManager = WalletManager::instance();
|
||||
QString logPath = QString("%1/daemon.log").arg(configDirectory);
|
||||
Monero::Utils::onStartup();
|
||||
Monero::Wallet::init("", "feather", logPath.toStdString(), true);
|
||||
Monero::Wallet::init("", "wowlet", logPath.toStdString(), true);
|
||||
|
||||
bool logLevelFromEnv;
|
||||
int logLevel = qEnvironmentVariableIntValue("MONERO_LOG_LEVEL", &logLevelFromEnv);
|
||||
|
@ -173,26 +182,32 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
|
|||
|
||||
// libwallet connects
|
||||
connect(this->walletManager, &WalletManager::walletOpened, this, &AppContext::onWalletOpened);
|
||||
|
||||
// hideOnClose
|
||||
auto hideOnClose = config()->get(Config::hideOnClose).toBool();
|
||||
if(hideOnClose)
|
||||
QApplication::setQuitOnLastWindowClosed(false);
|
||||
}
|
||||
|
||||
void AppContext::initTor() {
|
||||
this->tor = new Tor(this, this);
|
||||
this->tor->start();
|
||||
|
||||
if (!(isWhonix)) {
|
||||
auto networkProxy = new QNetworkProxy(QNetworkProxy::Socks5Proxy, Tor::torHost, Tor::torPort);
|
||||
this->network->setProxy(*networkProxy);
|
||||
if (m_wsUrl.host().endsWith(".onion"))
|
||||
this->ws->webSocket.setProxy(*networkProxy);
|
||||
if (!isWhonix && !backendHost.contains(".onion")) {
|
||||
qDebug() << "'backend-host' did not contain '.onion' - running without Tor proxy.";
|
||||
return;
|
||||
}
|
||||
|
||||
this->networkProxy = new QNetworkProxy(QNetworkProxy::Socks5Proxy, Tor::torHost, Tor::torPort);
|
||||
this->network->setProxy(*networkProxy);
|
||||
this->ws->webSocket.setProxy(*networkProxy);
|
||||
}
|
||||
|
||||
void AppContext::initWS() {
|
||||
this->ws->start();
|
||||
}
|
||||
|
||||
void AppContext::onCancelTransaction(PendingTransaction *tx, const QString &address) {
|
||||
void AppContext::onCancelTransaction(PendingTransaction *tx, const QVector<QString> &address) {
|
||||
// tx cancelled by user
|
||||
double amount = tx->amount() / globals::cdiv;
|
||||
emit createTransactionCancelled(address, amount);
|
||||
|
@ -213,13 +228,7 @@ void AppContext::onSweepOutput(const QString &keyImage, QString address, bool ch
|
|||
this->currentWallet->createTransactionSingleAsync(keyImage, address, outputs, this->tx_priority);
|
||||
}
|
||||
|
||||
void AppContext::onCreateTransaction(XmrToOrder *order) {
|
||||
// tx creation via xmr.to
|
||||
const QString description = QString("XmrTo order %1").arg(order->uuid);
|
||||
this->onCreateTransaction(order->receiving_subaddress, order->incoming_amount_total, description, false);
|
||||
}
|
||||
|
||||
void AppContext::onCreateTransaction(const QString &address, const double amount, const QString &description, bool all) {
|
||||
void AppContext::onCreateTransaction(QString address, quint64 amount, QString description, bool all) {
|
||||
// tx creation
|
||||
this->tmpTxDescription = description;
|
||||
|
||||
|
@ -228,13 +237,13 @@ void AppContext::onCreateTransaction(const QString &address, const double amount
|
|||
return;
|
||||
}
|
||||
|
||||
if (!all && amount <= 0) {
|
||||
if (!all && amount == 0) {
|
||||
emit createTransactionError("Cannot send nothing");
|
||||
return;
|
||||
}
|
||||
|
||||
auto balance = this->currentWallet->balance() / globals::cdiv;
|
||||
auto unlocked_balance = this->currentWallet->unlockedBalance() / globals::cdiv;
|
||||
auto balance = this->currentWallet->balance();
|
||||
auto unlocked_balance = this->currentWallet->unlockedBalance();
|
||||
if(!all && amount > unlocked_balance) {
|
||||
emit createTransactionError("Not enough money to spend");
|
||||
return;
|
||||
|
@ -243,12 +252,35 @@ void AppContext::onCreateTransaction(const QString &address, const double amount
|
|||
return;
|
||||
}
|
||||
|
||||
auto amount_num = static_cast<quint64>(amount * globals::cdiv);
|
||||
qDebug() << "creating tx";
|
||||
if(all || amount == balance)
|
||||
if (all)
|
||||
this->currentWallet->createTransactionAllAsync(address, "", this->tx_mixin, this->tx_priority);
|
||||
else
|
||||
this->currentWallet->createTransactionAsync(address, "", amount_num, this->tx_mixin, this->tx_priority);
|
||||
this->currentWallet->createTransactionAsync(address, "", amount, this->tx_mixin, this->tx_priority);
|
||||
|
||||
emit initiateTransaction();
|
||||
}
|
||||
|
||||
void AppContext::onCreateTransactionMultiDest(const QVector<QString> &addresses, const QVector<quint64> &amounts, const QString &description) {
|
||||
this->tmpTxDescription = description;
|
||||
|
||||
if (this->currentWallet == nullptr) {
|
||||
emit createTransactionError("Cannot create transaction; no wallet loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
quint64 total_amount = 0;
|
||||
for (auto &amount : amounts) {
|
||||
total_amount += amount;
|
||||
}
|
||||
|
||||
auto unlocked_balance = this->currentWallet->unlockedBalance();
|
||||
if (total_amount > unlocked_balance) {
|
||||
emit createTransactionError("Not enough money to spend");
|
||||
}
|
||||
|
||||
qDebug() << "Creating tx";
|
||||
this->currentWallet->createTransactionMultiDestAsync(addresses, amounts, this->tx_priority);
|
||||
|
||||
emit initiateTransaction();
|
||||
}
|
||||
|
@ -258,15 +290,21 @@ void AppContext::onCreateTransactionError(const QString &msg) {
|
|||
emit endTransaction();
|
||||
}
|
||||
|
||||
void AppContext::walletClose(bool emitClosedSignal) {
|
||||
if(this->currentWallet == nullptr) return;
|
||||
emit walletClosing();
|
||||
//ctx->currentWallet->store(); @TODO: uncomment to store on wallet close
|
||||
void AppContext::closeWallet(bool emitClosedSignal, bool storeWallet) {
|
||||
if (this->currentWallet == nullptr)
|
||||
return;
|
||||
|
||||
emit walletAboutToClose();
|
||||
|
||||
if (storeWallet) {
|
||||
this->storeWallet();
|
||||
}
|
||||
|
||||
this->currentWallet->disconnect();
|
||||
this->walletManager->closeWallet();
|
||||
if(this->currentWallet != nullptr)
|
||||
this->currentWallet = nullptr;
|
||||
if(emitClosedSignal)
|
||||
this->currentWallet = nullptr;
|
||||
|
||||
if (emitClosedSignal)
|
||||
emit walletClosed();
|
||||
}
|
||||
|
||||
|
@ -295,8 +333,8 @@ void AppContext::onPreferredFiatCurrencyChanged(const QString &symbol) {
|
|||
if(this->currentWallet) {
|
||||
auto *model = this->currentWallet->transactionHistoryModel();
|
||||
if(model != nullptr) {
|
||||
model->preferredFiatSign = AppContext::prices->fiat[symbol];
|
||||
model->preferredFiatSymbol = symbol;
|
||||
this->currentWallet->transactionHistoryModel()->transactionHistory()->calcFiatInfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -308,24 +346,27 @@ void AppContext::onWalletOpened(Wallet *wallet) {
|
|||
if(errMsg == QString("basic_string::_M_replace_aux") || errMsg == QString("std::bad_alloc")) {
|
||||
qCritical() << errMsg;
|
||||
this->walletManager->clearWalletCache(this->walletPath);
|
||||
errMsg = QString("%1\n\nAttempted to clean wallet cache. Please restart Feather.").arg(errMsg);
|
||||
this->walletClose(false);
|
||||
errMsg = QString("%1\n\nAttempted to clean wallet cache. Please restart WOWlet.").arg(errMsg);
|
||||
this->closeWallet(false);
|
||||
emit walletOpenedError(errMsg);
|
||||
} else if(errMsg.contains("wallet cannot be opened as")) {
|
||||
this->walletClose(false);
|
||||
this->closeWallet(false);
|
||||
emit walletOpenedError(errMsg);
|
||||
} else if(errMsg.contains("is opened by another wallet program")) {
|
||||
this->walletClose(false);
|
||||
this->closeWallet(false);
|
||||
emit walletOpenedError(errMsg);
|
||||
} else {
|
||||
this->walletClose(false);
|
||||
this->closeWallet(false);
|
||||
emit walletOpenPasswordNeeded(!this->walletPassword.isEmpty(), wallet->path());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this->refreshed = false;
|
||||
this->currentWallet = wallet;
|
||||
this->walletPath = this->currentWallet->path() + ".keys";
|
||||
QFileInfo fileInfo(this->currentWallet->path());
|
||||
this->walletName = fileInfo.fileName();
|
||||
this->walletViewOnly = this->currentWallet->viewOnly();
|
||||
config()->set(Config::walletPath, this->walletPath);
|
||||
|
||||
|
@ -338,9 +379,15 @@ void AppContext::onWalletOpened(Wallet *wallet) {
|
|||
connect(this->currentWallet, &Wallet::transactionCommitted, this, &AppContext::onTransactionCommitted);
|
||||
connect(this->currentWallet, &Wallet::heightRefreshed, this, &AppContext::onHeightRefreshed);
|
||||
connect(this->currentWallet, &Wallet::transactionCreated, this, &AppContext::onTransactionCreated);
|
||||
connect(this->currentWallet, &Wallet::connectionStatusChanged, this, &AppContext::onConnectionStatusChanged);
|
||||
|
||||
emit walletOpened();
|
||||
this->currentWallet->historyModel(); // load historyModel
|
||||
auto *txHistory = this->currentWallet->history();
|
||||
txHistory->refresh(this->currentWallet->currentSubaddressAccount());
|
||||
|
||||
connect(AppContext::prices, &Prices::fiatPricesUpdated, txHistory, &TransactionHistory::calcFiatInfo);
|
||||
connect(AppContext::prices, &Prices::cryptoPricesUpdated, txHistory, &TransactionHistory::calcFiatInfo);
|
||||
|
||||
emit walletOpened(wallet);
|
||||
|
||||
connect(this->currentWallet, &Wallet::connectionStatusChanged, [this]{
|
||||
this->nodes->autoConnect();
|
||||
|
@ -348,10 +395,6 @@ void AppContext::onWalletOpened(Wallet *wallet) {
|
|||
this->nodes->connectToNode();
|
||||
this->updateBalance();
|
||||
|
||||
#ifdef DONATE_BEG
|
||||
this->donateBeg();
|
||||
#endif
|
||||
|
||||
// force trigger preferredFiat signal for history model
|
||||
this->onPreferredFiatCurrencyChanged(config()->get(Config::preferredFiatCurrency).toString());
|
||||
this->setWindowTitle();
|
||||
|
@ -359,7 +402,7 @@ void AppContext::onWalletOpened(Wallet *wallet) {
|
|||
|
||||
void AppContext::setWindowTitle(bool mining) {
|
||||
QFileInfo fileInfo(this->walletPath);
|
||||
auto title = QString("Feather - [%1]").arg(fileInfo.fileName());
|
||||
auto title = QString("WOWlet - [%1]").arg(fileInfo.fileName());
|
||||
if(this->walletViewOnly)
|
||||
title += " [view-only]";
|
||||
if(mining)
|
||||
|
@ -378,22 +421,22 @@ void AppContext::onWSMessage(const QJsonObject &msg) {
|
|||
auto changed = false;
|
||||
|
||||
if(!this->heights.contains("mainnet")) {
|
||||
this->heights["mainnet"] = (unsigned int) mainnet;
|
||||
this->heights["mainnet"] = mainnet;
|
||||
changed = true;
|
||||
}
|
||||
else {
|
||||
if (mainnet > this->heights["mainnet"]) {
|
||||
this->heights["mainnet"] = (unsigned int) mainnet;
|
||||
this->heights["mainnet"] = mainnet;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if(!this->heights.contains("stagenet")) {
|
||||
this->heights["stagenet"] = (unsigned int) stagenet;
|
||||
this->heights["stagenet"] = stagenet;
|
||||
changed = true;
|
||||
}
|
||||
else {
|
||||
if (stagenet > this->heights["stagenet"]) {
|
||||
this->heights["stagenet"] = (unsigned int) stagenet;
|
||||
this->heights["stagenet"] = stagenet;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
@ -401,48 +444,81 @@ void AppContext::onWSMessage(const QJsonObject &msg) {
|
|||
if(changed)
|
||||
emit blockHeightWSUpdated(this->heights);
|
||||
}
|
||||
|
||||
else if(cmd == "nodes") {
|
||||
else if(cmd == "yellwow") {
|
||||
this->yellowPagesData = msg.value("data").toArray();
|
||||
emit yellowUpdated();
|
||||
}
|
||||
else if(cmd == "rpc_nodes") {
|
||||
this->onWSNodes(msg.value("data").toArray());
|
||||
}
|
||||
#if defined(HAS_XMRIG)
|
||||
else if(cmd == "xmrig") {
|
||||
this->XMRigDownloads(msg.value("data").toObject());
|
||||
}
|
||||
#endif
|
||||
else if(cmd == "wownerod_releases") {
|
||||
emit WownerodDownloads(msg.value("data").toObject());
|
||||
}
|
||||
else if(cmd == "crypto_rates") {
|
||||
QJsonArray crypto_rates = msg.value("data").toArray();
|
||||
AppContext::prices->cryptoPricesReceived(crypto_rates);
|
||||
}
|
||||
|
||||
else if(cmd == "fiat_rates") {
|
||||
QJsonObject fiat_rates = msg.value("data").toObject();
|
||||
AppContext::prices->fiatPricesReceived(fiat_rates);
|
||||
}
|
||||
#if defined(HAS_XMRTO)
|
||||
else if(cmd == "xmrto_rates") {
|
||||
auto xmr_rates = msg.value("data").toObject();
|
||||
this->XMRTo->onRatesReceived(xmr_rates);
|
||||
}
|
||||
#endif
|
||||
else if(cmd == "reddit") {
|
||||
QJsonArray reddit_data = msg.value("data").toArray();
|
||||
this->onWSReddit(reddit_data);
|
||||
}
|
||||
|
||||
else if(cmd == "ccs") {
|
||||
else if(cmd == "forum") {
|
||||
QJsonArray forum_data = msg.value("data").toArray();
|
||||
this->onWSForum(forum_data);
|
||||
}
|
||||
else if(cmd == "funding_proposals") {
|
||||
auto ccs_data = msg.value("data").toArray();
|
||||
this->onWSCCS(ccs_data);
|
||||
}
|
||||
|
||||
else if(cmd == "suchwow") {
|
||||
QJsonArray such_data = msg.value("data").toArray();
|
||||
emit suchWowUpdated(such_data);
|
||||
}
|
||||
else if(cmd == "txFiatHistory") {
|
||||
auto txFiatHistory_data = msg.value("data").toObject();
|
||||
AppContext::txFiatHistory->onWSData(txFiatHistory_data);
|
||||
}
|
||||
else if(cmd == "wowlet_releases") {
|
||||
versionPending = msg.value("data").toObject();
|
||||
auto version_str = versionPending.value("version").toString();
|
||||
|
||||
if(Utils::versionOutdated(WOWLET_VERSION_SEMVER, version_str))
|
||||
emit versionOutdated(version_str, versionPending);
|
||||
}
|
||||
else if(cmd == "kill") {
|
||||
// used *only* in dire emergencies
|
||||
auto killme = msg.value("data").toBool();
|
||||
if(killme)
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
#if defined(HAS_OPENVR)
|
||||
else if(cmd == "requestPIN") {
|
||||
auto pin = msg.value("data").toString();
|
||||
emit pinReceived(pin);
|
||||
}
|
||||
|
||||
else if(cmd == "lookupPIN") {
|
||||
auto lookup_data = msg.value("data").toObject();
|
||||
auto address = lookup_data.value("address").toString();
|
||||
auto pin = lookup_data.value("PIN").toString();
|
||||
|
||||
if(address.isEmpty())
|
||||
emit pinLookupErrorReceived();
|
||||
else
|
||||
emit pinLookupReceived(address, pin);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void AppContext::onWSNodes(const QJsonArray &nodes) {
|
||||
QList<QSharedPointer<FeatherNode>> l;
|
||||
QList<QSharedPointer<WowletNode>> l;
|
||||
for (auto &&entry: nodes) {
|
||||
auto obj = entry.toObject();
|
||||
auto nettype = obj.value("nettype");
|
||||
|
@ -461,17 +537,34 @@ void AppContext::onWSNodes(const QJsonArray &nodes) {
|
|||
if(type == "tor" && (!(this->isTails || this->isWhonix || this->isTorSocks)))
|
||||
continue;
|
||||
|
||||
auto node = new FeatherNode(
|
||||
auto node = new WowletNode(
|
||||
obj.value("address").toString(),
|
||||
obj.value("height").toInt(),
|
||||
obj.value("target_height").toInt(),
|
||||
obj.value("online").toBool());
|
||||
QSharedPointer<FeatherNode> r = QSharedPointer<FeatherNode>(node);
|
||||
QSharedPointer<WowletNode> r = QSharedPointer<WowletNode>(node);
|
||||
l.append(r);
|
||||
}
|
||||
this->nodes->onWSNodesReceived(l);
|
||||
}
|
||||
|
||||
void AppContext::onWSForum(const QJsonArray& forum_data) {
|
||||
QList<QSharedPointer<ForumPost>> l;
|
||||
|
||||
for (auto &&entry: forum_data) {
|
||||
auto obj = entry.toObject();
|
||||
auto forumPost = new ForumPost(
|
||||
obj.value("thread").toString(),
|
||||
obj.value("member_name").toString(),
|
||||
obj.value("permalink").toString(),
|
||||
obj.value("member_name").toString());
|
||||
QSharedPointer<ForumPost> r = QSharedPointer<ForumPost>(forumPost);
|
||||
l.append(r);
|
||||
}
|
||||
|
||||
emit forumUpdated(l);
|
||||
}
|
||||
|
||||
void AppContext::onWSReddit(const QJsonArray& reddit_data) {
|
||||
QList<QSharedPointer<RedditPost>> l;
|
||||
|
||||
|
@ -480,7 +573,7 @@ void AppContext::onWSReddit(const QJsonArray& reddit_data) {
|
|||
auto redditPost = new RedditPost(
|
||||
obj.value("title").toString(),
|
||||
obj.value("author").toString(),
|
||||
obj.value("url").toString(),
|
||||
obj.value("permalink").toString(),
|
||||
obj.value("comments").toInt());
|
||||
QSharedPointer<RedditPost> r = QSharedPointer<RedditPost>(redditPost);
|
||||
l.append(r);
|
||||
|
@ -517,15 +610,12 @@ void AppContext::onWSCCS(const QJsonArray &ccs_data) {
|
|||
l.append(c);
|
||||
}
|
||||
|
||||
if(l.count() == 0)
|
||||
emit ccsEmpty();
|
||||
|
||||
emit ccsUpdated(l);
|
||||
}
|
||||
|
||||
void AppContext::createConfigDirectory(const QString &dir) {
|
||||
QString config_dir_tor = QString("%1%2").arg(dir).arg("tor");
|
||||
QString config_dir_tordata = QString("%1%2").arg(dir).arg("tor/data");
|
||||
auto config_dir_tor = QString("%1%2").arg(dir).arg("tor");
|
||||
auto config_dir_tordata = QString("%1%2").arg(dir).arg("tor/data");
|
||||
|
||||
QStringList createDirs({dir, config_dir_tor, config_dir_tordata});
|
||||
for(const auto &d: createDirs) {
|
||||
|
@ -535,9 +625,24 @@ void AppContext::createConfigDirectory(const QString &dir) {
|
|||
throw std::runtime_error("Could not create directory " + d.toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAS_OPENVR
|
||||
auto config_dir_vr = QString("%1%2").arg(dir, "vr");
|
||||
if(!Utils::dirExists(config_dir_vr)) {
|
||||
qDebug() << QString("Creating directory: %1").arg(config_dir_vr);
|
||||
if (!QDir().mkpath(config_dir_vr))
|
||||
throw std::runtime_error("Could not create directory " + config_dir_vr.toStdString());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void AppContext::createWallet(FeatherSeed seed, const QString &path, const QString &password) {
|
||||
void AppContext::createWalletWithoutSpecifyingSeed(const QString &name, const QString &password) {
|
||||
WowletSeed seed = WowletSeed(this->restoreHeights[this->networkType], this->coinName, this->seedLanguage);
|
||||
auto path = QDir(this->defaultWalletDir).filePath(name);
|
||||
this->createWallet(seed, path, password);
|
||||
}
|
||||
|
||||
void AppContext::createWallet(WowletSeed seed, const QString &path, const QString &password) {
|
||||
if(Utils::fileExists(path)) {
|
||||
auto err = QString("Failed to write wallet to path: \"%1\"; file already exists.").arg(path);
|
||||
qCritical() << err;
|
||||
|
@ -545,12 +650,21 @@ void AppContext::createWallet(FeatherSeed seed, const QString &path, const QStri
|
|||
return;
|
||||
}
|
||||
|
||||
if(seed.mnemonicSeed.isEmpty()) {
|
||||
if(seed.mnemonic.isEmpty()) {
|
||||
emit walletCreatedError("Mnemonic seed error. Failed to write wallet.");
|
||||
return;
|
||||
}
|
||||
|
||||
this->currentWallet = seed.writeWallet(this->walletManager, this->networkType, path, password, this->kdfRounds);
|
||||
Wallet *wallet = nullptr;
|
||||
if (seed.seedType == SeedType::TEVADOR) {
|
||||
wallet = this->walletManager->createDeterministicWalletFromSpendKey(path, password, seed.language, this->networkType, seed.spendKey, seed.restoreHeight, this->kdfRounds);
|
||||
wallet->setCacheAttribute("wowlet.seed", seed.mnemonic.join(" "));
|
||||
}
|
||||
if (seed.seedType == SeedType::WOWNERO) {
|
||||
wallet = this->walletManager->recoveryWallet(path, password, seed.mnemonic.join(" "), "", this->networkType, seed.restoreHeight, this->kdfRounds);
|
||||
}
|
||||
|
||||
this->currentWallet = wallet;
|
||||
if(this->currentWallet == nullptr) {
|
||||
emit walletCreatedError("Failed to write wallet");
|
||||
return;
|
||||
|
@ -597,16 +711,19 @@ void AppContext::createWalletFinish(const QString &password) {
|
|||
this->currentWallet->store();
|
||||
this->walletPassword = password;
|
||||
emit walletCreated(this->currentWallet);
|
||||
|
||||
// emit signal on behalf of walletManager, open wallet
|
||||
this->walletManager->walletOpened(this->currentWallet);
|
||||
}
|
||||
|
||||
void AppContext::initRestoreHeights() {
|
||||
restoreHeights[NetworkType::TESTNET] = new RestoreHeightLookup(NetworkType::TESTNET);
|
||||
restoreHeights[NetworkType::STAGENET] = RestoreHeightLookup::fromFile(":/assets/restore_heights_monero_stagenet.txt", NetworkType::STAGENET);
|
||||
restoreHeights[NetworkType::MAINNET] = RestoreHeightLookup::fromFile(":/assets/restore_heights_monero_mainnet.txt", NetworkType::MAINNET);
|
||||
restoreHeights[NetworkType::TESTNET] = RestoreHeightLookup::fromFile(":/assets/restore_heights_wownero_mainnet.txt", NetworkType::TESTNET);
|
||||
restoreHeights[NetworkType::STAGENET] = RestoreHeightLookup::fromFile(":/assets/restore_heights_wownero_mainnet.txt", NetworkType::STAGENET);
|
||||
restoreHeights[NetworkType::MAINNET] = RestoreHeightLookup::fromFile(":/assets/restore_heights_wownero_mainnet.txt", NetworkType::MAINNET);
|
||||
}
|
||||
|
||||
void AppContext::onSetRestoreHeight(unsigned int height){
|
||||
auto seed = this->currentWallet->getCacheAttribute("feather.seed");
|
||||
void AppContext::onSetRestoreHeight(quint64 height){
|
||||
auto seed = this->currentWallet->getCacheAttribute("wowlet.seed");
|
||||
if(!seed.isEmpty()) {
|
||||
const auto msg = "This wallet has a 14 word mnemonic seed which has the restore height embedded.";
|
||||
emit setRestoreHeightError(msg);
|
||||
|
@ -665,24 +782,7 @@ void AppContext::onOpenAliasResolve(const QString &openAlias) {
|
|||
emit openAliasResolveError(msg);
|
||||
}
|
||||
|
||||
void AppContext::donateBeg() {
|
||||
if(this->currentWallet == nullptr) return;
|
||||
if(this->networkType != NetworkType::Type::MAINNET) return;
|
||||
if(this->currentWallet->viewOnly()) return;
|
||||
|
||||
auto donationCounter = config()->get(Config::donateBeg).toInt();
|
||||
if(donationCounter == -1)
|
||||
return; // previously donated
|
||||
|
||||
donationCounter += 1;
|
||||
if (donationCounter % m_donationBoundary == 0)
|
||||
emit donationNag();
|
||||
config()->set(Config::donateBeg, donationCounter);
|
||||
}
|
||||
|
||||
AppContext::~AppContext() {
|
||||
this->walletClose(false);
|
||||
}
|
||||
AppContext::~AppContext() {}
|
||||
|
||||
// ############################################## LIBWALLET QT #########################################################
|
||||
|
||||
|
@ -703,7 +803,7 @@ void AppContext::onUnconfirmedMoneyReceived(const QString &txId, quint64 amount)
|
|||
qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num);
|
||||
|
||||
if(this->currentWallet->synchronized()) {
|
||||
auto notify = QString("%1 XMR (pending)").arg(amount_num);
|
||||
auto notify = QString("%1 WOW (pending)").arg(amount_num);
|
||||
Utils::desktopNotify("Payment received", notify, 5000);
|
||||
}
|
||||
}
|
||||
|
@ -711,17 +811,19 @@ void AppContext::onUnconfirmedMoneyReceived(const QString &txId, quint64 amount)
|
|||
void AppContext::onWalletUpdate() {
|
||||
if (this->currentWallet->synchronized()) {
|
||||
this->refreshModels();
|
||||
this->storeWallet();
|
||||
}
|
||||
|
||||
this->updateBalance();
|
||||
this->storeWallet();
|
||||
}
|
||||
|
||||
void AppContext::onWalletRefreshed(bool success) {
|
||||
if (!this->refreshed) {
|
||||
refreshModels();
|
||||
this->refreshed = true;
|
||||
this->storeWallet();
|
||||
emit walletRefreshed();
|
||||
// store wallet immediately upon finishing synchronization
|
||||
this->currentWallet->store();
|
||||
}
|
||||
|
||||
qDebug() << "Wallet refresh status: " << success;
|
||||
|
@ -753,13 +855,84 @@ void AppContext::onHeightRefreshed(quint64 walletHeight, quint64 daemonHeight, q
|
|||
}
|
||||
}
|
||||
|
||||
void AppContext::onTransactionCreated(PendingTransaction *tx, const QString &address, const QString &paymentId, quint32 mixin) {
|
||||
if(address == this->donationAddress)
|
||||
this->donationSending = true;
|
||||
void AppContext::onTransactionCreated(PendingTransaction *tx, const QVector<QString> &address) {
|
||||
// Let UI know that the transaction was constructed
|
||||
emit endTransaction();
|
||||
|
||||
// Some validation
|
||||
auto tx_status = tx->status();
|
||||
auto err = QString("Can't create transaction: ");
|
||||
|
||||
if(tx_status != PendingTransaction::Status_Ok){
|
||||
auto tx_err = tx->errorString();
|
||||
qCritical() << tx_err;
|
||||
|
||||
if (this->currentWallet->connectionStatus() == Wallet::ConnectionStatus_WrongVersion)
|
||||
err = QString("%1 Wrong daemon version: %2").arg(err).arg(tx_err);
|
||||
else
|
||||
err = QString("%1 %2").arg(err).arg(tx_err);
|
||||
|
||||
qDebug() << Q_FUNC_INFO << err;
|
||||
emit createTransactionError(err);
|
||||
this->currentWallet->disposeTransaction(tx);
|
||||
return;
|
||||
} else if (tx->txCount() == 0) {
|
||||
err = QString("%1 %2").arg(err).arg("No unmixable outputs to sweep.");
|
||||
qDebug() << Q_FUNC_INFO << err;
|
||||
emit createTransactionError(err);
|
||||
this->currentWallet->disposeTransaction(tx);
|
||||
return;
|
||||
}
|
||||
|
||||
// tx created, but not sent yet. ask user to verify first.
|
||||
emit createTransactionSuccess(tx, address, mixin);
|
||||
emit endTransaction();
|
||||
emit createTransactionSuccess(tx, address);
|
||||
|
||||
if(this->autoCommitTx) {
|
||||
this->currentWallet->commitTransactionAsync(tx);
|
||||
}
|
||||
}
|
||||
|
||||
QString AppContext::getAddress(quint32 accountIndex, quint32 addressIndex) {
|
||||
return this->currentWallet->address(accountIndex, addressIndex);
|
||||
}
|
||||
|
||||
void AppContext::onAskReceivingPIN() {
|
||||
// request new receiving PIN from wowlet-backend
|
||||
if(this->currentWallet == nullptr)
|
||||
return;
|
||||
|
||||
auto address = this->currentWallet->address(0, 1);
|
||||
QString signature = this->currentWallet->signMessage(address, false, address);
|
||||
|
||||
QJsonObject data;
|
||||
data["signature"] = signature;
|
||||
data["address"] = address;
|
||||
|
||||
QJsonObject obj;
|
||||
obj["cmd"] = "requestPIN";
|
||||
obj["data"] = data;
|
||||
|
||||
QJsonDocument doc = QJsonDocument(obj);
|
||||
this->ws->sendMsg(doc.toJson(QJsonDocument::Compact));
|
||||
}
|
||||
|
||||
void AppContext::onLookupReceivingPIN(QString pin) {
|
||||
// lookup PIN -> address
|
||||
if(this->currentWallet == nullptr)
|
||||
return;
|
||||
|
||||
auto address = this->currentWallet->address(0, 1);
|
||||
QString signature = this->currentWallet->signMessage(address, false, address);
|
||||
|
||||
QJsonObject data;
|
||||
data["PIN"] = pin;
|
||||
|
||||
QJsonObject obj;
|
||||
obj["cmd"] = "lookupPIN";
|
||||
obj["data"] = data;
|
||||
|
||||
QJsonDocument doc = QJsonDocument(obj);
|
||||
this->ws->sendMsg(doc.toJson(QJsonDocument::Compact));
|
||||
}
|
||||
|
||||
void AppContext::onTransactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid){
|
||||
|
@ -769,37 +942,35 @@ void AppContext::onTransactionCommitted(bool status, PendingTransaction *tx, con
|
|||
// Store wallet immediately so we don't risk losing tx key if wallet crashes
|
||||
this->currentWallet->store();
|
||||
|
||||
this->updateBalance();
|
||||
|
||||
emit transactionCommitted(status, tx, txid);
|
||||
|
||||
// this tx was a donation to Feather, stop our nagging
|
||||
if(this->donationSending) {
|
||||
this->donationSending = false;
|
||||
config()->set(Config::donateBeg, -1);
|
||||
}
|
||||
}
|
||||
|
||||
void AppContext::onConnectionStatusChanged(int status) {
|
||||
|
||||
}
|
||||
|
||||
void AppContext::storeWallet() {
|
||||
if (m_storeTimer->isActive())
|
||||
// Do not store a synchronizing wallet: store() is NOT thread safe and may crash the wallet
|
||||
if (this->currentWallet == nullptr || !this->currentWallet->synchronized())
|
||||
return;
|
||||
|
||||
m_storeTimer->start(60000);
|
||||
qDebug() << "Storing wallet";
|
||||
this->currentWallet->store();
|
||||
}
|
||||
|
||||
void AppContext::updateBalance() {
|
||||
if(!this->currentWallet)
|
||||
if (!this->currentWallet)
|
||||
return;
|
||||
|
||||
AppContext::balance = this->currentWallet->balance() / globals::cdiv;
|
||||
auto balance_str = QString::number(balance, 'f');
|
||||
quint64 balance_u = this->currentWallet->balance();
|
||||
AppContext::balance = balance_u / globals::cdiv;
|
||||
double spendable = this->currentWallet->unlockedBalance();
|
||||
|
||||
double unlocked = this->currentWallet->unlockedBalance() / globals::cdiv;
|
||||
auto unlocked_str = QString::number(unlocked, 'f');
|
||||
// formatted
|
||||
QString fmt_str = QString("Balance: %1 WOW").arg(Utils::balanceFormat(spendable));
|
||||
if (balance > spendable)
|
||||
fmt_str += QString(" (+%1 WOW unconfirmed)").arg(Utils::balanceFormat(balance - spendable));
|
||||
|
||||
emit balanceUpdated(balance, unlocked, balance_str, unlocked_str);
|
||||
emit balanceUpdated(balance_u, spendable);
|
||||
emit balanceUpdatedFormatted(fmt_str);
|
||||
}
|
||||
|
||||
void AppContext::syncStatusUpdated(quint64 height, quint64 target) {
|
||||
|
@ -821,3 +992,38 @@ void AppContext::refreshModels() {
|
|||
this->currentWallet->coins()->refresh(this->currentWallet->currentSubaddressAccount());
|
||||
// Todo: set timer for refreshes
|
||||
}
|
||||
|
||||
void AppContext::setupPathsUnix() {
|
||||
this->defaultWalletDir = QString("%1/Wownero/wallets").arg(this->configRoot);
|
||||
this->defaultWalletDirRoot = QString("%1/Wownero").arg(this->configRoot);
|
||||
}
|
||||
|
||||
void AppContext::setupPathsWindows() {
|
||||
this->defaultWalletDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/Wownero";
|
||||
this->defaultWalletDirRoot = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
||||
}
|
||||
|
||||
void AppContext::setupPathsAndroid() {
|
||||
this->defaultWalletDir = QString("%1/Wownero/wallets").arg(this->pathGenericData);
|
||||
this->defaultWalletDirRoot = QString("%1/Wownero").arg(this->pathGenericData);
|
||||
}
|
||||
|
||||
void AppContext::setupPathsTails() {
|
||||
QString portablePath = []{
|
||||
QString appImagePath = qgetenv("APPIMAGE");
|
||||
if (appImagePath.isEmpty()) {
|
||||
qDebug() << "Not an appimage, using currentPath()";
|
||||
return QDir::currentPath() + "/.wowlet";
|
||||
}
|
||||
|
||||
QFileInfo appImageDir(appImagePath);
|
||||
return appImageDir.absoluteDir().path() + "/.wowlet";
|
||||
}();
|
||||
|
||||
if (QDir().mkpath(portablePath)) {
|
||||
this->configRoot = portablePath;
|
||||
} else {
|
||||
qCritical() << "Unable to create portable directory: " << portablePath;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
154
src/appcontext.h
|
@ -1,8 +1,8 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
// Copyright (c) 2020-2021, The Monero Project.
|
||||
|
||||
#ifndef FEATHER_APPCONTEXT_H
|
||||
#define FEATHER_APPCONTEXT_H
|
||||
#ifndef WOWLET_APPCONTEXT_H
|
||||
#define WOWLET_APPCONTEXT_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QProcess>
|
||||
|
@ -10,16 +10,18 @@
|
|||
#include <QTimer>
|
||||
|
||||
#include "utils/tails.h"
|
||||
#include "utils/whonix.h"
|
||||
#include "utils/prices.h"
|
||||
#include "utils/networking.h"
|
||||
#include "utils/tor.h"
|
||||
#include "utils/xmrto.h"
|
||||
#include "utils/xmrig.h"
|
||||
#include "utils/wsclient.h"
|
||||
#include "utils/txfiathistory.h"
|
||||
#include "utils/WowletSeed.h"
|
||||
#include "widgets/RedditPost.h"
|
||||
#include "widgets/ForumPost.h"
|
||||
#include "widgets/CCSEntry.h"
|
||||
#include "utils/seeds.h"
|
||||
#include "utils/RestoreHeightLookup.h"
|
||||
#include "utils/nodes.h"
|
||||
|
||||
#include "libwalletqt/WalletManager.h"
|
||||
|
@ -35,51 +37,72 @@ Q_OBJECT
|
|||
|
||||
public:
|
||||
explicit AppContext(QCommandLineParser *cmdargs);
|
||||
~AppContext();
|
||||
~AppContext() override;
|
||||
bool isTails = false;
|
||||
bool isWhonix = false;
|
||||
bool isAndroid = false;
|
||||
bool isLinux = false;
|
||||
bool isMac = false;
|
||||
bool isWindows = false;
|
||||
bool isDebug = false;
|
||||
static bool isQML;
|
||||
bool androidDebug = false;
|
||||
|
||||
// Donation config
|
||||
const QString donationAddress = "47ntfT2Z5384zku39pTM6hGcnLnvpRYW2Azm87GiAAH2bcTidtq278TL6HmwyL8yjMeERqGEBs3cqC8vvHPJd1cWQrGC65f";
|
||||
const QString donationAddress = "Wo3MWeKwtA918DU4c69hVSNgejdWFCRCuWjShRY66mJkU2Hv58eygJWDJS1MNa2Ge5M1WjUkGHuLqHkweDxwZZU42d16v94mP";
|
||||
const int donationAmount = 25; // euro
|
||||
bool donationSending = false;
|
||||
|
||||
QCommandLineParser *cmdargs;
|
||||
|
||||
QString coinName = "monero";
|
||||
QString coinName = "wownero";
|
||||
bool isTorSocks = false;
|
||||
QString pathGenericData;
|
||||
QString homeDir;
|
||||
QString accountName;
|
||||
QString configRoot;
|
||||
QString configDirectory;
|
||||
QString configDirectoryVR;
|
||||
QString defaultWalletDir;
|
||||
QString defaultWalletDirRoot;
|
||||
QString tmpTxDescription;
|
||||
|
||||
// https://git.wownero.com/wowlet/wowlet-backend/
|
||||
QString backendHost = "l3hkasj5nnrh24yzj4acj5dgqlscq56o5xjvvqsftj55fkonqly5aiid.onion";
|
||||
unsigned int backendPort = 80;
|
||||
bool backendTLS = false;
|
||||
QString backendWSUrl;
|
||||
QString backendHTTPUrl;
|
||||
|
||||
QString walletPath;
|
||||
QString walletPassword = "";
|
||||
QString walletName;
|
||||
bool walletViewOnly = false;
|
||||
NetworkType::Type networkType;
|
||||
|
||||
Q_PROPERTY(QString walletName MEMBER walletName);
|
||||
|
||||
QString applicationPath;
|
||||
|
||||
static void createConfigDirectory(const QString &dir) ;
|
||||
|
||||
QMap<QString, unsigned int> heights;
|
||||
QMap<QString, int> heights;
|
||||
QMap<NetworkType::Type, RestoreHeightLookup*> restoreHeights;
|
||||
const unsigned int kdfRounds = 1;
|
||||
const quint64 kdfRounds = 1;
|
||||
PendingTransaction::Priority tx_priority = PendingTransaction::Priority::Priority_Low;
|
||||
quint32 tx_mixin = static_cast<const quint32 &>(10);
|
||||
QString seedLanguage = "English"; // 14 word `monero-seed` only has English
|
||||
// turn this on if you want to auto commit tx's after they have
|
||||
// been created. Caution while using this setting is advised. This
|
||||
// probably also breaks the default QtWidgets GUI. It is meant for
|
||||
// alternative users of AppContext.
|
||||
bool autoCommitTx = false;
|
||||
|
||||
QNetworkAccessManager *network;
|
||||
QNetworkAccessManager *networkClearnet;
|
||||
QNetworkProxy *networkProxy;
|
||||
QNetworkProxy *networkProxy{};
|
||||
|
||||
Tor *tor;
|
||||
Tor *tor{};
|
||||
WSClient *ws;
|
||||
XmrTo *XMRTo;
|
||||
XmRig *XMRig;
|
||||
Nodes *nodes;
|
||||
static Prices *prices;
|
||||
|
@ -88,42 +111,63 @@ public:
|
|||
static QMap<QString, QString> txDescriptionCache;
|
||||
static QMap<QString, QString> txCache;
|
||||
static TxFiatHistory *txFiatHistory;
|
||||
QJsonArray yellowPagesData;
|
||||
QJsonObject versionPending;
|
||||
|
||||
// libwalletqt
|
||||
unsigned int blockHeight = 0;
|
||||
bool refreshed = false;
|
||||
|
||||
WalletManager *walletManager;
|
||||
Wallet *currentWallet = nullptr;
|
||||
void createWallet(FeatherSeed seed, const QString &path, const QString &password);
|
||||
void createWallet(WowletSeed seed, const QString &path, const QString &password);
|
||||
Q_INVOKABLE void createWalletWithoutSpecifyingSeed(const QString &name, const QString &password);
|
||||
void createWalletViewOnly(const QString &path, const QString &password, const QString &address, const QString &viewkey, const QString &spendkey, quint64 restoreHeight);
|
||||
void createWalletFinish(const QString &password);
|
||||
void syncStatusUpdated(quint64 height, quint64 target);
|
||||
void updateBalance();
|
||||
void initTor();
|
||||
Q_INVOKABLE void initTor();
|
||||
Q_INVOKABLE void initWS();
|
||||
void initRestoreHeights();
|
||||
void initWS();
|
||||
void donateBeg();
|
||||
void walletClose(bool emitClosedSignal = true);
|
||||
void storeWallet();
|
||||
void refreshModels();
|
||||
void setWindowTitle(bool mining = false);
|
||||
|
||||
// Closes the currently opened wallet
|
||||
Q_INVOKABLE void closeWallet(bool emitClosedSignal = true, bool storeWallet = false);
|
||||
void storeWallet();
|
||||
|
||||
Q_INVOKABLE QVariantList listWallets() {
|
||||
m_walletKeysFilesModel->refresh();
|
||||
|
||||
QVariantList list;
|
||||
for(const WalletKeysFiles &wallet: m_walletKeysFilesModel->listWallets())
|
||||
list << wallet.toVariant();
|
||||
return list;
|
||||
}
|
||||
|
||||
Q_INVOKABLE QString displayAmount(quint64 amount) {
|
||||
return Utils::balanceFormat(amount);
|
||||
}
|
||||
|
||||
public slots:
|
||||
void onOpenWallet(const QString& path, const QString &password);
|
||||
void onCreateTransaction(const QString &address, const double amount, const QString &description, bool all);
|
||||
void onCreateTransaction(XmrToOrder *order);
|
||||
void onCancelTransaction(PendingTransaction *tx, const QString &address);
|
||||
Q_INVOKABLE void onOpenWallet(const QString& path, const QString &password);
|
||||
void onCreateTransaction(QString address, quint64 amount, const QString description, bool all);
|
||||
void onCreateTransactionMultiDest(const QVector<QString> &addresses, const QVector<quint64> &amounts, const QString &description);
|
||||
void onCancelTransaction(PendingTransaction *tx, const QVector<QString> &address);
|
||||
void onSweepOutput(const QString &keyImage, QString address, bool churn, int outputs) const;
|
||||
void onCreateTransactionError(const QString &msg);
|
||||
void onOpenAliasResolve(const QString &openAlias);
|
||||
void onSetRestoreHeight(unsigned int height);
|
||||
void onSetRestoreHeight(quint64 height);
|
||||
void onPreferredFiatCurrencyChanged(const QString &symbol);
|
||||
Q_INVOKABLE void onAskReceivingPIN();
|
||||
Q_INVOKABLE void onLookupReceivingPIN(QString pin);
|
||||
Q_INVOKABLE QString getAddress(quint32 accountIndex, quint32 addressIndex);
|
||||
|
||||
private slots:
|
||||
void onWSNodes(const QJsonArray &nodes);
|
||||
void onWSMessage(const QJsonObject& msg);
|
||||
void onWSCCS(const QJsonArray &ccs_data);
|
||||
void onWSReddit(const QJsonArray& reddit_data);
|
||||
void onWSForum(const QJsonArray& forum_data);
|
||||
|
||||
void onMoneySpent(const QString &txId, quint64 amount);
|
||||
void onMoneyReceived(const QString &txId, quint64 amount);
|
||||
|
@ -133,50 +177,70 @@ private slots:
|
|||
void onWalletOpened(Wallet *wallet);
|
||||
void onWalletNewBlock(quint64 blockheight, quint64 targetHeight);
|
||||
void onHeightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight);
|
||||
void onTransactionCreated(PendingTransaction *tx, const QString &address, const QString &paymentId, quint32 mixin);
|
||||
void onTransactionCreated(PendingTransaction *tx, const QVector<QString> &address);
|
||||
void onTransactionCommitted(bool status, PendingTransaction *t, const QStringList& txid);
|
||||
void onConnectionStatusChanged(int status);
|
||||
|
||||
signals:
|
||||
void balanceUpdated(double balance, double unlocked, QString balance_str, QString unlocked_str);
|
||||
// Emitted just before the wallet is closed
|
||||
void walletAboutToClose();
|
||||
|
||||
// Emitted after a wallet has been closed
|
||||
void walletClosed();
|
||||
|
||||
void balanceUpdated(quint64 balance, quint64 spendable);
|
||||
void balanceUpdatedFormatted(QString fmt);
|
||||
void blockchainSync(int height, int target);
|
||||
void refreshSync(int height, int target);
|
||||
void synchronized();
|
||||
void blockHeightWSUpdated(QMap<QString, unsigned int> heights);
|
||||
void walletSynchronized();
|
||||
void walletOpened();
|
||||
void walletClosed();
|
||||
void blockHeightWSUpdated(QMap<QString, int> heights);
|
||||
void walletRefreshed();
|
||||
void walletOpened(Wallet *wallet);
|
||||
void walletCreatedError(const QString &msg);
|
||||
void walletCreated(Wallet *wallet);
|
||||
void walletOpenedError(QString msg);
|
||||
void walletOpenPasswordNeeded(bool invalidPassword, QString path);
|
||||
void transactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid);
|
||||
void createTransactionError(QString message);
|
||||
void createTransactionCancelled(QString address, double amount);
|
||||
void createTransactionSuccess(PendingTransaction *tx, const QString &address, const quint32 &mixin);
|
||||
void createTransactionCancelled(const QVector<QString> &address, double amount);
|
||||
void createTransactionSuccess(PendingTransaction *tx, const QVector<QString> &address);
|
||||
void wsConnected();
|
||||
void wsDisconnected();
|
||||
void redditUpdated(QList<QSharedPointer<RedditPost>> &posts);
|
||||
void nodesUpdated(QList<QSharedPointer<FeatherNode>> &nodes);
|
||||
void forumUpdated(QList<QSharedPointer<ForumPost>> &posts);
|
||||
void nodesUpdated(QList<QSharedPointer<WowletNode>> &nodes);
|
||||
void ccsUpdated(QList<QSharedPointer<CCSEntry>> &entries);
|
||||
void suchWowUpdated(const QJsonArray &such_data);
|
||||
void yellowUpdated();
|
||||
void nodeSourceChanged(NodeSource nodeSource);
|
||||
void XMRigDownloads(const QJsonObject &data);
|
||||
void setCustomNodes(QList<FeatherNode> nodes);
|
||||
void ccsEmpty();
|
||||
void WownerodDownloads(const QJsonObject &data);
|
||||
void pinLookupReceived(QString address, QString pin);
|
||||
void pinLookupErrorReceived();
|
||||
void pinReceived(QString pin);
|
||||
void setCustomNodes(QList<WowletNode> nodes);
|
||||
void openAliasResolveError(const QString &msg);
|
||||
void openAliasResolved(const QString &address, const QString &openAlias);
|
||||
void setRestoreHeightError(const QString &msg);
|
||||
void customRestoreHeightSet(unsigned int height);
|
||||
void customRestoreHeightSet(int height);
|
||||
void closeApplication();
|
||||
void donationNag();
|
||||
void initiateTransaction();
|
||||
void endTransaction();
|
||||
void walletClosing();
|
||||
void setTitle(const QString &title); // set window title
|
||||
void versionOutdated(QString version_string, QJsonObject data);
|
||||
|
||||
private:
|
||||
const unsigned int m_donationBoundary = 15;
|
||||
UtilsNetworking *m_utilsNetworkingNodes;
|
||||
QTimer *m_storeTimer = new QTimer(this);
|
||||
QUrl m_wsUrl = QUrl(QStringLiteral("ws://7e6egbawekbkxzkv4244pqeqgoo4axko2imgjbedwnn6s5yb6b7oliqd.onion/ws"));
|
||||
WalletKeysFilesModel *m_walletKeysFilesModel;
|
||||
const int m_donationBoundary = 15;
|
||||
QTimer m_storeTimer;
|
||||
QTimer m_hibernateTimer;
|
||||
std::chrono::seconds m_hibernateDetectInterval{300};
|
||||
std::chrono::time_point<std::chrono::steady_clock> m_hibernatePreviousTime;
|
||||
|
||||
void setupPathsUnix();
|
||||
void setupPathsWindows();
|
||||
void setupPathsAndroid();
|
||||
void setupPathsTails();
|
||||
};
|
||||
|
||||
#endif //FEATHER_APPCONTEXT_H
|
||||
#endif //WOWLET_APPCONTEXT_H
|
||||
|
|
172
src/assets.qrc
|
@ -3,7 +3,8 @@
|
|||
<file>assets/about.txt</file>
|
||||
<file>assets/ack.txt</file>
|
||||
<file>assets/contributors.txt</file>
|
||||
<file>assets/feather.desktop</file>
|
||||
<file>assets/org.wowlet.wowlet.desktop</file>
|
||||
<file>assets/nodes.json</file>
|
||||
<file>assets/images/appicons/32x32.png</file>
|
||||
<file>assets/images/appicons/48x48.png</file>
|
||||
<file>assets/images/appicons/64x64.png</file>
|
||||
|
@ -27,15 +28,18 @@
|
|||
<file>assets/images/confirmed.svg</file>
|
||||
<file>assets/images/connect.svg</file>
|
||||
<file>assets/images/copy.png</file>
|
||||
<file>assets/images/cutexmrfox.png</file>
|
||||
<file>assets/images/dog_running.gif</file>
|
||||
<file>assets/images/dog_sitting.gif</file>
|
||||
<file>assets/images/edit.png</file>
|
||||
<file>assets/images/exchange.png</file>
|
||||
<file>assets/images/exchange_white.png</file>
|
||||
<file>assets/images/expired.png</file>
|
||||
<file>assets/images/expired_icon.png</file>
|
||||
<file>assets/images/eye1.png</file>
|
||||
<file>assets/images/eye_blind.png</file>
|
||||
<file>assets/images/feather.png</file>
|
||||
<file>assets/images/wowlet.png</file>
|
||||
<file>assets/images/file.png</file>
|
||||
<file>assets/images/fire.png</file>
|
||||
<file>assets/images/gnome-calc.png</file>
|
||||
<file>assets/images/history.png</file>
|
||||
<file>assets/images/info.png</file>
|
||||
|
@ -48,13 +52,136 @@
|
|||
<file>assets/images/lock.svg</file>
|
||||
<file>assets/images/microphone.png</file>
|
||||
<file>assets/images/mining.png</file>
|
||||
<file>assets/images/morphtoken.png</file>
|
||||
<file>assets/images/network.png</file>
|
||||
<file>assets/images/offline_tx.png</file>
|
||||
<file>assets/images/person.svg</file>
|
||||
<file>assets/images/photos/1.png</file>
|
||||
<file>assets/images/illiterate_illuminati.png</file>
|
||||
<file>assets/images/welcome/wow1.png</file>
|
||||
<file>assets/images/welcome/wow2.png</file>
|
||||
<file>assets/images/welcome/wow3.png</file>
|
||||
<file>assets/images/welcome/wow4.png</file>
|
||||
<file>assets/images/welcome/wow5.png</file>
|
||||
<file>assets/images/welcome/wow6.png</file>
|
||||
<file>assets/images/welcome/wow7.png</file>
|
||||
<file>assets/images/welcome/wow8.png</file>
|
||||
<file>assets/images/welcome/wow9.png</file>
|
||||
<file>assets/images/welcome/wow10.png</file>
|
||||
<file>assets/images/welcome/wow11.png</file>
|
||||
<file>assets/images/welcome/wow12.png</file>
|
||||
<file>assets/images/welcome/wow13.png</file>
|
||||
<file>assets/images/welcome/wow14.png</file>
|
||||
<file>assets/images/welcome/wow15.png</file>
|
||||
<file>assets/images/welcome/wow16.png</file>
|
||||
<file>assets/images/welcome/wow17.png</file>
|
||||
<file>assets/images/welcome/wow18.png</file>
|
||||
<file>assets/images/welcome/wow19.png</file>
|
||||
<file>assets/images/welcome/wow20.png</file>
|
||||
<file>assets/images/welcome/wow21.png</file>
|
||||
<file>assets/images/welcome/wow22.png</file>
|
||||
<file>assets/images/welcome/wow23.png</file>
|
||||
<file>assets/images/welcome/wow24.png</file>
|
||||
<file>assets/images/welcome/wow25.png</file>
|
||||
<file>assets/images/welcome/wow26.png</file>
|
||||
<file>assets/images/welcome/wow27.png</file>
|
||||
<file>assets/images/welcome/wow28.png</file>
|
||||
<file>assets/images/welcome/wow29.png</file>
|
||||
<file>assets/images/welcome/wow30.png</file>
|
||||
<file>assets/images/welcome/wow31.png</file>
|
||||
<file>assets/images/welcome/wow32.png</file>
|
||||
<file>assets/images/welcome/wow33.png</file>
|
||||
<file>assets/images/welcome/wow34.png</file>
|
||||
<file>assets/images/welcome/wow35.png</file>
|
||||
<file>assets/images/welcome/wow36.png</file>
|
||||
<file>assets/images/welcome/wow37.png</file>
|
||||
<file>assets/images/welcome/wow38.png</file>
|
||||
<file>assets/images/welcome/wow39.png</file>
|
||||
<file>assets/images/welcome/wow40.png</file>
|
||||
<file>assets/images/welcome/wow41.png</file>
|
||||
<file>assets/images/welcome/wow42.png</file>
|
||||
<file>assets/images/welcome/wow43.png</file>
|
||||
<file>assets/images/welcome/wow44.png</file>
|
||||
<file>assets/images/welcome/wow45.png</file>
|
||||
<file>assets/images/welcome/wow46.png</file>
|
||||
<file>assets/images/welcome/wow47.png</file>
|
||||
<file>assets/images/welcome/wow48.png</file>
|
||||
<file>assets/images/welcome/wow49.png</file>
|
||||
<file>assets/images/welcome/wow50.png</file>
|
||||
<file>assets/images/welcome/wow51.png</file>
|
||||
<file>assets/images/welcome/wow52.png</file>
|
||||
<file>assets/images/welcome/wow53.png</file>
|
||||
<file>assets/images/welcome/wow54.png</file>
|
||||
<file>assets/images/welcome/wow55.png</file>
|
||||
<file>assets/images/welcome/wow56.png</file>
|
||||
<file>assets/images/welcome/wow57.png</file>
|
||||
<file>assets/images/welcome/wow58.png</file>
|
||||
<file>assets/images/welcome/wow59.png</file>
|
||||
<file>assets/images/welcome/wow60.png</file>
|
||||
<file>assets/images/welcome/wow61.png</file>
|
||||
<file>assets/images/welcome/wow62.png</file>
|
||||
<file>assets/images/welcome/wow63.png</file>
|
||||
<file>assets/images/welcome/wow64.png</file>
|
||||
<file>assets/images/welcome/wow65.png</file>
|
||||
<file>assets/images/welcome/wow66.png</file>
|
||||
<file>assets/images/welcome/wow67.png</file>
|
||||
<file>assets/images/welcome/wow68.png</file>
|
||||
<file>assets/images/welcome/wow69.png</file>
|
||||
<file>assets/images/welcome/wow70.png</file>
|
||||
<file>assets/images/welcome/wow71.png</file>
|
||||
<file>assets/images/welcome/wow72.png</file>
|
||||
<file>assets/images/welcome/wow73.png</file>
|
||||
<file>assets/images/welcome/wow74.png</file>
|
||||
<file>assets/images/welcome/wow75.png</file>
|
||||
<file>assets/images/welcome/wow76.png</file>
|
||||
<file>assets/images/welcome/wow77.png</file>
|
||||
<file>assets/images/welcome/wow78.png</file>
|
||||
<file>assets/images/welcome/wow79.png</file>
|
||||
<file>assets/images/welcome/wow80.png</file>
|
||||
<file>assets/images/welcome/wow81.png</file>
|
||||
<file>assets/images/welcome/wow82.png</file>
|
||||
<file>assets/images/welcome/wow83.png</file>
|
||||
<file>assets/images/welcome/wow84.png</file>
|
||||
<file>assets/images/welcome/wow85.png</file>
|
||||
<file>assets/images/welcome/wow86.png</file>
|
||||
<file>assets/images/welcome/wow87.png</file>
|
||||
<file>assets/images/welcome/wow88.png</file>
|
||||
<file>assets/images/welcome/wow89.png</file>
|
||||
<file>assets/images/welcome/wow90.png</file>
|
||||
<file>assets/images/welcome/wow91.png</file>
|
||||
<file>assets/images/welcome/wow92.png</file>
|
||||
<file>assets/images/welcome/wow93.png</file>
|
||||
<file>assets/images/welcome/wow94.png</file>
|
||||
<file>assets/images/welcome/wow95.png</file>
|
||||
<file>assets/images/welcome/wow96.png</file>
|
||||
<file>assets/images/welcome/wow97.png</file>
|
||||
<file>assets/images/welcome/wow98.png</file>
|
||||
<file>assets/images/welcome/wow99.png</file>
|
||||
<file>assets/images/welcome/wow100.png</file>
|
||||
<file>assets/images/welcome/wow101.png</file>
|
||||
<file>assets/images/welcome/wow102.png</file>
|
||||
<file>assets/images/welcome/wow103.png</file>
|
||||
<file>assets/images/welcome/wow104.png</file>
|
||||
<file>assets/images/welcome/wow105.png</file>
|
||||
<file>assets/images/welcome/wow106.png</file>
|
||||
<file>assets/images/welcome/wow107.png</file>
|
||||
<file>assets/images/welcome/wow108.png</file>
|
||||
<file>assets/images/welcome/wow109.png</file>
|
||||
<file>assets/images/welcome/wow110.png</file>
|
||||
<file>assets/images/welcome/wow111.png</file>
|
||||
<file>assets/images/welcome/wow112.png</file>
|
||||
<file>assets/images/welcome/wow113.png</file>
|
||||
<file>assets/images/welcome/wow114.png</file>
|
||||
<file>assets/images/welcome/wow115.png</file>
|
||||
<file>assets/images/welcome/wow116.png</file>
|
||||
<file>assets/images/welcome/wow117.png</file>
|
||||
<file>assets/images/welcome/wow118.png</file>
|
||||
<file>assets/images/welcome/wow119.png</file>
|
||||
<file>assets/images/welcome/wow120.png</file>
|
||||
<file>assets/images/welcome/wow121.png</file>
|
||||
<file>assets/images/welcome/wow122.png</file>
|
||||
<file>assets/images/welcome/wow123.png</file>
|
||||
<file>assets/images/preferences.png</file>
|
||||
<file>assets/images/preferences.svg</file>
|
||||
<file>assets/images/credits.jpg</file>
|
||||
<file>assets/images/qrcode.png</file>
|
||||
<file>assets/images/qrcode_white.png</file>
|
||||
<file>assets/images/revealer_c.png</file>
|
||||
|
@ -62,6 +189,7 @@
|
|||
<file>assets/images/seal.png</file>
|
||||
<file>assets/images/seed.png</file>
|
||||
<file>assets/images/speaker.png</file>
|
||||
<file>assets/images/pls_update.jpg</file>
|
||||
<file>assets/images/status_connected_fork.png</file>
|
||||
<file>assets/images/status_connected.png</file>
|
||||
<file>assets/images/status_connected_proxy_fork.png</file>
|
||||
|
@ -95,13 +223,39 @@
|
|||
<file>assets/images/unpaid.png</file>
|
||||
<file>assets/images/update.png</file>
|
||||
<file>assets/images/warning.png</file>
|
||||
<file>assets/images/xmrto_big.png</file>
|
||||
<file>assets/images/xmrto.png</file>
|
||||
<file>assets/images/xmrig.ico</file>
|
||||
<file>assets/images/xmrig.svg</file>
|
||||
<file>assets/images/zoom.png</file>
|
||||
<file>assets/mnemonic_25_english.txt</file>
|
||||
<file>assets/restore_heights_monero_mainnet.txt</file>
|
||||
<file>assets/restore_heights_monero_stagenet.txt</file>
|
||||
<file>assets/restore_heights_wownero_mainnet.txt</file>
|
||||
|
||||
<file alias="mining/bottom_center_console.png">assets/images/mining/bottom_center_console.png</file>
|
||||
<file alias="mining/intel.png">assets/images/mining/intel.png</file>
|
||||
<file alias="mining/amd.png">assets/images/mining/amd.png</file>
|
||||
<file alias="mining/overlay.png">assets/images/mining/overlay.png</file>
|
||||
<file alias="mining/mining_gradient.png">assets/images/mining/mining_gradient.png</file>
|
||||
<file alias="mining/bg1.gif">assets/images/mining/bg1.gif</file>
|
||||
<file alias="mining/lowerleft_circle.png">assets/images/mining/lowerleft_circle.png</file>
|
||||
<file alias="mining/lowerleft.png">assets/images/mining/lowerleft.png</file>
|
||||
<file alias="mining/lower_repeat.png">assets/images/mining/lower_repeat.png</file>
|
||||
<file alias="mining/lowerright.png">assets/images/mining/lowerright.png</file>
|
||||
<file alias="mining/r_bottom.png">assets/images/mining/r_bottom.png</file>
|
||||
<file alias="mining/r_left.png">assets/images/mining/r_left.png</file>
|
||||
<file alias="mining/r_right.png">assets/images/mining/r_right.png</file>
|
||||
<file alias="mining/topleft.png">assets/images/mining/topleft.png</file>
|
||||
<file alias="mining/topright_bar.png">assets/images/mining/topright_bar.png</file>
|
||||
<file alias="mining/topright_left.png">assets/images/mining/topright_left.png</file>
|
||||
<file alias="mining/topright_middle.png">assets/images/mining/topright_middle.png</file>
|
||||
<file alias="mining/topright_right.png">assets/images/mining/topright_right.png</file>
|
||||
<file alias="mining/warning.png">assets/images/mining/warning.png</file>
|
||||
<file alias="mining/axe.png">assets/images/mining/axe.png</file>
|
||||
<file alias="mining/lowerleft_btn.png">assets/images/mining/lowerleft_btn.png</file>
|
||||
<file alias="mining/elmo.gif">assets/images/mining/elmo.gif</file>
|
||||
<file alias="mining/bubble.png">assets/images/mining/bubble.png</file>
|
||||
<file alias="mining/mining.webp">assets/images/mining/mining.webp</file>
|
||||
|
||||
<file alias="fonts/ComicMono.ttf">assets/fonts/ComicMono.ttf</file>
|
||||
<file alias="fonts/ComicMono-Bold.ttf">assets/fonts/ComicMono-Bold.ttf</file>
|
||||
<file alias="mining.qml">ui/qml/mining.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
Feather <feather_version> (<feather_git_head>)
|
||||
WOWlet <wowlet_version> (<wowlet_git_head>)
|
||||
|
||||
https://featherwallet.org
|
||||
Website: https://wownero.org
|
||||
E-mail: dev@wownero.org
|
||||
|
||||
Created by dsc <dsc@xmr.pm>, tobtoht <thotbot@protonmail.com>, and contributors.
|
||||
Created by dsc, tobtoht, and contributors.
|
||||
|
||||
Copyright (c) 2020-<current_year>, The Monero Project
|
||||
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
Feather uses monero-seed written by Tevador, for 14 word mnemonic seeds.
|
||||
|
||||
Initial CMake support for the Monero GUI was coded by TheCharlatan/xiphon.
|
||||
WOWlet is a fork of Feather (https://git.featherwallet.org/feather/feather).
|
||||
|
||||
The wallet UI is heavily inspired by Electrum. We would like to recognize Thomas Voegtlin for his pioneering work on Bitcoin.
|
||||
|
||||
Huge thanks to nioc, fluffypony, wowario, thrmo for help during development.
|
||||
WOWlet uses monero-seed written by Tevador, for 14 word mnemonic seeds.
|
||||
|
||||
Some more shoutouts for people for hosting nodes and/or having good ideas:
|
||||
dnale0r, dEBRUYNE, binaryFate, lza_menace, jwinterm, kico, wowario
|
||||
Wizard banner art was adapted from a paper wallet design by the themonera (themonera.art).
|
||||
|
||||
Initial CMake support for the Monero GUI was coded by TheCharlatan/xiphon.
|
||||
|
||||
Huge thanks to dsc, tobtoht, nioc, fluffypony, wowario, thrmo for help during development.
|
||||
|
||||
rottensox for testing :-)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
dsc <dsc@xmr.pm>
|
||||
tobtoht <thotbot@protonmail.com>
|
||||
selsta <selsta@sent.at>
|
||||
Diego Salazar <rehrar@tuta.io>
|
||||
Matt Smith <matt@offtopica.uk>
|
||||
dsc
|
||||
tobtoht
|
||||
selsta
|
||||
Diego Salazar
|
||||
Matt Smith
|
|
@ -1,14 +0,0 @@
|
|||
[Desktop Entry]
|
||||
Comment=Lightweight Monero Wallet
|
||||
Exec=feather
|
||||
GenericName[en_US]=Monero Wallet
|
||||
GenericName=Monero Wallet
|
||||
Icon=feather
|
||||
Name[en_US]=Feather
|
||||
Name=Feather
|
||||
Categories=Finance;Network;
|
||||
StartupNotify=false
|
||||
StartupWMClass=feather
|
||||
Terminal=false
|
||||
Type=Application
|
||||
MimeType=x-scheme-handler/monero;
|
BIN
src/assets/fonts/ComicMono-Bold.ttf
Normal file
BIN
src/assets/fonts/ComicMono.ttf
Normal file
BIN
src/assets/images/appicons/1024x1024.png
Normal file
After Width: | Height: | Size: 98 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 8.9 KiB |
BIN
src/assets/images/appicons/16x16.png
Normal file
After Width: | Height: | Size: 941 B |
BIN
src/assets/images/appicons/192x192.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
src/assets/images/appicons/22x22.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
src/assets/images/appicons/24x24.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 1.9 KiB |
BIN
src/assets/images/appicons/36x36.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
src/assets/images/appicons/42x42.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 2.9 KiB |
BIN
src/assets/images/appicons/512x512.png
Normal file
After Width: | Height: | Size: 42 KiB |