SystemTrayIconComponent in console application


#1

Trying to use a SystemTrayIconComponent in a console application.

Icon appears as expected but PopupMenu only appears for moment when icon is clicked (using showMenuAsync)

This is because window.doesAnyJuceCompHaveFocus in checkButtonState in MouseSourceState (found in juce_PopupMenu.cpp - line 1082) returns false - I assume because it is a console application and there aren’t any components to focus.

Is there another way around this?

example code pretty much lifted out of the JUCE demo:

class TestTrayIcon : public SystemTrayIconComponent, private Timer
{
public:
    TestTrayIcon(){
        setIconImage (ImageFileFormat::loadFrom(BinaryData::TestTrayIcon_png,BinaryData::TestTrayIcon_pngSize));
        setIconTooltip ("TestTrayIcon");
        m.addItem (1, "Quit");
    }
    ~TestTrayIcon(){
        
    }
    void mouseDown(const MouseEvent& event) override{
        startTimer (50);
    }
    static void menuInvocationCallback (int chosenItemID, TestTrayIcon*)
    {
        if (chosenItemID == 1)
            JUCEApplication::getInstance()->systemRequestedQuit();
    }
    void timerCallback() override
    {
        stopTimer();
        m.showMenuAsync (PopupMenu::Options(), ModalCallbackFunction::forComponent (menuInvocationCallback, this));
    }
private:
    PopupMenu m;
};

#2

friendly bump


#3

It looks like your mouseDown() is missing a call to Process::makeForegroundProcess(), like so:

void mouseDown (const MouseEvent&) override
{
    Process::makeForegroundProcess();
    startTimer (50);
}

#4

@ed95 - thanks for the reply. I had tried that but removed it as it made no difference. Here is the example code with that included and still same issue - clicking on the menu bar icon only shows the popup temporarily.

class TestTrayIcon : public SystemTrayIconComponent, private Timer
{
public:
    TestTrayIcon(){
        setIconImage (ImageFileFormat::loadFrom(BinaryData::TestTrayIcon_png,BinaryData::TestTrayIcon_pngSize));
        setIconTooltip ("TestTrayIcon");
        m.addItem (1, "Quit");
    }
    ~TestTrayIcon(){
        
    }
    void mouseDown(const MouseEvent& event) override{
        Process::makeForegroundProcess();
        startTimer (50);
    }
    static void menuInvocationCallback (int chosenItemID, TestTrayIcon*)
    {
        if (chosenItemID == 1)
            JUCEApplication::getInstance()->systemRequestedQuit();
    }
    void timerCallback() override
    {
        stopTimer();
        m.showMenuAsync (PopupMenu::Options(), ModalCallbackFunction::forComponent (menuInvocationCallback, this));
    }
private:
    PopupMenu m;
};

#5

@ed95 - any other things to try here? thanks


#6

It looks like this is a macOS specific issue and Process::isForegroundProcess() (which on macOS calls [NSApp isActive]) is always returning false for a console application, which in turn causes the doesAnyJuceCompHaveFocus() method to return false and immediately dismisses the popup. I’ve tried a few things, such as using the PID to check whether our process is the foreground instead of isActive but that didn’t work, and I’ve tried forcing the app to be the foreground process but that fails too. I’m not sure what else we can do here.