//------------------------------------------------------------------------ // Copyright 2008-2009 (c) Jeff Brown // // This file is part of the ZBar Bar Code Reader. // // The ZBar Bar Code Reader is free software; you can redistribute it // and/or modify it under the terms of the GNU Lesser Public License as // published by the Free Software Foundation; either version 2.1 of // the License, or (at your option) any later version. // // The ZBar Bar Code Reader 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 Lesser Public License for more details. // // You should have received a copy of the GNU Lesser Public License // along with the ZBar Bar Code Reader; if not, write to the Free // Software Foundation, Inc., 51 Franklin St, Fifth Floor, // Boston, MA 02110-1301 USA // // http://sourceforge.net/projects/zbar //------------------------------------------------------------------------ #include #include #include #include #include "QZBarThread.h" using namespace zbar; QZBar::QZBar(QWidget *parent, int verbosity) : QWidget(parent), thread(NULL), _videoDevice(), _videoEnabled(false), _attached(false) { setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_PaintOnScreen); #if QT_VERSION >= 0x040400 setAttribute(Qt::WA_NativeWindow); setAttribute(Qt::WA_DontCreateNativeAncestors); #endif QSizePolicy sizing(QSizePolicy::Preferred, QSizePolicy::Preferred); sizing.setHeightForWidth(true); setSizePolicy(sizing); thread = new QZBarThread(verbosity); if (testAttribute(Qt::WA_WState_Created)) { #if QT_VERSION >= 0x050000 thread->window.attach(QX11Info::display(), winId()); #else thread->window.attach(x11Info().display(), winId()); #endif _attached = 1; } connect(thread, SIGNAL(videoOpened(bool)), this, SIGNAL(videoOpened(bool))); connect(this, SIGNAL(videoOpened(bool)), this, SLOT(sizeChange())); connect(thread, SIGNAL(update()), this, SLOT(update())); connect(thread, SIGNAL(decoded(int, const QString &)), this, SIGNAL(decoded(int, const QString &))); connect(thread, SIGNAL(decodedText(const QString &)), this, SIGNAL(decodedText(const QString &))); thread->start(); } QZBar::~QZBar() { if (thread) { thread->pushEvent(new QEvent((QEvent::Type)QZBarThread::Exit)); thread->wait(); delete thread; thread = NULL; } } QPaintEngine *QZBar::paintEngine() const { return (NULL); } QString QZBar::videoDevice() const { return (_videoDevice); } void QZBar::setVideoDevice(const QString &videoDevice) { if (!thread) return; if (_videoDevice != videoDevice) { _videoDevice = videoDevice; _videoEnabled = _attached && !videoDevice.isEmpty(); if (_attached) thread->pushEvent(new QZBarThread::VideoDeviceEvent(videoDevice)); } } int QZBar::get_controls(int index, char **name, char **group, enum ControlType *type, int *min, int *max, int *def, int *step) { if (!thread) return 0; return thread->get_controls(index, name, group, type, min, max, def, step); } void QZBar::request_size(unsigned width, unsigned height, bool trigger) { if (!thread) return; thread->request_size(width, height); if (trigger) thread->pushEvent(new QEvent((QEvent::Type)QZBarThread::ReOpen)); } int QZBar::get_resolution(int index, unsigned &width, unsigned &height, float &max_fps) { if (!thread) return 0; return thread->get_resolution(index, width, height, max_fps); } unsigned QZBar::videoWidth() { if (!thread) return 0; return thread->reqWidth; } unsigned QZBar::videoHeight() { if (!thread) return 0; return thread->reqHeight; } QVector > QZBar::get_menu(int index) { if (!thread) { QVector > empty; return empty; } return thread->get_menu(index); } int QZBar::set_control(char *name, bool value) { if (!thread) return 0; return thread->set_control(name, value); } int QZBar::set_control(char *name, int value) { if (!thread) return 0; return thread->set_control(name, value); } int QZBar::get_control(char *name, bool *value) { if (!thread) return 0; return thread->get_control(name, value); } int QZBar::get_control(char *name, int *value) { if (!thread) return 0; return thread->get_control(name, value); } int QZBar::set_config(std::string cfgstr) { if (!thread) return 0; return thread->set_config(cfgstr); } int QZBar::set_config(zbar_symbol_type_t symbology, zbar_config_t config, int value) { if (!thread) return 0; return thread->set_config(symbology, config, value); } int QZBar::get_config(zbar_symbol_type_t symbology, zbar_config_t config, int &value) { if (!thread) return 0; return thread->get_config(symbology, config, value); } int QZBar::request_dbus(bool enabled) { if (!thread) return 0; return thread->request_dbus(enabled); } bool QZBar::isVideoEnabled() const { return (_videoEnabled); } void QZBar::setVideoEnabled(bool videoEnabled) { if (!thread) return; if (_videoEnabled != videoEnabled) { _videoEnabled = videoEnabled; thread->pushEvent(new QZBarThread::VideoEnabledEvent(videoEnabled)); } } bool QZBar::isVideoOpened() const { if (!thread) return (false); QMutexLocker locker(&thread->mutex); return (thread->_videoOpened); } void QZBar::scanImage(const QImage &image) { if (!thread) return; thread->pushEvent(new QZBarThread::ScanImageEvent(image)); } void QZBar::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasImage() || event->mimeData()->hasUrls()) event->acceptProposedAction(); } void QZBar::dropEvent(QDropEvent *event) { if (event->mimeData()->hasImage()) { QImage image = qvariant_cast(event->mimeData()->imageData()); scanImage(image); event->setDropAction(Qt::CopyAction); event->accept(); } else { // FIXME TBD load URIs and queue for processing #if 0 std::cerr << "drop: " << event->mimeData()->formats().join(", ").toStdString() << std::endl; QList urls = event->mimeData()->urls(); for(int i = 0; i < urls.size(); ++i) std::cerr << "[" << i << "] " << urls.at(i).toString().toStdString() << std::endl; #endif } } QSize QZBar::sizeHint() const { if (!thread) return (QSize(640, 480)); QMutexLocker locker(&thread->mutex); return (QSize(thread->reqWidth, thread->reqHeight)); } int QZBar::heightForWidth(int width) const { if (thread) { QMutexLocker locker(&thread->mutex); int base_width = thread->reqWidth; int base_height = thread->reqHeight; if (base_width > 0 && base_height > 0) return (base_height * width / base_width); } return (width * 3 / 4); } void QZBar::paintEvent(QPaintEvent *event) { try { if (thread) thread->window.redraw(); } catch (Exception &) { // sometimes Qt attempts to paint the widget before it's parented(?) // just ignore this (can't throw from event anyway) } } void QZBar::resizeEvent(QResizeEvent *event) { QSize size = event->size(); try { if (thread) thread->window.resize(size.rwidth(), size.rheight()); } catch (Exception &) { /* ignore */ } } void QZBar::changeEvent(QEvent *event) { try { QMutexLocker locker(&thread->mutex); if (event->type() == QEvent::ParentChange) #if QT_VERSION >= 0x050000 thread->window.attach(QX11Info::display(), winId()); #else thread->window.attach(x11Info().display(), winId()); #endif } catch (Exception &) { /* ignore (FIXME do something w/error) */ } } void QZBar::attach() { if (_attached) return; try { #if QT_VERSION >= 0x050000 thread->window.attach(QX11Info::display(), winId()); #else thread->window.attach(x11Info().display(), winId()); #endif thread->window.resize(width(), height()); _attached = 1; _videoEnabled = !_videoDevice.isEmpty(); if (_videoEnabled) thread->pushEvent(new QZBarThread::VideoDeviceEvent(_videoDevice)); } catch (Exception &) { /* ignore (FIXME do something w/error) */ } } void QZBar::showEvent(QShowEvent *event) { if (thread && !_attached) attach(); } void QZBar::sizeChange() { update(); updateGeometry(); }