Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. The invisible QApplication

The invisible QApplication

Scheduled Pinned Locked Moved Unsolved General and Desktop
15 Posts 4 Posters 4.6k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    Moose2342
    wrote on 21 Feb 2016, 14:05 last edited by
    #1

    Hello Qt community,

    I am currently developing in project which involves rendering a Qt Application (or more specifically one widget) into a VR context. To that end I am spawning the Application in a contained thread and use everything Qt from there. When updates come in, I QWidget::render() into a QPixbuf and consume the buffer from there to be used as a texture in an rather extensive OpenGL application. This works surprisingly well so far.

    However, my current challenge is, that the QApplication itself, main Window and all, still spawn to be visible on the desktop. I understand show() is necessary for the event loop to fire up and the actual rendering to happen.
    What I need to do is to suppress this. I want a show() that doesn't show. ;-) I want the application to live and process signals and render the widgets all normally but all this without actually displaying anything to the user. All I need is the rendered pixbuf content, which I already have. I will then multiplex necessary input signals into the application to mimic user interaction.

    Is there a way to do this?

    I have the following preconditions:

    • Windows and ideally Linux is OK. Other platforms are not required
    • It would be alright to tell Qt to display into some kind of buffer or virtual screen or whatever as long as I can discard the content and only show what I have now. Possible performance penalty by this are acceptable
    • A solution should not be too invasive
    • It would be OK to use the Windows API or some other platform specific solution (I thought about unused OpenGL contexts)?

    If anyone can give me a hint as to how I can proceed with that it would help a lot.

    Cheers,
    Moose

    M 1 Reply Last reply 23 Feb 2016, 09:41
    0
    • M Moose2342
      21 Feb 2016, 14:05

      Hello Qt community,

      I am currently developing in project which involves rendering a Qt Application (or more specifically one widget) into a VR context. To that end I am spawning the Application in a contained thread and use everything Qt from there. When updates come in, I QWidget::render() into a QPixbuf and consume the buffer from there to be used as a texture in an rather extensive OpenGL application. This works surprisingly well so far.

      However, my current challenge is, that the QApplication itself, main Window and all, still spawn to be visible on the desktop. I understand show() is necessary for the event loop to fire up and the actual rendering to happen.
      What I need to do is to suppress this. I want a show() that doesn't show. ;-) I want the application to live and process signals and render the widgets all normally but all this without actually displaying anything to the user. All I need is the rendered pixbuf content, which I already have. I will then multiplex necessary input signals into the application to mimic user interaction.

      Is there a way to do this?

      I have the following preconditions:

      • Windows and ideally Linux is OK. Other platforms are not required
      • It would be alright to tell Qt to display into some kind of buffer or virtual screen or whatever as long as I can discard the content and only show what I have now. Possible performance penalty by this are acceptable
      • A solution should not be too invasive
      • It would be OK to use the Windows API or some other platform specific solution (I thought about unused OpenGL contexts)?

      If anyone can give me a hint as to how I can proceed with that it would help a lot.

      Cheers,
      Moose

      M Offline
      M Offline
      Moose2342
      wrote on 23 Feb 2016, 09:41 last edited by
      #2

      I would like to add current state of investigations. During the last couple of days I have experimented with the approach of trying to create a native Win32 Window, have Qt use it and try to turn this invisble.

      Similar to this:

      HWND native_window = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, "Static", "InvisbleQtWrap", WS_VISIBLE, 100, 100, 800, 1200, 0, 0, 0, nullptr);
       ...
      QWindow *win = QWindow::fromWinId((WId)native_window);
      QWidget *container = QWidget::createWindowContainer(win);
      // create my widget using Container as parent.
      container->show();
      

      This doesn't seem to work. I can get the native window to spawn and the QtContainer appears to take it over but there's nothing rendered and my widget seems to be dormant.

      I will investigate in other directions now.

      Maybe someone has an idea.

      1 Reply Last reply
      0
      • R Offline
        R Offline
        rturrentine
        wrote on 23 Feb 2016, 19:49 last edited by
        #3

        We support a command line option for hiding the GUI of our Qt based app. This works on Windows, Linux and Solaris.

        Hiding a window can't be done in the constructor so you need to use a single shot timer.

        In the main window constructor,

                qApp->setQuitOnLastWindowClosed( false );
                QTimer::singleShot( 0, this, SLOT( hide() ) );
        

        The main app creates the window but does not call show or anything on it. We simply call the exec method for our application object.

        M 1 Reply Last reply 24 Feb 2016, 08:51
        1
        • R rturrentine
          23 Feb 2016, 19:49

          We support a command line option for hiding the GUI of our Qt based app. This works on Windows, Linux and Solaris.

          Hiding a window can't be done in the constructor so you need to use a single shot timer.

          In the main window constructor,

                  qApp->setQuitOnLastWindowClosed( false );
                  QTimer::singleShot( 0, this, SLOT( hide() ) );
          

          The main app creates the window but does not call show or anything on it. We simply call the exec method for our application object.

          M Offline
          M Offline
          Moose2342
          wrote on 24 Feb 2016, 08:51 last edited by
          #4

          @rturrentine Thanks a lot for your response. I just gave that a test. In my scenario the window remains hidden but the widgets are nor receiving paint events either.
          I suppose this is due to the nature of Qt's event loop. In my research everything I read pointed towards "Your widgets will not be painted as long as they are hidden.". But I do need them painted so I can intercept the events and render() into my own buffer.
          Or is there another way? Maybe I can send those events myself in a QTimer triggered frequency? Is that a viable approach?

          Cheers,
          Moose

          1 Reply Last reply
          0
          • M Offline
            M Offline
            mrjj
            Lifetime Qt Champion
            wrote on 24 Feb 2016, 09:17 last edited by
            #5

            Hi
            If a Widget is hidden it gets no paint events as far as i know.

            One thing you could test is the render() function
            http://doc.qt.io/qt-5.5/qwidget.html#render

            It lets you draw a widget directly to pixmap so I think it can work with hidden
            widget but never tested it.

            QPixmap pixmap(mywidget->size());
            mywidget->render(&pixmap);

            I know u already use render() but I wonder if u tried calling it directly, not using paintevent at all?

            One thing that could also be issue is that while hidden , it do not receive resize events
            so might be of wrong size even if Render() does work.

            Maybe you already tested all this. Just asking :)

            M 1 Reply Last reply 24 Feb 2016, 09:50
            0
            • E Offline
              E Offline
              eureka
              wrote on 24 Feb 2016, 09:38 last edited by
              #6

              @Moose2342 said:

              I want a show() that doesn't show.

              I'm quite new to Qt. Please explain why setting the widget geometry (X, Y) to negative values doesn't take the widget off screen .. effectively hiding the widget?

              M 1 Reply Last reply 24 Feb 2016, 09:45
              0
              • E eureka
                24 Feb 2016, 09:38

                @Moose2342 said:

                I want a show() that doesn't show.

                I'm quite new to Qt. Please explain why setting the widget geometry (X, Y) to negative values doesn't take the widget off screen .. effectively hiding the widget?

                M Offline
                M Offline
                mrjj
                Lifetime Qt Champion
                wrote on 24 Feb 2016, 09:45 last edited by
                #7

                @eureka
                Hi
                For some platforms that might work.
                But some platforms/windows managers do not allow it or
                it can have side effects in multiple monitor setup.
                Some windows managers might even help you and move it into view :)

                1 Reply Last reply
                0
                • M mrjj
                  24 Feb 2016, 09:17

                  Hi
                  If a Widget is hidden it gets no paint events as far as i know.

                  One thing you could test is the render() function
                  http://doc.qt.io/qt-5.5/qwidget.html#render

                  It lets you draw a widget directly to pixmap so I think it can work with hidden
                  widget but never tested it.

                  QPixmap pixmap(mywidget->size());
                  mywidget->render(&pixmap);

                  I know u already use render() but I wonder if u tried calling it directly, not using paintevent at all?

                  One thing that could also be issue is that while hidden , it do not receive resize events
                  so might be of wrong size even if Render() does work.

                  Maybe you already tested all this. Just asking :)

                  M Offline
                  M Offline
                  Moose2342
                  wrote on 24 Feb 2016, 09:50 last edited by
                  #8

                  @mrjj Yes, I tried calling this directly. It only produces an empty buffer though. I suppose this is due to the widget in question being quite complex.
                  It is a QWebEngineWidget.
                  It creates a lot of underlying child widgets and they pass their sizes and status back and forth. It wasn't even straight forward hooking up to it's paint event at all.

                  So when I trigger render on it, say from a QTimer without having the widget visible it simply paints a white screen into the buffer. At this point I can only assume that the size information are not correctly passed to the child widgets if it is invisible.

                  So far all my tests with manually generating events were inconclusive or negative. Personally I believe messing with the event loop too much will only bring complexity and no solution. My gut tells me a solution will work best if I can redirect the graphical output to the now legendary /dev/null without Qt knowing about it.

                  Thank you very much for the hint though!

                  Moose

                  M 1 Reply Last reply 24 Feb 2016, 10:00
                  0
                  • M Moose2342
                    24 Feb 2016, 09:50

                    @mrjj Yes, I tried calling this directly. It only produces an empty buffer though. I suppose this is due to the widget in question being quite complex.
                    It is a QWebEngineWidget.
                    It creates a lot of underlying child widgets and they pass their sizes and status back and forth. It wasn't even straight forward hooking up to it's paint event at all.

                    So when I trigger render on it, say from a QTimer without having the widget visible it simply paints a white screen into the buffer. At this point I can only assume that the size information are not correctly passed to the child widgets if it is invisible.

                    So far all my tests with manually generating events were inconclusive or negative. Personally I believe messing with the event loop too much will only bring complexity and no solution. My gut tells me a solution will work best if I can redirect the graphical output to the now legendary /dev/null without Qt knowing about it.

                    Thank you very much for the hint though!

                    Moose

                    M Offline
                    M Offline
                    mrjj
                    Lifetime Qt Champion
                    wrote on 24 Feb 2016, 10:00 last edited by
                    #9

                    @Moose2342

                    Well Qt will queue resize events if widget is hidden. ( as far as i know)
                    so if your widget does stuff in these events then it will not have happened.

                    I was wondering if u played around with
                    http://doc.qt.io/qt-5.5/qcoreapplication.html#postEvent

                    In theory , you could construct the same events and send to it.

                    But yes, it suddenly becomes complex and I agree with your gut feeling that a
                    simple solution exists once found :)

                    M 1 Reply Last reply 24 Feb 2016, 10:32
                    0
                    • M mrjj
                      24 Feb 2016, 10:00

                      @Moose2342

                      Well Qt will queue resize events if widget is hidden. ( as far as i know)
                      so if your widget does stuff in these events then it will not have happened.

                      I was wondering if u played around with
                      http://doc.qt.io/qt-5.5/qcoreapplication.html#postEvent

                      In theory , you could construct the same events and send to it.

                      But yes, it suddenly becomes complex and I agree with your gut feeling that a
                      simple solution exists once found :)

                      M Offline
                      M Offline
                      Moose2342
                      wrote on 24 Feb 2016, 10:32 last edited by
                      #10

                      @mrjj
                      I have tested the resize events. Contrary to what I thought hide() or any other means of hiding it don't cause any such events. At least not that I see them.
                      About the postEvent, that does sound interesting. I will need those things anyway, once I start creating user interaction on the by then hopefully invisible widget.

                      But to hide it in the first place (or making it work without show()ing it) I wouldn't know which events to send.
                      What I tried before was QShowEvent. After creating the widget and before I go into QApplication::exec() I tried sending one, hoping to fool the widget. It didn't work though.
                      The widget never went into paint(). And when I sent the paint myself it crashed somewhere in QtOpenGLs innards. Apparently some initial contexts have not been created. I guess show() is necessary for it to work.

                      I'm currently trying to move the widget into its own process to live remotely on its own machine where I'm not bothered by the output. I was so hoping to avoid the network bridge for such a seemingly simple thing...

                      Cheers,
                      Moose

                      1 Reply Last reply
                      0
                      • M Offline
                        M Offline
                        mrjj
                        Lifetime Qt Champion
                        wrote on 24 Feb 2016, 10:42 last edited by
                        #11

                        Oh
                        So later the users will also click on the texture of the widgets
                        and it needs to react as the real widget would?
                        That is pretty advanced. :)

                        what types of widget do u need to support ? i if may ask.

                        M 1 Reply Last reply 24 Feb 2016, 11:12
                        0
                        • M mrjj
                          24 Feb 2016, 10:42

                          Oh
                          So later the users will also click on the texture of the widgets
                          and it needs to react as the real widget would?
                          That is pretty advanced. :)

                          what types of widget do u need to support ? i if may ask.

                          M Offline
                          M Offline
                          Moose2342
                          wrote on 24 Feb 2016, 11:12 last edited by Moose2342
                          #12

                          @mrjj
                          Well, that's the plan. :-)
                          At the moment I will be OK with basic interaction such as mouse wheel and perhaps clicks. No keyboard or other stuff yet.

                          In the long run I am hoping to adapt more widgets as long as they are content with my basic means of interaction.
                          For now, QWebEngine is primary target as it gives me a modern web browser in-a-box with all capabilities I need. My research ha turned up no other implementation but Qt's here that can do this. Also, due to its complexity and overall weirdness (OpenGL, child widgets) I suppose if it works with that chances are it works with everything.

                          At the moment I am also looking into Windows 10's new virtual desktops. If I can open an application on one of those I wouldn't have to bridge the network and could grab the buffer via IPC or shared memory or something. This desktop would be my /dev/null. As long as Qt doesn't notice it's not actually visible that is.

                          Cheers,
                          Moose

                          1 Reply Last reply
                          0
                          • M Offline
                            M Offline
                            mrjj
                            Lifetime Qt Champion
                            wrote on 24 Feb 2016, 11:26 last edited by mrjj
                            #13

                            @Moose2342 said:
                            Thats a fine plan :)
                            To boldly go .. ;)

                            Yes, if you can get QWebEngine to work as hidden then most other
                            widgets will just work / you will have the code to do it.

                            Oh, virtual desktops is a pretty good idea if not considered hidden by Qt when other desktop is active.
                            Far more fun than running on a other pc and need to handle that traffic too.

                            M 1 Reply Last reply 25 Feb 2016, 19:19
                            0
                            • M mrjj
                              24 Feb 2016, 11:26

                              @Moose2342 said:
                              Thats a fine plan :)
                              To boldly go .. ;)

                              Yes, if you can get QWebEngine to work as hidden then most other
                              widgets will just work / you will have the code to do it.

                              Oh, virtual desktops is a pretty good idea if not considered hidden by Qt when other desktop is active.
                              Far more fun than running on a other pc and need to handle that traffic too.

                              M Offline
                              M Offline
                              Moose2342
                              wrote on 25 Feb 2016, 19:19 last edited by
                              #14

                              @mrjj
                              Thanks! To boldly go indeed. As a final little update in the matter I would like to add that my approach with the Windows 10 virtual desktops seems to work. I have created a shared memory server which runs the QApplication and renders into a shared memory buffer. This buffer is now consumed where the app-in-a-box used to live. And to my great relief Qt, being oblivious to new Windows features, seems not to notice that the application is actually invisible, so events are processed fine. Let's just pray this stays that way.

                              As a welcome side effect my actual application now suffers a lot less performance impact from creating and running the Qt app since it has only to access the buffer. Next step are the user events.

                              Thanks for your input!

                              Cheers,
                              Moose

                              1 Reply Last reply
                              1
                              • M Offline
                                M Offline
                                mrjj
                                Lifetime Qt Champion
                                wrote on 25 Feb 2016, 19:31 last edited by
                                #15

                                Ok. super :)
                                Thank you for the feedback. it's good to know that being on other desktop is not the
                                same as being hidden.

                                Good luck with user interaction :)

                                1 Reply Last reply
                                0

                                6/15

                                24 Feb 2016, 09:38

                                • Login

                                • Login or register to search.
                                6 out of 15
                                • First post
                                  6/15
                                  Last post
                                0
                                • Categories
                                • Recent
                                • Tags
                                • Popular
                                • Users
                                • Groups
                                • Search
                                • Get Qt Extensions
                                • Unsolved