t[macOS] Added QR scanner facility using platform-native helper app. - electrum - Electrum Bitcoin wallet
 (HTM) git clone https://git.parazyd.org/electrum
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
       ---
 (DIR) commit db89286ec3fa19156b7a85628e93469ef1616546
 (DIR) parent d0e6b8c89dee017e4ad790d63e4f642a7e28e67c
 (HTM) Author: Calin Culianu <calin.culianu@gmail.com>
       Date:   Thu, 29 Nov 2018 00:09:06 +0200
       
       t[macOS] Added QR scanner facility using platform-native helper app.
       
       Diffstat:
         M .gitmodules                         |       3 +++
         A contrib/CalinsQRReader              |       1 +
         M contrib/build-osx/base.sh           |       2 +-
         M contrib/build-osx/make_osx          |       9 +++++++++
         M contrib/build-osx/osx.spec          |       3 +++
         M electrum/qrscanner.py               |      25 ++++++++++++++++++++++++-
       
       6 files changed, 41 insertions(+), 2 deletions(-)
       ---
 (DIR) diff --git a/.gitmodules b/.gitmodules
       t@@ -4,3 +4,6 @@
        [submodule "contrib/deterministic-build/electrum-locale"]
                path = contrib/deterministic-build/electrum-locale
                url = https://github.com/spesmilo/electrum-locale
       +[submodule "contrib/CalinsQRReader"]
       +        path = contrib/CalinsQRReader
       +        url = https://github.com/spesmilo/CalinsQRReader
 (DIR) diff --git a/contrib/CalinsQRReader b/contrib/CalinsQRReader
       t@@ -0,0 +1 @@
       +Subproject commit 20189155a461cf7fbad14357e58fbc8e7c964608
 (DIR) diff --git a/contrib/build-osx/base.sh b/contrib/build-osx/base.sh
       t@@ -21,7 +21,7 @@ function DoCodeSignMaybe { # ARGS: infoName fileOrDirName codesignIdentity
            identity="$3"
            deep=""
            if [ -z "$identity" ]; then
       -        # we are ok with them not passing anything -- master script calls us always even if no identity is specified
       +        # we are ok with them not passing anything; master script calls us unconditionally even if no identity is specified
                return
            fi
            if [ -d "$file" ]; then
 (DIR) diff --git a/contrib/build-osx/make_osx b/contrib/build-osx/make_osx
       t@@ -16,6 +16,7 @@ export PYTHONHASHSEED=22
        VERSION=`git describe --tags --dirty --always`
        
        which brew > /dev/null 2>&1 || fail "Please install brew from https://brew.sh/ to continue"
       +which xcodebuild > /dev/null 2>&1 || fail "Please install Xcode and xcode command line tools to continue"
        
        # Code Signing: See https://developer.apple.com/library/archive/documentation/Security/Conceptual/CodeSigningGuide/Procedures/Procedures.html
        APP_SIGN=""
       t@@ -87,6 +88,14 @@ popd
        cp $BUILDDIR/secp256k1/.libs/libsecp256k1.0.dylib contrib/build-osx
        DoCodeSignMaybe "libsecp256k1" "contrib/build-osx/libsecp256k1.0.dylib" "$APP_SIGN" # If APP_SIGN is empty will be a noop
        
       +info "Building CalinsQRReader..."
       +d=contrib/CalinsQRReader
       +pushd $d
       +rm -fr build
       +xcodebuild || fail "Could not build CalinsQRReader"
       +popd
       +DoCodeSignMaybe "CalinsQRReader.app" "${d}/build/Release/CalinsQRReader.app" "$APP_SIGN" # If APP_SIGN is empty will be a noop
       +
        
        info "Installing requirements..."
        python3 -m pip install -Ir ./contrib/deterministic-build/requirements.txt --user && \
 (DIR) diff --git a/contrib/build-osx/osx.spec b/contrib/build-osx/osx.spec
       t@@ -41,6 +41,9 @@ datas += collect_data_files('btchip')
        datas += collect_data_files('keepkeylib')
        datas += collect_data_files('ckcc')
        
       +# Add the QR Scanner helper app
       +datas += [(electrum + "contrib/CalinsQRReader/build/Release/CalinsQRReader.app", "./contrib/CalinsQRReader/build/Release/CalinsQRReader.app")]
       +
        # Add libusb so Trezor and Safe-T mini will work
        binaries = [(electrum + "contrib/build-osx/libusb-1.0.dylib", ".")]
        binaries += [(electrum + "contrib/build-osx/libsecp256k1.0.dylib", ".")]
 (DIR) diff --git a/electrum/qrscanner.py b/electrum/qrscanner.py
       t@@ -40,7 +40,7 @@ except BaseException:
            libzbar = None
        
        
       -def scan_barcode(device='', timeout=-1, display=True, threaded=False, try_again=True):
       +def scan_barcode_ctypes(device='', timeout=-1, display=True, threaded=False, try_again=True):
            if libzbar is None:
                raise RuntimeError("Cannot start QR scanner; zbar not available.")
            libzbar.zbar_symbol_get_data.restype = ctypes.c_char_p
       t@@ -69,6 +69,29 @@ def scan_barcode(device='', timeout=-1, display=True, threaded=False, try_again=
            data = libzbar.zbar_symbol_get_data(symbol)
            return data.decode('utf8')
        
       +def scan_barcode_osx(*args_ignored, **kwargs_ignored):
       +    import subprocess
       +    # NOTE: This code needs to be modified if the positions of this file changes with respect to the helper app!
       +    # This assumes the built macOS .app bundle which ends up putting the helper app in
       +    # .app/contrib/CalinsQRReader/build/Release/CalinsQRReader.app.
       +    root_ec_dir = os.path.abspath(os.path.dirname(__file__) + "/../")
       +    prog = root_ec_dir + "/" + "contrib/CalinsQRReader/build/Release/CalinsQRReader.app/Contents/MacOS/CalinsQRReader"
       +    if not os.path.exists(prog):
       +        raise RuntimeError("Cannot start QR scanner; helper app not found.")
       +    data = ''
       +    try:
       +        # This will run the "CalinsQRReader" helper app (which also gets bundled with the built .app)
       +        # Just like the zbar implementation -- the main app will hang until the QR window returns a QR code
       +        # (or is closed). Communication with the subprocess is done via stdout.
       +        # See contrib/CalinsQRReader for the helper app source code.
       +        with subprocess.Popen([prog], stdout=subprocess.PIPE) as p:
       +            data = p.stdout.read().decode('utf-8').strip()
       +        return data
       +    except OSError as e:
       +        raise RuntimeError("Cannot start camera helper app; {}".format(e.strerror))
       +
       +scan_barcode = scan_barcode_osx if sys.platform == 'darwin' else scan_barcode_ctypes
       +
        def _find_system_cameras():
            device_root = "/sys/class/video4linux"
            devices = {} # Name -> device