Electrum: URI Handling totally broken on Mac

Created on 24 Oct 2018  路  5Comments  路  Source: spesmilo/electrum

Hi all,

Electron Cash dev here. I'm posting this issue here to create a discussion about potential ways to fix this issue.

So URI handling for: bitcoin:bc1qs5q679tac0uvfunt0gdwuymves5re7v7q8fntv-style URIs is completely not working as expected on all 3 major platforms.

The issue:

If Electrum Was Not Running

  1. Windows & Linux: The URI works fine and opening the URI ends up spawning an Electrum instance with the correct behavior: "send" tab is pre-filled-in.

  2. Mac: The URI handling is completely broken. It does indeed spawn a new Electrum app, however the send tab is not pre-filled-in.

If Electrum Is Already Running

  1. Windows & Linux: Nothing happens. The app is not brought to foreground and the send tab is not pre-populated with anything.

  2. Mac: Nothing happens. Same as (1) above.

Why This Is Broken

In the Windows & Linux case, URI handling ends up invoking the electrum script with the URI as the first argument. In the "not already running" case, this is fine -- it makes Electrum start up and parse the URI and pre-populate the send tab. In the "already running" case, the second Electrum quits early because it detects an already-running GUI.

On Mac -- the situation is a bit more pathological. On macs, URIs are opened by basically (1) starting the app if it was not running and (2) calling some platform-specific code in the app to pass on the URI. That platform-specific code normally gets translated by Qt into a "File Open" event. This normally works fine on Qt -- however with PyQt _our pyinstaller bootloader/child process setup this is not working_.

I believe there is a bug in PyQt which is causing it to drop the QFileOpenEvent event from being propagated to the Electrum app (QApplication instance). Event number 116 (QtCore.QEvent.FileOpen) never makes it to the application event queue. So the mac implementation is never told about it! _I
now think the bug is rather in pyinstaller's bootloader parent process not forwarding the URI event to the Electrum/python child process._

In order to verify this bug exists, I wrote a small test program (attached) in C++. If I compile this program and replace the "Electrum" program in Contents/MacOS/Electrum with it -- the program does indeed receive the FileOpen event.

It's only our PyQt _pyinstaller_ implementation on Mac that does not receive this event.

/* Sample C++ program that correctly receives FileOpen event -- if this is compiled to replace Electrum in the Electrum.app bundle, everything works fine.  But our PyQt based Electrum program does NOT receive this event! */
#include <QGuiApplication>
#include <QFileOpenEvent>
#include <stdio.h>

class MyApp : public QGuiApplication
{
        public:
                MyApp(int argc, char **argv) : QGuiApplication(argc, argv) {}
                bool event(QEvent *) override;
};

bool MyApp::event(QEvent *e) 
{
        if (e->type() == QEvent::FileOpen) {
                QFileOpenEvent *fe = dynamic_cast<QFileOpenEvent *>(e);
                printf("File open event: %s\n", fe->url().toString().toUtf8().constData());
        }
        return QGuiApplication::event(e);
}

int main(int argc, char **argv) {

        MyApp app(argc, argv);

        return app.exec();
}

Potential Fixes

  1. On Windows & Linux the fix would be to have the second Electrum process inform the first about the arrival of a URI via some cross-platform, python-only IPC mechanism.

  2. On Mac there is no easy fix unless we can figure out how to get the FileOpen events to properly make it to our QApplication instance. Potentially we may have to submit a patch to the PyQt project (I will investigate this further). _Potentially we may have to see about different pyinstaller setups (such as one-directory mode versus one-file mode) and see if we can get pyinstaller to play nice. I suspect pyinstaller's bootloader will interfere in either case..._

I am wondering, for the Windows & Linux case -- would you be open to the approach I outlined above (some IPC mechanism to signal the first process that a URI has arrived)?

Let me know what you guys think! This issue is not high priority -- but it is relatively sad that URI handling doesn't quite work for both Electron Cash and Electrum at the present moment.

OS-mac bug 馃悶 builpackaging 馃摝

Most helpful comment

I'll have a go at fixing the other part of the issue. ("If Electrum Is Already Running")

All 5 comments

Update: Mac is actually hindered not by a bug in PyQt, but by the fact that pyinstaller uses a bootloader program as a parent process to Electrum (and Electron-Cash). This parent process receives the URI event but never forwards to the actual Electrum child process -- so Qt never sees it.

I will play around with different pyinstaller options -- perhaps "one directory mode" versus "one file mode" would work better for us... (although both modes use a bootloader so it may not help).

We may have to investigate doing away with pyinstaller on macOS and using setup.py or some other mechanism to generate the app bundle (if we really want this fixed on macOS). _Pyinstaller is pretty awesome even with this bug as compared to py2app. I do not recommend going back to the old py2app way regardless of what happens..._

I'll have a go at fixing the other part of the issue. ("If Electrum Is Already Running")

Update2: I am digging into the pyintsaller sources and attempting to modify them to forward events from parent to child process (this is for macOS issues only). Apparently this is a known issue and the devs seems to have wished it fixed but never got it working on macos. If I am successful, I will submit a patch to pyinstaller.

In any case I do not recommend going back to py2app for packaging. Pyinstaller has many advantages even with this extant bug on MacOS. :)

@SomberNight Nice fix! I just stole it and brought it over to Electron Cash and it works flawlessly on Windows & Linux. I admit I didn't realize the daemon can tell the other process to start a new window. whoosh. I guess there's still stuff I need to learn about the program's architecture. Nice fix!!

I am working on a pyinstaller fixup -- you did correctly label this as MacOS/Packaging -- which is what it is down to.

Thanks for the quick fix!!!

Update3: I did it! I submitted a patch to pyinstaller for fix this on macOS! Woohoo!

https://github.com/pyinstaller/pyinstaller/pull/3832

Now let's hope they merge it in...

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Javcho2020 picture Javcho2020  路  3Comments

GuestInCorle picture GuestInCorle  路  3Comments

juniorjp picture juniorjp  路  5Comments

zzAD26KAH59cYpL picture zzAD26KAH59cYpL  路  5Comments

karelbilek picture karelbilek  路  4Comments