[Kwintv] several problems/bugs

Neil Macvicar kwintv@mail.kde.org
Sat, 29 Mar 2003 12:47:40 +0000


--Boundary-00=_sXZh+Bls+90gqAX
Content-Type: text/plain;
  charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

On Friday 28 March 2003 11:27 pm, BoZ wrote:
> Hi,
>
> While using QtVision I encountered the following problems:
>
> - When I close QtVision the sound gets muted. (I'm using the OSS mixer
> plugin.)

The code that causes this behaviour is commented out in this file 
(qtvision.cpp). I'm not sure why this behaviour was introduced in the first 
place. Replace file in the cvs directory with this one.

Regards,
Neil.
--Boundary-00=_sXZh+Bls+90gqAX
Content-Type: text/x-c++src;
  charset="iso-8859-1";
  name="qtvision.cpp"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="qtvision.cpp"

/* vim: sw=4 et
 *
 * Copyright (C) 2002 George Staikos <staikos@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <qapplication.h>
#include <qlabel.h>
#include <qmessagebox.h>
#include <qpainter.h>
#include <qtimer.h>
#include <qcolor.h>

#include <dcopclient.h>
#include <dcopobject.h>
#include <kapplication.h>
#include <kdebug.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kglobal.h>
#include <kstandarddirs.h>
#include <kfiledialog.h>
#include <kconfig.h>

#include <stdlib.h>
#include <unistd.h>
#include <assert.h>

#include "pluginfactory.h"
#include "chwizard.h"
#include "viewmanager.h"
#include "channelscanner.h"
#include "channelstore.h"
#include "view.h"
#include "audiomanager.h"
#include "osdmanager.h"
#include "channelimportdlg.h"
#include "miscmanager.h"
#include "statusmanager.h"

#include "qtvision.h"
#include "qtvision.moc"



QtVision::QtVision( QObject *parent, const char *name) 
         :QObject( parent, name ? name : "qtvision" ),
          DCOPObject( "QtVisionIface" ), _view(0), _vsrc(0), 
          _number(""), _prevChannel(-1)

{
    _mm = 0;
    _osd = 0;
    _sm = 0;
    _am = 0;
    _grabNumber = 1;
    _pf = new PluginFactory(this);
    grabPix.resize( 200, 200 );
    grabPix.fill( Qt::blue );
    KGlobal::dirs()->addResourceType("qtvision", "share/apps/qtvision");
    _quitting = false;    
    connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(aboutToQuit()));       
        
    _config = new KConfig ("qtvisionrc");
    
    _cfg = new ConfigData (_config);
    
    if (_cfg->load() == -1)
    {
        kdFatal() << "QtVision::QtVision: Unable to read config file..." << endl;
        exit (1);
    }
    
    // Force the audio manager to initialize and set the volume
    _am = new AudioManager(this);
    connect(_am, SIGNAL(volumeChanged(int,int)), this, SIGNAL(volumeChanged(int,int)));
      
    _viewmng = new ViewManager( this );

    // Register with DCOP
    if ( !kapp->dcopClient()->isRegistered() ) {
      kapp->dcopClient()->registerAs( "qtvisioniface" );
      kapp->dcopClient()->setDefaultObject( objId() );
    }

    _cs = new ChannelStore( this, this, "channel_store" );

    if (_cfg->firstTime) {
        kdDebug() << "This is a first run.  let's ask to migrate.." << endl;
        doMigration();
    }
    
    // Restore the volume settings...
    _muted = _cfg->volumeMuted;    
    ChannelVolState.left = _cfg->volumeLeft;
    ChannelVolState.right = _cfg->volumeRight;    

    _keypresstimer = new QTimer(parent);
    connect(_keypresstimer, SIGNAL(timeout()), this, SLOT(slotKeyPressTimeout()));

    _sm = new StatusManager;
    connect(this, SIGNAL(channelChanged(int)), _sm, SIGNAL(channelChanged()));
}

QtVision::~QtVision()
{
    _cs->save();
    stopDevice();
    
    // Save volume related settings...
    // _cfg->volumeMuted = _muted;
    _cfg->volumeLeft = _am->volumeLeft();
    _cfg->volumeRight= _am->volumeRight();
    
    delete _cfg;
    delete _config;
    delete _viewmng;
    delete _keypresstimer;
    delete _am;
    delete _sm;
    delete _mm;
    delete _osd;
    delete _pf;

    _cfg = 0;
    _config = 0;
    _viewmng = 0;
    _keypresstimer = 0;
    _am = 0;
    _sm = 0;
    _mm = 0;
    _osd = 0;
    _pf = 0;
}

DCOPRef QtVision::channelStoreIface()
{
    return DCOPRef( _cs );
}

DCOPRef QtVision::channelIface()
{
    return DCOPRef( _chan );
}

void QtVision::start()
{
    kdDebug () << "QtVision::start: Set initial volume settings... " << endl;    
    
    // -2 is a bogus value used during initialization to stop ::setChannel
    // from storing the current device volume settings when restoring the
    // previous channel.  See ::setChannel.
    ChannelVolState.changeEventId = -2;
    
    // Make sure the volume mute state is restored...
    _muted = !_muted;
    volumeMute();
     
    emit volumeChanged (ChannelVolState.left, ChannelVolState.right);
    kdDebug () << "QtVision::start: Emitted volume settings...." << endl;
    
    if ( !_view )
        return;

    bool started = false;
    if ( _cfg->autoStart ) {
        started = tryAutoStart();
    }

    if ( !started )
        selectDevice();

    if ( !_vsrc ) {
        kdWarning() << "QtVision::start() No device selected" << endl;
        return;
    }
}

void QtVision::stop()
{
    if ( !_view )
        return;
    
    // Preserve the volume state incase this is 
    // invoked through DCOP.
    if (_am) {
        ChannelVolState.left = _am->volumeLeft ();
        ChannelVolState.right = _am->volumeRight ();
        kdDebug () << "QtVision::stop: Volume => left = " <<  ChannelVolState.left
                   <<  ", right = " << ChannelVolState.right << endl;
    }
               
    stopDevice();    
}

bool QtVision::tryAutoStart()
{
    kdDebug() << "QtVision::tryAutoStart()" << endl;
    assert(_vsrc == 0);

    QString dev = _cfg->prevDev;
    if ( dev.isEmpty() )
        return false;

    QString src = _cfg->prevSrc;
    if ( src.isEmpty() )
        return false;

    kdDebug() << "QtVision::tryAutoStart() Trying device '" << dev
              << "', and source '" << src << "'" << endl;

    for (PluginDesc *plug = _pf->videoPlugins().first(); plug;
                     plug = _pf->videoPlugins().next()) {
        QVSourcePlugin *v = _pf->getVideoPlugin(plug,screen());
        if (!v)
            continue;
        v->probeDevices();
        for (QStringList::ConstIterator it = v->deviceList().begin();
                                         it != v->deviceList().end();
                                                                 ++it) {
            if (*it == dev) {
                if (v->sourceList(dev).contains(src)) {
                    v->setDevice(dev);
                    setDevice(v);
                    setSource(src);
                    startCapture();
                    return true;
                }
            }
        }
        delete v;
    }

    return false;  // didn't work
}


void QtVision::selectDevice()
{
    kdDebug() << "QtVision::selectDevice()" << endl;

    do {
        int rc = _viewmng->launchSourceDialog( _view );
        if ( rc == QDialog::Rejected )
            return;
    } while( !hasDevice() );

    kdDebug() << "QtVision::selectDevice() Starting capture" << endl;
    startCapture();
}

void QtVision::setSource( const QString &src )
{
    if (_vsrc) {
        _vsrc->setSource(src);
        _cfg->prevSrc = src;
    }
}

void QtVision::setDevice( QVSourcePlugin *dev )
{
    stopDevice();
    _vsrc = dev;
    _osd->setColourKey(_vsrc->colourKey());
    if (dev) {
        kdDebug() << "Device set to: " << dev->device() << endl;
        _cfg->prevDev = dev->device();
    }

    emit deviceChanged( _vsrc );
    _view->repaint();
}


void QtVision::startCapture()
{
    kdDebug() << "QtVision::startCapture()" << endl;

    if (!_vsrc)
        return;
    
    if (_cfg->loadTuning(_vsrc->device(), _vsrc->source()) >= 0) {
        kdDebug() << "QTVision::startCapture() : Setting attributes" << endl;
        kdDebug() << "brightness = " << _cfg->brightness << " colour = " 
                  << _cfg->colour << " hue = " << _cfg->hue << " contrast = " 
                  << _cfg->contrast << endl;

        setBrightness(_cfg->brightness);
        setColour(_cfg->colour);
        setHue(_cfg->hue);
        setContrast(_cfg->contrast);
        setWhiteness(_cfg->whiteness);

        if (_cs->fileName().isEmpty()) {
            if (_cfg->channelFile.isEmpty()) {
                // create a new Channel file.
                _cs->load();
                _cfg->channelFile = _cs->fileName();
            } else {
                // load the Channel file
                _cs->load(_cfg->channelFile);
            }
        } else { 
            if (_cs->fileName() != _cfg->channelFile && !_cfg->channelFile.isEmpty()) {
                // load a different Channel file
                _cs->load(_cfg->channelFile);
            }
        }
    }

    if (_cs->isEmpty()) {
        importDefaultChannels();
    } else if (_cfg->firstTime) {
        setChannel(_cs->channelAt(0));
    } else {
        Channel *x = _cs->channelNumber(_cfg->lastChannel);
        Channel *y = x;

        if (!x)
            x = _cs->channelAt(0);

        while (x && !x->enabled() && x != y)
            x = _cs->channelAfter(x);

        setChannel(x);
    }

    kdDebug() << "QtVision::startCapture() -- starting video now!" << endl;
    if (_vsrc->startVideo() != 0)
        kdDebug() << "QtVision::startCapture() - ERROR STARTING VIDEO!" << endl;
}


void QtVision::stopDevice()
{
    if ( _vsrc ) {
        // setMuteVolume (true);
        _cfg->lastSource = _vsrc->source();
        _cfg->saveTuning(_vsrc->device(), _vsrc->source());
        _vsrc->stopVideo();
        delete _vsrc;
        _vsrc = 0;
        
        emit deviceChanged( _vsrc );
    }    
}


void QtVision::openChannelFile()
{
    QString p = KGlobal::dirs()->saveLocation("qtvision");
    QString fn = KFileDialog::getOpenFileName(p, QString("*"), _view, i18n("Select Channel File"));

    openChannelFile(fn);
}

void QtVision::importChannelFile()
{
    QString p = KGlobal::dirs()->saveLocation("qtvision");
    QString fn = KFileDialog::getOpenFileName(p, QString("*"), _view, i18n("Select Channel File"));

    if (fn.isEmpty())
        return;

    ChannelStore tcs( this, 0 );
    if (tcs.load(fn)) {
        _cs->addChannels(tcs);
    }
}

void QtVision::openChannelFile(const QString &filename)
{
    if (filename.isEmpty())
        return;

    _cs->clear();
    
    if (_cs->load(filename)) {
        _cfg->channelFile = filename;
        kdDebug() << "QtVision::openChannelFile(" << filename << ")" << endl;
        Channel *x = _cs->channelNumber(_cfg->lastChannel);
        Channel *y = x;

        if (!x)
            x = _cs->channelAt(0);

        while (x && !x->enabled() && x != y)
            x = _cs->channelAfter(x);

        _prevChannel = -1;
        setChannel(x);
    }
}


bool QtVision::doMigration()
{
    KGlobal::dirs()->addResourceType("kwintv", "share/apps/kwintv");
    QString p = KGlobal::dirs()->saveLocation("kwintv");

    if (p.isEmpty())
      return false;

    p += "/default.ch";

    if (!QFile::exists(p))
      return false;

    if (KMessageBox::Yes !=
      KMessageBox::questionYesNo(NULL, 
          i18n("Migrate old KWinTV configuration?"),
          i18n("QtVision"))) {
      return false;
    }

    _cs->setName("");
    bool rc = importLegacyChannels();
    _cfg->channelFile = _cs->fileName();  // set to the default name
    return rc;
}


bool QtVision::importLegacyChannels()
{
    KGlobal::dirs()->addResourceType("kwintv", "share/apps/kwintv");

    QString p = KGlobal::dirs()->saveLocation("kwintv");

    if (p.isEmpty())
      return false;

    p += "/default.ch";

    if (!QFile::exists(p))
      return false;

    QString oldname = _cs->fileName();
    openChannelFile(p);
    _cs->setName(oldname);
    _cfg->channelFile = oldname;
    Channel *x = _cs->channelNumber(_cfg->lastChannel);
    Channel *y = x;

    if (!x)
        x = _cs->channelAt(0);

    while (x && !x->enabled() && x != y)
        x = _cs->channelAfter(x);

    _prevChannel = -1;
    setChannel(x);

    return true;
}


void QtVision::importDefaultChannels()
{
    ChannelImportDlg *dlg = new ChannelImportDlg(_view);
    dlg->setDriver(this);
    dlg->populateWithDefaults();
    int rc = dlg->exec();

    if (rc == QDialog::Accepted) {
        QString fn = dlg->selectedFile();
        if (!fn.isEmpty()) {
            QString oldname = _cs->fileName();
            _cs->clear();
            _cs->load(fn);
            _cs->setName(oldname);
            if (_cfg->channelFile.isEmpty())
                _cfg->channelFile = oldname;

            Channel *x = _cs->channelNumber(_cfg->lastChannel);
            Channel *y = x;
            
            if (!x)
                x = _cs->channelAt(0);

            while (x && !x->enabled() && x != y)
                x = _cs->channelAfter(x);
            
            _prevChannel = -1;
            setChannel(x);
        }
    }

    delete dlg;
}

QString QtVision::channelName() const
{
    return _chan->name();
}

int QtVision::channelNumber() const
{
    return _chan->number();
}


void QtVision::setChannel( Channel *channel )
{
    if (!channel)
        return;

    //kdDebug() << "QtVision::setChannel()" << endl;
    
    if (_chan)
      _prevChannel = _chan->number ();
    
    _chan = channel;
    
    _cfg->lastChannel = _chan->number();               
     
    kdDebug() << "QtVision::setChannel(): emit channel changed" << endl;
    emit channelChanged( _chan->number() );
    emit channelChanged( _chan->name() );
    emit channelChanged( _chan );
     
    if (_vsrc) {
        kdDebug() << "QtVision::setChannel() to frequency: " << _chan->freq() << endl;
        _osd->displayChannel(_chan->number(), _chan->name());
        
        if (_am && !_muted) {
            if (ChannelVolState.changeEventId == -1) {
                kdDebug() << "QTVision::setChannel(): Volume => left = "
                          << ChannelVolState.left << ", right = "
                          << ChannelVolState.right << endl;
                ChannelVolState.left = _am->volumeLeft();
                ChannelVolState.right = _am->volumeRight();
            }
            
            _am->setVolume (0, 0);
            ChannelVolState.changeEventId = startTimer(_cfg->volumeRestoreDelay);
        }
        
        _vsrc->setFrequency(_chan->freq());
    }
}


void QtVision::setChannel(int channel)
{
    kdDebug () << "QTVision::setChannel (int)" << endl;
    // Ignore request if the channel number
    if (_chan && _chan->number () == channel)
    {
        _prevChannel = channel;
        return;
    }
        
    if (_cs->channelNumber(channel))
        setChannel(_cs->channelNumber(channel));
    else {
        if (_chan) {
            // if the new channel is not valid, just repeat the original number
            // so that the LCD display knows what to show
            kdDebug() << "emitting channelChanged((int) " << _chan->number() << ")" << endl;
            emit channelChanged(_chan->number());
        }
    }
    
    return;
} // setChannel


void QtVision::channelUp()
{
    Channel *c = _cs->channelAfter(_chan);

    if (!c)
        return;

    // skip channels that the user has disabled
    while (!c->enabled() && c != _chan)
        c = _cs->channelAfter(c);
    setChannel( c );
}


void QtVision::channelDown()
{
    Channel *c = _cs->channelBefore(_chan);

    if (!c)
        return;

    // skip channels that the user has disabled
    while (!c->enabled() && c != _chan)
        c = _cs->channelBefore(c);
    setChannel( c );
}

void QtVision::previousChannel()
{
    if (_prevChannel != -1)
      setChannel (_prevChannel);
}

void QtVision::setVideoDesktop( bool on )
{
    if (!_vsrc || _quitting)
      return;

    QByteArray qba;
    QDataStream arg(qba, IO_WriteOnly);
    
    arg << (bool)true;
    bool rc = kapp->dcopClient()->send("kdesktop", "KDesktopIface", "setVRoot(bool)", qba);
    
    kdDebug() << "kdesktop setVRoot returned " << (rc ? "true" : "false") << endl;
    if (_vsrc->canVideoDesktop())
        _vsrc->setVideoDesktop(on);

    // FIXME: this is an ugly hack really.  It won't work with other
    //        desktops (vroots), and it's not the right place for
    //        this anyways.
    if (!on) {
      rc = kapp->dcopClient()->send("kdesktop", "KDesktopIface", "refresh()", qba);
      kdDebug() << "kdesktop refresh returned " << (rc ? "true" : "false") << endl;
    }
}

void QtVision::startVideo()
{
    _vsrc->startVideo();
}

void QtVision::stopVideo()
{
    _vsrc->stopVideo();
}

void QtVision::snapshot()
{
    if (_vsrc->grabStill( &grabPix )) {
        QString mf = QString("qtvision-snapshot-%1.png").arg(_grabNumber++);
        while (QFileInfo(mf).exists())
            mf = QString("qtvision-snapshot-%1.png").arg(_grabNumber++);

        grabPix.save(mf, "PNG" );
        _sm->message(i18n("Snapshot saved to %1").arg(mf));
    } else {
        KMessageBox::sorry(_view, i18n("Error grabbing image.  Snapshots may not be supported with this plugin."), i18n("QtVision"));
    }
}

void QtVision::settings()
{
    _viewmng->launchSettings( _view );
}


void QtVision::setTunerMode( int mode )
{
    _cfg->nps = mode;
    if (_vsrc && _vsrc->needsNorm())
        _vsrc->setNorm(mode);
}


void QtVision::volumeMute()
{
    _muted = !_muted;
    setMuteVolume (_muted);
    emit volumeMuted (_muted);
}

void QtVision::setMuteVolume (bool mute)
{
    if ( _am ) {
        _am->setMuted(mute);
        kdDebug() << "QtVision::setMuteVolume(): Mixer says volume is "
                  << (_am->muted() ? "Muted" : "Not Muted")
                  << endl;    
    }
    if ( _vsrc ) {
        _vsrc->setMuted(mute);
        kdDebug() << "QtVision::setMuteVolume(): Tuner says volume is "
                  << (_am->muted() ? "Muted" : "Not Muted")
                  << endl;    
    }
}

void QtVision::volumeUp() {
    setVolume(_am->volumeLeft()+1, _am->volumeRight()+1);
}

void QtVision::volumeDown() {
    setVolume(QMAX(_am->volumeLeft()-1, 0), QMAX(_am->volumeRight()-1, 0));
}

void QtVision::setVolume(int left, int right) {
    // Unmute, set the flag to unmute and emit
    // a volumeMuted signal to update the GUI
    if (_muted)
    {
      _muted = false;
      emit volumeMuted (_muted);
    }
    
    _am->setVolume(left, right);
    emit volumeChanged(_am->volumeLeft(), _am->volumeRight());
}

void QtVision::setVolume(int vol) {
    setVolume(vol, vol);
}

QtVisionView *QtVision::createScreen( QWidget *parent, const char *name )
{
    _view = new QtVisionView( parent, name ? name : "qtvision_screen" );
    // Init the OSD
    _osd = new OSDManager(this, _view);
    // Load the other misc plugins
    _mm = new MiscManager(this, _view);

    // Make sure the TV background is black (looks best)
    _view->setPaletteBackgroundColor( QColor( 0, 0, 0 ) );

    // Check the setting of "Fix Aspect Ratio" and apply it.
    // The "Aspect Ratio Mode" determines how the algorithm works.
    if ( _cfg->fixAR ) {
      _view->setFixedAspectRatio( ASPECT_RATIO_NORMAL, _cfg->ARmode );
    } else {
      _view->setFixedAspectRatio( ASPECT_RATIO_NONE, _cfg->ARmode );
    }

    connect(_view, SIGNAL(resized(int,int)), this, SLOT(viewResized(int,int)));
    connect(_view, SIGNAL(moved(int,int)), this, SLOT(viewMoved(int,int)));
    connect(_view, SIGNAL(channelUp()), this, SLOT(channelUp()));
    connect(_view, SIGNAL(channelDown()), this, SLOT(channelDown()));
    connect(_view, SIGNAL(numberKeyPressed(int)), this, SLOT(processNumberKeyEvent(int)));

    connect(this, SIGNAL(volumeChanged(int,int)), _osd, SLOT(displayVolume(int,int)));
    connect(this, SIGNAL(volumeMuted(bool)), _osd, SLOT(displayMuted(bool)));
    connect(this, SIGNAL(channelText(const QString &)), _osd, SLOT(displayMisc(const QString &)));

    // Connect the _viewmanager's signals to the slots to propagate configuration _changes
    connect(_viewmng, SIGNAL(setFixedAspectRatio(bool, int)), _view,
            SLOT(setFixedAspectRatio(bool, int)));

    return _view;
}


void QtVision::viewResized(int w, int h)
{
    if (_vsrc) {
        _vsrc->viewResized(w,h);
    }
}


void QtVision::viewMoved(int x, int y)
{
    if (_vsrc) {
        _vsrc->viewMoved(x,y);
    }
}


int QtVision::launchWizard()
{
    if ( !hasDevice() ) {
      selectDevice();
      if ( !hasDevice() )
          return QDialog::Rejected;
    }

    return _viewmng->launchWizard( _view );
}


void QtVision::setBrightness(int val)
{
    if (_vsrc) {
        _vsrc->setBrightness(val);
        _cfg->brightness = val;
    }
}

void QtVision::setColour(int val)
{
    if (_vsrc) {
        _vsrc->setColour(val);
        _cfg->colour = val;
    }
}

void QtVision::setHue(int val)
{
    if (_vsrc) {
        _vsrc->setHue(val);
        _cfg->hue = val;
    }
}

void QtVision::setContrast(int val)
{
    if (_vsrc) {
        _vsrc->setContrast(val);
        _cfg->contrast = val;
    }
}

void QtVision::setWhiteness(int val)
{
    if (_vsrc) {
        _vsrc->setWhiteness(val);
        _cfg->whiteness = val;
    }
}


int QtVision::brightness() {
    if (_vsrc) {
        return _vsrc->brightness();
    }
    return 0;
}


QColor QtVision::colourKey() {
    if (_vsrc) {
        return _vsrc->colourKey();
    }
    return QColor();
}


int QtVision::colour() {
    if (_vsrc) {
        return _vsrc->colour();
    }
    return 0;
}


int QtVision::hue() {
    if (_vsrc) {
        return _vsrc->hue();
    }
    return 0;
}


int QtVision::contrast() {
    if (_vsrc) {
        return _vsrc->contrast();
    }
    return 0;
}


int QtVision::whiteness() {
    if (_vsrc) {
        return _vsrc->whiteness();
    }
    return 0;
}


void QtVision::aboutToQuit() {
    _quitting = true;
}

void QtVision::timerEvent (QTimerEvent *ev) {
    if (ev) {
        if (ChannelVolState.changeEventId == ev->timerId ()) {
        
            kdDebug() << "QtVision::timerEvent: restoreVolume, event id = "
                      << ev->timerId () << ", Left volume = " << ChannelVolState.left
                      << ", Right volume = " << ChannelVolState.right
                      << endl;
                      
            // Restore the volume to whatever level it was before
            // change channel requests.
            if (_am)
                _am->setVolume (ChannelVolState.left, ChannelVolState.right);

            ChannelVolState.changeEventId = -1;
        }
        killTimer (ev->timerId());
    }
}

void QtVision::processNumberKeyEvent(int key)
{
    if (_mm->filterNumberKey(key))
        return;
    if (_keypresstimer->isActive())
        _keypresstimer->stop();

    // key == -1 means ENTER was pressed. Simply force a 
    // channel change and return...
    if (key == -1)
    {
        slotKeyPressTimeout ();
        return;
    }

    Q_ASSERT (_cs);

    // Get the highest channel number...
    Channel * ch = _cs->channelAt (_cs->count()-1);
    Q_ASSERT (ch);
    int maxChNum = ch->number();

    // For every '0' entered before the number lower the max channel by
    // 10 times
    int len = _number.length();
        
    for (int i = 0; i < len && _number[i] == '0'; i++)
        maxChNum /= 10;

    _number += QString::number(key);

    // If by entering another digit you can get a number lesser than
    // the highest channel number configured/detected, start a timer
    // (wait for that next keypress).
    // Otherwise, simply tune to the channel.
    if (_number.toInt() * 10 < maxChNum) {
        kdDebug() << "channelText(" << _number.rightJustify(3,'-') << ")" << endl;
        emit channelText(_number.rightJustify(3,'-'));
        _keypresstimer->start(2000, true);  // start the count-down timer
    } else {
        if (_number != "0")
            _keypresstimer->singleShot(0, this, SLOT(slotKeyPressTimeout()));
    } // else
}// processNumberKeyEvent


void QtVision::slotKeyPressTimeout()
{
    if (_number != "0") {
        kdDebug() << "QtVision: calling setChannel(" << _number << ")" << endl;
        setChannel(_number.toInt());
    }

    _number = "";
    return;
} // slotKeyPressTimeout

--Boundary-00=_sXZh+Bls+90gqAX--