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. QThread - moveToThread: Cannot move objects with a parent
Forum Updated to NodeBB v4.3 + New Features

QThread - moveToThread: Cannot move objects with a parent

Scheduled Pinned Locked Moved Solved General and Desktop
16 Posts 4 Posters 7.0k Views 1 Watching
  • 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.
  • Christian EhrlicherC Offline
    Christian EhrlicherC Offline
    Christian Ehrlicher
    Lifetime Qt Champion
    wrote on last edited by
    #2

    @fem_dev said in QThread - moveToThread: Cannot move objects with a parent:

    selectedPlugin

    This object has a parent which lives in the current thread so it can not be moved. Therefore un-parent it (or create it without a parent) and move it then.

    Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
    Visit the Qt Academy at https://academy.qt.io/catalog

    F 1 Reply Last reply
    5
    • Christian EhrlicherC Christian Ehrlicher

      @fem_dev said in QThread - moveToThread: Cannot move objects with a parent:

      selectedPlugin

      This object has a parent which lives in the current thread so it can not be moved. Therefore un-parent it (or create it without a parent) and move it then.

      F Offline
      F Offline
      fem_dev
      wrote on last edited by fem_dev
      #3

      @Christian-Ehrlicher thank you, but I'm lost in this concept of parent here. Could you help me a little more?

      In my case, each selectPlugin is generated from the Plugin class.
      The Plugin class uses the Plugin_API class to interface.

      Here is the Plugin class:

      #ifndef PLUGIN_H
      #define PLUGIN_H
      
      #include <iostream>
      
      #include <QObject>
      #include <QtPlugin>
      #include <QtCore/qglobal.h>
      
      #if defined(PLUGIN_LIBRARY)
      #  define PLUGIN_EXPORT Q_DECL_EXPORT
      #else
      #  define PLUGIN_EXPORT Q_DECL_IMPORT
      #endif
      
      #include "plugin_api.h"
      
      class PLUGIN_EXPORT Plugin: public Plugin_API
      {
          Q_OBJECT
          Q_PLUGIN_METADATA(IID "com.rotortest.plugin")
          Q_INTERFACES(Plugin_API)
      
      public:
          explicit Plugin();
          ~Plugin() override;
      
      private:
          void process() override;
      };
      
      #endif // PLUGIN_H
      
      

      Here is the Plugin_API class (shared library interface):

      #ifndef PLUGIN_API_H
      #define PLUGIN_API_H
      
      #include <QObject>
      
      class Plugin_API : public QObject
      {
          Q_OBJECT
      
      private:
      
      public:
          Plugin_API() 
          {
          }
      
          virtual ~Plugin_API() = default;
      
          void start() { 
              // Some code ...
          }
      
      public slots:
          virtual void process() = 0;
      
      signals:
          void finished();
      };
      
      // Declare our interface:
      Q_DECLARE_INTERFACE(Plugin_API, "com.rotortest.plugin")
      
      #endif // PLUGIN_API_H
      

      I need the Plugin_API always to interface the plugin with the main app.

      How can I fix it?

      F 1 Reply Last reply
      0
      • F fem_dev

        @Christian-Ehrlicher thank you, but I'm lost in this concept of parent here. Could you help me a little more?

        In my case, each selectPlugin is generated from the Plugin class.
        The Plugin class uses the Plugin_API class to interface.

        Here is the Plugin class:

        #ifndef PLUGIN_H
        #define PLUGIN_H
        
        #include <iostream>
        
        #include <QObject>
        #include <QtPlugin>
        #include <QtCore/qglobal.h>
        
        #if defined(PLUGIN_LIBRARY)
        #  define PLUGIN_EXPORT Q_DECL_EXPORT
        #else
        #  define PLUGIN_EXPORT Q_DECL_IMPORT
        #endif
        
        #include "plugin_api.h"
        
        class PLUGIN_EXPORT Plugin: public Plugin_API
        {
            Q_OBJECT
            Q_PLUGIN_METADATA(IID "com.rotortest.plugin")
            Q_INTERFACES(Plugin_API)
        
        public:
            explicit Plugin();
            ~Plugin() override;
        
        private:
            void process() override;
        };
        
        #endif // PLUGIN_H
        
        

        Here is the Plugin_API class (shared library interface):

        #ifndef PLUGIN_API_H
        #define PLUGIN_API_H
        
        #include <QObject>
        
        class Plugin_API : public QObject
        {
            Q_OBJECT
        
        private:
        
        public:
            Plugin_API() 
            {
            }
        
            virtual ~Plugin_API() = default;
        
            void start() { 
                // Some code ...
            }
        
        public slots:
            virtual void process() = 0;
        
        signals:
            void finished();
        };
        
        // Declare our interface:
        Q_DECLARE_INTERFACE(Plugin_API, "com.rotortest.plugin")
        
        #endif // PLUGIN_API_H
        

        I need the Plugin_API always to interface the plugin with the main app.

        How can I fix it?

        F Offline
        F Offline
        fem_dev
        wrote on last edited by
        #4

        @Christian-Ehrlicher , I don't know why, but now my error message has change to:

        QObject::moveToThread: Current thread (0x7fa149605d40) is not the object's thread (0x7fa14ae4f3b0).
        Cannot move to target thread (0x7fa1494d0bb0)
        
        You might be loading two sets of Qt binaries into the same process. Check that all plugins are compiled against the right Qt binaries. Export DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded.
        18:27:58: The program has unexpectedly finished.
        

        Any ideas?

        VRoninV 1 Reply Last reply
        0
        • Christian EhrlicherC Offline
          Christian EhrlicherC Offline
          Christian Ehrlicher
          Lifetime Qt Champion
          wrote on last edited by
          #5

          @fem_dev said in QThread - moveToThread: Cannot move objects with a parent:

          Any ideas?

          I already gave you the answer - don't set a parent or unparent it.

          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
          Visit the Qt Academy at https://academy.qt.io/catalog

          F 1 Reply Last reply
          0
          • F fem_dev

            @Christian-Ehrlicher , I don't know why, but now my error message has change to:

            QObject::moveToThread: Current thread (0x7fa149605d40) is not the object's thread (0x7fa14ae4f3b0).
            Cannot move to target thread (0x7fa1494d0bb0)
            
            You might be loading two sets of Qt binaries into the same process. Check that all plugins are compiled against the right Qt binaries. Export DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded.
            18:27:58: The program has unexpectedly finished.
            

            Any ideas?

            VRoninV Offline
            VRoninV Offline
            VRonin
            wrote on last edited by
            #6

            @fem_dev said in QThread - moveToThread: Cannot move objects with a parent:

            QObject::moveToThread: Current thread (0x7fa149605d40) is not the object's thread (0x7fa14ae4f3b0).

            Error is pretty clear. If you already moved a plugin to a thread you can't pull it from the thread you put it in and push it into another. moveToThread is push only so only the thread that owns the object can move it to another one

            "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
            ~Napoleon Bonaparte

            On a crusade to banish setIndexWidget() from the holy land of Qt

            F 1 Reply Last reply
            3
            • Christian EhrlicherC Christian Ehrlicher

              @fem_dev said in QThread - moveToThread: Cannot move objects with a parent:

              Any ideas?

              I already gave you the answer - don't set a parent or unparent it.

              F Offline
              F Offline
              fem_dev
              wrote on last edited by
              #7

              @Christian-Ehrlicher sorry...I'm not identifying the parent in this case.

              I have 3 elements in this code:

              • QThread
              • Plugin Class
              • Plugin_API Class (Interface)

              I didn't set a parent in any of these 3 elements. You can see it in the code above.

              So:
              1- Who is the parent and the children here?
              2- How can I "don't set a parent"?
              3- How can I "unparent"?

              VRoninV 1 Reply Last reply
              0
              • VRoninV VRonin

                @fem_dev said in QThread - moveToThread: Cannot move objects with a parent:

                QObject::moveToThread: Current thread (0x7fa149605d40) is not the object's thread (0x7fa14ae4f3b0).

                Error is pretty clear. If you already moved a plugin to a thread you can't pull it from the thread you put it in and push it into another. moveToThread is push only so only the thread that owns the object can move it to another one

                F Offline
                F Offline
                fem_dev
                wrote on last edited by
                #8

                @VRonin Thank you, but I'm newer in the QThread...and my english is not so good.

                Could you please give me a simple example? May be a pseudo-code or a sequence that I need to do to fix it?

                I appreciate your help and support.

                1 Reply Last reply
                0
                • F fem_dev

                  @Christian-Ehrlicher sorry...I'm not identifying the parent in this case.

                  I have 3 elements in this code:

                  • QThread
                  • Plugin Class
                  • Plugin_API Class (Interface)

                  I didn't set a parent in any of these 3 elements. You can see it in the code above.

                  So:
                  1- Who is the parent and the children here?
                  2- How can I "don't set a parent"?
                  3- How can I "unparent"?

                  VRoninV Offline
                  VRoninV Offline
                  VRonin
                  wrote on last edited by VRonin
                  #9

                  @fem_dev said in QThread - moveToThread: Cannot move objects with a parent:

                  I didn't set a parent in any of these 3 elements. You can see it in the code above.

                  Actually the code above is pretty lacking in this sense. we have no information regarding how you fill _pluginStack.

                  How can I "unparent"?

                  call _pluginStack[step_id]->setParent(nullptr);

                  @fem_dev said in QThread - moveToThread: Cannot move objects with a parent:

                  Could you please give me a simple example? May be a pseudo-code or a sequence that I need to do to fix it?

                  It's not clear what you are trying to do here. seems like you are creating a dedicated thread for each plugin but then you try to move those plugins in other threads, hard to give you an example if we don't know what you want to do. In this recent thread there are some examples of working with threads but I'm not 100% sure it applies to your case

                  "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                  ~Napoleon Bonaparte

                  On a crusade to banish setIndexWidget() from the holy land of Qt

                  F 1 Reply Last reply
                  4
                  • VRoninV VRonin

                    @fem_dev said in QThread - moveToThread: Cannot move objects with a parent:

                    I didn't set a parent in any of these 3 elements. You can see it in the code above.

                    Actually the code above is pretty lacking in this sense. we have no information regarding how you fill _pluginStack.

                    How can I "unparent"?

                    call _pluginStack[step_id]->setParent(nullptr);

                    @fem_dev said in QThread - moveToThread: Cannot move objects with a parent:

                    Could you please give me a simple example? May be a pseudo-code or a sequence that I need to do to fix it?

                    It's not clear what you are trying to do here. seems like you are creating a dedicated thread for each plugin but then you try to move those plugins in other threads, hard to give you an example if we don't know what you want to do. In this recent thread there are some examples of working with threads but I'm not 100% sure it applies to your case

                    F Offline
                    F Offline
                    fem_dev
                    wrote on last edited by fem_dev
                    #10

                    @VRonin I will try to explain better...

                    Here is how I load each plugin using QPluginLoader where the input argument called plugins is a list of shared libraries absolute path.

                    void job_manager::load_plugins(const QStringList plugins)
                    {
                        foreach(QString file, plugins) {
                    
                            QPluginLoader loader(file);
                            if (loader.load()) {
                                qInfo() << "Loaded: " << loader.fileName();
                                Plugin_API* plugin = qobject_cast<Plugin_API*>(loader.instance());
                    
                                if (plugin) {
                                     // Store plugin in a QMap<std::string, Plugin_API*>
                                    _pluginsMap[plugin->getName()] = plugin;
                                } else {
                                    qCritical() << "Wrong Plugin API! Could not cast: " << loader.fileName();
                                }
                            } else {
                                qCritical() << "ERROR: " << loader.fileName() << " - Msg: " << loader.errorString();
                            }
                        }
                    }
                    

                    In the UI, I have a button called "run". Here is the onClick() action:

                    void job_manager::on_run_btn_clicked()
                    {
                        // ===== Fill the plugin stack vector ===== //
                        _numSteps = ui->added_list->count(); // UI execution plugin list. Each plugin is added by the user
                        _pluginStack.reserve(_numSteps); // std::vector<Plugin_API*>
                    
                        for (size_t s = 0; s < _numSteps; s++) {
                            // Get the plugin name:
                            const std::string pluginName = ui->added_list->item(s)->text().toStdString();
                    
                            // Store the plugin in a vector. 
                            // I do that because the user can run the same plugin multiple times in a user defined execution sequence.
                            // Always in the serial order
                            _pluginStack[s] = _pluginsMap[pluginName];
                        }
                    
                        callNextPlugin();
                    }
                    

                    So, my _pluginMap can be something like:

                    ---------------------
                    | ["A"] => Plugin A |
                    | ["B"] => Plugin B |
                    ---------------------
                    

                    And, my _pluginStack vector can be something like:

                    | 0 | Plugin A |
                    | 1 | Plugin A |
                    | 2 | Plugin B |
                    | 3 | Plugin A |
                    

                    As you can see above, inside the job_manager::on_run_btn_clicked() method, I call the callNextPlugin().

                    void job_manager::callNextPlugin(void)
                    {
                       if (_currentStep + 1 > _numSteps) { // _current_step start from 0
                           std::cout << "Finished: All done!" << std::endl;
                           return;
                       } else {
                           runPlugin(_currentStep);
                           _currentStep++;
                       }
                    }
                    

                    And here is the final runPlugin() method:

                    void job_manager::runPlugin(const size_t step_id)
                    {
                        const auto& selectedPlugin = _pluginStack[step_id];
                    
                        QThread* thread = new QThread;
                        selectedPlugin->moveToThread(thread); // Runs Ok for the first time, but I got a error in the second time.
                    
                        connect(selectedPlugin, &Plugin_API::sendMsg, this, &job_manager::pluginMessage);
                        connect(selectedPlugin, &Plugin_API::finished, thread, &QThread::quit);
                        connect(selectedPlugin, &Plugin_API::finished, selectedPlugin, &Plugin_API::deleteLater);
                        connect(selectedPlugin, &Plugin_API::finished, this, &job_manager::callNextPlugin);
                        connect(thread, &QThread::started, selectedPlugin, &Plugin_API::start);
                        connect(thread, &QThread::finished, thread, &QThread::deleteLater);
                    
                        thread->start(QThread::NormalPriority);
                    }
                    

                    So, when one plugin finish your job, the job_manager receives a signal &Plugin_API::finished and it calls the callNextPlugin() method.

                    I added the _pluginStack[step_id]->setParent(nullptr); right after the moveToThread() line, but I got the same run-time error.

                    QObject::moveToThread: Current thread (0x7fdf56f056e0) is not the object's thread (0x7fdf56e39c80).
                    Cannot move to target thread (0x7fdf582ba950)
                    
                    You might be loading two sets of Qt binaries into the same process. Check that all plugins are compiled against the right Qt binaries. Export DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded.
                    

                    Please, could you help me a little bit more? How can I fix it?

                    VRoninV 1 Reply Last reply
                    0
                    • F fem_dev

                      @VRonin I will try to explain better...

                      Here is how I load each plugin using QPluginLoader where the input argument called plugins is a list of shared libraries absolute path.

                      void job_manager::load_plugins(const QStringList plugins)
                      {
                          foreach(QString file, plugins) {
                      
                              QPluginLoader loader(file);
                              if (loader.load()) {
                                  qInfo() << "Loaded: " << loader.fileName();
                                  Plugin_API* plugin = qobject_cast<Plugin_API*>(loader.instance());
                      
                                  if (plugin) {
                                       // Store plugin in a QMap<std::string, Plugin_API*>
                                      _pluginsMap[plugin->getName()] = plugin;
                                  } else {
                                      qCritical() << "Wrong Plugin API! Could not cast: " << loader.fileName();
                                  }
                              } else {
                                  qCritical() << "ERROR: " << loader.fileName() << " - Msg: " << loader.errorString();
                              }
                          }
                      }
                      

                      In the UI, I have a button called "run". Here is the onClick() action:

                      void job_manager::on_run_btn_clicked()
                      {
                          // ===== Fill the plugin stack vector ===== //
                          _numSteps = ui->added_list->count(); // UI execution plugin list. Each plugin is added by the user
                          _pluginStack.reserve(_numSteps); // std::vector<Plugin_API*>
                      
                          for (size_t s = 0; s < _numSteps; s++) {
                              // Get the plugin name:
                              const std::string pluginName = ui->added_list->item(s)->text().toStdString();
                      
                              // Store the plugin in a vector. 
                              // I do that because the user can run the same plugin multiple times in a user defined execution sequence.
                              // Always in the serial order
                              _pluginStack[s] = _pluginsMap[pluginName];
                          }
                      
                          callNextPlugin();
                      }
                      

                      So, my _pluginMap can be something like:

                      ---------------------
                      | ["A"] => Plugin A |
                      | ["B"] => Plugin B |
                      ---------------------
                      

                      And, my _pluginStack vector can be something like:

                      | 0 | Plugin A |
                      | 1 | Plugin A |
                      | 2 | Plugin B |
                      | 3 | Plugin A |
                      

                      As you can see above, inside the job_manager::on_run_btn_clicked() method, I call the callNextPlugin().

                      void job_manager::callNextPlugin(void)
                      {
                         if (_currentStep + 1 > _numSteps) { // _current_step start from 0
                             std::cout << "Finished: All done!" << std::endl;
                             return;
                         } else {
                             runPlugin(_currentStep);
                             _currentStep++;
                         }
                      }
                      

                      And here is the final runPlugin() method:

                      void job_manager::runPlugin(const size_t step_id)
                      {
                          const auto& selectedPlugin = _pluginStack[step_id];
                      
                          QThread* thread = new QThread;
                          selectedPlugin->moveToThread(thread); // Runs Ok for the first time, but I got a error in the second time.
                      
                          connect(selectedPlugin, &Plugin_API::sendMsg, this, &job_manager::pluginMessage);
                          connect(selectedPlugin, &Plugin_API::finished, thread, &QThread::quit);
                          connect(selectedPlugin, &Plugin_API::finished, selectedPlugin, &Plugin_API::deleteLater);
                          connect(selectedPlugin, &Plugin_API::finished, this, &job_manager::callNextPlugin);
                          connect(thread, &QThread::started, selectedPlugin, &Plugin_API::start);
                          connect(thread, &QThread::finished, thread, &QThread::deleteLater);
                      
                          thread->start(QThread::NormalPriority);
                      }
                      

                      So, when one plugin finish your job, the job_manager receives a signal &Plugin_API::finished and it calls the callNextPlugin() method.

                      I added the _pluginStack[step_id]->setParent(nullptr); right after the moveToThread() line, but I got the same run-time error.

                      QObject::moveToThread: Current thread (0x7fdf56f056e0) is not the object's thread (0x7fdf56e39c80).
                      Cannot move to target thread (0x7fdf582ba950)
                      
                      You might be loading two sets of Qt binaries into the same process. Check that all plugins are compiled against the right Qt binaries. Export DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded.
                      

                      Please, could you help me a little bit more? How can I fix it?

                      VRoninV Offline
                      VRoninV Offline
                      VRonin
                      wrote on last edited by
                      #11

                      I added the _pluginStack[step_id]->setParent(nullptr); right after the moveToThread() line, but I got the same run-time error.

                      It should be added before


                      This running through workers is exactly the case described in the topic linked above, have a look at the last 2 examples to avoid unecessary operations

                      QObject::moveToThread: Current thread (0x7fdf56f056e0) is not the object's thread (0x7fdf56e39c80).

                      This error is saying that you called moveToThread on that plugin already. The main thread (0x7fdf56f056e0) sent the object to a secondary thread (0x7fdf56e39c80) already so it can't send it to 0x7fdf582ba950. only 0x7fdf56e39c80 can send the object to 0x7fdf582ba950

                      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                      ~Napoleon Bonaparte

                      On a crusade to banish setIndexWidget() from the holy land of Qt

                      F 1 Reply Last reply
                      0
                      • VRoninV VRonin

                        I added the _pluginStack[step_id]->setParent(nullptr); right after the moveToThread() line, but I got the same run-time error.

                        It should be added before


                        This running through workers is exactly the case described in the topic linked above, have a look at the last 2 examples to avoid unecessary operations

                        QObject::moveToThread: Current thread (0x7fdf56f056e0) is not the object's thread (0x7fdf56e39c80).

                        This error is saying that you called moveToThread on that plugin already. The main thread (0x7fdf56f056e0) sent the object to a secondary thread (0x7fdf56e39c80) already so it can't send it to 0x7fdf582ba950. only 0x7fdf56e39c80 can send the object to 0x7fdf582ba950

                        F Offline
                        F Offline
                        fem_dev
                        wrote on last edited by
                        #12

                        @VRonin I tried to put the _pluginStack[step_id]->setParent(nullptr); before the moveToThread() too, but i got the same error message.

                        I will try to look better the topic that you send to me.

                        If I have doubts, I will come back here, ok?

                        CP71C 1 Reply Last reply
                        0
                        • F fem_dev

                          @VRonin I tried to put the _pluginStack[step_id]->setParent(nullptr); before the moveToThread() too, but i got the same error message.

                          I will try to look better the topic that you send to me.

                          If I have doubts, I will come back here, ok?

                          CP71C Offline
                          CP71C Offline
                          CP71
                          wrote on last edited by
                          #13

                          @fem_dev
                          Hi,
                          how our colleagues have already said a object has a parent which lives in the current thread so it cannot be moved!

                          I don’t understand why you wrote:
                          const auto& selectedPlugin = _pluginStack[step_id];

                          instead of
                          auto& selectedPlugin = _pluginStack[step_id];

                          https://www.programming-books.io/essential/cpp/auto-const-and-references-b0a629204f0a4ed6a8b4b02f30835c31

                          I'm wondering why the first instance runs well and then fail, or it seems so.
                          What difference are there? If I'd be you I'd try to find the differences between two plugins creation.

                          F 1 Reply Last reply
                          0
                          • VRoninV Offline
                            VRoninV Offline
                            VRonin
                            wrote on last edited by
                            #14

                            if we want to be picky then connect(selectedPlugin, &Plugin_API::finished, selectedPlugin, &Plugin_API::deleteLater); will cause _pluginsMap to contain dangling pointers (unless it's a QMap<QString, QPointer<Plugin_API> > then it's just null pointers)

                            "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                            ~Napoleon Bonaparte

                            On a crusade to banish setIndexWidget() from the holy land of Qt

                            F 1 Reply Last reply
                            2
                            • CP71C CP71

                              @fem_dev
                              Hi,
                              how our colleagues have already said a object has a parent which lives in the current thread so it cannot be moved!

                              I don’t understand why you wrote:
                              const auto& selectedPlugin = _pluginStack[step_id];

                              instead of
                              auto& selectedPlugin = _pluginStack[step_id];

                              https://www.programming-books.io/essential/cpp/auto-const-and-references-b0a629204f0a4ed6a8b4b02f30835c31

                              I'm wondering why the first instance runs well and then fail, or it seems so.
                              What difference are there? If I'd be you I'd try to find the differences between two plugins creation.

                              F Offline
                              F Offline
                              fem_dev
                              wrote on last edited by
                              #15

                              @CP71 There's no difference. You are right.

                              1 Reply Last reply
                              1
                              • VRoninV VRonin

                                if we want to be picky then connect(selectedPlugin, &Plugin_API::finished, selectedPlugin, &Plugin_API::deleteLater); will cause _pluginsMap to contain dangling pointers (unless it's a QMap<QString, QPointer<Plugin_API> > then it's just null pointers)

                                F Offline
                                F Offline
                                fem_dev
                                wrote on last edited by
                                #16

                                @VRonin Yes...I think that this is my problem. Thank you!

                                1 Reply Last reply
                                1

                                • Login

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