/* qlscribe - Qt based application to print lightScribe discs Copyright (C) 2009 Vyacheslav Kononenko This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA $Id$ */ #include "qlightscribe.h" #include "qcdscene.h" #include #include #include #include #include #include using namespace LightScribe; struct QLightScribe::Task { enum Action { getDrives, preview, print, stop }; Action m_action; bool m_done; QLightDrive *m_selectedDrive; PrintParameters m_parameters; QSize m_size; QImage *m_image; QList< QLightDrive * > m_drives; QTemporaryFile m_tmpFile; QString m_error; Task( Action action ) : m_action( action ), m_done( false ), m_selectedDrive( 0 ), m_image( 0 ) {} ~Task() { delete m_image; } }; QLightScribe *QLightScribe::instance() { static QLightScribe inst; return &inst; } QLightScribe::QLightScribe() : m_task( 0 ), m_aborted( false ), m_mutex( new QMutex ), m_waitQueue( new QWaitCondition ), m_waitDone( new QWaitCondition ) { start(); } QLightScribe::~QLightScribe() { delete m_waitDone; delete m_waitQueue; delete m_mutex; } QList< QLightDrive * > QLightScribe::getDrives( bool refresh ) { if( m_drives.empty() || refresh ) { QMutexLocker lock( m_mutex ); if( m_task ) // what should we do? return m_drives; m_task = new Task( Task::getDrives ); m_waitQueue->wakeOne(); while( !m_task->m_done ) m_waitDone->wait( m_mutex ); while( m_drives.count() ) { delete m_drives.front(); m_drives.erase( m_drives.begin() ); } m_drives = m_task->m_drives; delete m_task; m_task = 0; } return m_drives; } static QImage *printScene( QCDScene *scene ) { QImage *image = new QImage( 2772, 2772, QImage::Format_RGB888 ); image->fill( 0xFFFFFFFF ); scene->clearSelection(); { QPainter painter( image ); scene->render( &painter, image->rect() ); } image->setDotsPerMeterX( 23622 ); image->setDotsPerMeterY( 23622 ); return image; } QPixmap QLightScribe::preview( QLightDrive *drive, const PrintParameters ¶ms, QCDScene *scene, const QSize &size ) throw( QString ) { QMutexLocker lock( m_mutex ); if( m_task ) // what should we do? return QPixmap(); m_task = new Task( Task::preview ); m_task->m_selectedDrive = drive; m_task->m_parameters = params; m_task->m_size = size; m_task->m_image = printScene( scene ); m_aborted = false; m_waitQueue->wakeOne(); while( !m_task->m_done ) m_waitDone->wait( m_mutex ); QString err = m_task->m_error; QPixmap pixmap; if( err.isEmpty() ) pixmap.load( m_task->m_tmpFile.fileName(), "bmp" ); delete m_task; m_task = 0; if( !err.isEmpty() ) throw err; return pixmap; } void QLightScribe::print( QLightDrive *drive, const PrintParameters ¶ms, QCDScene *scene ) { QMutexLocker lock( m_mutex ); if( m_task ) // what should we do? return; m_task = new Task( Task::print ); m_task->m_selectedDrive = drive; m_task->m_parameters = params; m_task->m_image = printScene( scene ); m_aborted = false; m_waitQueue->wakeOne(); } void QLightScribe::abort() { m_aborted = true; } void QLightScribe::stopThread() { QMutexLocker lock( m_mutex ); delete m_task; m_task = new Task( Task::stop ); m_waitQueue->wakeOne(); } bool QLightScribe::clAbortLabel() { return QLightScribe::instance()->m_aborted; } void QLightScribe::clReportPrepareProgress(long current, long final) { emit instance()->prepareProgress( current, final ); } void QLightScribe::clReportLabelProgress(long current, long final) { emit instance()->labelProgress( current, final ); } void QLightScribe::clReportFinished(LSError status) { emit instance()->finished( status ); } bool QLightScribe::clReportLabelTimeEstimate(long time) { emit instance()->timeEstimate( time ); return false; } extern uid_t realUserId; void QLightScribe::run() { QMutexLocker lock( m_mutex ); while( true ) { while( m_task == 0 || m_task->m_done ) m_waitQueue->wait( m_mutex ); if( m_task->m_action == Task::stop ) break; QString function; try { function = "LS_DiscPrintMgr_Create"; DiscPrintMgr manager; function = "LS_DiscPrintMgr_EnumDiscPrinters"; EnumDiscPrinters printers = manager.EnumDiscPrinters(); function = ""; if( m_task->m_action == Task::getDrives ) { const unsigned count = printers.Count(); for( unsigned i = 0; i < count; ++i ) { DiscPrinter printer = printers.Item( i ); QLightDrive *drive = new QLightDrive; drive->m_displayName = QString::fromStdString( printer.GetPrinterDisplayName() ); drive->m_productName = QString::fromStdString( printer.GetPrinterProductName() ); drive->m_vendorName = QString::fromStdString( printer.GetPrinterVendorName() ); drive->m_path = QString::fromStdString( printer.GetPrinterPath() ); drive->m_innerRadius = printer.GetDriveInnerRadius() / 1000.0; drive->m_outerRadius = printer.GetDriveOuterRadius() / 1000.0; m_task->m_drives.append( drive ); } } else { QByteArray ba; QBuffer buffer( &ba ); buffer.open( QIODevice::WriteOnly ); m_task->m_image->save( &buffer, "bmp", 100 ); int found = -1; for( size_t i = 0; i < printers.Count(); ++i ) if( printers.Item( i ).GetPrinterDisplayName() == m_task->m_selectedDrive->displayName().toStdString() ) { found = i; break; } if( found == -1 ) throw tr( "Cannot find drive: \"" ) + m_task->m_selectedDrive->displayName() + "\""; DiscPrinter printer = printers.Item( found ); if( m_task->m_action == Task::print ) { setreuid( realUserId, 0 ); function = "LS_DiscPrinter_AddExclusiveUse"; printer.AddExclusiveUse(); function = "LS_DiscPrinter_LockDriveTray"; printer.LockDriveTray(); } { function = "LS_DiscPrinter_OpenPrintSession"; DiscPrintSession session = printer.OpenPrintSession(); LS_PrintCallbacks callbacks; callbacks.AbortLabel = clAbortLabel; callbacks.ReportPrepareProgress = clReportPrepareProgress; callbacks.ReportLabelProgress = clReportLabelProgress; callbacks.ReportFinished = clReportFinished; callbacks.ReportLabelTimeEstimate = clReportLabelTimeEstimate; session.SetProgressCallback( &callbacks ); const size_t bitmapHeaderSize = 54; if( m_task->m_action == Task::preview ) { LS_Size size; size.x = m_task->m_size.width(); size.y = m_task->m_size.height(); m_task->m_tmpFile.open(); function = "LS_DiscPrintSession_PrintPreview"; session.PrintPreview( LS_windows_bitmap, LS_LabelMode( m_task->m_parameters.m_labelMode ), LS_DrawOptions( m_task->m_parameters.m_drawOptions ), LS_PrintQuality( m_task->m_parameters.m_printQuality ), LS_MediaOptimizationLevel( m_task->m_parameters.m_mediaOptimizationLevel ), ba.data() + 14, bitmapHeaderSize - 14, ba.data() + bitmapHeaderSize, ba.size() - bitmapHeaderSize, m_task->m_tmpFile.fileName().toAscii().data(), LS_windows_bitmap, size, true ); } else { PrintParameters params = m_task->m_parameters; delete m_task; m_task = 0; lock.unlock(); // print here try { session.PrintDisc( LS_windows_bitmap, LS_LabelMode( params.m_labelMode ), LS_DrawOptions( params.m_drawOptions ), LS_PrintQuality( params.m_printQuality ), LS_MediaOptimizationLevel( params.m_mediaOptimizationLevel ), ba.data() + 14, bitmapHeaderSize - 14, ba.data() + bitmapHeaderSize, ba.size() - bitmapHeaderSize ); } catch( LightScribe::LSException &ex ) { emit finished( ex.GetCode() ); throw; } } } if( m_task->m_action == Task::print ) { function = "LS_DiscPrinter_UnlockDriveTray"; printer.UnlockDriveTray(); function = "LS_DiscPrinter_ReleaseExclusiveUse"; printer.ReleaseExclusiveUse(); setreuid( 0, realUserId ); } function = ""; } } catch( LightScribe::LSException &ex ) { if( m_task ) m_task->m_error = function + tr( " failed with code 0x" ) + QString::number( ex.GetCode(), 16 ); } catch( const QString &err ) { if( m_task ) m_task->m_error = err; } if( m_task ) { m_task->m_done = true; m_waitDone->wakeAll(); } } }