void migrateConfigToAppDir() { const QString appDir = QCoreApplication::applicationDirPath(); const QString path = appDir + "/config"; const QString uninstPath = appDir + "/unins000.exe"; QDir dir(path); if ( !QFile::exists(uninstPath) && QFileInfo(appDir).isWritable() && dir.mkpath("copyq") && dir.cd("copyq") && dir.isReadable() && QFileInfo(dir.absolutePath()).isWritable() ) { QSettings oldSettings; const QString oldConfigFileName = QSettings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName()).fileName(); const QString oldConfigPath = QDir::cleanPath(oldConfigFileName + "/.."); QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, path); QSettings::setDefaultFormat(QSettings::IniFormat); Settings newSettings; if ( Settings::canModifySettings() && newSettings.isEmpty() ) { COPYQ_LOG("Migrating configuration to application directory."); const QString newConfigPath = QDir::cleanPath(newSettings.fileName() + "/.."); // Migrate configuration from system directory. migrateDirectory(oldConfigPath, newConfigPath); // Migrate themes from system directory. migrateDirectory(oldConfigPath + "/themes", newConfigPath + "/themes"); // Migrate rest of the configuration from the system registry. migrateConfig(oldSettings, newSettings); } } else { log( QString("Ignoring configuration in \"%1\" (https://github.com/hluk/CopyQ/issues/583).") .arg(path), LogWarning ); QSettings oldSettings; QSettings::setDefaultFormat(QSettings::IniFormat); Settings newSettings; // Move settings from Windows registry. if (newSettings.isEmpty()) { COPYQ_LOG("Moving configuration from Windows registry."); migrateConfig(oldSettings, newSettings); } } }
void resetClipboard() { if (m_resetTimer.isActive() || m_syncTimer.isActive()) return; if (m_resetSelection && !m_selectionData.isEmpty()) { COPYQ_LOG( QString("Resetting selection") ); setClipboardData(m_selectionData, QClipboard::Selection); } if (m_resetClipboard && !m_clipboardData.isEmpty()) { COPYQ_LOG( QString("Resetting clipboard") ); setClipboardData(m_clipboardData, QClipboard::Clipboard); } }
void ClipboardServer::onSaveState(QSessionManager &sessionManager) { COPYQ_LOG("Got save state request from session manager."); QSettings settings(QSettings::IniFormat, QSettings::UserScope, "copyq", "copyq_no_session"); const auto sessionNameKey = "session_" + sessionManager.sessionId(); const auto sessionName = qApp->property("CopyQ_session_name").toString(); settings.setValue(sessionNameKey, sessionName); const QString lastSessionIdPrefix = "last_session_id_for_"; const auto lastSessionIdKey = lastSessionIdPrefix + sessionName; const auto lastSessionId = settings.value(lastSessionIdKey).toString(); const auto lastSessionNameKey = "session_" + lastSessionId; settings.setValue(lastSessionIdKey, sessionNameKey); // Remove no longer valid sessions from configuration. QSet<QString> validSessions; for (const QString &key : settings.childKeys()) { if ( key.startsWith(lastSessionIdPrefix) ) validSessions.insert( settings.value(key).toString() ); } for (const QString &key : settings.childKeys()) { if ( !key.startsWith(lastSessionIdPrefix) && !validSessions.contains(key) ) settings.remove(key); } }
void ActionHandler::action(Action *action) { action->setParent(this); m_lastAction = action; connect( action, SIGNAL(newItems(QStringList, QString)), this, SLOT(addItems(QStringList, QString)) ); connect( action, SIGNAL(newItems(QStringList, QModelIndex)), this, SLOT(addItems(QStringList, QModelIndex)) ); connect( action, SIGNAL(newItem(QByteArray, QString, QString)), this, SLOT(addItem(QByteArray, QString, QString)) ); connect( action, SIGNAL(newItem(QByteArray, QString, QModelIndex)), this, SLOT(addItem(QByteArray, QString, QModelIndex)) ); connect( action, SIGNAL(actionStarted(Action*)), this, SLOT(actionStarted(Action*)) ); connect( action, SIGNAL(actionFinished(Action*)), this, SLOT(closeAction(Action*)) ); connect( action, SIGNAL(actionError(Action*)), this, SLOT(closeAction(Action*)) ); ++m_actionCounter; if ( !action->outputFormat().isEmpty() && action->outputTab().isEmpty() ) action->setOutputTab(m_currentTabName); m_activeActionDialog->actionAboutToStart(action); COPYQ_LOG( QString("Executing: %1").arg(action->command()) ); action->start(); }
QDataStream &operator<<(QDataStream &stream, const ClipboardModel &model) { int length = model.rowCount(); stream << length; COPYQ_LOG( QString("Saving %1 items.").arg(length) ); // save in reverse order so the items // can be later restored in right order for(int i = 0; i < length; ++i) stream << *model.at(i); COPYQ_LOG("Items saved."); return stream; }
void migrateConfigToAppDir() { const QString path = QCoreApplication::applicationDirPath() + "/config"; QDir dir(path); if ( (dir.isReadable() || dir.mkdir(".")) && dir.mkpath("copyq") ) { QSettings oldSettings; const QString oldConfigFileName = QSettings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName()).fileName(); const QString oldConfigPath = QDir::cleanPath(oldConfigFileName + "/.."); QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, path); QSettings::setDefaultFormat(QSettings::IniFormat); Settings newSettings; if ( Settings::isEmpty(newSettings) ) { COPYQ_LOG("Migrating configuration to application directory."); const QString newConfigPath = QDir::cleanPath(newSettings.fileName() + "/.."); // Migrate configuration from system directory. migrateDirectory(oldConfigPath, newConfigPath); // Migrate themes from system directory. QDir(newConfigPath).mkdir("themes"); migrateDirectory(oldConfigPath + "/themes", newConfigPath + "/themes"); // Migrate rest of the configuration from the system registry. foreach ( const QString &key, oldSettings.allKeys() ) newSettings.setValue(key, oldSettings.value(key)); } } else {
void ClipboardServer::onClientNewConnection(const ClientSocketPtr &client) { if (m_ignoreNewConnections) { COPYQ_LOG("Ignoring new client while exiting"); client->close(); return; } auto proxy = new ScriptableProxy(m_wnd); connect( client.get(), &ClientSocket::destroyed, proxy, &ScriptableProxy::safeDeleteLater ); connect( proxy, &ScriptableProxy::sendMessage, client.get(), &ClientSocket::sendMessage ); m_clients.insert( client->id(), ClientData(client, proxy) ); connect( this, &ClipboardServer::closeClients, client.get(), &ClientSocket::close ); connect( client.get(), &ClientSocket::messageReceived, this, &ClipboardServer::onClientMessageReceived ); connect( client.get(), &ClientSocket::disconnected, this, &ClipboardServer::onClientDisconnected ); connect( client.get(), &ClientSocket::disconnected, proxy, &ScriptableProxy::clientDisconnected ); connect( client.get(), &ClientSocket::connectionFailed, this, &ClipboardServer::onClientConnectionFailed ); client->start(); }
ClipboardMonitor::ClipboardMonitor(int &argc, char **argv) : QObject() , App(new QApplication(argc, argv)) , m_formats() , m_newdata() #ifdef COPYQ_WS_X11 , m_copyclip(false) , m_checksel(false) , m_copysel(false) #endif , m_socket( new QLocalSocket(this) ) , m_updateTimer( new QTimer(this) ) , m_needCheckClipboard(false) #ifdef COPYQ_WS_X11 , m_needCheckSelection(false) , m_x11(new PrivateX11) #endif { connect( m_socket, SIGNAL(readyRead()), this, SLOT(readyRead()), Qt::DirectConnection ); connect( m_socket, SIGNAL(disconnected()), QApplication::instance(), SLOT(quit()) ); QStringList args = QCoreApplication::instance()->arguments(); Q_ASSERT(args.size() == 3); const QString &serverName = args[2]; COPYQ_LOG( QString("Connecting to server \"%1\".").arg(serverName) ); m_socket->connectToServer(serverName); if ( !m_socket->waitForConnected(2000) ) { log( tr("Cannot connect to server!"), LogError ); exit(1); } COPYQ_LOG("Connected to server."); m_updateTimer->setSingleShot(true); m_updateTimer->setInterval(300); connect( m_updateTimer, SIGNAL(timeout()), this, SLOT(updateTimeout())); #ifdef COPYQ_WS_X11 connect( &m_x11->timer(), SIGNAL(timeout()), this, SLOT(updateSelection()) ); connect( &m_x11->syncTimer(), SIGNAL(timeout()), this, SLOT(synchronize()) ); #endif }
void ClipboardServer::callback(const QString &scriptFunction) { waitForCallbackToFinish(); COPYQ_LOG( QString("Starting callback: %1").arg(scriptFunction) ); m_callback = new Action(); m_callback->setCommand(QStringList() << "copyq" << scriptFunction); m_wnd->runInternalAction(m_callback); }
void migrateConfigToAppDir() { const QString path = QCoreApplication::applicationDirPath() + "/config"; QDir dir(path); if ( dir.mkpath("copyq") && dir.isReadable() && QFileInfo(path).isWritable() ) { QSettings oldSettings; const QString oldConfigFileName = QSettings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName()).fileName(); const QString oldConfigPath = QDir::cleanPath(oldConfigFileName + "/.."); QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, path); QSettings::setDefaultFormat(QSettings::IniFormat); Settings newSettings; if ( Settings::canModifySettings() && newSettings.isEmpty() ) { COPYQ_LOG("Migrating configuration to application directory."); const QString newConfigPath = QDir::cleanPath(newSettings.fileName() + "/.."); // Migrate configuration from system directory. migrateDirectory(oldConfigPath, newConfigPath); // Migrate themes from system directory. migrateDirectory(oldConfigPath + "/themes", newConfigPath + "/themes"); // Migrate rest of the configuration from the system registry. migrateConfig(oldSettings, newSettings); } } else { COPYQ_LOG( QString("Cannot use \"%1\" directory to save user configuration and items.") .arg(path) ); QSettings oldSettings; QSettings::setDefaultFormat(QSettings::IniFormat); Settings newSettings; // Move settings from Windows registry. if (newSettings.isEmpty()) { COPYQ_LOG("Moving configuration from Windows registry."); migrateConfig(oldSettings, newSettings); } } }
bool ShortcutDialog::eventFilter(QObject *object, QEvent *event) { if (object != ui->lineEditShortcut) return false; if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event); COPYQ_LOG(QString("Shortcut key press: %1").arg(keyEvent->key())); const int key = createPlatformNativeInterface()->keyCode(*keyEvent); Qt::KeyboardModifiers mods = getModifiers(*keyEvent); if (mods == Qt::NoModifier) { if (key == Qt::Key_Tab) return false; if (key == Qt::Key_Escape) { reject(); return true; } if (m_expectModifier) return true; } event->accept(); processKey(key, mods); if ( isNonModifierKey(key) ) accept(); return false; } else if (event->type() == QEvent::KeyRelease) { QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event); COPYQ_LOG(QString("Shortcut key release: %1").arg(keyEvent->key())); Qt::KeyboardModifiers mods = getModifiers(*keyEvent); processKey(0, mods); return true; } return false; }
void Server::close() { m_server->close(); COPYQ_LOG( QString("Sockets open: %1").arg(m_socketCount) ); while (m_socketCount > 0) QCoreApplication::processEvents(); deleteLater(); }
void UnixSignalHandler::handleSignal() { m_signalFdNotifier.setEnabled(false); char tmp; ::read(signalFd[Read], &tmp, sizeof(tmp)); COPYQ_LOG("Terminating application on signal."); QCoreApplication::exit(); }
bool ItemEncryptedSaver::saveItems(const QString &, const QAbstractItemModel &model, QIODevice *file) { const auto length = model.rowCount(); if (length == 0) return false; // No need to encode empty tab. QByteArray bytes; { QDataStream stream(&bytes, QIODevice::WriteOnly); stream.setVersion(QDataStream::Qt_4_7); stream << static_cast<quint64>(length); for (int i = 0; i < length && stream.status() == QDataStream::Ok; ++i) { QModelIndex index = model.index(i, 0); const QVariantMap dataMap = index.data(contentType::data).toMap(); stream << dataMap; } } bytes = readGpgOutput(QStringList("--encrypt"), bytes); if ( bytes.isEmpty() ) { emitEncryptFailed(); COPYQ_LOG("ItemEncrypt ERROR: Failed to read encrypted data"); return false; } QDataStream stream(file); stream.setVersion(QDataStream::Qt_4_7); stream << QString(dataFileHeaderV2); stream.writeRawData( bytes.data(), bytes.size() ); if ( stream.status() != QDataStream::Ok ) { emitEncryptFailed(); COPYQ_LOG("ItemEncrypt ERROR: Failed to write encrypted data"); return false; } return true; }
bool ShortcutDialog::eventFilter(QObject *object, QEvent *event) { if (object != ui->lineEditShortcut) return QDialog::eventFilter(object, event); if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) { auto keyEvent = static_cast<QKeyEvent*>(event); const int key = createPlatformNativeInterface()->keyCode(*keyEvent); const int mods = getModifiers(*keyEvent); if (mods == Qt::NoModifier) { if (key == Qt::Key_Tab) return QDialog::eventFilter(object, event); if (key == Qt::Key_Escape) { reject(); return true; } } event->accept(); if (event->type() == QEvent::KeyPress) { COPYQ_LOG(QString("Shortcut key press: %1").arg(keyEvent->key())); if ( isModifierKey(keyEvent->key()) ) { processKey(0, mods); } else { processKey(key, mods); accept(); } } else if (result() != QDialog::Accepted) { COPYQ_LOG(QString("Shortcut key release: %1").arg(keyEvent->key())); processKey(0, mods); } return true; } return QDialog::eventFilter(object, event); }
void ClipboardServer::onAboutToQuit() { COPYQ_LOG("Closing server."); m_ignoreNewConnections = true; terminateClients(10000); m_server->close(); // No new connections can be open. terminateClients(5000); m_wnd->saveTabs(); }
void ClipboardServer::startMonitoring() { if (m_monitor || m_ignoreNewConnections || !m_wnd->isMonitoringEnabled()) return; COPYQ_LOG("Starting monitor"); m_monitor = new Action(); m_monitor->setCommand("copyq monitorClipboard"); connect( m_monitor.data(), &QObject::destroyed, this, &ClipboardServer::onMonitorFinished ); m_wnd->runInternalAction(m_monitor); }
void ShortcutDialog::processKey(int key, int mods) { m_shortcut = QKeySequence(mods | key); // WORKAROUND: Qt has convert some keys to upper case which // breaks some shortcuts on some keyboard layouts. m_shortcut = QKeySequence(portableShortcutText(m_shortcut)); const QString shortcut = m_shortcut.toString(); COPYQ_LOG(QString("Shortcut: %1").arg(shortcut)); ui->lineEditShortcut->setText(shortcut); }
bool pasteWithCtrlV(PlatformWindow &window) { const QRegExp re( QSettings().value(optionName).toString() ); if (re.isEmpty()) return false; if (!re.isValid()) { log(QString("Invalid regular expression in option \"%1\": %2") .arg(optionName, re.errorString()), LogWarning); return false; } const QString windowTitle = window.getTitle(); if (re.indexIn(windowTitle) == -1) { COPYQ_LOG(QString("Paste with standard shortcut to window \"%1\".") .arg(windowTitle)); return false; } COPYQ_LOG(QString("Paste with Ctrl+V requested with option \"%1\" for window \"%2\".") .arg(optionName, windowTitle)); return true; }
ClientSocket::ClientSocket(const QString &serverName, QObject *parent) : QObject(parent) , m_socket(new QLocalSocket) , m_socketId(++lastSocketId) , m_closed(false) { m_socket->connectToServer(serverName); // Try to connect again in case the server just started. if ( m_socket->state() == QLocalSocket::UnconnectedState ) { COPYQ_LOG("Waiting for server to start"); SleepTimer t(1000); do { m_socket->connectToServer(serverName); } while ( m_socket->state() == QLocalSocket::UnconnectedState && t.sleep() ); } }
Qt::KeyboardModifiers ShortcutDialog::getModifiers(const QKeyEvent &event) { int key = event.key(); Qt::KeyboardModifiers mods = event.modifiers(); if (key == Qt::Key_Meta || key == Qt::Key_Super_L || key == Qt::Key_Super_R || key == Qt::Key_Hyper_L || key == Qt::Key_Hyper_R) { m_metaPressed = (event.type() == QEvent::KeyPress); COPYQ_LOG(QString("Shortcut \"Meta\" key %1.").arg(m_metaPressed ? "pressed" : "released")); } if (m_metaPressed) mods |= Qt::MetaModifier; else mods &= ~Qt::MetaModifier; return mods; }
void ClipboardServer::onSaveState(QSessionManager &sessionManager) { COPYQ_LOG("Got save state request from session manager."); QSettings settings(QSettings::IniFormat, QSettings::UserScope, "copyq", "copyq_no_session"); const auto sessionNameKey = "session_" + sessionManager.sessionId(); const auto sessionName = qApp->property("CopyQ_session_name").toString(); settings.setValue(sessionNameKey, sessionName); // Remove last session name from configuration. const auto lastSessionIdKey = "last_session_id_for_" + sessionName; const auto lastSessionId = settings.value(lastSessionIdKey).toString(); if ( !lastSessionId.isEmpty() ) { const auto lastSessionNameKey = "session_" + lastSessionId; settings.remove(lastSessionNameKey); } settings.setValue(lastSessionIdKey, sessionNameKey); }
void ClipboardServer::stopMonitoring() { if (!m_monitor) return; COPYQ_LOG("Terminating monitor"); for (auto it = m_clients.constBegin(); it != m_clients.constEnd(); ++it) { const auto &clientData = it.value(); if (!clientData.isValid()) continue; const auto actionId = clientData.proxy->actionId(); if ( actionId == m_monitor->id() ) { clientData.client->sendMessage(QByteArray(), CommandStop); break; } } }
void ClipboardServer::onCommitData(QSessionManager &sessionManager) { COPYQ_LOG("Got commit data request from session manager."); const bool cancel = sessionManager.allowsInteraction() && !askToQuit(); sessionManager.release(); if (cancel) { sessionManager.cancel(); startMonitoring(); } else { m_wnd->saveTabs(); // WORKAROUND: This is required to exit application from // installer, otherwise main window is only // minimized after this when tray is disabled. m_wnd->hide(); exit(); } }
void ShortcutDialog::processKey(int key, Qt::KeyboardModifiers mods) { int keys = 0; if ( isNonModifierKey(key) ) keys = key; if (mods & Qt::ControlModifier) keys += Qt::CTRL; if (mods & Qt::ShiftModifier) keys += Qt::SHIFT; if (mods & Qt::AltModifier) keys += Qt::ALT; if (mods & Qt::MetaModifier) keys += Qt::META; m_shortcut = QKeySequence(keys); QString shortcut = m_shortcut.toString(QKeySequence::NativeText); COPYQ_LOG(QString("Shortcut: %1").arg(m_shortcut.toString())); ui->lineEditShortcut->setText(shortcut); }
bool isAltTabWindow(HWND window) { if (!window || window == GetShellWindow()) return false; HWND root = GetAncestor(window, GA_ROOTOWNER); if (getLastVisibleActivePopUpOfWindow(root) != window) return false; const QString cls = windowClass(window); COPYQ_LOG( QString("cls: \"%1\"").arg(cls) ); return !cls.isEmpty() && cls != "Shell_TrayWnd" && cls != "Shell_SecondaryTrayWnd" && cls != "DV2ControlHost" && cls != "MsgrIMEWindowClass" && cls != "SysShadow" && cls != "Button" && !cls.startsWith("WMP9MediaBarFlyout"); }
/** * Remember last non-empty clipboard content and reset clipboard after interval if there is no owner. * * @return return true if clipboard/selection has no owner and will be reset */ bool maybeResetClipboard(QClipboard::Mode mode) { bool isClip = (mode == QClipboard::Clipboard); bool isEmpty = isClip ? m_x11Platform.isClipboardEmpty() : m_x11Platform.isSelectionEmpty(); QVariantMap &clipData = isClip ? m_clipboardData : m_selectionData; // Need reset? if ( !isEmpty || clipData.isEmpty() ) return false; COPYQ_LOG( QString("%1 is empty").arg(isClip ? "Clipboard" : "Selection") ); bool &reset = isClip ? m_resetClipboard : m_resetSelection; reset = !m_syncTimer.isActive() || m_syncTo == mode; if (reset) { m_syncTimer.stop(); m_resetTimer.start(); } else if (m_resetTimer.isActive() && !m_resetClipboard && !m_resetSelection) { m_resetTimer.stop(); } return true; }
int ShortcutDialog::getModifiers(const QKeyEvent &event) { int key = event.key(); const Qt::KeyboardModifiers mods = event.modifiers(); int result = 0; if (key == Qt::Key_Meta || key == Qt::Key_Super_L || key == Qt::Key_Super_R || key == Qt::Key_Hyper_L || key == Qt::Key_Hyper_R) { m_metaPressed = (event.type() == QEvent::KeyPress); COPYQ_LOG(QString("Shortcut \"Meta\" key %1.").arg(m_metaPressed ? "pressed" : "released")); } if (mods & Qt::ShiftModifier) result |= Qt::SHIFT; if (mods & Qt::ControlModifier) result |= Qt::CTRL; if (mods & Qt::AltModifier) result |= Qt::ALT; if (m_metaPressed || mods & Qt::MetaModifier) result |= Qt::META; return result; }
void ClientSocket::onReadyRead() { if (!m_socket) { SOCKET_LOG("Cannot read message from client. Socket is already deleted."); return; } const qint64 available = m_socket->bytesAvailable(); m_message.append( m_socket->read(available) ); while ( !m_message.isEmpty() ) { if (!m_hasMessageLength) { const int preambleSize = headerDataSize() + streamDataSize(m_messageLength); if ( m_message.length() < preambleSize ) break; { QDataStream stream(m_message); stream.setVersion(QDataStream::Qt_5_0); quint32 magicNumber; quint32 version; stream >> magicNumber >> version >> m_messageLength; if ( stream.status() != QDataStream::Ok ) { error("Failed to read message length from client!"); return; } if (magicNumber != protocolMagicNumber) { error("Unexpected message magic number from client!"); return; } if (version != protocolVersion) { error("Unexpected message version from client!"); return; } } m_message.remove(0, preambleSize); m_hasMessageLength = true; if (m_messageLength > bigMessageThreshold) COPYQ_LOG( QString("Receiving big message: %1 MiB").arg(m_messageLength / 1024 / 1024) ); } const auto length = static_cast<int>(m_messageLength); if ( m_message.length() < length ) break; QByteArray msg = m_message.mid(0, length); qint32 messageCode; if ( !readValue(&messageCode, &msg) ) { error("Failed to read message code from client!"); return; } m_hasMessageLength = false; m_message = m_message.mid(length); emit messageReceived(msg, messageCode, id()); } }
ClipboardServer::ClipboardServer(QApplication *app, const QString &sessionName) : QObject() , App(app, sessionName) , m_wnd(nullptr) , m_shortcutActions() , m_ignoreKeysTimer() { setCurrentThreadName("Server"); const QString serverName = clipboardServerName(); m_server = new Server(serverName, this); if ( m_server->isListening() ) { ::createSessionMutex(); restoreSettings(true); COPYQ_LOG("Server \"" + serverName + "\" started."); } else { restoreSettings(false); COPYQ_LOG("Server \"" + serverName + "\" already running!"); log( tr("CopyQ server is already running."), LogWarning ); exit(0); return; } QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true); QApplication::setQuitOnLastWindowClosed(false); m_itemFactory = new ItemFactory(this); m_wnd = new MainWindow(m_itemFactory); m_itemFactory->loadPlugins(); if ( !m_itemFactory->hasLoaders() ) log("No plugins loaded", LogNote); m_wnd->loadSettings(); m_wnd->setCurrentTab(0); m_wnd->enterBrowseMode(); connect( m_server, &Server::newConnection, this, &ClipboardServer::onClientNewConnection ); connect( qApp, &QCoreApplication::aboutToQuit, this, &ClipboardServer::onAboutToQuit ); connect( qApp, &QGuiApplication::commitDataRequest, this, &ClipboardServer::onCommitData ); connect( qApp, &QGuiApplication::saveStateRequest, this, &ClipboardServer::onSaveState ); #if QT_VERSION >= QT_VERSION_CHECK(5,6,0) qApp->setFallbackSessionManagementEnabled(false); #endif connect( m_wnd, &MainWindow::requestExit, this, &ClipboardServer::maybeQuit ); connect( m_wnd, &MainWindow::disableClipboardStoringRequest, this, &ClipboardServer::onDisableClipboardStoringRequest ); loadSettings(); // notify window if configuration changes connect( m_wnd, &MainWindow::configurationChanged, this, &ClipboardServer::loadSettings ); connect( m_wnd, &MainWindow::commandsSaved, this, &ClipboardServer::onCommandsSaved ); onCommandsSaved(); qApp->installEventFilter(this); m_server->start(); // Ignore global shortcut key presses in any widget. m_ignoreKeysTimer.setInterval(100); m_ignoreKeysTimer.setSingleShot(true); startMonitoring(); }