Пример #1
0
void X11IdleDetector::checkIdleness()
{
    xcb_screensaver_query_info_cookie_t cookie;
    cookie = xcb_screensaver_query_info(m_connection, m_screen->root);
    xcb_screensaver_query_info_reply_t *info;
    info = xcb_screensaver_query_info_reply(m_connection, cookie, NULL);    //krazy:exclude=null
    const int idleSecs = info->ms_since_user_input / 1000;
    free(info);

    if (idleSecs >= idlenessDuration())
        maybeIdle(IdlePeriod(QDateTime::currentDateTime().addSecs(-idleSecs),
                             QDateTime::currentDateTime()));

    if (m_heartbeat.secsTo(QDateTime::currentDateTime()) > idlenessDuration())
        maybeIdle(IdlePeriod(m_heartbeat, QDateTime::currentDateTime()));

    m_heartbeat = QDateTime::currentDateTime();
}
Пример #2
0
void X11IdleDetector::checkIdleness()
{
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
    XScreenSaverInfo* _mit_info = XScreenSaverAllocInfo();
    if (!_mit_info)
        return;
    XScreenSaverQueryInfo(QX11Info::display(), QX11Info::appRootWindow(), _mit_info);
    const int idleSecs = _mit_info->idle / 1000;
    XFree(_mit_info);

    if (idleSecs >= idlenessDuration())
        maybeIdle( IdlePeriod(QDateTime::currentDateTime().addSecs( -idleSecs ),
                              QDateTime::currentDateTime() ) );

    if ( m_heartbeat.secsTo( QDateTime::currentDateTime() ) > idlenessDuration() )
        maybeIdle( IdlePeriod( m_heartbeat, QDateTime::currentDateTime() ) );
#endif
    m_heartbeat = QDateTime::currentDateTime();
}
void WindowsIdleDetector::timeout() {
    LASTINPUTINFO lif;
    lif.cbSize = sizeof( lif );
    const bool ret = GetLastInputInfo( &lif );
    if ( !ret ) {
        qWarning() << "Idle detection: GetLastInputInfo failed.";
        return;
    }

    const qint64 dwTime = static_cast<qint64>( lif.dwTime );
    const qint64 ctk = static_cast<qint64>( GetTickCount() );
    const int idleSecs = ( ctk - dwTime ) / 1000;
    if ( idleSecs >= idlenessDuration() )
        maybeIdle( IdlePeriod(QDateTime::currentDateTime().addSecs( -idleSecs ),
                              QDateTime::currentDateTime() ) );
}
Пример #4
0
void IdleDetector::maybeIdle( IdlePeriod period )
{
    if ( ! Configuration::instance().detectIdling ) {
        return;
    }

    qDebug() << "IdleDetector::maybeIdle: Checking for idleness";

    // merge overlapping idle periods
    IdlePeriods periods ( idlePeriods() );
    periods << period;
//     // TEMP (this was used to test the overlapping-idle-period compression below, leave it in
//     {
//         IdlePeriod i2( period.first.addSecs( 1 ), period.second.addSecs( 1 ) ); // should be merged
//         IdlePeriod i3( period.second.addSecs( 2 ), period.second.addSecs( 5 ) ); // should not be merged
//         periods << i2 << i3;
//     }

    qSort( periods );
    m_idlePeriods.clear();
    while ( ! periods.isEmpty() ) {
        IdlePeriod first = periods.first();
        periods.pop_front();
        while ( ! periods.isEmpty() ) {
            IdlePeriod second = periods.first();
            if ( second.first >= first.first && second.first <= first.second ) {
                first.second = qMax( first.second, second.second );
                // first.first is already the earlier time, because the container is sorted
            } else {
                break;
            }
            periods.pop_front();
        }
        if ( first.first.secsTo( first.second ) >= idlenessDuration() ) {
            // we ignore idle period of less than MinimumSeconds
            m_idlePeriods << first;
        }
    }
    // notify application
    if ( ! idlePeriods().isEmpty() ) {
        qDebug() << "IdleDetector::maybeIdle: Found idleness";
        emit maybeIdle();
    }
}
Пример #5
0
ApplicationCore::ApplicationCore(TaskId startupTask, bool hideAtStart, QObject *parent)
    : QObject(parent)
    , m_actionStopAllTasks(this)
    , m_actionQuit(this)
    , m_actionAboutDialog(this)
    , m_actionPreferences(this)
    , m_actionExportToXml(this)
    , m_actionImportFromXml(this)
    , m_actionSyncTasks(this)
    , m_actionImportTasks(this)
    , m_actionExportTasks(this)
    , m_actionCheckForUpdates(this)
    , m_actionEnterVacation(this)
    , m_actionActivityReport(this)
    , m_actionWeeklyTimesheetReport(this)
    , m_actionMonthlyTimesheetReport(this)
    , m_uiElements(
{
    &m_timeTracker, &m_tasksView, &m_eventView
}),
    m_startupTask(startupTask)
  , m_hideAtStart(hideAtStart)

#ifdef Q_OS_WIN
    , m_windowsJumpList(new QWinJumpList(this))
