diff -r 000000000000 -r 1918ee327afb tools/qvfb/qvfbshmem.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/qvfb/qvfbshmem.cpp Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,314 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlock_p.h" + +#include "qvfbshmem.h" +#include "qvfbhdr.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +#ifdef Q_WS_QWS +#error qvfb must be compiled with the Qt for X11 package +#endif + +// Get the name of the directory where Qt for Embedded Linux temporary data should +// live. +static QString qws_dataDir(int qws_display_id) +{ + QByteArray dataDir = QT_VFB_DATADIR(qws_display_id).toLocal8Bit(); + if (mkdir(dataDir, 0700)) { + if (errno != EEXIST) { + qFatal("Cannot create Qt for Embedded Linux data directory: %s", dataDir.constData()); + } + } + + struct stat buf; + if (lstat(dataDir, &buf)) + qFatal("stat failed for Qt for Embedded Linux data directory: %s", dataDir.constData()); + + if (!S_ISDIR(buf.st_mode)) + qFatal("%s is not a directory", dataDir.constData()); + if (buf.st_uid != getuid()) + qFatal("Qt for Embedded Linux data directory is not owned by user %uh", getuid()); + + if ((buf.st_mode & 0677) != 0600) + qFatal("Qt for Embedded Linux data directory has incorrect permissions: %s", dataDir.constData()); + dataDir += "/"; + + return QString(dataDir); +} + + +static QString displayPipe; +static QString displayPiped; +class DisplayLock +{ +public: + DisplayLock() : qlock(0) { + if (QFile::exists(displayPiped)) { + qlock = new QLock(displayPipe, 'd', false); + qlock->lock(QLock::Read); + } + } + ~DisplayLock() { + if (qlock) { + qlock->unlock(); + delete qlock; + qlock = 0; + } + } +private: + QLock *qlock; +}; + +QShMemViewProtocol::QShMemViewProtocol(int displayid, const QSize &s, + int d, QObject *parent) + : QVFbViewProtocol(displayid, parent), hdr(0), dataCache(0), lockId(-1), + windowId(0) +{ + int w = s.width(); + int h = s.height(); + + QString username = "unknown"; + const char *logname = getenv("LOGNAME"); + if ( logname ) + username = logname; + + qws_dataDir(displayid); + + QString oldPipe = "/tmp/qtembedded-" + username + "/" + QString("QtEmbedded-%1").arg(displayid); + int oldPipeSemkey = ftok(oldPipe.toLatin1().constData(), 'd'); + if (oldPipeSemkey != -1) { + int oldPipeLockId = semget(oldPipeSemkey, 0, 0); + if (oldPipeLockId >= 0){ + sembuf sops; + sops.sem_num = 0; + sops.sem_op = 1; + sops.sem_flg = SEM_UNDO; + int rv; + do { + rv = semop(lockId,&sops,1); + } while (rv == -1 && errno == EINTR); + + perror("QShMemViewProtocol::QShMemViewProtocol"); + qFatal("Cannot create lock file as an old version of QVFb has " + "opened %s. Close other QVFb and try again", + oldPipe.toLatin1().constData()); + } + } + + displayPipe = QTE_PIPE_QVFB(displayid); + + kh = new QVFbKeyPipeProtocol(displayid); + /* should really depend on receiving qt version, but how can + one tell? */ + mh = new QVFbMousePipe(displayid); + + QString mousePipe = mh->pipeName(); + + key_t key = ftok(mousePipe.toLatin1().constData(), 'b'); + + int bpl; + if (d < 8) + bpl = (w * d + 7) / 8; + else + bpl = w * ((d + 7) / 8); + + displaySize = bpl * h; + + unsigned char *data; + uint data_offset_value = sizeof(QVFbHeader); + + int dataSize = bpl * h + data_offset_value; + shmId = shmget(key, dataSize, IPC_CREAT | 0666); + if (shmId != -1) + data = (unsigned char *)shmat(shmId, 0, 0); + else { + struct shmid_ds shm; + shmctl(shmId, IPC_RMID, &shm); + shmId = shmget(key, dataSize, IPC_CREAT | 0666); + if (shmId == -1) { + perror("QShMemViewProtocol::QShMemViewProtocol"); + qFatal("Cannot get shared memory 0x%08x", key); + } + data = (unsigned char *)shmat(shmId, 0, 0); + } + + if ((long)data == -1) { + delete kh; + delete mh; + perror("QShMemViewProtocol::QShMemViewProtocol"); + qFatal("Cannot attach to shared memory %d",shmId); + } + dataCache = (unsigned char *)malloc(displaySize); + memset(dataCache, 0, displaySize); + memset(data+sizeof(QVFbHeader), 0, displaySize); + + hdr = (QVFbHeader *)data; + hdr->width = w; + hdr->height = h; + hdr->depth = d; + hdr->linestep = bpl; + hdr->dataoffset = data_offset_value; + hdr->update = QRect(); + hdr->dirty = 0; + hdr->numcols = 0; + hdr->viewerVersion = QT_VERSION; + hdr->brightness = 255; + hdr->windowId = 0; + + displayPiped = displayPipe + 'd'; + + + mRefreshTimer = new QTimer(this); + connect(mRefreshTimer, SIGNAL(timeout()), this, SLOT(flushChanges())); +} + +QShMemViewProtocol::~QShMemViewProtocol() +{ + struct shmid_ds shm; + shmdt( (char*)hdr ); + shmctl( shmId, IPC_RMID, &shm ); + free(dataCache); + delete kh; + delete mh; +} + +int QShMemViewProtocol::width() const +{ + return hdr->width; +} + +int QShMemViewProtocol::height() const +{ + return hdr->height; +} + +int QShMemViewProtocol::depth() const +{ + return hdr->depth; +} + +int QShMemViewProtocol::linestep() const +{ + return hdr->linestep; +} + +int QShMemViewProtocol::numcols() const +{ + return hdr->numcols; +} + +QVector QShMemViewProtocol::clut() const +{ + QVector vector(hdr->numcols); + for (int i=0; i < hdr->numcols; ++i) + vector[i]=hdr->clut[i]; + + return vector; +} + +unsigned char *QShMemViewProtocol::data() const +{ + return dataCache; + //return ((unsigned char *)hdr)+hdr->dataoffset; +} + +int QShMemViewProtocol::brightness() const +{ + return hdr->brightness; +} + +void QShMemViewProtocol::flushChanges() +{ + QRect r; + if (hdr->dirty) { + DisplayLock(); + + hdr->dirty = false; + r = hdr->update; + hdr->update = QRect(); + + if (hdr->windowId != windowId) { + windowId = hdr->windowId; + emit displayEmbedRequested(hdr->windowId); + } else if (!hdr->windowId) { + // copy the memory area, for now, be inefficient. + memcpy(dataCache, ((char *)hdr) + hdr->dataoffset, displaySize); + } + } + emit displayDataChanged(r); +} + +void QShMemViewProtocol::setRate(int interval) +{ + if (interval > 0) + return mRefreshTimer->start(1000/interval); + else + mRefreshTimer->stop(); +} + +int QShMemViewProtocol::rate() const +{ + int i = mRefreshTimer->interval(); + if (i > 0) + return 1000/i; + else + return 0; +} + +QT_END_NAMESPACE