Adds the LxQt::SingleApplication class.
authorLuís Pereira <luis.artur.pereira@gmail.com>
Fri, 21 Nov 2014 15:19:45 +0000 (07:19 -0800)
committerLuís Pereira <luis.artur.pereira@gmail.com>
Fri, 21 Nov 2014 22:18:25 +0000 (14:18 -0800)
The SingleApplication class provides an single instance Application.

This class allows the user to create applications where only one instance
is allowed to be running at an given time. If the user tries to launch
another instance, the already running instance will be activated instead.

CMakeLists.txt
cmake/lxqt_use.cmake.in
dbus/org.lxqt.SingleApplication.xml [new file with mode: 0644]
lxqtsingleapplication.cpp [new file with mode: 0644]
lxqtsingleapplication.h [new file with mode: 0644]

index 4092f21..4533e4c 100644 (file)
@@ -19,6 +19,7 @@ set(PUB_HDRS
     lxqtpowermanager.h
     lxqtscreensaver.h
     lxqtapplication.h
+    lxqtsingleapplication.h
     lxqttranslator.h
     lxqtprogramfinder.h
 
@@ -42,6 +43,7 @@ set(PUBLIC_CLASSES
     AddPluginDialog
     ScreenSaver
     Application
+    SingleApplication
     Translator
     ProgramFinder
 
@@ -71,6 +73,7 @@ set(SRCS
     lxqtsettings.cpp
     lxqtscreensaver.cpp
     lxqtapplication.cpp
+    lxqtsingleapplication.cpp
     lxqttranslator.cpp
     lxqtprogramfinder.cpp
 
@@ -130,6 +133,7 @@ find_package(Qt5DBus REQUIRED QUIET)
 find_package(Qt5X11Extras REQUIRED QUIET)
 find_package(Qt5LinguistTools REQUIRED QUIET)
 find_package(Qt5Xdg REQUIRED)
+find_package(KF5WindowSystem REQUIRED QUIET)
 message(STATUS "Building with Qt ${Qt5Core_VERSION_STRING}")
 
 QT5_WRAP_UI(UIS ${FORMS})
@@ -139,8 +143,15 @@ QT5_ADD_DBUS_INTERFACE(SRCS
     notifications_interface
 )
 
+QT5_ADD_DBUS_ADAPTOR(SRCS
+    dbus/org.lxqt.SingleApplication.xml
+    lxqtsingleapplication.h LxQt::SingleApplication
+)
+
 set(LXQT_QT_VERSION "5")
 set(LXQT_QT_VERSION_SUFFIX "-qt5")
+
+# KF5WindowSystem is missing here. KF5WindowSystem doesn't provide an .pc file.
 set(LXQT_PKG_CONFIG_REQUIRES "Qt5Widgets Qt5Xml Qt5DBus Qt5X11Extras")
 
 include(${QTXDG_USE_FILE})
@@ -291,6 +302,7 @@ add_library(${LXQT_LIBRARY_NAME}
 )
 
 target_link_libraries(${LXQT_LIBRARY_NAME}
+    KF5::WindowSystem
     Qt5::Widgets
     Qt5::DBus
     Qt5::X11Extras
index e6472ac..55df65e 100644 (file)
@@ -59,6 +59,7 @@ elseif(LXQT_QT_VERSION EQUAL "5")
     find_package(Qt5X11Extras REQUIRED QUIET)
     find_package(Qt5LinguistTools REQUIRED QUIET)
     find_package(Qt5Xdg REQUIRED)
+    find_package(KF5WindowSystem REQUIRED QUIET)
 else()
     message(FATAL "Qt${LXQT_QT_VERSION} is not supported.")
 endif()
diff --git a/dbus/org.lxqt.SingleApplication.xml b/dbus/org.lxqt.SingleApplication.xml
new file mode 100644 (file)
index 0000000..f580356
--- /dev/null
@@ -0,0 +1,7 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+  <interface name="org.lxqt.SingleApplication">
+    <method name="activateWindow">
+    </method>
+  </interface>
+</node>
diff --git a/lxqtsingleapplication.cpp b/lxqtsingleapplication.cpp
new file mode 100644 (file)
index 0000000..b4b7145
--- /dev/null
@@ -0,0 +1,100 @@
+/* BEGIN_COMMON_COPYRIGHT_HEADER
+ * (c)LGPL2+
+ *
+ * LXQt - a lightweight, Qt based, desktop toolset
+ * http://lxqt.org
+ *
+ * Copyright: 2014 LXQt team
+ * Authors:
+ *  Luís Pereira <luis.artur.pereira@gmail.com>
+ *
+ * This program or library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * END_COMMON_COPYRIGHT_HEADER */
+
+#include "lxqtsingleapplication.h"
+#include "singleapplicationadaptor.h"
+#include <KF5/KWindowSystem/KWindowSystem>
+#include <KF5/KWindowSystem/NETWM>
+#include <QDBusMessage>
+#include <QWidget>
+#include <QDebug>
+
+using namespace LxQt;
+
+SingleApplication::SingleApplication(int &argc, char **argv)
+    : Application(argc, argv),
+    mActivationWindow(0)
+{
+    QString service =
+        QString::fromLatin1("org.lxqt.%1").arg(QApplication::applicationName());
+
+    SingleApplicationAdaptor *mAdaptor = new SingleApplicationAdaptor(this);
+    QDBusConnection bus = QDBusConnection::sessionBus();
+
+    if (!bus.isConnected()) {
+        QLatin1String errorMessage("Can't connect to the D-Bus session bus\n"
+                                   "Make sure the D-Bus daemon is running");
+        qCritical() << errorMessage;
+        ::exit(1);
+    }
+
+    bool registered = (bus.registerService(service) ==
+                       QDBusConnectionInterface::ServiceRegistered);
+    if (registered) { // We are the primary instance
+        QLatin1String objectPath("/");
+        bus.registerObject(objectPath, mAdaptor,
+            QDBusConnection::ExportAllSlots);
+    } else { // We are the second outstance
+        QDBusMessage msg = QDBusMessage::createMethodCall(service,
+            QStringLiteral("/"),
+            QStringLiteral("org.lxqt.SingleApplication"),
+            QStringLiteral("activateWindow"));
+        QDBusConnection::sessionBus().send(msg);
+
+        ::exit(0);
+    }
+}
+
+SingleApplication::~SingleApplication()
+{
+}
+
+void SingleApplication::setActivationWindow(QWidget *w)
+{
+    mActivationWindow = w;
+}
+
+QWidget *SingleApplication::activationWindow() const
+{
+    return mActivationWindow;
+}
+
+void SingleApplication::activateWindow()
+{
+    if (mActivationWindow) {
+        WId window = mActivationWindow->effectiveWinId();
+
+        KWindowInfo info(window, NET::WMDesktop);
+        int windowDesktop = info.desktop();
+
+        if (windowDesktop != KWindowSystem::currentDesktop())
+            KWindowSystem::setCurrentDesktop(windowDesktop);
+        KWindowSystem::activateWindow(window); 
+    } else {
+        qDebug() << Q_FUNC_INFO << "activationWindow not set or null";
+    }
+}
diff --git a/lxqtsingleapplication.h b/lxqtsingleapplication.h
new file mode 100644 (file)
index 0000000..d243e4c
--- /dev/null
@@ -0,0 +1,132 @@
+/* BEGIN_COMMON_COPYRIGHT_HEADER
+ * (c)LGPL2+
+ *
+ * LXQt - a lightweight, Qt based, desktop toolset
+ * http://lxqt.org
+ *
+ * Copyright: 2014 LXQt team
+ * Authors:
+ *  Luís Pereira <luis.artur.pereira@gmail.com>
+ *
+ * This program or library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * END_COMMON_COPYRIGHT_HEADER */
+
+#ifndef LXQTSINGLEAPPLICATION_H
+#define LXQTSINGLEAPPLICATION_H
+
+#include "lxqtapplication.h"
+
+class QWidget;
+
+namespace LxQt {
+
+/*! \class SingleApplication
+ *  \brief The SingleApplication class provides an single instance Application.
+ *
+ *  This class allows the user to create applications where only one instance
+ *  is allowed to be running at an given time. If the user tries to launch
+ *  another instance, the already running instance will be activated instead.
+ *
+ *  The user has to set the activation window with setActivationWindow. If it
+ *  doesn't the second instance will quietly exit without activating the first
+ *  instance window. In any case only one instance is allowed.
+ *
+ *  This classes depends uses D-Bus and KF5::WindowSystem
+ *
+ *  \code
+ *
+ *  // Original code
+ *  int main(int argc, char **argv)
+ *  {
+ *      LxQt::Application app(argc, argv);
+ *
+ *      MainWidget w;
+ *      w.show();
+ *
+ *      return app.exec();
+ *  }
+ *
+ *  // SingleApplication code
+ *  int main(int argc, char **argv)
+ *  {
+ *      LxQt::SingleApplication app(argc, argv);
+ *
+ *      MainWidget w;
+ *      app.setActivationWindow(&w);
+ *      w.show();
+ *
+ *      return app.exec();
+ *  }
+ *  \endcode
+ *  \sa SingleApplication
+ */
+
+class LXQT_API SingleApplication : public Application {
+    Q_OBJECT
+
+public:
+    /*!
+     * \brief Construct a LxQt SingleApplication object.
+     * \param argc standard argc as in QApplication
+     * \param argv standard argv as in QApplication
+     */
+    SingleApplication(int &argc, char **argv);
+    virtual ~SingleApplication();
+
+    /*!
+     * \brief Sets the activation window.
+     * \param w activation window.
+     *
+     * Sets the activation window of this application to w. The activation
+     * window is the widget that will be activated by \a activateWindow().
+     *
+     * \sa activationWindow() \sa activateWindow();
+     */
+    void setActivationWindow(QWidget *w);
+
+    /*!
+     * \brief Gets the current activation window.
+     * \return The current activation window.
+     *
+     * \sa setActivationWindow();
+     */
+    QWidget *activationWindow() const;
+
+public Q_SLOTS:
+    /*!
+     * \brief Activates this application activation window.
+     *
+     * Changes to the desktop where this applications is. It then de-minimizes,
+     * raises and activates the application's activation window.
+     * If no activation window has been set, this function does nothing.
+     *
+     * \sa setActivationWindow();
+     */
+    void activateWindow();
+
+private:
+    QWidget *mActivationWindow;
+};
+
+#if defined(lxqtSingleApp)
+#undef lxqtSingleApp
+#endif
+#define lxqtSingleApp (static_cast<LxQt::SingleApplication *>(qApp))
+
+}; // namespace LxQt
+
+#endif // LXQTSINGLEAPPLICATION_H