#endif
    , m_dateChangeWatcher(new DateChangeWatcher(this))
{
    // QApplication setup
    QApplication::setQuitOnLastWindowClosed(false);
    // application metadata setup
    // note that this modifies the behaviour of QSettings:
    QCoreApplication::setOrganizationName(QStringLiteral("KDAB"));
    QCoreApplication::setOrganizationDomain(QStringLiteral("kdab.com"));
    QCoreApplication::setApplicationName(QStringLiteral("Charm"));
    QCoreApplication::setApplicationVersion(CharmVersion());

    QLocalSocket uniqueApplicationSocket;
    QString serverName(QStringLiteral("com.kdab.charm"));
    QString charmHomeEnv(QString::fromLocal8Bit(qgetenv("CHARM_HOME")));
    if (!charmHomeEnv.isEmpty()) {
        serverName.append(QStringLiteral("_%1").arg(
                              charmHomeEnv.replace(QRegExp(QLatin1String(":?/|:?\\\\")),
                                                   QStringLiteral("_"))));
    }
#ifndef NDEBUG
    serverName.append(QStringLiteral("_debug"));
#endif
    uniqueApplicationSocket.connectToServer(serverName, QIODevice::ReadWrite);
    if (uniqueApplicationSocket.waitForConnected(1000)) {
        QByteArray command;
        if (startupTask != -1) {
            command = StartTaskCommand + QByteArray::number(startupTask);
        } else {
            command = RaiseWindowCommand;
        }
        command += '\n';
        qint64 written = uniqueApplicationSocket.write(command);
        if (written == -1 || written != command.length()) {
            qWarning() << "Failed to pass " << command << " to running charm instance, error: "
                        << uniqueApplicationSocket.errorString();
        }
        uniqueApplicationSocket.flush();
        uniqueApplicationSocket.waitForBytesWritten();
        throw AlreadyRunningException();
    }

    connect(&m_uniqueApplicationServer, &QLocalServer::newConnection,
            this, &ApplicationCore::slotHandleUniqueApplicationConnection, Qt::QueuedConnection);

    QFile::remove(QDir::tempPath() + QLatin1Char('/') + serverName);
    bool listening = m_uniqueApplicationServer.listen(serverName);
    if (!listening)
        qDebug() << "Failed to create QLocalServer for unique application support:"
                 << m_uniqueApplicationServer.errorString();

    Q_INIT_RESOURCE(CharmResources);
    Q_ASSERT_X(m_instance == 0, "Application ctor",
               "Application is a singleton and cannot be created more than once");
    m_instance = this;
    qRegisterMetaType<State>("State");
    qRegisterMetaType<Event>("Event");

    // exit process (app will only exit once controller says it is ready)
    connect(&m_controller, &Controller::readyToQuit,
            this, &ApplicationCore::slotControllerReadyToQuit);

    connectControllerAndModel(&m_controller, m_model.charmDataModel());
    Charm::connectControllerAndView(&m_controller, &m_timeTracker);

    // save the configuration (configuration is managed by the application)
    connect(&m_timeTracker, &CharmWindow::saveConfiguration,
            this, &ApplicationCore::slotSaveConfiguration);
    connect(&m_timeTracker, &TimeTrackingWindow::showNotification,
            this, &ApplicationCore::slotShowNotification);
    connect(&m_timeTracker, &TimeTrackingWindow::taskMenuChanged,
            this, &ApplicationCore::slotPopulateTrayIconMenu);

    // save the configuration (configuration is managed by the application)
    connect(&m_tasksView, &TasksView::saveConfiguration,
            this, &ApplicationCore::slotSaveConfiguration);
    // due to multiple inheritence we can't use the new style connects here
    connect(&m_tasksView, SIGNAL(emitCommand(CharmCommand*)),
            &m_timeTracker, SLOT(sendCommand(CharmCommand*)));
    connect(&m_tasksView, SIGNAL(emitCommandRollback(CharmCommand*)),
            &m_timeTracker, SLOT(sendCommandRollback(CharmCommand*)));
    connect(&m_eventView, SIGNAL(emitCommand(CharmCommand*)),
            &m_timeTracker, SLOT(sendCommand(CharmCommand*)));
    connect(&m_eventView, SIGNAL(emitCommandRollback(CharmCommand*)),
            &m_timeTracker, SLOT(sendCommandRollback(CharmCommand*)));

    // my own signals:
    connect(this, &ApplicationCore::goToState,
             this, &ApplicationCore::setState, Qt::QueuedConnection);

    // system tray icon:
    m_actionStopAllTasks.setText(tr("Stop Current Task"));
    m_actionStopAllTasks.setShortcut(Qt::Key_Escape);
    m_actionStopAllTasks.setShortcutContext(Qt::ApplicationShortcut);
    mainView().addAction(&m_actionStopAllTasks); // for the shortcut to work
    connect(&m_actionStopAllTasks, &QAction::triggered, this, &ApplicationCore::slotStopAllTasks);

    m_systrayContextMenu.addAction(&m_actionStopAllTasks);
    m_systrayContextMenu.addSeparator();

    m_systrayContextMenu.addAction(m_timeTracker.openCharmAction());
    m_systrayContextMenu.addAction(&m_actionQuit);

    m_trayIcon.setContextMenu(&m_systrayContextMenu);
    m_trayIcon.setToolTip(tr("No active events"));
    m_trayIcon.setIcon(Data::charmTrayIcon());
    m_trayIcon.show();

    QApplication::setWindowIcon(Data::charmIcon());

    // set up actions:
    m_actionQuit.setShortcut(Qt::CTRL + Qt::Key_Q);
    m_actionQuit.setText(tr("Quit"));
    m_actionQuit.setIcon(Data::quitCharmIcon());
    connect(&m_actionQuit, &QAction::triggered,
            this, &ApplicationCore::slotQuitApplication);

    m_actionAboutDialog.setText(tr("About Charm"));
    connect(&m_actionAboutDialog, &QAction::triggered,
           &m_timeTracker, &TimeTrackingWindow::slotAboutDialog);

    m_actionPreferences.setText(tr("Preferences"));
    m_actionPreferences.setIcon(Data::configureIcon());
    connect(&m_actionPreferences, &QAction::triggered,
            &m_timeTracker, &TimeTrackingWindow::slotEditPreferences);
    m_actionPreferences.setEnabled(true);

    m_actionImportFromXml.setText(tr("Import Database from Previous Export..."));
    connect(&m_actionImportFromXml, &QAction::triggered,
            &m_timeTracker, &TimeTrackingWindow::slotImportFromXml);
    m_actionExportToXml.setText(tr("Export Database..."));
    connect(&m_actionExportToXml, &QAction::triggered,
            &m_timeTracker, &TimeTrackingWindow::slotExportToXml);
    m_actionSyncTasks.setText(tr("Update Task Definitions..."));
    //the signature of QAction::triggered does not match slotSyncTasks
    connect(&m_actionSyncTasks,&QAction::triggered,
            &m_timeTracker, &TimeTrackingWindow::slotSyncTasksVerbose);
    m_actionImportTasks.setText(tr("Import and Merge Task Definitions..."));
    connect(&m_actionImportTasks, &QAction::triggered,
            &m_timeTracker, &TimeTrackingWindow::slotImportTasks);
    m_actionExportTasks.setText(tr("Export Task Definitions..."));
    connect(&m_actionExportTasks, &QAction::triggered,
            &m_timeTracker, &TimeTrackingWindow::slotExportTasks);
    m_actionCheckForUpdates.setText(tr("Check for Updates..."));
#if 0
    // TODO this role should be set to have the action in the app menu, but that
    // leads to duplicated entries, as each of the three main windows adds the action to the menu
    // and Qt doesn't prevent duplicates (#222)
    m_actionCheckForUpdates.setMenuRole(QAction::ApplicationSpecificRole);
#endif
    connect(&m_actionCheckForUpdates, &QAction::triggered,
            &m_timeTracker, &TimeTrackingWindow::slotCheckForUpdatesManual);
    m_actionEnterVacation.setText(tr("Enter Vacation..."));
    connect(&m_actionEnterVacation, &QAction::triggered,
            &m_timeTracker, &TimeTrackingWindow::slotEnterVacation);
    m_actionActivityReport.setText(tr("Activity Report..."));
    m_actionActivityReport.setShortcut(Qt::CTRL + Qt::Key_A);
    connect(&m_actionActivityReport, &QAction::triggered,
            &m_timeTracker, &TimeTrackingWindow::slotActivityReport);
    m_actionWeeklyTimesheetReport.setText(tr("Weekly Timesheet..."));
    m_actionWeeklyTimesheetReport.setShortcut(Qt::CTRL + Qt::Key_R);
    connect(&m_actionWeeklyTimesheetReport, &QAction::triggered,
            &m_timeTracker, &TimeTrackingWindow::slotWeeklyTimesheetReport);
    m_actionMonthlyTimesheetReport.setText(tr("Monthly Timesheet..."));
    m_actionMonthlyTimesheetReport.setShortcut(Qt::CTRL + Qt::Key_M);
    connect(&m_actionMonthlyTimesheetReport, &QAction::triggered,
            &m_timeTracker, &TimeTrackingWindow::slotMonthlyTimesheetReport);

    // set up idle detection
    m_idleDetector = IdleDetector::createIdleDetector(this);
    Q_ASSERT(m_idleDetector);
    connect(m_idleDetector, SIGNAL(maybeIdle()), SLOT(slotMaybeIdle()));

    setHttpActionsVisible(Lotsofcake::Configuration().isConfigured());
    // add default plugin path for deployment
    QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath()
                                     + QStringLiteral("/plugins"));

    if (QCoreApplication::applicationDirPath().endsWith(QLatin1String("MacOS")))
        QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath()
                                         + QStringLiteral("/../plugins"));

    // set up command interface
#ifdef CHARM_CI_SUPPORT
    m_cmdInterface = new CharmCommandInterface(this);
#endif // CHARM_CI_SUPPORT

    // Ladies and gentlemen, please raise upon your seats -
    // the show is about to begin:
    emit goToState(StartingUp);
}