文件更改句柄,QSocketNotifier由于无效套接字而禁用

时间:2012-10-23 20:52:05

标签: qt sockets io qfile

我正在开发触摸屏,需要检测触摸事件才能重新打开屏幕。我正在使用Qt和套接字,并遇到了一个有趣的问题。

每当我的QSocketNotifier检测到该事件时,它就会向我发送有关它的无限通知。因此,我需要关闭并打开事件文件以循环通知程序(以下代码中的inputNotifier)。问题通常在设备运行几分钟后出现,文件(inputDevice)突然将其句柄从24改为其他东西(通常为17)。

我不知道该怎么做,因为初始的connect语句链接到初始的Notifier指针。如果我使用新句柄创建新的通告程序,则连接无效。据我所知,没有选项可以在正在运行的QSocketNotifier上设置新的套接字值。建议?相关代码如下:

#include "backlightcontroller.h"
#include <QTimer>
#include <QFile>
#include <syslog.h>
#include <QDebug>
#include <QSocketNotifier>




BacklightController::BacklightController(QObject *parent) :
    QObject(parent)
{
    backlightActive = true;

    // setup timer
    trigger = new QTimer;
    trigger->setSingleShot(false);
    connect(trigger, SIGNAL(timeout()), SLOT(deactivateBacklight()));

    idleTimer = new QTimer;
    idleTimer->setInterval(IDLE_TIME * 1000);
    idleTimer->setSingleShot(false);
    connect(idleTimer, SIGNAL(timeout()), SIGNAL(idled()));
    idleTimer->start();

    // setup socket notifier
    inputDevice = new QFile(USERINPUT_DEVICE);
    if (!inputDevice->open(QIODevice::ReadOnly))
    {
        syslog (LOG_ERR, "Input file for Backlight controller could not been opened.");
    }
    else
    {
        inputNotifier = new QSocketNotifier(inputDevice->handle(), QSocketNotifier::Read);
        inputNotifier->setEnabled(true);
        connect(inputNotifier, SIGNAL(activated(int)), SLOT(activateBacklight()));
    }

    qDebug()<<"backlight socket: "<<inputNotifier->socket();

    // read out settings-file
    QString intensity = Global::system_settings->getValue("BelatronUS_backlight_intensity");
    if (intensity.length() == 0) intensity = "100";
    QString duration = Global::system_settings->getValue("BelatronUS_backlight_duration");
    if (duration.length() == 0) duration = "180";
    QString always_on = Global::system_settings->getValue("BelatronUS_backlight_always_on");
    if (always_on.length() == 0) always_on = "0";

    setIntensity(intensity.toInt());
    setDuration(duration.toInt());

    if (always_on == "0")
      setAlwaysOn(false);
    else
      setAlwaysOn(true);
}


BacklightController::~BacklightController()
{
    trigger->stop();
    inputNotifier->setEnabled(false);
    inputDevice->close();

    delete trigger;
    delete inputDevice;
    delete inputNotifier;
}


void BacklightController::setCurrentIntensity(int intensity)
{
    // adapt backlight intensity
    QFile backlightFile("/sys/class/backlight/atmel-pwm-bl/brightness");
    if (!backlightFile.open(QIODevice::WriteOnly))
    {
      syslog (LOG_ERR, "Backlight intensity file could not been opened.");
    }
    else
    {
      QString intensityString = QString::number(TO_BRIGHTNESS(intensity));
      if (backlightFile.write(
              qPrintable(intensityString), intensityString.length()
              ) < intensityString.length())
      {
        syslog (LOG_ERR, "Backlight intensity could not been changed.");
      }
      backlightFile.close();
    }
}


void BacklightController::resetNotifier()
{

    inputDevice->close();
    if (!inputDevice->open(QIODevice::ReadOnly))
    {
        syslog (LOG_ERR, "BacklightController::%s: Input file could not been opened.", __FUNCTION__);
    }
    qDebug()<<"reset, handle: "<<inputDevice->handle();
    //inputNotifier=QSocketNotifier(inputDevice->handle(), QSocketNotifier::Read);


    // restart timer after user input
    idleTimer->start();
}


void BacklightController::activateBacklight()
{
    // only activate backlight, if it's off (avoid to useless fileaccess)
    if (!backlightActive)
    {
        setCurrentIntensity(_intensity);
        backlightActive = true;
        emit backlightActivated();
    }

    // restart backlight timeout, but only if we don't want the backlight to shine all the time
    if (!_alwaysOn)
        trigger->start();

    // reset notifier to be able to catch the next userinput
    resetNotifier();
}


void BacklightController::deactivateBacklight()
{
    // don't turn it off, if it's forced on
    if (!_alwaysOn)
    {
        if (backlightActive)
        {
            // only deactivate backlight, if it's on (avoid to useless fileaccess)
            setCurrentIntensity(BACKLIGHT_INTENSITY_OFF);
            backlightActive = false;
            emit backlightDeactivated();
        }
    }
    qDebug()<<"trigger stopping";
    trigger->stop();
}


void BacklightController::setIntensity(int intensity)
{
    if (intensity > 100)
        intensity = 100;
    else if (intensity < 0)
        intensity = 0;

    _intensity = intensity;

    // write new intensity to file if it's active at the moment
    if (backlightActive)
    {
        setCurrentIntensity(_intensity);
        trigger->start();
    }
}


void BacklightController::setDuration(int duration)
{
    if (duration < 1)
        duration = 1;

    _duration = duration;
    trigger->setInterval(_duration * MS_IN_SEC);

    // reset trigger after changing duration
    if (backlightActive)
    {
        trigger->start();
    }
}


void BacklightController::setAlwaysOn(bool always_on)
{
    _alwaysOn = always_on;

    // tell the timer what to to now
    if (_alwaysOn)
    {
        this->activateBacklight();
        trigger->stop();
    }
    else
    {
        trigger->start();
    }
}

1 个答案:

答案 0 :(得分:1)

我现在似乎找到了一个有效的解决方案。这不是最好的,如果有更好的解决方案,我会有兴趣听到它们。之前我没有想到这个的原因是因为我认为如果我在函数中有一个新的连接语句,它将在函数结束时限制范围。

解决方案是简单地检查文件中是否发生句柄更改,然后使用该句柄为通知程序创建新指针。然后重新启用通知程序,因为它现在可能已被禁用,然后为指针创建一个新的连接语句。这是我使用的代码,在事件文件的关闭和重新打开之后添加:

if(inputDevice->handle()!=inputNotifier->socket()){
    inputNotifier = new QSocketNotifier(inputDevice->handle(), QSocketNotifier::Read);
    inputNotifier->setEnabled(true);
    connect(inputNotifier, SIGNAL(activated(int)), SLOT(activateBacklight()));
}