Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Qt bring QProcess application to the front



  • Problem arises under the Windows OS.

    I have the main application and I start a new application from that using QProcess (let's call it child application), at first child application just runs in the background, but on click to some button in the main app, child app should be shown. For that purpose (and also for some other reasons) I run a local server and both applications are connected to the server and exchange messages using sockets. When child app gets appropriate message, I call function to display it, which also should raise and bring to the front child application.

    Here is a piece of code related to that part.

    // Case 1 (child app is shown, but not a foreground window)
    
    // Main app
    
    QScopedPointer<QLocalServer> localServer;
    QLocalSocket connection; // connection listens on the same local server as we have in the child application
    
    // this function is called in class constructor and runs process in the background
    void startChildApplication()
    {
      childProcess.reset(new QProcess);
      // args are unimportant here
      childProcess.start(Utilities::getchildProcessLocation(), args);
    }
    
    // this function called onClick of some button to display child process running in the background
    void displayChildApplication()
    {
      const std::string message = "display";
      connection.write(message.data(), message.size());
    }
    
    // Child app
    
    QScopedPointer<QLocalServer> localServer;
    QLocalSocket childConnection; // childConnection listens on the same local server as we have in the main application
    
    void displayApplication()
    {
        appWindow->setWindowState((appWindow->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
        appWindow->show();
        appWindow->activateWindow();
        appWindow->raise();
    }
    
    connect(childConnection, &QLocalSocket::readyRead, this, [this]()
    {
      const auto message = childConnection->readAll();
      if (message == "display")
      {
        displayApplication();
      }
    };
    

    So problem is application is shown, but it's not a foreground window. I also tried Windows specific WINAPI functions (SetForegroundWindow, etc), which also didn't work.

    Funny part of the problem is that if I don't run child app in the background and try to display on button click, but just run QProcess on click and in constructor for child app I call displayApplication function, it works as expected, child application is shown and it's a foreground window.

    // Case 2 (child app is shown and it's a foreground window)
    
    // Main app
    
    // this function is called onClick of some button to start and display child process
    void startChildApplication()
    {
      childProcess.reset(new QProcess);
      // args are unimportant here
      childProcess.start(Utilities::getchildProcessLocation(), args);
    }
    
    // Child app
    
    // this function is called in class constructor
    void displayApplication()
    {
        appWindow->setWindowState((appWindow->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
        appWindow->show();
        appWindow->activateWindow();
        appWindow->raise();
    }
    

    Question is how to get behavior of case 2 in case 1, or at least understand why it doesn't work in the first case and works in the second case.

    P.S. I know that its a Windows specific thing, but as you can see it's possible to get behavior I want.


  • Moderators

    See the Remarks section in the SetForegroundWindow. This also applies to Qt which uses SetForegroundWindow internally.

    To summarize - on Windows you're restricted on when you can bring your window to the foreground. That's to prevent popups and other annoying behavior of some apps. You have to be either the active process, a child of the active process or have input focus.

    The method with a button and QProcess works because it falls under one of the exceptions listed - you're started as a child of the active process and so can raise yourself to the foreground. When you communicate through a server your processes are not related, so the one receiving a message can't raise itself.



  • This post is deleted!


  • @lamozg6 said in Qt bring QProcess application to the front:

    So problem is application is shown, but it's not a foreground window.

    This is purely a guess/hunch. From your description, you are trying to up-front spawned child from a click in parent. Maybe the order of events is important to the windowing system. Maybe the child is trying to up-front while you're still interacting with the parent window and that's not good?

    In child put in a delay before up-fronting itself. In parent finish the click, releasing the button, then the child up-fronts. Does it now up-front correctly?


  • Moderators

    See the Remarks section in the SetForegroundWindow. This also applies to Qt which uses SetForegroundWindow internally.

    To summarize - on Windows you're restricted on when you can bring your window to the foreground. That's to prevent popups and other annoying behavior of some apps. You have to be either the active process, a child of the active process or have input focus.

    The method with a button and QProcess works because it falls under one of the exceptions listed - you're started as a child of the active process and so can raise yourself to the foreground. When you communicate through a server your processes are not related, so the one receiving a message can't raise itself.



  • @Chris-Kawa
    An excellent Windows point!

    But I get confused. The OP shows

     childProcess.start(Utilities::getchildProcessLocation(), args);
    

    being run from the program where he clicks the button, not the "server", as I understand it. Which would put the relationship in your

    a child of the active process

    situation. So as I read it, it ought be able to foreground itself when it receives a message from the active parent app? Which I think the OP is saying does not happen.


  • Moderators

    @JonB As I understood it the parent is the process which can't raise itself or its child, but now reading the OP again I'm not sure which app gets a message and which tries to raise what window. I guess we need a clarification from @lamozg6 on that, but I believe what I mentioned applies to this problem in some form.



  • @Chris-Kawa said in Qt bring QProcess application to the front:

    When you communicate through a server your processes are not related, so the one receiving a message can't raise itself.

    @JonB said in Qt bring QProcess application to the front:

    being run from the program where he clicks the button, not the "server", as I understand it.

    Yes, that's the case, child application is run from main application, server is used just for communication (main app sends message to notify child app that it should be displayed now). So processes communicate by server, but that processes are related, child application is a child process of the active process. As I understand this should fall into the same case that @Chris-Kawa mentioned, child process of the active process tries to raise itself, but it can't (I only get that application icon blinking in the toolbar), what did I miss?

    Also, what I noticed in Task Manager, when that child process is shown, now its a separate process, not a child process of my main application as it was, but that's for both cases.



  • Problem was solved by adding call to the AllowSetForegroundWindow from main application just before sending message to the child application, not quite sure why it's needed, but anyway problem is gone, so thank you guys.


Log in to reply